Page MenuHomeFreeBSD

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/.depend b/.depend
index c7bff499c5a3..78629a54c8ad 100644
--- a/.depend
+++ b/.depend
@@ -1,183 +1,183 @@
# Automatically generated by makedepend.
# Run "make depend" to rebuild.
# DO NOT DELETE
addr.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h addr.h
-addrmatch.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h addr.h match.h log.h ./ssherr.h
+addrmatch.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h addr.h match.h log.h ssherr.h
atomicio.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h atomicio.h
audit-bsm.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
audit-linux.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
audit.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
auth-bsdauth.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-auth-krb5.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ./ssherr.h sshbuf.h sshkey.h misc.h servconf.h uidswap.h hostfile.h auth.h auth-pam.h audit.h loginrec.h
-auth-options.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ./ssherr.h log.h sshbuf.h misc.h sshkey.h match.h ssh2.h auth-options.h
+auth-krb5.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h sshkey.h misc.h servconf.h uidswap.h hostfile.h auth.h auth-pam.h audit.h loginrec.h
+auth-options.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssherr.h log.h sshbuf.h misc.h sshkey.h match.h ssh2.h auth-options.h
auth-pam.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-auth-passwd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h packet.h openbsd-compat/sys-queue.h dispatch.h sshbuf.h ./ssherr.h log.h misc.h servconf.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth-options.h
-auth-rhosts.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h packet.h openbsd-compat/sys-queue.h dispatch.h uidswap.h pathnames.h log.h ./ssherr.h misc.h sshbuf.h sshkey.h servconf.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h
+auth-passwd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h packet.h openbsd-compat/sys-queue.h dispatch.h sshbuf.h ssherr.h log.h misc.h servconf.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth-options.h
+auth-rhosts.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h packet.h openbsd-compat/sys-queue.h dispatch.h uidswap.h pathnames.h log.h ssherr.h misc.h sshbuf.h sshkey.h servconf.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h
auth-shadow.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
auth-sia.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
auth.o: authfile.h monitor_wrap.h compat.h channels.h
-auth.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h match.h groupaccess.h log.h ./ssherr.h sshbuf.h misc.h servconf.h openbsd-compat/sys-queue.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth-options.h canohost.h uidswap.h packet.h dispatch.h
-auth2-chall.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh2.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h sshbuf.h packet.h openbsd-compat/sys-queue.h dispatch.h ./ssherr.h log.h misc.h servconf.h
+auth.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h match.h groupaccess.h log.h ssherr.h sshbuf.h misc.h servconf.h openbsd-compat/sys-queue.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth-options.h canohost.h uidswap.h packet.h dispatch.h
+auth2-chall.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh2.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h sshbuf.h packet.h openbsd-compat/sys-queue.h dispatch.h ssherr.h log.h misc.h servconf.h
auth2-gss.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
auth2-hostbased.o: canohost.h monitor_wrap.h pathnames.h match.h
-auth2-hostbased.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h kex.h mac.h crypto_api.h sshbuf.h log.h ./ssherr.h misc.h servconf.h compat.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h
-auth2-kbdint.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h packet.h openbsd-compat/sys-queue.h dispatch.h hostfile.h auth.h auth-pam.h audit.h loginrec.h log.h ./ssherr.h misc.h servconf.h
-auth2-none.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h atomicio.h xmalloc.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ./ssherr.h misc.h servconf.h compat.h ssh2.h monitor_wrap.h
-auth2-passwd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h packet.h openbsd-compat/sys-queue.h dispatch.h ./ssherr.h log.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h monitor_wrap.h misc.h servconf.h
-auth2-pubkey.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h kex.h mac.h crypto_api.h sshbuf.h log.h ./ssherr.h misc.h servconf.h compat.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h
+auth2-hostbased.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h kex.h mac.h crypto_api.h sshbuf.h log.h ssherr.h misc.h servconf.h compat.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h
+auth2-kbdint.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h packet.h openbsd-compat/sys-queue.h dispatch.h hostfile.h auth.h auth-pam.h audit.h loginrec.h log.h ssherr.h misc.h servconf.h
+auth2-none.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h atomicio.h xmalloc.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h misc.h servconf.h compat.h ssh2.h monitor_wrap.h
+auth2-passwd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h packet.h openbsd-compat/sys-queue.h dispatch.h ssherr.h log.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h monitor_wrap.h misc.h servconf.h
+auth2-pubkey.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h kex.h mac.h crypto_api.h sshbuf.h log.h ssherr.h misc.h servconf.h compat.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h
auth2-pubkey.o: pathnames.h uidswap.h auth-options.h canohost.h monitor_wrap.h authfile.h match.h channels.h session.h sk-api.h
auth2.o: digest.h
-auth2.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h atomicio.h xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ./ssherr.h sshbuf.h misc.h servconf.h compat.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h pathnames.h monitor_wrap.h
-authfd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h sshbuf.h sshkey.h authfd.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h compat.h log.h ./ssherr.h atomicio.h misc.h
-authfile.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h ssh.h log.h ./ssherr.h authfile.h misc.h atomicio.h sshkey.h sshbuf.h krl.h
+auth2.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h atomicio.h xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h misc.h servconf.h compat.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h pathnames.h monitor_wrap.h
+authfd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h sshbuf.h sshkey.h authfd.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h compat.h log.h ssherr.h atomicio.h misc.h
+authfile.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h ssh.h log.h ssherr.h authfile.h misc.h atomicio.h sshkey.h sshbuf.h krl.h
bitmap.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h bitmap.h
-canohost.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ./ssherr.h canohost.h misc.h
+canohost.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h canohost.h misc.h
chacha.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h chacha.h
-channels.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h ./ssherr.h sshbuf.h packet.h dispatch.h log.h misc.h channels.h compat.h canohost.h sshkey.h authfd.h pathnames.h match.h
+channels.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h ssherr.h sshbuf.h packet.h dispatch.h log.h misc.h channels.h compat.h canohost.h sshkey.h authfd.h pathnames.h match.h
cipher-aes.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/openssl-compat.h
cipher-aesctr.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h cipher-aesctr.h rijndael.h
cipher-chachapoly-libcrypto.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-cipher-chachapoly.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ./ssherr.h sshbuf.h cipher-chachapoly.h chacha.h poly1305.h
+cipher-chachapoly.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h sshbuf.h cipher-chachapoly.h chacha.h poly1305.h
cipher-ctr.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-cipher.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h misc.h sshbuf.h ./ssherr.h digest.h openbsd-compat/openssl-compat.h
-cleanup.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ./ssherr.h
+cipher.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h misc.h sshbuf.h ssherr.h digest.h openbsd-compat/openssl-compat.h
+cleanup.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h
clientloop.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h packet.h dispatch.h sshbuf.h compat.h channels.h sshkey.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h kex.h mac.h crypto_api.h
-clientloop.o: myproposal.h log.h ./ssherr.h misc.h readconf.h clientloop.h sshconnect.h authfd.h atomicio.h sshpty.h match.h msg.h hostfile.h
-compat.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h packet.h openbsd-compat/sys-queue.h dispatch.h compat.h log.h ./ssherr.h match.h kex.h mac.h crypto_api.h
+clientloop.o: myproposal.h log.h ssherr.h misc.h readconf.h clientloop.h sshconnect.h authfd.h atomicio.h sshpty.h match.h msg.h hostfile.h
+compat.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h packet.h openbsd-compat/sys-queue.h dispatch.h compat.h log.h ssherr.h match.h kex.h mac.h crypto_api.h
dh.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-digest-libc.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./ssherr.h sshbuf.h digest.h
+digest-libc.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssherr.h sshbuf.h digest.h
digest-openssl.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-dispatch.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh2.h log.h ./ssherr.h dispatch.h packet.h openbsd-compat/sys-queue.h compat.h
-dns.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h sshkey.h ./ssherr.h dns.h log.h digest.h
+dispatch.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh2.h log.h ssherr.h dispatch.h packet.h openbsd-compat/sys-queue.h compat.h
+dns.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h sshkey.h ssherr.h dns.h log.h digest.h
ed25519.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h crypto_api.h ge25519.h fe25519.h sc25519.h
entropy.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-fatal.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ./ssherr.h
+fatal.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h
fe25519.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h fe25519.h crypto_api.h
ge25519.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h fe25519.h crypto_api.h sc25519.h ge25519.h ge25519_base.data
-groupaccess.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h groupaccess.h match.h log.h ./ssherr.h
+groupaccess.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h groupaccess.h match.h log.h ssherr.h
gss-genr.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
gss-serv-krb5.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
gss-serv.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
hash.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h crypto_api.h
hmac.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshbuf.h digest.h hmac.h
-hostfile.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h match.h sshkey.h hostfile.h log.h ./ssherr.h misc.h pathnames.h digest.h hmac.h sshbuf.h
-kex.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh.h ssh2.h atomicio.h version.h packet.h openbsd-compat/sys-queue.h dispatch.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h sshkey.h kex.h mac.h crypto_api.h log.h ./ssherr.h
+hostfile.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h match.h sshkey.h hostfile.h log.h ssherr.h misc.h pathnames.h digest.h hmac.h sshbuf.h
+kex.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh.h ssh2.h atomicio.h version.h packet.h openbsd-compat/sys-queue.h dispatch.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h sshkey.h kex.h mac.h crypto_api.h log.h ssherr.h
kex.o: match.h misc.h monitor.h sshbuf.h digest.h
-kexc25519.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshkey.h kex.h mac.h crypto_api.h sshbuf.h digest.h ./ssherr.h ssh2.h
+kexc25519.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshkey.h kex.h mac.h crypto_api.h sshbuf.h digest.h ssherr.h ssh2.h
kexdh.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-kexecdh.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./ssherr.h
-kexgen.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshkey.h kex.h mac.h crypto_api.h log.h ./ssherr.h packet.h openbsd-compat/sys-queue.h dispatch.h ssh2.h sshbuf.h digest.h
+kexecdh.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssherr.h
+kexgen.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshkey.h kex.h mac.h crypto_api.h log.h ssherr.h packet.h openbsd-compat/sys-queue.h dispatch.h ssh2.h sshbuf.h digest.h
kexgex.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
kexgexc.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
kexgexs.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-kexsntrup761x25519.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./ssherr.h
-krl.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h sshbuf.h ./ssherr.h sshkey.h authfile.h misc.h log.h digest.h bitmap.h utf8.h krl.h
-log.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ./ssherr.h match.h
-loginrec.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h sshkey.h hostfile.h ssh.h loginrec.h log.h ./ssherr.h atomicio.h packet.h openbsd-compat/sys-queue.h dispatch.h canohost.h auth.h auth-pam.h audit.h sshbuf.h
+kexsntrup761x25519.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssherr.h
+krl.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h sshbuf.h ssherr.h sshkey.h authfile.h misc.h log.h digest.h bitmap.h utf8.h krl.h
+log.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h match.h
+loginrec.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h sshkey.h hostfile.h ssh.h loginrec.h log.h ssherr.h atomicio.h packet.h openbsd-compat/sys-queue.h dispatch.h canohost.h auth.h auth-pam.h audit.h sshbuf.h
logintest.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h loginrec.h
-mac.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h digest.h hmac.h umac.h mac.h misc.h ./ssherr.h sshbuf.h openbsd-compat/openssl-compat.h
+mac.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h digest.h hmac.h umac.h mac.h misc.h ssherr.h sshbuf.h openbsd-compat/openssl-compat.h
match.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h match.h misc.h
md5crypt.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-misc.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h misc.h log.h ./ssherr.h ssh.h sshbuf.h
+misc.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h misc.h log.h ssherr.h ssh.h sshbuf.h
moduli.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-monitor.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h kex.h mac.h crypto_api.h dh.h packet.h dispatch.h auth-options.h sshpty.h channels.h session.h sshlogin.h canohost.h log.h ./ssherr.h misc.h servconf.h monitor.h monitor_wrap.h monitor_fdpass.h compat.h ssh2.h authfd.h match.h sk-api.h
+monitor.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h kex.h mac.h crypto_api.h dh.h packet.h dispatch.h auth-options.h sshpty.h channels.h session.h sshlogin.h canohost.h log.h ssherr.h misc.h servconf.h monitor.h monitor_wrap.h monitor_fdpass.h compat.h ssh2.h authfd.h match.h sk-api.h
monitor.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h openbsd-compat/openssl-compat.h atomicio.h xmalloc.h ssh.h sshkey.h sshbuf.h hostfile.h auth.h auth-pam.h audit.h loginrec.h cipher.h cipher-chachapoly.h
-monitor_fdpass.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ./ssherr.h monitor_fdpass.h
+monitor_fdpass.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h monitor_fdpass.h
monitor_wrap.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssh.h sshbuf.h sshkey.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h kex.h mac.h crypto_api.h hostfile.h auth.h auth-pam.h audit.h
-monitor_wrap.o: loginrec.h auth-options.h packet.h dispatch.h log.h ./ssherr.h monitor.h monitor_wrap.h atomicio.h monitor_fdpass.h misc.h channels.h session.h servconf.h
-msg.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshbuf.h ./ssherr.h log.h atomicio.h msg.h misc.h
-mux.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h log.h ./ssherr.h ssh.h ssh2.h pathnames.h misc.h match.h sshbuf.h channels.h msg.h packet.h dispatch.h monitor_fdpass.h sshpty.h sshkey.h readconf.h clientloop.h
-nchan.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h ssh2.h sshbuf.h ./ssherr.h packet.h dispatch.h channels.h compat.h log.h
+monitor_wrap.o: loginrec.h auth-options.h packet.h dispatch.h log.h ssherr.h monitor.h monitor_wrap.h atomicio.h monitor_fdpass.h misc.h channels.h session.h servconf.h
+msg.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshbuf.h ssherr.h log.h atomicio.h msg.h misc.h
+mux.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h log.h ssherr.h ssh.h ssh2.h pathnames.h misc.h match.h sshbuf.h channels.h msg.h packet.h dispatch.h monitor_fdpass.h sshpty.h sshkey.h readconf.h clientloop.h
+nchan.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h ssh2.h sshbuf.h ssherr.h packet.h dispatch.h channels.h compat.h log.h
packet.o: channels.h ssh.h packet.h dispatch.h sshbuf.h
-packet.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h compat.h ssh2.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h sshkey.h kex.h mac.h crypto_api.h digest.h log.h ./ssherr.h canohost.h misc.h
+packet.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h compat.h ssh2.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h sshkey.h kex.h mac.h crypto_api.h digest.h log.h ssherr.h canohost.h misc.h
platform-misc.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
platform-pledge.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-platform-tracing.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ./ssherr.h
-platform.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ./ssherr.h misc.h servconf.h openbsd-compat/sys-queue.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h
+platform-tracing.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h
+platform.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h misc.h servconf.h openbsd-compat/sys-queue.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h
poly1305.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h poly1305.h
progressmeter.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h progressmeter.h atomicio.h misc.h utf8.h
-readconf.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/glob.h xmalloc.h ssh.h ./ssherr.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h pathnames.h log.h sshkey.h misc.h readconf.h match.h kex.h mac.h crypto_api.h
+readconf.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/glob.h xmalloc.h ssh.h ssherr.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h pathnames.h log.h sshkey.h misc.h readconf.h match.h kex.h mac.h crypto_api.h
readconf.o: uidswap.h myproposal.h digest.h
-readpass.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h misc.h pathnames.h log.h ./ssherr.h ssh.h uidswap.h
+readpass.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h misc.h pathnames.h log.h ssherr.h ssh.h uidswap.h
rijndael.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h rijndael.h
sandbox-capsicum.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
sandbox-darwin.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
sandbox-null.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
sandbox-pledge.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
sandbox-rlimit.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
sandbox-seccomp-filter.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
sandbox-solaris.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
sandbox-systrace.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
sc25519.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sc25519.h crypto_api.h
-scp.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h atomicio.h pathnames.h log.h ./ssherr.h misc.h progressmeter.h utf8.h
-servconf.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/glob.h openbsd-compat/sys-queue.h xmalloc.h ssh.h log.h ./ssherr.h sshbuf.h misc.h servconf.h compat.h pathnames.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h
-servconf.o: sshkey.h kex.h mac.h crypto_api.h match.h channels.h groupaccess.h canohost.h packet.h dispatch.h hostfile.h auth.h auth-pam.h audit.h loginrec.h myproposal.h digest.h
+scp.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h atomicio.h pathnames.h log.h ssherr.h misc.h progressmeter.h utf8.h
+servconf.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/glob.h openbsd-compat/sys-queue.h xmalloc.h ssh.h log.h ssherr.h sshbuf.h misc.h servconf.h compat.h pathnames.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h sshkey.h
+servconf.o: kex.h mac.h crypto_api.h match.h channels.h groupaccess.h canohost.h packet.h dispatch.h hostfile.h auth.h auth-pam.h audit.h loginrec.h myproposal.h digest.h
serverloop.o: cipher-aesctr.h rijndael.h kex.h mac.h crypto_api.h hostfile.h auth.h auth-pam.h audit.h loginrec.h session.h auth-options.h serverloop.h
-serverloop.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h packet.h dispatch.h sshbuf.h log.h ./ssherr.h misc.h servconf.h canohost.h sshpty.h channels.h compat.h ssh2.h sshkey.h cipher.h cipher-chachapoly.h chacha.h poly1305.h
-session.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshpty.h packet.h dispatch.h sshbuf.h ./ssherr.h match.h uidswap.h compat.h channels.h sshkey.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h
+serverloop.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h packet.h dispatch.h sshbuf.h log.h ssherr.h misc.h servconf.h canohost.h sshpty.h channels.h compat.h ssh2.h sshkey.h cipher.h cipher-chachapoly.h chacha.h poly1305.h
+session.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshpty.h packet.h dispatch.h sshbuf.h ssherr.h match.h uidswap.h compat.h channels.h sshkey.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h
session.o: rijndael.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth-options.h authfd.h pathnames.h log.h misc.h servconf.h sshlogin.h serverloop.h canohost.h session.h kex.h mac.h crypto_api.h monitor_wrap.h sftp.h atomicio.h
-sftp-client.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ./ssherr.h sshbuf.h log.h atomicio.h progressmeter.h misc.h utf8.h sftp.h sftp-common.h sftp-client.h openbsd-compat/glob.h
-sftp-common.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ./ssherr.h sshbuf.h log.h misc.h sftp.h sftp-common.h
+sftp-client.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssherr.h sshbuf.h log.h atomicio.h progressmeter.h misc.h utf8.h sftp.h sftp-common.h sftp-client.h openbsd-compat/glob.h
+sftp-common.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssherr.h sshbuf.h log.h misc.h sftp.h sftp-common.h
sftp-glob.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h sftp.h sftp-common.h sftp-client.h openbsd-compat/glob.h
sftp-realpath.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-sftp-server-main.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ./ssherr.h sftp.h misc.h xmalloc.h
-sftp-server.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h sshbuf.h ./ssherr.h log.h misc.h match.h uidswap.h sftp.h sftp-common.h
-sftp.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ./ssherr.h pathnames.h misc.h utf8.h sftp.h sshbuf.h sftp-common.h sftp-client.h openbsd-compat/glob.h
+sftp-server-main.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h sftp.h misc.h xmalloc.h
+sftp-server.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h sshbuf.h ssherr.h log.h misc.h match.h uidswap.h sftp.h sftp-common.h
+sftp.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ssherr.h pathnames.h misc.h utf8.h sftp.h sshbuf.h sftp-common.h sftp-client.h openbsd-compat/glob.h
sk-usbhid.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
sntrup761.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-srclimit.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h addr.h canohost.h log.h ./ssherr.h misc.h srclimit.h xmalloc.h
-ssh-add.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h log.h ./ssherr.h sshkey.h sshbuf.h authfd.h authfile.h pathnames.h misc.h digest.h ssh-sk.h sk-api.h
-ssh-agent.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshbuf.h sshkey.h authfd.h compat.h log.h ./ssherr.h misc.h digest.h match.h msg.h pathnames.h ssh-pkcs11.h sk-api.h
+srclimit.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h addr.h canohost.h log.h ssherr.h misc.h srclimit.h xmalloc.h
+ssh-add.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h log.h ssherr.h sshkey.h sshbuf.h authfd.h authfile.h pathnames.h misc.h digest.h ssh-sk.h sk-api.h
+ssh-agent.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshbuf.h sshkey.h authfd.h compat.h log.h ssherr.h misc.h digest.h match.h msg.h pathnames.h ssh-pkcs11.h sk-api.h
ssh-dss.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-ssh-ecdsa-sk.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/openssl-compat.h sshbuf.h ./ssherr.h digest.h sshkey.h
+ssh-ecdsa-sk.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/openssl-compat.h sshbuf.h ssherr.h digest.h sshkey.h
ssh-ecdsa.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-ssh-ed25519-sk.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h crypto_api.h log.h ./ssherr.h sshbuf.h sshkey.h ssh.h digest.h
-ssh-ed25519.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h crypto_api.h log.h ./ssherr.h sshbuf.h sshkey.h ssh.h
+ssh-ed25519-sk.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h crypto_api.h log.h ssherr.h sshbuf.h sshkey.h ssh.h digest.h
+ssh-ed25519.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h crypto_api.h log.h ssherr.h sshbuf.h sshkey.h ssh.h
ssh-keygen.o: cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h
-ssh-keygen.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h sshkey.h authfile.h sshbuf.h pathnames.h log.h ./ssherr.h misc.h match.h hostfile.h dns.h ssh.h ssh2.h ssh-pkcs11.h atomicio.h krl.h digest.h utf8.h authfd.h sshsig.h ssh-sk.h sk-api.h cipher.h
-ssh-keyscan.o: ./ssherr.h atomicio.h misc.h hostfile.h ssh_api.h ssh2.h dns.h
+ssh-keygen.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h sshkey.h authfile.h sshbuf.h pathnames.h log.h ssherr.h misc.h match.h hostfile.h dns.h ssh.h ssh2.h ssh-pkcs11.h atomicio.h krl.h digest.h utf8.h authfd.h sshsig.h ssh-sk.h sk-api.h cipher.h
ssh-keyscan.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssh.h sshbuf.h sshkey.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h kex.h mac.h crypto_api.h compat.h myproposal.h packet.h dispatch.h log.h
-ssh-keysign.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ./ssherr.h sshkey.h ssh.h ssh2.h misc.h sshbuf.h authfile.h msg.h canohost.h pathnames.h readconf.h uidswap.h
+ssh-keyscan.o: ssherr.h atomicio.h misc.h hostfile.h ssh_api.h ssh2.h dns.h
+ssh-keysign.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ssherr.h sshkey.h ssh.h ssh2.h misc.h sshbuf.h authfile.h msg.h canohost.h pathnames.h readconf.h uidswap.h
ssh-pkcs11-client.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-ssh-pkcs11-helper.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h sshbuf.h log.h ./ssherr.h misc.h sshkey.h authfd.h ssh-pkcs11.h
-ssh-pkcs11.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ./ssherr.h sshkey.h
+ssh-pkcs11-helper.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h sshbuf.h log.h ssherr.h misc.h sshkey.h authfd.h ssh-pkcs11.h
+ssh-pkcs11.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h sshkey.h
ssh-rsa.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-ssh-sk-client.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ./ssherr.h sshbuf.h sshkey.h msg.h digest.h pathnames.h ssh-sk.h misc.h
-ssh-sk-helper.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ./ssherr.h sshkey.h authfd.h misc.h sshbuf.h msg.h uidswap.h ssh-sk.h
+ssh-sk-client.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h sshbuf.h sshkey.h msg.h digest.h pathnames.h ssh-sk.h misc.h
+ssh-sk-helper.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ssherr.h sshkey.h authfd.h misc.h sshbuf.h msg.h uidswap.h ssh-sk.h
ssh-sk.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
ssh-xmss.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
ssh.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/openssl-compat.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h canohost.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h packet.h dispatch.h sshbuf.h channels.h
-ssh.o: sshkey.h authfd.h authfile.h pathnames.h clientloop.h log.h ./ssherr.h misc.h readconf.h sshconnect.h kex.h mac.h crypto_api.h sshpty.h match.h msg.h version.h myproposal.h utf8.h
+ssh.o: sshkey.h authfd.h authfile.h pathnames.h clientloop.h log.h ssherr.h misc.h readconf.h sshconnect.h kex.h mac.h crypto_api.h sshpty.h match.h msg.h version.h myproposal.h utf8.h
ssh_api.o: authfile.h misc.h version.h myproposal.h sshbuf.h openbsd-compat/openssl-compat.h
-ssh_api.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh_api.h openbsd-compat/sys-queue.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h sshkey.h kex.h mac.h crypto_api.h ssh.h ssh2.h packet.h dispatch.h compat.h log.h ./ssherr.h
-sshbuf-getput-basic.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./ssherr.h sshbuf.h
+ssh_api.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh_api.h openbsd-compat/sys-queue.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h sshkey.h kex.h mac.h crypto_api.h ssh.h ssh2.h packet.h dispatch.h compat.h log.h ssherr.h
+sshbuf-getput-basic.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssherr.h sshbuf.h
sshbuf-getput-crypto.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-sshbuf-io.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./ssherr.h sshbuf.h atomicio.h
-sshbuf-misc.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./ssherr.h sshbuf.h
-sshbuf.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./ssherr.h sshbuf.h misc.h
+sshbuf-io.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssherr.h sshbuf.h atomicio.h
+sshbuf-misc.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssherr.h sshbuf.h
+sshbuf.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssherr.h sshbuf.h misc.h
sshconnect.o: authfd.h kex.h mac.h crypto_api.h
-sshconnect.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h hostfile.h ssh.h sshbuf.h packet.h openbsd-compat/sys-queue.h dispatch.h compat.h sshkey.h sshconnect.h log.h ./ssherr.h misc.h readconf.h atomicio.h dns.h monitor_fdpass.h ssh2.h version.h authfile.h
+sshconnect.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h hostfile.h ssh.h sshbuf.h packet.h openbsd-compat/sys-queue.h dispatch.h compat.h sshkey.h sshconnect.h log.h ssherr.h misc.h readconf.h atomicio.h dns.h monitor_fdpass.h ssh2.h version.h authfile.h
sshconnect2.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshbuf.h packet.h dispatch.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h sshkey.h kex.h mac.h crypto_api.h
-sshconnect2.o: myproposal.h sshconnect.h authfile.h dh.h authfd.h log.h ./ssherr.h misc.h readconf.h match.h canohost.h msg.h pathnames.h uidswap.h hostfile.h utf8.h ssh-sk.h sk-api.h
-sshd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshpty.h packet.h dispatch.h log.h ./ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h chacha.h
-sshd.o: poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h kex.h mac.h crypto_api.h myproposal.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h ssh-sandbox.h auth-options.h version.h sk-api.h srclimit.h
-ssherr.o: ./ssherr.h
+sshconnect2.o: myproposal.h sshconnect.h authfile.h dh.h authfd.h log.h ssherr.h misc.h readconf.h match.h canohost.h msg.h pathnames.h uidswap.h hostfile.h utf8.h ssh-sk.h sk-api.h
+sshd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshpty.h packet.h dispatch.h log.h ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h chacha.h
+sshd.o: poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h kex.h mac.h crypto_api.h myproposal.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h ssh-sandbox.h auth-options.h version.h sk-api.h srclimit.h dh.h
+ssherr.o: ssherr.h
sshkey-xmss.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-sshkey.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h crypto_api.h ssh2.h ./ssherr.h misc.h sshbuf.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h match.h ssh-sk.h openbsd-compat/openssl-compat.h
-sshlogin.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshlogin.h ./ssherr.h loginrec.h log.h sshbuf.h misc.h servconf.h openbsd-compat/sys-queue.h
-sshpty.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshpty.h log.h ./ssherr.h misc.h
-sshsig.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h authfd.h authfile.h log.h ./ssherr.h misc.h sshbuf.h sshsig.h sshkey.h match.h digest.h
+sshkey.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h crypto_api.h ssh2.h ssherr.h misc.h sshbuf.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h match.h ssh-sk.h openbsd-compat/openssl-compat.h
+sshlogin.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshlogin.h ssherr.h loginrec.h log.h sshbuf.h misc.h servconf.h openbsd-compat/sys-queue.h
+sshpty.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshpty.h log.h ssherr.h misc.h
+sshsig.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h authfd.h authfile.h log.h ssherr.h misc.h sshbuf.h sshsig.h sshkey.h match.h digest.h
sshtty.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshpty.h
-ttymodes.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ./ssherr.h compat.h sshbuf.h ttymodes.h
-uidswap.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ./ssherr.h uidswap.h xmalloc.h
+ttymodes.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h compat.h sshbuf.h ttymodes.h
+uidswap.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h uidswap.h xmalloc.h
umac.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h umac.h misc.h rijndael.h
umac128.o: umac.c includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h umac.h misc.h rijndael.h
utf8.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h utf8.h
verify.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h crypto_api.h
-xmalloc.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ./ssherr.h
+xmalloc.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ssherr.h
xmss_commons.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
xmss_fast.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
xmss_hash.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
xmss_hash_address.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
xmss_wots.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
diff --git a/.github/configs b/.github/configs
index 1c06e00d110c..c47f1a523b16 100755
--- a/.github/configs
+++ b/.github/configs
@@ -1,110 +1,126 @@
#!/bin/sh
#
# usage: configs vmname test_config (or '' for default)
#
# Sets the following variables:
# CONFIGFLAGS options to ./configure
# SSHD_CONFOPTS sshd_config options
# TEST_TARGET make target used when testing. defaults to "tests".
# LTESTS
config=$1
TEST_TARGET="tests"
LTESTS=""
SKIP_LTESTS=""
SUDO=sudo # run with sudo by default
TEST_SSH_UNSAFE_PERMISSIONS=1
CONFIGFLAGS=""
LIBCRYPTOFLAGS=""
case "$config" in
default|sol64)
;;
kitchensink)
CONFIGFLAGS="--with-kerberos5 --with-libedit --with-pam"
CONFIGFLAGS="${CONFIGFLAGS} --with-security-key-builtin --with-selinux"
CONFIGFLAGS="${CONFIGFLAGS} --with-cflags=-DSK_DEBUG"
;;
hardenedmalloc)
CONFIGFLAGS="--with-ldflags=-lhardened_malloc"
;;
kerberos5)
CONFIGFLAGS="--with-kerberos5"
;;
libedit)
CONFIGFLAGS="--with-libedit"
;;
*pam)
CONFIGFLAGS="--with-pam"
SSHD_CONFOPTS="UsePam yes"
;;
libressl-head)
LIBCRYPTOFLAGS="--with-ssl-dir=/opt/libressl/head --with-rpath=-Wl,-rpath,"
;;
openssl-head)
LIBCRYPTOFLAGS="--with-ssl-dir=/opt/openssl/head --with-rpath=-Wl,-rpath,"
;;
selinux)
CONFIGFLAGS="--with-selinux"
;;
sk)
CONFIGFLAGS="--with-security-key-builtin"
;;
without-openssl)
LIBCRYPTOFLAGS="--without-openssl"
TEST_TARGET=t-exec
;;
- valgrind-1)
+ valgrind-[1-4]|valgrind-unit)
# rlimit sandbox and FORTIFY_SOURCE confuse Valgrind.
CONFIGFLAGS="--without-sandbox --without-hardening"
CONFIGFLAGS="$CONFIGFLAGS --with-cppflags=-D_FORTIFY_SOURCE=0"
+ TEST_TARGET="t-exec USE_VALGRIND=1"
+ TEST_SSH_ELAPSED_TIMES=1
+ export TEST_SSH_ELAPSED_TIMES
# Valgrind slows things down enough that the agent timeout test
# won't reliably pass, and the unit tests run longer than allowed
- # by github.
- TEST_TARGET="t-exec USE_VALGRIND=1"
- SKIP_LTESTS="agent-timeout rekey try-ciphers cert-userkey integrity"
- ;;
- valgrind-2)
- CONFIGFLAGS="--without-sandbox --without-hardening"
- CONFIGFLAGS="$CONFIGFLAGS --with-cppflags=-D_FORTIFY_SOURCE=0"
- # The rekey test takes >30 min so run separately.
- TEST_TARGET="t-exec USE_VALGRIND=1"
- LTESTS="rekey try-ciphers cert-userkey integrity"
+ # by github so split into three separate tests.
+ tests2="rekey integrity"
+ tests3="krl forward-control sshsig"
+ tests4="cert-userkey cert-hostkey kextype sftp-perm keygen-comment"
+ case "$config" in
+ valgrind-1)
+ # All tests except agent-timeout (which is flaky under valgrind)
+ #) and slow ones that run separately to increase parallelism.
+ SKIP_LTESTS="agent-timeout ${tests2} ${tests3} ${tests4}"
+ ;;
+ valgrind-2)
+ LTESTS="${tests2}"
+ ;;
+ valgrind-3)
+ LTESTS="${tests3}"
+ ;;
+ valgrind-4)
+ LTESTS="${tests4}"
+ ;;
+ valgrind-unit)
+ TEST_TARGET="unit USE_VALGRIND=1"
+ ;;
+ esac
;;
*)
echo "Unknown configuration $config"
exit 1
;;
esac
# The Solaris 64bit targets are special since they need a non-flag arg.
case "$config" in
sol64*)
CONFIGFLAGS="x86_64 --with-cflags=-m64 --with-ldflags=-m64 ${CONFIGFLAGS}"
LIBCRYPTOFLAGS="--with-ssl-dir=/usr/local/ssl64"
;;
esac
case "${TARGET_HOST}" in
sol10|sol11)
# sol10 VM is 32bit and the unit tests are slow.
# sol11 has 4 test configs so skip unit tests to speed up.
TEST_TARGET="tests SKIP_UNIT=1"
;;
esac
# If we have a local openssl/libressl, use that.
if [ -z "${LIBCRYPTOFLAGS}" ]; then
# last-match
for i in /usr/local /usr/local/ssl /usr/local/opt/openssl; do
if [ -x ${i}/bin/openssl ]; then
LIBCRYPTOFLAGS="--with-ssl-dir=${i}"
fi
done
fi
CONFIGFLAGS="${CONFIGFLAGS} ${LIBCRYPTOFLAGS}"
export LTESTS SUDO TEST_TARGET TEST_SSH_UNSAFE_PERMISSIONS
diff --git a/.github/setup_ci.sh b/.github/setup_ci.sh
index e53a351c5bdf..6240ef06ef53 100755
--- a/.github/setup_ci.sh
+++ b/.github/setup_ci.sh
@@ -1,97 +1,97 @@
#!/usr/bin/env bash
case $(./config.guess) in
*-darwin*)
brew install automake
exit 0
;;
esac
TARGETS=$@
PACKAGES=""
INSTALL_FIDO_PPA="no"
#echo "Setting up for '$TARGETS'"
set -ex
lsb_release -a
if [ "${TARGETS}" = "kitchensink" ]; then
TARGETS="kerberos5 libedit pam sk selinux"
fi
for TARGET in $TARGETS; do
case $TARGET in
default|without-openssl|without-zlib)
# nothing to do
;;
kerberos5)
PACKAGES="$PACKAGES heimdal-dev"
#PACKAGES="$PACKAGES libkrb5-dev"
;;
libedit)
PACKAGES="$PACKAGES libedit-dev"
;;
*pam)
PACKAGES="$PACKAGES libpam0g-dev"
;;
sk)
INSTALL_FIDO_PPA="yes"
- PACKAGES="$PACKAGES libfido2-dev libu2f-host-dev"
+ PACKAGES="$PACKAGES libfido2-dev libu2f-host-dev libcbor-dev"
;;
selinux)
PACKAGES="$PACKAGES libselinux1-dev selinux-policy-dev"
;;
hardenedmalloc)
INSTALL_HARDENED_MALLOC=yes
;;
openssl-head)
INSTALL_OPENSSL_HEAD=yes
;;
libressl-head)
INSTALL_LIBRESSL_HEAD=yes
;;
valgrind*)
PACKAGES="$PACKAGES valgrind"
;;
*) echo "Invalid option '${TARGET}'"
exit 1
;;
esac
done
if [ "yes" == "$INSTALL_FIDO_PPA" ]; then
sudo apt update -qq
sudo apt install software-properties-common
sudo apt-add-repository ppa:yubico/stable
fi
if [ "x" != "x$PACKAGES" ]; then
sudo apt update -qq
sudo apt install -qy $PACKAGES
fi
if [ "${INSTALL_HARDENED_MALLOC}" = "yes" ]; then
(cd ${HOME} &&
git clone https://github.com/GrapheneOS/hardened_malloc.git &&
cd ${HOME}/hardened_malloc &&
make -j2 && sudo cp libhardened_malloc.so /usr/lib/)
fi
if [ "${INSTALL_OPENSSL_HEAD}" = "yes" ];then
(cd ${HOME} &&
git clone https://github.com/openssl/openssl.git &&
cd ${HOME}/openssl &&
./config no-threads no-engine no-fips no-shared --prefix=/opt/openssl/head &&
make -j2 && sudo make install_sw)
fi
if [ "${INSTALL_LIBRESSL_HEAD}" = "yes" ];then
(mkdir -p ${HOME}/libressl && cd ${HOME}/libressl &&
git clone https://github.com/libressl-portable/portable.git &&
cd ${HOME}/libressl/portable && sh update.sh && sh autogen.sh &&
./configure --prefix=/opt/libressl/head &&
make -j2 && sudo make install_sw)
fi
diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml
index c2e9c5327ecb..c4ae28434305 100644
--- a/.github/workflows/c-cpp.yml
+++ b/.github/workflows/c-cpp.yml
@@ -1,63 +1,66 @@
name: C/C++ CI
on:
push:
branches: [ master, ci ]
pull_request:
branches: [ master ]
jobs:
ci:
if: github.repository != 'openssh/openssh-portable-selfhosted'
strategy:
fail-fast: false
matrix:
# First we test all OSes in the default configuration.
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-16.04, macos-10.15]
configs: [default]
# Then we include any extra configs we want to test for specific VMs.
# Valgrind slows things down quite a bit, so start them first.
include:
- { os: ubuntu-20.04, configs: valgrind-1 }
- { os: ubuntu-20.04, configs: valgrind-2 }
+ - { os: ubuntu-20.04, configs: valgrind-3 }
+ - { os: ubuntu-20.04, configs: valgrind-4 }
+ - { os: ubuntu-20.04, configs: valgrind-unit }
- { os: ubuntu-20.04, configs: pam }
- { os: ubuntu-20.04, configs: kitchensink }
- { os: ubuntu-20.04, configs: hardenedmalloc }
- { os: ubuntu-20.04, configs: libressl-head }
- { os: ubuntu-20.04, configs: openssl-head }
- { os: ubuntu-18.04, configs: pam }
- { os: ubuntu-18.04, configs: kerberos5 }
- { os: ubuntu-18.04, configs: libedit }
- { os: ubuntu-18.04, configs: sk }
- { os: ubuntu-18.04, configs: selinux }
- { os: ubuntu-18.04, configs: kitchensink }
- { os: ubuntu-18.04, configs: without-openssl }
- { os: ubuntu-16.04, configs: pam }
- { os: ubuntu-16.04, configs: kitchensink }
- { os: macos-10.15, configs: pam }
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: setup CI system
run: ./.github/setup_ci.sh ${{ matrix.configs }}
- name: autoreconf
run: autoreconf
- name: configure
run: ./.github/configure.sh ${{ matrix.configs }}
- name: make
run: make -j2
- - name: install moduli
- run: sudo sh -c "mkdir -p /usr/local/etc/; cp moduli /usr/local/etc/"
- name: make tests
run: ./.github/run_test.sh ${{ matrix.configs }}
env:
SUDO: sudo
TEST_SSH_UNSAFE_PERMISSIONS: 1
- - name: save regress logs
+ - name: save logs
if: failure()
uses: actions/upload-artifact@v2
with:
- name: ${{ matrix.os }}-${{ matrix.configs }}-regress-logs
+ name: ${{ matrix.os }}-${{ matrix.configs }}-logs
path: |
+ config.h
+ config.log
regress/*.log
regress/valgrind-out/
diff --git a/.github/workflows/selfhosted.yml b/.github/workflows/selfhosted.yml
index aadcb42b4ddc..1cf6b5da0a34 100644
--- a/.github/workflows/selfhosted.yml
+++ b/.github/workflows/selfhosted.yml
@@ -1,68 +1,60 @@
name: C/C++ CI self-hosted
on:
push:
branches: [ master, ci ]
jobs:
selfhosted:
if: github.repository == 'openssh/openssh-portable-selfhosted'
runs-on: ${{ matrix.os }}
env:
TARGET_HOST: ${{ matrix.os }}
SUDO: sudo
strategy:
fail-fast: false
# We use a matrix in two parts: firstly all of the VMs are tested with the
# default config. "vm" corresponds to a label associated with the worker.
matrix:
os: [bbone, dfly30, dfly48, dfly58, fbsd6, fbsd7, fbsd12, sol10, sol11]
configs:
- default
# Then we include any extra configs we want to test for specific VMs.
include:
- { os: dfly30, configs: without-openssl}
- { os: dfly48, configs: pam }
- { os: dfly58, configs: pam }
- { os: fbsd6, configs: pam }
- { os: fbsd7, configs: pam }
- { os: fbsd12, configs: pam }
- { os: sol10, configs: pam }
- { os: sol11, configs: pam }
- { os: sol11, configs: sol64 }
# - { os: sol11, configs: sol64-pam }
steps:
- uses: actions/checkout@v2
- name: autoreconf
run: autoreconf
- name: shutdown VM if running
run: vmshutdown
- name: startup VM
run: vmstartup
- name: configure
run: vmrun ./.github/configure.sh ${{ matrix.configs }}
- - name: save config files
- if: failure()
- uses: actions/upload-artifact@v2
- with:
- name: ${{ matrix.os }}-${{ matrix.configs }}-config-files
- path: |
- config.h
- config.log
- name: make
run: vmrun make
- - name: install moduli
- run: vmrun "sudo mkdir -p /usr/local/etc/; sudo cp moduli /usr/local/etc/"
- name: make tests
run: vmrun ./.github/run_test.sh ${{ matrix.configs }}
- - name: save regress logs
+ - name: save logs
if: failure()
uses: actions/upload-artifact@v2
with:
- name: ${{ matrix.os }}-${{ matrix.configs }}-regress-logs
+ name: ${{ matrix.os }}-${{ matrix.configs }}-logs
path: |
+ config.h
+ config.log
regress/*.log
regress/valgrind-out/
- name: shutdown VM
if: always()
run: vmshutdown
diff --git a/.skipped-commit-ids b/.skipped-commit-ids
index 495dbf1d1df3..1de78172232a 100644
--- a/.skipped-commit-ids
+++ b/.skipped-commit-ids
@@ -1,50 +1,51 @@
5317f294d63a876bfc861e19773b1575f96f027d remove libssh from makefiles
a337e886a49f96701ccbc4832bed086a68abfa85 Makefile changes
f2c9feb26963615c4fece921906cf72e248b61ee more Makefile
fa728823ba21c4b45212750e1d3a4b2086fd1a62 more Makefile refactoring
1de0e85522051eb2ffa00437e1885e9d7b3e0c2e moduli update
814b2f670df75759e1581ecef530980b2b3d7e0f remove redundant make defs
04431e8e7872f49a2129bf080a6b73c19d576d40 moduli update
c07772f58028fda683ee6abd41c73da3ff70d403 moduli update
db6375fc302e3bdf07d96430c63c991b2c2bd3ff moduli update
5ea3d63ab972691f43e9087ab5fd8376d48e898f uuencode.c Makefile accident
99dd10e72c04e93849981d43d64c946619efa474 include sshbuf-misc.c
9e1c23476bb845f3cf3d15d9032da3ed0cb2fcf5 sshbuf-misc.c in regress
569f08445c27124ec7c7f6c0268d844ec56ac061 Makefile tweaks for !openssl
58ec755be4e51978ecfee73539090eb68652a987 moduli update
4bd5551b306df55379afe17d841207990eb773bf Makefile.inc
14806a59353152f843eb349e618abbf6f4dd3ada Makefile.inc
8ea4455a2d9364a0a04f9e4a2cbfa4c9fcefe77e Makefile.inc
d9b910e412d139141b072a905e66714870c38ac0 Makefile.inc
7b7b619c1452a459310b0cf4391c5757c6bdbc0f moduli update
5010ff08f7ad92082e87dde098b20f5c24921a8f moduli regen script update
3bcae7a754db3fc5ad3cab63dd46774edb35b8ae moduli regen script update
52ff0e3205036147b2499889353ac082e505ea54 moduli update
07b5031e9f49f2b69ac5e85b8da4fc9e393992a0 Makefile.inc
cc12a9029833d222043aecd252d654965c351a69 moduli-gen Makefile
+7ac6c252d2a5be8fbad4c66d9d35db507c9dac5b moduli update
Old upstream tree:
321065a95a7ccebdd5fd08482a1e19afbf524e35 Update DH groups
d4f699a421504df35254cf1c6f1a7c304fb907ca Remove 1k bit groups
aafe246655b53b52bc32c8a24002bc262f4230f7 Remove intermediate moduli
8fa9cd1dee3c3339ae329cf20fb591db6d605120 put back SSH1 for 6.9
f31327a48dd4103333cc53315ec53fe65ed8a17a Generate new moduli
edbfde98c40007b7752a4ac106095e060c25c1ef Regen moduli
052fd565e3ff2d8cec3bc957d1788f50c827f8e2 Switch to tame-based sandbox
7cf73737f357492776223da1c09179fa6ba74660 Remove moduli <2k
180d84674be1344e45a63990d60349988187c1ae Update moduli
f6ae971186ba68d066cd102e57d5b0b2c211a5ee systrace is dead.
96c5054e3e1f170c6276902d5bc65bb3b87a2603 remove DEBUGLIBS from Makefile
6da9a37f74aef9f9cc639004345ad893cad582d8 Update moduli file
77bcb50e47b68c7209c7f0a5a020d73761e5143b unset REGRESS_FAIL_EARLY
38c2133817cbcae75c88c63599ac54228f0fa384 Change COMPILER_VERSION tests
30c20180c87cbc99fa1020489fe7fd8245b6420c resync integrity.sh shell
1e6b51ddf767cbad0a4e63eb08026c127e654308 integrity.sh reliability
fe5b31f69a60d47171836911f144acff77810217 Makefile.inc bits
5781670c0578fe89663c9085ed3ba477cf7e7913 Delete sshconnect1.c
ea80f445e819719ccdcb237022cacfac990fdc5c Makefile.inc warning flags
b92c93266d8234d493857bb822260dacf4366157 moduli-gen.sh tweak
b25bf747544265b39af74fe0716dc8d9f5b63b95 Updated moduli
1bd41cba06a7752de4df304305a8153ebfb6b0ac rsa.[ch] already removed
e39b3902fe1d6c4a7ba6a3c58e072219f3c1e604 Makefile changes
diff --git a/ChangeLog b/ChangeLog
index f3216b8c7340..3e2b682088e7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,12631 +1,12906 @@
+commit e86968280e358e62649d268d41f698d64d0dc9fa
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Apr 16 13:55:25 2021 +1000
+
+ depend
+
+commit 2fb25ca11e8b281363a2a2a4dec4c497a1475d9a
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Apr 16 13:53:02 2021 +1000
+
+ crank version in README and RPM spec files
+
+commit b2b60ebab0cb77b5bc02d364d72e13db882f33ae
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Apr 16 03:42:00 2021 +0000
+
+ upstream: openssh-8.6
+
+ OpenBSD-Commit-ID: b5f3e133c846127ec114812248bc17eff07c3e19
+
+commit faf2b86a46c9281d237bcdec18c99e94a4eb820a
+Author: markus@openbsd.org <markus@openbsd.org>
+Date: Thu Apr 15 16:24:31 2021 +0000
+
+ upstream: do not pass file/func to monitor; noted by Ilja van Sprundel;
+
+ ok djm@
+
+ OpenBSD-Commit-ID: 85ae5c063845c410283cbdce685515dcd19479fa
+
+commit 2dc328023f60212cd29504fc05d849133ae47355
+Author: Damien Miller <djm@mindrot.org>
+Date: Wed Apr 14 11:42:55 2021 +1000
+
+ sshd don't exit on transient read errors
+
+ openssh-8.5 introduced a regression that would cause sshd to exit
+ because of transient read errors on the network socket (e.g. EINTR,
+ EAGAIN). Reported by balu.gajjala AT gmail.com via bz3297
+
+commit d5d6b7d76d171a2e6861609dcd92e714ee62ad88
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Apr 10 18:45:00 2021 +1000
+
+ perform report_failed_grab() inline
+
+commit ea996ce2d023aa3c6d31125e2c3ebda1cb42db8c
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Apr 10 18:22:57 2021 +1000
+
+ dedicated gnome-ssk-askpass3 source
+
+ Compatibility with Wayland requires that we use the gdk_seat_grab()
+ API for grabbing mouse/keyboard, however these API don't exist in
+ Gtk+2.
+
+ This branches gnome-ssk-askpass2.c => gnome-ssk-askpass3.c and
+ makes the changes to use the gdk_seat_grab() instead of grabbing
+ mouse/focus separately via GDK.
+
+ In the future, we can also use the branched file to avoid some
+ API that has been soft-deprecated in GTK+3, e.g. gtk_widget_modify_fg
+
+commit bfa5405da05d906ffd58216eb77c4375b62d64c2
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Apr 8 15:18:15 2021 +1000
+
+ Ensure valgrind-out exists.
+
+ Normally the regress tests would create it, but running the unit tests
+ on their own would fail because the directory did not exist.
+
+commit 1f189181f3ea09a9b08aa866f78843fec800874f
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Apr 8 15:17:19 2021 +1000
+
+ Pass OBJ to unit test make invocation.
+
+ At least the Valgrind unit tests uses $OBJ.
+
+commit f42b550c281d28bd19e9dd6ce65069164f3482b0
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Apr 8 14:20:12 2021 +1000
+
+ Add pattern for valgrind-unit.
+
+commit 19e534462710e98737478fd9c44768b50c27c4c6
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Apr 8 13:31:08 2021 +1000
+
+ Run unit tests under valgrind.
+
+ Run a separate build for the unit tests under Valgrind. They take long
+ enough that running in parallel with the other Valgrind tests helps.
+
+commit 80032102d05e866dc2a48a5caf760cf42c2e090e
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Apr 8 13:25:57 2021 +1000
+
+ ifdef out MIN and MAX.
+
+ In -portable, defines.h ensures that these are defined, so redefining
+ potentially causes a warning. We don't just delete it to make any
+ future code syncs a little but easier. bz#3293.
+
+commit d1bd184046bc310c405f45da3614a1dc5b3e521a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Apr 7 10:23:51 2021 +1000
+
+ Remove only use of warn().
+
+ The warn() function is only used in one place in portable and does not
+ exist upstream. Upgrade the only instance it's used to fail()
+ (the privsep/sandbox+proxyconnect, from back when that was new) and
+ remove the now-unused function.
+
+commit fea8f4b1aa85026ad5aee5ad8e1599a8d5141fe0
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Apr 7 10:18:32 2021 +1000
+
+ Move make_tmpdir() into portable-specific area.
+
+ Reduces diff vs OpenBSD and makes it more likely diffs will apply
+ cleanly.
+
+commit 13e5fa2acffd26e754c6ee1d070d0afd035d4cb7
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Apr 6 23:57:56 2021 +0000
+
+ upstream: Add TEST_SSH_ELAPSED_TIMES environment variable to print the
+
+ elapsed time in seconds of each test. This depends on "date +%s" which is
+ not specified by POSIX but is commonly implemented.
+
+ OpenBSD-Regress-ID: ec3c8c19ff49b2192116a0a646ee7c9b944e8a9c
+
+commit ef4f46ab4387bb863b471bad124d46e8d911a79a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Apr 7 09:59:15 2021 +1000
+
+ Move the TEST_SSH_PORT section down a bit.
+
+ This groups the portable-specific changes together and makes it a
+ little more likely that patches will apply cleanly.
+
+commit 3674e33fa70dfa1fe69b345bf576113af7b7be11
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Apr 7 10:05:10 2021 +1000
+
+ Further split Valgrind tests.
+
+ Even split in two, the Valgrind tests take by far the longest to run,
+ so split them four ways to further increase parallelism.
+
+commit 961af266b861e30fce1e26170ee0dbb5bf591f29
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Apr 6 23:24:30 2021 +0000
+
+ upstream: include "ssherr.h" not <ssherr.h>; from Balu Gajjala via
+
+ bz#3292
+
+ OpenBSD-Commit-ID: e9535cd9966eb2e69e73d1ede1f44905c30310bd
+
+commit e7d0a285dbdd65d8df16123ad90f15e91862f959
+Author: Damien Miller <djm@mindrot.org>
+Date: Wed Apr 7 08:50:38 2021 +1000
+
+ wrap struct rlimit in HAVE_GETRLIMIT too
+
+commit f283a6c2e0a9bd9369e18462acd00be56fbe5b0d
+Author: Damien Miller <djm@mindrot.org>
+Date: Wed Apr 7 08:20:35 2021 +1000
+
+ wrap getrlimit call in HAVE_GETRLIMIT; bz3291
+
+commit 679bdc4a5c9244f427a7aee9c14b0a0ed086da1f
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Apr 6 09:07:33 2021 +0000
+
+ upstream: Don't check return value of unsetenv(). It's part of the
+
+ environment setup and not part of the actual test, and some platforms
+ -portable runs on declare it as returning void, which prevents the test from
+ compiling.
+
+ OpenBSD-Regress-ID: 24f08543ee3cdebc404f2951f3e388cc82b844a1
+
+commit 320af2f3de6333aa123f1b088eca146a245e968a
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Sun Apr 4 11:36:56 2021 +0000
+
+ upstream: remove stray inserts; from matthias schmidt
+
+ OpenBSD-Commit-ID: 2c36ebdc54e14bbf1daad70c6a05479a073d5c63
+
+commit 801f710953b24dd2f21939171c622eac77c7484d
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Sun Apr 4 06:11:24 2021 +0000
+
+ upstream: missing comma; from kawashima james
+
+ OpenBSD-Commit-ID: 31cec6bf26c6db4ffefc8a070715ebef274e68ea
+
+commit b3ca08cb174266884d44ec710a84cd64c12414ea
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Apr 5 23:46:42 2021 +1000
+
+ Install libcbor with libfido2.
+
+commit f3ca8af87a4c32ada660da12ae95cf03d190c083
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Apr 3 18:21:08 2021 +1100
+
+ enable authopt and misc unit tests
+
+ Neither were wired into the build, both required some build
+ adaptations for -portable
+
+commit dc1b45841fb97e3d7f655ddbcfef3839735cae5f
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Apr 3 06:58:30 2021 +0000
+
+ upstream: typos in comments; GHPR#180 from Vill
+
+ =?UTF-8?q?e=20Skytt=C3=A4?=
+ MIME-Version: 1.0
+ Content-Type: text/plain; charset=UTF-8
+ Content-Transfer-Encoding: 8bit
+
+ OpenBSD-Commit-ID: 93c732381ae0e2b680c79e67c40c1814b7ceed2c
+
+commit 53ea05e09b04fd7b6dea66b42b34d65fe61b9636
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Apr 3 06:55:52 2021 +0000
+
+ upstream: sync CASignatureAlgorithms lists with reality. GHPR#174 from
+
+ Matt Hazinski
+
+ OpenBSD-Commit-ID: f05e4ca54d7e67b90fe58fe1bdb1d2a37e0e2696
+
+commit 57ed647ee07bb883a2f2264231bcd1df6a5b9392
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Apr 3 17:47:37 2021 +1100
+
+ polish whitespace for portable files
+
+commit 31d8d231eb9377df474746a822d380c5d68d7ad6
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Apr 3 06:18:40 2021 +0000
+
+ upstream: highly polished whitespace, mostly fixing spaces-for-tab
+
+ and bad indentation on continuation lines. Prompted by GHPR#185
+
+ OpenBSD-Commit-ID: e5c81f0cbdcc6144df1ce468ec1bac366d8ad6e9
+
+commit 34afde5c73b5570d6f8cce9b49993b23b77bfb86
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Apr 3 05:54:14 2021 +0000
+
+ upstream: whitespace (tab after space)
+
+ OpenBSD-Commit-ID: 0e2b3f7674e985d3f7c27ff5028e690ba1c2efd4
+
+commit 7cd262c1c5a08cc7f4f30e3cab108ef089d0a57b
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Apr 3 16:59:10 2021 +1100
+
+ Save config.h and config.log on failure too.
+
+commit 460aee9298f365357e9fd26851c22e0dca51fd6a
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Apr 3 05:46:41 2021 +0000
+
+ upstream: fix incorrect plural; from Ville Skyt
+
+ =?UTF-8?q?t=C3=A4=20via=20GHPR#181?=
+ MIME-Version: 1.0
+ Content-Type: text/plain; charset=UTF-8
+ Content-Transfer-Encoding: 8bit
+
+ OpenBSD-Commit-ID: 92f31754c6296d8f403d7c293e09dc27292d22c9
+
+commit 082804c14e548cada75c81003a3c68ee098138ee
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Apr 3 05:40:39 2021 +0000
+
+ upstream: ensure that pkcs11_del_provider() is called before exit -
+
+ some PKCS#11 providers get upset if C_Initialize is not matched with
+ C_Finalize.
+
+ From Adithya Baglody via GHPR#234; ok markus
+
+ OpenBSD-Commit-ID: f8e770e03b416ee9a58f9762e162add900f832b6
+
+commit 464ebc82aa926dd132ec75a0b064574ef375675e
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Apr 3 05:28:43 2021 +0000
+
+ upstream: unused variable
+
+ OpenBSD-Commit-ID: 85f6a394c8e0f60d15ecddda75176f112007b205
+
+commit dc3c0be8208c488e64a8bcb7d9efad98514e0ffb
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Apr 3 05:21:46 2021 +0000
+
+ upstream: Fix two problems in string->argv conversion: 1) multiple
+
+ backslashes were not being dequoted correctly and 2) quoted space in the
+ middle of a string was being incorrectly split.
+ MIME-Version: 1.0
+ Content-Type: text/plain; charset=UTF-8
+ Content-Transfer-Encoding: 8bit
+
+ A unit test for these cases has already been committed
+
+ prompted by and based on GHPR#223 by Eero Häkkinen; ok markus@
+
+ OpenBSD-Commit-ID: d7ef27abb4eeeaf6e167e9312e4abe9e89faf1e4
+
+commit f75bcbba58a08c670727ece5e3f8812125969799
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Apr 3 16:22:48 2021 +1100
+
+ missing bits from 259d648e
+
+commit 4cbc4a722873d9b68cb5496304dc050d7168df78
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Mar 31 21:59:26 2021 +0000
+
+ upstream: cannot effectively test posix-rename extension after
+
+ changes in feature advertisment.
+
+ OpenBSD-Regress-ID: 5e390bf88d379162aaa81b60ed86b34cb0c54d29
+
+commit 259d648e63e82ade4fe2c2c73c8b67fe57d9d049
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Mar 19 04:23:50 2021 +0000
+
+ upstream: add a test for misc.c:argv_split(), currently fails
+
+ OpenBSD-Regress-ID: ad6b96d6ebeb9643b698b3575bdd6f78bb144200
+
+commit 473ddfc2d6b602cb2d1d897e0e5c204de145cd9a
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Mar 19 03:25:01 2021 +0000
+
+ upstream: split
+
+ OpenBSD-Regress-ID: f6c03c0e4c58b3b9e04b161757b8c10dc8378c34
+
+commit 1339800fef8d0dfbfeabff71b34670105bcfddd2
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Mar 31 22:16:34 2021 +0000
+
+ upstream: Use new limits@openssh.com protocol extension to let the
+
+ client select good limits based on what the server supports. Split the
+ download and upload buffer sizes to allow them to be chosen independently.
+
+ In practice (and assuming upgraded sftp/sftp-server at each end), this
+ increases the download buffer 32->64KiB and the upload buffer
+ 32->255KiB.
+
+ Patches from Mike Frysinger; ok dtucker@
+
+ OpenBSD-Commit-ID: ebd61c80d85b951b794164acc4b2f2fd8e88606c
+
+commit 6653c61202d104e59c8e741329fcc567f7bc36b8
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Mar 31 21:58:07 2021 +0000
+
+ upstream: do not advertise protocol extensions that have been
+
+ disallowed by the command-line options (e.g. -p/-P/-R); ok dtucker@
+
+ OpenBSD-Commit-ID: 3a8a76b3f5131741aca4b41bfab8d101c9926205
+
+commit 71241fc05db4bbb11bb29340b44b92e2575373d8
+Author: Damien Miller <djm@mindrot.org>
+Date: Mon Mar 29 15:14:25 2021 +1100
+
+ gnome-ssh-askpass3 is a valid target here
+
+commit 8a9520836e71830f4fccca066dba73fea3d16bda
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Mar 19 02:22:34 2021 +0000
+
+ upstream: return non-zero exit status when killed by signal; bz#3281 ok
+
+ dtucker@
+
+ OpenBSD-Commit-ID: 117b31cf3c807993077b596bd730c24da9e9b816
+
+commit 1269b8a686bf1254b03cd38af78167a04aa6ec88
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Mar 19 02:18:28 2021 +0000
+
+ upstream: increase maximum SSH2_FXP_READ to match the maximum
+
+ packet size. Also handle zero-length reads that are borderline nonsensical
+ but not explicitly banned by the spec. Based on patch from Mike Frysinger,
+ feedback deraadt@ ok dtucker@
+
+ OpenBSD-Commit-ID: 4e67d60d81bde7b84a742b4ee5a34001bdf80d9c
+
+commit 860b67604416640e8db14f365adc3f840aebcb1f
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Mar 16 06:15:43 2021 +0000
+
+ upstream: don't let logging clobber errno before use
+
+ OpenBSD-Commit-ID: ce6cca370005c270c277c51c111bb6911e1680ec
+
+commit 5ca8a9216559349c56e09039c4335636fd85c241
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Mar 13 14:40:43 2021 +1100
+
+ Only call dh_set_moduli_file if using OpenSSL.
+
+ Fixes link failure when configuring --without-openssl since dh.c is not
+ linked in.
+
+commit 867a7dcf003c51d5a83f83565771a35f0d9530ac
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Mar 13 13:52:53 2021 +1100
+
+ Don't install moduli during tests.
+
+ Now that we have TEST_SSH_MODULI_FILE pointing to the moduli in the
+ soure directory we don't need to install the file to prevent warnings
+ about it being missing.
+
+commit 0c054538fccf92b4a028008321d3711107bee6d5
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Mar 13 13:51:26 2021 +1100
+
+ Point TEST_SSH_MODULI_FILE at our own moduli.
+
+ This will allow the test to run without requiring a moduli file
+ installed at the configured default path.
+
+commit 4d48219c72ab0c71238806f057f0e9630b7dd25c
+Author: jsg@openbsd.org <jsg@openbsd.org>
+Date: Fri Mar 12 05:18:01 2021 +0000
+
+ upstream: spelling
+
+ OpenBSD-Commit-ID: 478bc3db04f62f1048ed6e1765400f3ab325e60f
+
+commit 88057eb6df912abf2678ea5c846d9d9cbc92752c
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Mar 12 04:08:19 2021 +0000
+
+ upstream: Add ModuliFile keyword to sshd_config to specify the
+
+ location of the "moduli" file containing the groups for DH-GEX. This will
+ allow us to run tests against arbitrary moduli files without having to
+ install them. ok djm@
+
+ OpenBSD-Commit-ID: 8df99d60b14ecaaa28f3469d01fc7f56bff49f66
+
+commit f07519a2af96109325b5a48b1af18b57601074ca
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Mar 12 03:43:40 2021 +0000
+
+ upstream: pwcopy() struct passwd that we're going to reuse across a
+
+ bunch of library calls; bz3273 ok dtucker@
+
+ OpenBSD-Commit-ID: b6eafa977b2e44607b1b121f5de855107809b762
+
+commit 69d6d4b0c8a88d3d1288415605f36e2df61a2f12
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Wed Mar 10 06:32:27 2021 +0000
+
+ upstream: Import regenerated moduli file.
+
+ OpenBSD-Commit-ID: 7ac6c252d2a5be8fbad4c66d9d35db507c9dac5b
+
+commit e5895e8ecfac65086ea6b34d0d168409a66a15e1
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Mar 10 04:58:45 2021 +0000
+
+ upstream: no need to reset buffer after send_msg() as that is done
+
+ for us; patch from Mike Frysinger
+
+ OpenBSD-Commit-ID: 565516495ff8362a38231e0f1a087b8ae66da59c
+
+commit 721948e67488767df0fa0db71ff2578ee2bb9210
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sat Mar 13 01:52:16 2021 +0000
+
+ upstream: Add TEST_SSH_MODULI_FILE variable to allow overriding of the
+
+ moduli file used during the test run.
+
+ OpenBSD-Regress-ID: be10f785263120edb64fc87db0e0d6570a10220a
+
+commit 82fef71e20ffef425b932bec26f5bc46aa1ed41c
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Mar 12 15:58:57 2021 +1100
+
+ Allow (but return EACCES) fstatat64 in sandbox.
+
+ This is apparently used in some configurations of OpenSSL when glibc
+ has getrandom(). bz#3276, patch from Kris Karas, ok djm@
+
+commit 1cd67ee15ce3d192ab51be22bc4872a6a7a4b6d9
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Mar 12 13:16:10 2021 +1100
+
+ Move generic includes outside of ifdef.
+
+ This ensures that the macros in log.h are defined in the case where
+ either of --with-solaris-projects or --with-solaris-privs are used
+ without --with-solaris-contracts. bz#3278.
+
+commit 2421a567a8862fe5102a4e7d60003ebffd1313dd
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Mar 10 17:41:21 2021 +1100
+
+ Import regenerated moduli file.
+
+commit e99080c05d9d48dbbdb022538533d53ae1bd567d
+Author: millert@openbsd.org <millert@openbsd.org>
+Date: Sat Mar 6 20:36:31 2021 +0000
+
+ upstream: Fix PRINT macro, the suffix param to sshlog() was missing.
+
+ Also remove redundant __func__ prefix from PRINT calls as the macro already
+ adds __FILE__, __func__ and __LINE__. From Christos Zoulas. OK dtucker@
+
+ OpenBSD-Commit-ID: 01fdfa9c5541151b5461d9d7d6ca186a3413d949
+
+commit 160db17fc678ceb5e3fd4a7e006cc73866f484aa
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Mar 3 22:41:49 2021 +0000
+
+ upstream: don't sshbuf_get_u32() into an enum; reported by goetze
+
+ AT dovetail.com via bz3269
+
+ OpenBSD-Commit-ID: 99a30a8f1df9bd72be54e21eee5c56a0f050921a
+
+commit cffd033817a5aa388764b6661855dcdaabab0588
+Author: sthen@openbsd.org <sthen@openbsd.org>
+Date: Wed Mar 3 21:40:16 2021 +0000
+
+ upstream: typo in other_hostkeys_message() display output, ok djm
+
+ OpenBSD-Commit-ID: 276f58afc97b6f5826e0be58380b737603dbf5f5
+
+commit 7fe141b96b13bd7dc67ca985e14d55b9bd8a03fd
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Mar 3 08:42:52 2021 +0000
+
+ upstream: needs FILE*; from Mike Frysinger
+
+ OpenBSD-Commit-ID: dddb3aa9cb5792eeeaa37a1af67b5a3f25ded41d
+
commit d2afd717e62d76bb41ab5f3ab4ce6f885c8edc98
Author: Damien Miller <djm@mindrot.org>
Date: Tue Mar 2 21:31:47 2021 +1100
update depend
commit f0c4eddf7cf224ebcac1f07ac8afdb30c6e9fe0a
Author: Damien Miller <djm@mindrot.org>
Date: Tue Mar 2 21:30:14 2021 +1100
update relnotes URL
commit 67a8bb7fe62a381634db4c261720092e7d514a3d
Author: Damien Miller <djm@mindrot.org>
Date: Tue Mar 2 21:29:54 2021 +1100
update RPM spec version numbers
commit 0a4b23b11b9a4e6eec332dd5c6ab2ac6f62aa164
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Mar 2 01:48:18 2021 +0000
upstream: openssh-8.5
OpenBSD-Commit-ID: 185e85d60fe042b8f8fa1ef29d4ef637bdf397d6
commit de3866383b6720ad4cad83be76fe4c8aa111a249
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Mar 1 21:13:24 2021 +1100
Only upload config logs if configure fails.
commit 85ff2a564ce838f8690050081176c1de1fb33116
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sun Feb 28 22:56:30 2021 +0000
upstream: Add %k to list of keywords. From
=?UTF-8?q?=20Eero=20H=C3=A4kkinenvia=20bz#3267?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
OpenBSD-Commit-ID: 9c87f39a048cee2a7d1c8bab951b2f716256865e
commit e774bac35933e71f924f4301786e7fb5bbe1422f
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sun Feb 28 01:50:47 2021 +0000
upstream: Do not try to reset signal handler for signal 0 in
subprocess. Prevents spurious debug message. ok djm@
OpenBSD-Commit-ID: 7f9785e292dcf304457566ad4637effd27ad1d46
commit 351c5dbbd74ce300c4f058112f9731c867c6e225
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Feb 27 23:42:37 2021 +0000
upstream: fix alphabetic ordering of options; spotted by Iain Morgan
OpenBSD-Commit-ID: f955fec617d74af0feb5b275831a9fee813d7ad5
commit 0d1c9dbe578597f8d45d3ac7690df10d32d743e5
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Feb 27 12:25:25 2021 +1100
zlib is now optional.
commit b7c6ee7b437d9adfd19ef49d6c0f19f13f26f9b3
Author: Jeffrey H. Johnson <61629094+johnsonjh@users.noreply.github.com>
Date: Sat Feb 27 01:04:58 2021 +0000
Fix punctuatio and typo in README.md.
Some very minor fixes, missing 's' and punctuation.
commit 6248b86074804983e8f7a2058856a516dbfe2924
Author: Damien Miller <djm@mindrot.org>
Date: Fri Feb 26 16:45:50 2021 +1100
Revert "ssh: optional bind interface if bind address specified."
This reverts commit 5a878a71a3528c2626aa1d331934fd964782d41c.
Apologies - I accidentally pushed this.
commit 493339a940b13be6071629c3c2dd5a3b6fc17023
Author: Damien Miller <djm@mindrot.org>
Date: Fri Feb 26 15:45:38 2021 +1100
detech BSD libc hash functions in libbsd / libmd
Some Linux distributions are shipping the BSD-style hashing functions
(e.g. SHA256Update) in libbsd and/or libmd. Detect this situation to
avoid header/replacement clashes later. ok dtucker@
commit 5a878a71a3528c2626aa1d331934fd964782d41c
Author: Dmitrii Turlupov <dturlupov@factor-ts.ru>
Date: Thu Feb 4 16:27:31 2021 +0300
ssh: optional bind interface if bind address specified.
Allows the -b and -B options to be used together.
For example, when the interface is in the VRF.
commit 1fe4d70df94d3bcc2b35fd57cad6b5fc4b2d7b16
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Feb 26 04:18:42 2021 +0000
upstream: remove this KEX fuzzer; it's awkward to use and doesn't play
nice with popular fuzzing drivers like libfuzzer. AFAIK nobody has used it
but me.
OpenBSD-Regress-ID: cad919522b3ce90c147c95abaf81b0492ac296c9
commit 24a3a67bd7421740d08803b84bd784e764107928
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Feb 26 11:49:19 2021 +1100
Remove macos-11.00 PAM test target too.
These are failing apparently due to some kind of infrastructure problem,
making it look like every commit is busted.
commit 473201783f732ca8b0ec528b56aa55fa0d8cf717
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Feb 26 00:16:58 2021 +0000
upstream: a bit more debugging behind #ifdef DEBUG_SK
OpenBSD-Commit-ID: d9fbce14945721061cb322f0084c2165d33d1993
commit fd9fa76a344118fe1ef10b9a6c9e85d39599e9a8
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Feb 26 01:15:10 2021 +1100
Remove macos-11.0 from the test target list.
It has been consistently failing for the past few days with a github
actions internal error.
commit 476ac8e9d33dbf96ef97aab812b8d7089d0cdc24
Author: Philip Hands <phil@hands.com>
Date: Wed Feb 24 23:43:16 2021 +0100
tidy the $INSTALLKEY_SH code layout a little
SSH-Copy-ID-Upstream: 78178aa5017222773e4c23d9001391eeaeca8983
commit 983e05ef3b81329d76d6a802b39ad0d1f637c06c
Author: Jakub Jelen <jjelen@redhat.com>
Date: Tue Sep 29 10:02:45 2020 +0000
if unable to add a missing newline, fail
SSH-Copy-ID-Upstream: 76b25e18f55499ea9edb4c4d6dc4a80bebc36d95
commit 3594b3b015f6014591da88ba71bf6ff010be7411
Author: Philip Hands <phil@hands.com>
Date: Tue Oct 13 14:12:58 2020 +0200
use $AUTH_KEY_DIR, now that we have it
since that was a change made since jjelen's commit was written
also, quote the variables
SSH-Copy-ID-Upstream: 588cd8e5cbf95f3443d92b9ab27c5d73ceaf6616
commit 333e25f7bc43cee6e36f766e39dad6f9918b318c
Author: Jakub Jelen <jjelen@redhat.com>
Date: Tue Sep 29 10:00:01 2020 +0000
restorecon the correct directory
if using different path for authorized_keys file
SSH-Copy-ID-Upstream: 791a3df47b48412c726bff6f7b1d190721e65d51
commit 9beeab8a37a49a9e3ffb1972fff6621ee5bd7a71
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Feb 25 03:27:34 2021 +0000
upstream: s/PubkeyAcceptedKeyTypes/PubkeyAcceptedAlgorithms/
OpenBSD-Regress-ID: 3dbc005fa29f69dc23d97e433b6dffed6fe7cb69
commit 2dd9870c16ddbd83740adeead5030d6840288c8f
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Feb 24 23:12:35 2021 +0000
upstream: Rename pubkeyacceptedkeytypes to pubkeyacceptedalgorithms in
test to match change to config-dump output.
OpenBSD-Regress-ID: 74c9a4ad50306be873d032819d5e55c24eb74d5d
commit b9225c3a1c3f5827e31d5d64a71b8e0504a25619
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Feb 24 01:18:08 2021 +0000
upstream: Put obsolete aliases for hostbasedalgorithms and
pubkeyacceptedalgorithms after their current names so that the config-dump
mode finds and uses the current names. Spotted by Phil Pennock.
OpenBSD-Commit-ID: 5dd10e93cccfaff3aaaa09060c917adff04a9b15
commit 8b8b60542d6652b2c91e0ef9e9cc81bcb65e6b42
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Feb 23 21:55:08 2021 +0000
upstream: lots more s/key types/signature algorithms/ mostly in
HostbasedAcceptedAlgorithms and HostKeyAlgorithms; prompted by Jakub Jelen
OpenBSD-Commit-ID: 3f719de4385b1a89e4323b2549c66aae050129cb
commit 0aeb508aaabc4818970c90831e3d21843c3c6d09
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Feb 23 21:50:18 2021 +0000
upstream: Correct reference to signature algorithms as keys; from
Jakub Jelen
OpenBSD-Commit-ID: 36f7ecee86fc811aa0f8e21e7a872eee044b4be5
commit f186a020f2ba5f9c462a23293750e29ba0a746b1
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Feb 23 16:05:22 2021 +1100
Add a couple more test VMs.
commit ffcdd3d90e74176b3bb22937ad1f65a6c1cd3f9d
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Feb 22 08:09:27 2021 +1100
Valgrind test: split and move up list.
Since the valgrind test takes so long it approaches the limit allowed by
github, move it to the head of the list so it's the first one started and
split the longest tests out into a second instance that runs concurrently
with the first.
commit c3b1636770785cc2830dedd0f22ef7d3d3491d6d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Feb 23 00:05:31 2021 +0000
upstream: warn when the user specifies a ForwardAgent path that does
not exist and exit if ExitOnForwardFailure is set; bz3264
OpenBSD-Commit-ID: 72f7875865e723e464c71bf8692e83110699bf26
commit 5fcb0514949d61aadaf4a89cf16eb78fb47491ec
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Feb 20 13:34:02 2021 +1100
Disable rlimit sandbox, doesn't work with valgrind
Only run regress tests, runing unit tests as well makes it run longer
than allowed y github.
commit bb0b9bf45396c19486080d3eb0a159f94de7e6ba
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Feb 20 13:06:25 2021 +1100
Upload valgrind logs on failure.
commit ebb3b75e974cb241c6b9b9f5881b09c7bd32b651
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Feb 19 22:18:50 2021 +1100
Rename "vm" to "os" in selfhosted to match c-cpp.
Should make it easier to share code or maybe merge at some point.
commit 76c0be0fe0465cb2b975dbd409f8d38b55e55bcb
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Feb 19 22:15:22 2021 +1100
Upload regress failure logs in c-cpp too.
commit 8751b6c3136f5225c40f41bbf29aa29e15795f6e
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Feb 19 22:13:36 2021 +1100
Comment out Solaris 64bit PAM build...
until I can figure out why it's failing.
commit e9f6d563c06886b277c6b9abafa99fa80726dc48
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Feb 19 10:20:17 2021 +1100
Actually run Valgrind tests.
commit 41d232e226624f1a81c17091c36b44c9010aae62
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Feb 19 10:16:56 2021 +1100
Add test against Valgrind.
commit e6528d91f12fba05f0ea64224091c9d0f38bdf1d
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Feb 18 16:30:01 2021 +1100
Add fbsd12 test target.
commit 6506cb2798d98ff03a7cc06567c392a81f540680
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Feb 18 15:21:13 2021 +1100
Remove unused arg.
commit 93c31a623973b0fad508214593aab6ca94b11dcb
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Feb 18 14:54:07 2021 +1100
Add DEBUG_SK to kitchensink builds.
commit 65085740d3574eeb3289d592f042df62c2689bb0
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Feb 18 14:53:14 2021 +1100
Add bbone test target (arm32).
commit 63238f5aed66148b8d6ca7bd5fb347d624200155
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Feb 18 02:49:35 2021 +0000
upstream: Fix the hostkeys rotation extension documentation
The documentation was lacking the needed want-reply field in the initial
global request.
https://github.com/openssh/openssh-portable/pull/218 by dbussink
OpenBSD-Commit-ID: 051824fd78edf6d647a0b9ac011bf88e28775054
commit 34c5ef6e2d06d9f0e20cb04a9aebf67a6f96609a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Feb 18 02:15:07 2021 +0000
upstream: make names in function prototypes match those in
definition from https://github.com/openssh/openssh-portable/pull/225 by
ZenithalHourlyRate
OpenBSD-Commit-ID: 7c736307bf3f2c7cb24d6f82f244eee959485acd
commit 88e3d4de31ab4f14cac658e9e0c512043b15b146
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Feb 18 02:13:58 2021 +0000
upstream: unbreak SK_DEBUG builds
from https://github.com/openssh/openssh-portable/pull/225 by
ZenithalHourlyRate
OpenBSD-Commit-ID: 28d7259ce1b04d025411464decfa2f1a097b43eb
commit 788cbc5b74a53956ba9fff11e1ca506271a3597f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Feb 18 00:30:17 2021 +0000
upstream: sftp-server: implement limits@openssh.com extension
This is a simple extension that allows the server to clearly
communicate transfer limits it is imposing so the client doesn't
have to guess, or force the user to manually tune. This is
particularly useful when an attempt to use too large of a value
causes the server to abort the connection.
Patch from Mike Frysinger; ok dtucker@
OpenBSD-Commit-ID: f96293221e5aa24102d9bf30e4f4ef04d5f4fb51
commit 324449a68d510720d0e4dfcc8e9e5a702fe6a48f
Author: Damien Miller <djm@mindrot.org>
Date: Thu Feb 18 12:06:25 2021 +1100
support OpenSSL 3.x cipher IV API change
OpenSSL renamed the "get current CIPHER_CTX" IV operation in 3.x.
This uses the new name if available.
https://github.com/openssl/openssl/issues/13411
bz#3238 ok dtucker@
commit 845fe9811c047063d935eca89188ed55c993626b
Author: Damien Miller <djm@mindrot.org>
Date: Thu Feb 18 11:25:38 2021 +1100
prefer login_getpwclass() to login_getclass()
FreeBSD has login_getpwclass() that does some special magic for
UID=0. Prefer this to login_getclass() as its easier to emulate
the former with the latter.
Based on FreeBSD PR 37416 via Ed Maste; ok dtucker@
commit d0763c8d566119cce84d9806e419badf20444b02
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Feb 18 10:45:27 2021 +1100
Fixing quoting for installing moduli on target guest.
commit b3afc243bc820f323a09e3218e9ec8a30a3c1933
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Feb 18 10:27:16 2021 +1100
Install moduli on target not host.
commit f060c2bc85d59d111fa18a12eb3872ee4b9f7e97
Author: Damien Miller <djm@mindrot.org>
Date: Thu Feb 18 10:33:58 2021 +1100
don't free string returned by login_getcapstr(3)
OpenBSD and NetBSD require the caller to free strings returned
bu the login_* functions, but FreeBSD requires that callers don't.
Fortunately in this case, we can harmlessly leak as the process is
about to exec the shell/command.
From https://reviews.freebsd.org/D28617 via Ed Maste; ok dtucker@
commit bc9b0c25703215501da28aa7a6539f96c0fa656f
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Feb 18 10:10:00 2021 +1100
Skip unit tests on sol11 to speed things up.
commit 161873035c12cc22211fc73d07170ade47746bc5
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Feb 18 10:09:27 2021 +1100
Remove SKIP_UNIT as it needs to be a make arg.
commit 1c293868e4b4e8e74e3ea15b8dff90f6b089967a
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Feb 18 10:05:03 2021 +1100
Always intall moduli.
Allows us to run tests without falling back to a fixed modulus. Ensure that
the directory exists.
commit 5c8f41ad100601ec2fdcbccdfe92890c31f81bbe
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Feb 18 09:59:09 2021 +1100
Quote SSHD_CONFOPTS in case it contains spaces.
commit 4653116c1f5384ea7006e6396d9b53c33d218975
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Feb 18 09:51:18 2021 +1100
Fix labels on targets (dots vs underscores).
commit 4512047f57ca3c6e8cd68f0cc69be59e98b25287
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Feb 17 21:47:48 2021 +1100
More compact representation of config matrix.
commit 0406cd09f05c2e419b113dd4c0eac8bc34ec915b
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Feb 17 21:19:18 2021 +1100
Skip unit tests on hosted VMs to speed things up.
commit 4582612e6147d766c336198c498740242fb8f1ec
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Feb 17 20:21:29 2021 +1100
Merge macos and ubuntu tests.
commit 09f4b84654b71099559492e9aed5e1a38bf24815
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Feb 17 18:41:30 2021 +1100
Convert most github hosted tests to new config structure.
commit 65380ff7e054be1454e5ab4fd7bb9c66f8fcbaa9
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Feb 17 18:27:36 2021 +1100
Only run selfhosted tests from selfhosted repo.
commit f031366535650b88248ed7dbf23033afdf466240
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jan 15 14:11:43 2021 +1100
Add self-hosted runners for VMs of other platforms.
Github only hosts a limited number of platforms, and the runner code
is only supported on slightly wider range of platforms. To increase
our test coverage beyond that, we run the runner natively on a VM host,
where it runs a jobs that boot VMs of other platforms, waits for them
to come up then runs the build and test by ssh'ing into the guest.
This means that the minimum dependencies for the guests are quite low
(basically just sshd, a compiler and make).
The interface to the VM host is fairly simple (basically 3 scripts:
vmstartup, vmrun and vmshutdown), but those are specific to the VM host
so are not in the public repo. We also mount the working directory on the
host via sshfs, so things like artifact upload by the runner also work.
As part of this we are moving the per-test-target configs into a single
place (.github/configs) where there will be referenced by a single short
"config" key. I plan to make the github-hosted runners use this too.
The self-hosted runners are run off a private repo on github since that
prevents third parties from accessing them[0], and since runner quota is
limited on private repos, we avoid running the tests we run on the public
repo.
[0] https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners#self-hosted-runner-security-with-public-repositories
commit 64bbd7444d658ef7ee14a7ea5ccc7f5810279ee7
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Feb 17 03:59:00 2021 +0000
upstream: Make sure puttygen is new enough to successfully run the
PuTTY interop tests, otherwise skip them.
OpenBSD-Regress-ID: 34565bb50b8aec58331ed02a5e9e0a9a929bef51
commit da0a9afcc446a30ca49dd216612c41ac3cb1f2d4
Author: markus@openbsd.org <markus@openbsd.org>
Date: Mon Feb 15 20:43:15 2021 +0000
upstream: ssh: add PermitRemoteOpen for remote dynamic forwarding
with SOCKS ok djm@, dtucker@
OpenBSD-Commit-ID: 64fe7b6360acc4ea56aa61b66498b5ecc0a96a7c
commit b696858a7f9db72a83d02cb6edaca4b30a91b386
Author: markus@openbsd.org <markus@openbsd.org>
Date: Mon Feb 15 20:36:35 2021 +0000
upstream: factor out opt_array_append; ok djm@
OpenBSD-Commit-ID: 571bc5dd35f99c5cf9de6aaeac428b168218e74a
commit ad74fc127cc45567e170e8c6dfa2cfd9767324ec
Author: dlg@openbsd.org <dlg@openbsd.org>
Date: Mon Feb 15 11:09:22 2021 +0000
upstream: ProxyJump takes "none" to disable processing like
ProxyCommand does
ok djm@ jmc@
OpenBSD-Commit-ID: 941a2399da2193356bdc30b879d6e1692f18b6d3
commit 16eacdb016ccf38dd9959c78edd3a6282513aa53
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Feb 12 03:49:09 2021 +0000
upstream: sftp: add missing lsetstat@openssh.com documentation
patch from Mike Frysinger
OpenBSD-Commit-ID: 9c114db88d505864075bfe7888b7c8745549715b
commit e04fd6dde16de1cdc5a4d9946397ff60d96568db
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Feb 12 03:14:18 2021 +0000
upstream: factor SSH_AGENT_CONSTRAIN_EXTENSION parsing into its own
function and remove an unused variable; ok dtucker@
OpenBSD-Commit-ID: e1a938657fbf7ef0ba5e73b30365734a0cc96559
commit 1bb130ed34721d46452529d094d9bbf045607d79
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Feb 11 10:18:05 2021 +1100
Add __NR_futex_time64 to seccomp sandbox.
This is apparently needed for (some) 32 bit platforms with glibc 2.33.
Patch from nix at esperi.org.uk and jjelen at redhat.com via bz#3260.
commit f88a7a431212a16e572ecabd559e632f369c363e
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Feb 6 09:37:01 2021 +1100
Add a hostname function for systems that don't have it.
Some systems don't have a hostname command (it's not required by POSIX).
The do have uname -n (which is), but as found by tim@ some others (eg
UnixWare) do not report the FQDN from uname -n.
commit 5e385a71ef2317856f37c91a98658eb12eb5a89c
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Feb 5 22:03:40 2021 +0000
upstream: Roll back the hostname->uname change in rev 1.10. It turns
out uname -n doesn't do what we need for some platforms in portable, so we'll
fix the original problem (that some other platforms don't have hostname at
all) by providing wrapper function to implement it.
OpenBSD-Regress-ID: 827a707d6201d5a8e196a8c28aec1d2c76c52341
commit b446c214279de50ed8388e54897eb1be5281c894
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Feb 5 06:01:58 2021 +0000
upstream: hostname is not specified by POSIX but uname -n is, so use
the latter for portability. Patch from Geert Hendrickx via github PR#208.
OpenBSD-Regress-ID: d6a79c7c4d141a0d05ade4a042eb57dddbce89f3
commit 1cb6ce98d658e5fbdae025a3bd65793980e3b5d9
Author: David Carlier <devnexen@gmail.com>
Date: Sat Nov 21 12:22:23 2020 +0000
Using explicit_memset for the explicit_bzero compatibility layer.
Favoriting the native implementation in this case.
commit 2e0beff67def2120f4b051b1016d7fbf84823e78
Author: Luca Weiss <luca@z3ntu.xyz>
Date: Sun Nov 8 14:19:23 2020 +0100
Deny (non-fatal) statx in preauth privsep child.
commit a35d3e911e193a652bd09eed40907e3e165b0a7b
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Feb 5 02:20:23 2021 +0000
upstream: Remove debug message from sigchld handler. While this
works on OpenBSD it can cause problems on other platforms. From kircherlike
at outlook.com via bz#3259, ok djm@
OpenBSD-Commit-ID: 3e241d7ac1ee77e3de3651780b5dc47b283a7668
commit 69338ab46afe9e3dfb7762ad65351d854077c998
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Feb 2 22:36:59 2021 +0000
upstream: whitespace
OpenBSD-Commit-ID: 544bb092e03fcbecb420196cd0f70af13ea868ad
commit f71219a01d8f71c4b3ed7e456337a84ddba1653e
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Feb 2 22:36:46 2021 +0000
upstream: fix memleaks in private key deserialisation; enforce more
consistency between redundant fields in private key certificate and private
key body; ok markus@
OpenBSD-Commit-ID: dec344e414d47f0a7adc13aecf3760fe58101240
commit 3287790e78bf5b53c4a3cafb67bb5aa03e3910f0
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Feb 2 22:35:14 2021 +0000
upstream: memleak on error path; ok markus@
OpenBSD-Commit-ID: 2091a36d6ca3980c81891a6c4bdc544e63cb13a8
commit 3dd0c64e08f1bba21d71996d635c7256c8c139d1
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Jan 31 22:55:29 2021 +0000
upstream: more strictly enforce KEX state-machine by banning packet
types once they are received. Fixes memleak caused by duplicate
SSH2_MSG_KEX_DH_GEX_REQUEST (spotted by portable OpenSSH kex_fuzz via
oss-fuzz #30078).
ok markus@
OpenBSD-Commit-ID: 87331c715c095b587d5c88724694cdeb701c9def
commit 7a92a324a2e351fabd0ba8ef9b434d3b12d54ee3
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sun Jan 31 10:50:10 2021 +0000
upstream: Set linesize returned by getline to zero when freeing and
NULLing the returned string. OpenBSD's getline handles this just fine, but
some implementations used by -portable do not. ok djm@
OpenBSD-Commit-ID: 4d7bd5169d3397654247db9655cc69a9908d165c
commit a5dfc5bae8c16e2a7caf564758d812c7672480b5
Author: Damien Miller <djm@mindrot.org>
Date: Sat Jan 30 16:32:29 2021 +1100
allow a fuzz case to contain more than one request
loop until input buffer empty, no message consumed or 256 messages
processed
commit 0ef24ad60204022f7e33b6e9d171172c50514132
Author: Damien Miller <djm@mindrot.org>
Date: Sat Jan 30 16:28:23 2021 +1100
expect fuzz cases to have length prefix
might make life a little easier for the fuzzer, e.g. it can now
produce valid (multi-request) messages by smashing two cases together.
commit de613f2713d2dfcd3b03c00e5558a40997f52712
Author: Damien Miller <djm@mindrot.org>
Date: Sat Jan 30 12:03:30 2021 +1100
ssh-agent fuzzer
commit 7e96c877bcb2fb645355a687b8cb7347987c1c58
Author: Damien Miller <djm@mindrot.org>
Date: Sat Jan 30 12:02:46 2021 +1100
move keys out of kex_fuzz.cc into separate header
add certificates and missing key types
commit 76f46d75664fdaa1112739ca523ff85ee4eb52b4
Author: Damien Miller <djm@mindrot.org>
Date: Sat Jan 30 12:02:10 2021 +1100
some fixed test data (mostly keys) for fuzzing
commit 7c2e3d6de1f2edb0c8b4725b4c2b56360e032b19
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 30 00:56:38 2021 +0000
upstream: add a SK_DUMMY_INTEGRATE define that allows the dummy
security key middleware to be directly linked; useful for writing fuzzers,
etc.
OpenBSD-Regress-ID: 0ebd00159b58ebd85e61d8270fc02f1e45df1544
commit 1a4b92758690faa12f49079dd3b72567f909466d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 29 06:29:46 2021 +0000
upstream: fix the values of enum sock_type
OpenBSD-Commit-ID: 18d048f4dbfbb159ff500cfc2700b8fb1407facd
commit 8afaa7d7918419d3da6c0477b83db2159879cb33
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 29 06:28:10 2021 +0000
upstream: give typedef'd struct a struct name; makes the fuzzer I'm
writing a bit easier
OpenBSD-Commit-ID: 1052ab521505a4d8384d67acb3974ef81b8896cb
commit 1e660115f0c7c4a750cd31e468ff889f33dd8088
Author: Damien Miller <djm@mindrot.org>
Date: Fri Jan 29 11:09:14 2021 +1100
fuzz diffie-hellman-group-exchange-sha1 kex too
commit be5f0048ea2aaeddd27be7dcca23aaad345fa16c
Author: Damien Miller <djm@mindrot.org>
Date: Fri Jan 29 11:03:35 2021 +1100
support for running kex fuzzer with null cipher
commit 3d59e88c0e42182c3749b446ccd9027933c84be4
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Jan 28 20:55:16 2021 +1100
make with -j2 to use available CPUs.
commit 66dd9ddb5d2ea8c407908c8e8468c9d6e71db05b
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Jan 28 14:31:01 2021 +1100
Add test against openssl head and libressl head.
commit 237dbb34e24b6b7ea888d54bda4d17da0a0fd0fa
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Jan 28 14:30:50 2021 +1100
Remove whitespace.
commit d983e1732b8135d7ee8d92290d6dce35f736ab88
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Jan 27 23:49:46 2021 +0000
upstream: fix leak: was double allocating kex->session_id buffer
OpenBSD-Commit-ID: 3765f4cc3ae1df874dba9102a3588ba7b48b8183
commit 1134a48cdcef8e7363b9f6c73ebdd24405066738
Author: Damien Miller <djm@mindrot.org>
Date: Thu Jan 28 08:57:31 2021 +1100
correct kex name in disabled code
commit 67f47f1965abafc1830a287761125c2f4790857e
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Jan 27 10:15:08 2021 +0000
upstream: this needs kex.h now
OpenBSD-Commit-ID: c5a42166c5aa002197217421a971e48be7cb5d41
commit 39be3dc209f28f9c1ebfeba42adde8963b01e1cd
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Jan 27 10:05:28 2021 +0000
upstream: make ssh->kex->session_id a sshbuf instead of u_char*/size_t
and use that instead of global variables containing copies of it. feedback/ok
markus@
OpenBSD-Commit-ID: a4b1b1ca4afd2e37cb9f64f737b30a6a7f96af68
commit 4ca6a1fac328477c642329676d6469dba59019a3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Jan 27 09:26:53 2021 +0000
upstream: remove global variable used to stash compat flags and use the
purpose-built ssh->compat variable instead; feedback/ok markus@
OpenBSD-Commit-ID: 7c4f200e112dae6bcf99f5bae1a5629288378a06
commit bba229b6f3328171f5e3ae85de443002523c0452
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Jan 27 12:34:07 2021 +1100
Install moduli file before tests.
Reduces warnings during test runs.
commit 1b83185593a90a73860a503d753a95ca6d726c00
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Jan 27 11:58:26 2021 +1100
Run one test with -Werror to catch warnings.
commit d1532d90074b212054d5fd965f833231b09982f5
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Jan 27 00:37:26 2021 +0000
upstream: Logical not bitwise or. ok djm@
OpenBSD-Commit-ID: d4dc855cf04951b93c45caa383e1ac9af0a3b0e5
commit 507b448a2465a53ab03a88acbc71cc51b48ca6ac
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Tue Jan 26 15:40:17 2021 +0000
upstream: move HostbasedAcceptedAlgorithms to the right place in
alphabetical order
OpenBSD-Commit-ID: d766820d33dd874d944c14b0638239adb522c7ec
commit e26c980778b228bdd42b8353cc70101cf49b731b
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Jan 26 11:25:01 2021 +0000
upstream: Remove unused variables leftover from refactoring. ok
djm@
OpenBSD-Commit-ID: 8b3ad58bff828fcf874e54b2fc27a4cf1d9505e8
commit e9f78d6b06fc323bba1890b2dc3b8423138fb35c
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Jan 26 05:32:21 2021 +0000
upstream: Rename HostbasedKeyTypes (ssh) and
HostbasedAcceptedKeyTypes (sshd) to HostbasedAcceptedAlgorithms, which more
accurately reflects its effect. This matches a previous change to
PubkeyAcceptedAlgorithms. The previous names are retained as aliases. ok
djm@
OpenBSD-Commit-ID: 49451c382adc6e69d3fa0e0663eeef2daa4b199e
commit 48d0d7a4dd31154c4208ec39029d60646192f978
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jan 26 14:48:07 2021 +1100
Disable sntrup761 if compiler doesn't support VLAs.
The sntrup761 code sourced from supercop uses variable length
arrays. Although widely supported, they are not part of the ANSI
C89 spec so if the compiler does not support VLAs, disable the
sntrup761x25519-sha512@openssh.com KEX method by replacing the kex
functions with no-op ones similar to what we do in kexecdh.c.
This should allow OpenSSH to build with a plain C89 compiler again.
Spotted by tim@, ok djm@.
commit 37c70ea8d4f3664a88141bcdf0bf7a16bd5fd1ac
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jan 26 00:54:49 2021 +0000
upstream: refactor key constraint parsing in ssh-agent
Key constraints parsing code previously existed in both the "add regular
key" and "add smartcard key" path. This unifies them but also introduces
more consistency checking: duplicated constraints and constraints that
are nonsensical for a particular situation (e.g. FIDO provider for a
smartcard key) are now banned.
ok markus@
OpenBSD-Commit-ID: 511cb1b1c021ee1d51a4c2d649b937445de7983c
commit e0e8bee8024fa9e31974244d14f03d799e5c0775
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jan 26 00:53:31 2021 +0000
upstream: more ssh-agent refactoring
Allow confirm_key() to accept an additional reason suffix
Factor publickey userauth parsing out into its own function and allow
it to optionally return things it parsed out of the message to its
caller.
feedback/ok markus@
OpenBSD-Commit-ID: 29006515617d1aa2d8b85cd2bf667e849146477e
commit dfe18a295542c169ffde8533b3d7fe42088e2de7
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jan 26 00:51:30 2021 +0000
upstream: make struct hostkeys public; I have no idea why I made it
opaque originally.
ok markus@
OpenBSD-Commit-ID: e50780b34d4bbe628d69b2405b024dd749d982f3
commit 3b44f2513cae89c920e8fe927b9bc910a1c8c65a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jan 26 00:49:30 2021 +0000
upstream: move check_host_cert() from sshconnect,c to sshkey.c and
refactor it to make it more generally usable and testable.
ok markus@
OpenBSD-Commit-ID: 536f489f5ff38808c1fa711ba58d4579b636f9e4
commit 1fe16fd61bb53944ec510882acc0491abd66ff76
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jan 26 00:47:47 2021 +0000
upstream: use recallocarray to allocate the agent sockets table;
also clear socket entries that are being marked as unused.
spinkle in some debug2() spam to make it easier to watch an agent
do its thing.
ok markus
OpenBSD-Commit-ID: 74582c8e82e96afea46f6c7b6813a429cbc75922
commit cb7b22ea20a01332c81c0ddcb3555ad50de9cce2
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jan 26 00:46:17 2021 +0000
upstream: factor out common code in the agent client
Add a ssh_request_reply_decode() function that sends a message to
the agent, reads and parses a success/failure reply.
Use it for all requests that only expect success/failure
ok markus@
OpenBSD-Commit-ID: e0c1f4d5e6cfa525d62581e2b8de93be0cb85adb
commit d1e578afe7cd48140ad6e92a453f9b035363fd7f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Jan 25 06:00:17 2021 +0000
upstream: make ssh hostbased authentication send the signature
algorithm in its SSH2_MSG_USERAUTH_REQUEST packets instead of the key type.
This make HostbasedAcceptedAlgorithms do what it is supposed to - filter on
signature algorithm and not key type.
spotted with dtucker@ ok markus@
OpenBSD-Commit-ID: 25bffe19f0326972f5728170f7da81d5f45c78c6
commit 95eca1e195a3b41baa1a725c2c5af8a09d885e4b
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jan 23 18:26:05 2021 +1100
ifdef new instance of sin6_scope_id
Put inside HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID similar to
existing instance. Should fix error on UnixWare 7.
commit 6ffdcdda128045226dda7fbb3956407978028a1e
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Jan 18 11:43:34 2021 +0000
upstream: Fix long->int for convtime tests here too. Spotted by
tobhe@.
OpenBSD-Regress-ID: a87094f5863312d00938afba771d25f788c849d0
commit b55b7565f15327d82ad7acbddafa90b658c5f0af
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jan 22 02:46:40 2021 +0000
upstream: PubkeyAcceptedKeyTypes->PubkeyAcceptedAlgorithms
here too.
OpenBSD-Commit-ID: 3b64a640f8ce8c21d9314da9df7ce2420eefde3a
commit ee9c0da8035b3168e8e57c1dedc2d1b0daf00eec
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jan 22 02:44:58 2021 +0000
upstream: Rename PubkeyAcceptedKeyTypes keyword to
PubkeyAcceptedAlgorithms. While the two were originally equivalent, this
actually specifies the signature algorithms that are accepted. Some key
types (eg RSA) can be used by multiple algorithms (eg ssh-rsa, rsa-sha2-512)
so the old name is becoming increasingly misleading. The old name is
retained as an alias. Prompted by bz#3253, help & ok djm@, man page help jmc@
OpenBSD-Commit-ID: 0346b2f73f54c43d4e001089759d149bfe402ca5
commit a8e798feabe36d02de292bcfd274712cae1d8d17
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jan 15 02:58:11 2021 +0000
upstream: Change types in convtime() unit test to int to match change
its new type. Add tests for boundary conditions and fix convtime to work up
to INT_MAX. ok djm@
OpenBSD-Regress-ID: ba2b81e9a3257fff204b020affe85b604a44f97e
commit 9bde1a420626da5007bf7ab499fa2159b9eddf72
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jan 15 04:31:25 2021 +0000
upstream: Make output buffer larger to prevent potential truncation
warnings from compilers not smart enough to know the strftime calls won't
ever fully fill "to" and "from". ok djm@
OpenBSD-Commit-ID: 83733f1b01b82da88b9dd1769475952aff10bdd7
commit 02da325f10b214219eae2bb1bc2d3bf0c2f13f9f
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jan 15 02:58:11 2021 +0000
upstream: Change types in convtime() unit test to int to match
change its new type. Add tests for boundary conditions and fix convtime to
work up to INT_MAX. ok djm@
OpenBSD-Commit-ID: 01dc0475f1484ac2f47facdfcf9221f9472145de
commit 5339ab369c225b40bc64d5ec3374f5c91b3ad609
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jan 15 02:32:41 2021 +0000
upstream: In waitfd(), when poll returns early we are subtracting
the elapsed time from the timeout each loop, so we only want to measure the
elapsed time the poll() in that loop, not since the start of the function.
Spotted by chris.xj.zhu at gmail.com, ok djm@
OpenBSD-Commit-ID: 199df060978ee9aa89b8041a3dfaf1bf7ae8dd7a
commit a164862dfa863b54b7897f66e1dd75437f086c11
Author: rob@openbsd.org <rob@openbsd.org>
Date: Thu Jan 14 19:45:06 2021 +0000
upstream: Minor grammatical correction.
OK jmc@
OpenBSD-Commit-ID: de0fad0581e212b2750751e479b79c18ff8cac02
commit 8635e7df7e3a3fbb4a4f6cd5a7202883b2506087
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Jan 13 18:00:57 2021 +1100
Merge Mac OS X targets into a single config.
commit ac112ade990585c511048ed4edaf2d9fc92b61f0
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jan 12 19:22:47 2021 +1100
Add Mac OS X test targets.
commit 1050109b4b2884bf50fd1b3aa084c7fd0a42ae90
Author: anatasluo <luolongjuna@gmail.com>
Date: Mon Jan 11 13:51:39 2021 +0000
Remove duplicated declaration in fatal.c .
commit 7d0f8a3369579dfe398536eb4e3da7bc15da9599
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Jan 11 04:48:22 2021 +0000
upstream: Correct spelling of persourcenetblocksize in config-dump
mode.
OpenBSD-Commit-ID: ecdc49e2b6bde6b6b0e52163d621831f6ac7b13d
commit ba328bd7a6774f30daaf90b83f1933cc4afc866c
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sat Jan 9 12:31:46 2021 +0000
upstream: Adjust kexfuzz to addr.c/addrmatch.c split.
OpenBSD-Regress-ID: 1d8d23bb548078020be2fb52c4c643efb190f0eb
commit b08ef25552443e94c0857d5e3806dd019ccc55d7
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sat Jan 9 12:24:30 2021 +0000
upstream: Update unittests for addr.c/addrmatch.c split.
OpenBSD-Regress-ID: de2b415fb7af084a91c6ef147a90482d8f771eef
commit 6d30673fedec2d251f4962c526fd0451f70c4d97
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Jan 11 02:12:57 2021 +0000
upstream: Change convtime() from returning long to returning int.
On platforms where sizeof(int) != sizeof(long), convtime could accept values
>MAX_INT which subsequently truncate when stored in an int during config
parsing. bz#3250, ok djm@
OpenBSD-Commit-ID: 8fc932683d6b4660d52f50911d62bd6639c5db31
commit 7a57adb8b07b2ad0aead4b2e09ee18edc04d0481
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Sat Jan 9 12:51:12 2021 +0000
upstream: add a comma to previous;
OpenBSD-Commit-ID: 9139433701c0aa86a0d3a6c7afe10d1c9c2e0869
commit 3a923129534b007c2e24176a8655dec74eca9c46
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sat Jan 9 12:10:02 2021 +0000
upstream: Add PerSourceMaxStartups and PerSourceNetBlockSize
options which provide more fine grained MaxStartups limits. Man page help
jmc@, feedback & ok djm@
OpenBSD-Commit-ID: e2f68664e3d02c0895b35aa751c48a2af622047b
commit d9a2bc71693ea27461a78110005d5a2d8b0c6a50
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sat Jan 9 11:58:50 2021 +0000
upstream: Move address handling functions out into their own file
in order to reuse them for per-source maxstartups limiting. Supplement with
some additional functions from djm's flowtools that we'll also need. ok djm@
(as part of a larger diff).
OpenBSD-Commit-ID: e3e7d9ccc6c9b82e25cfef0ec83598e8e2327cbf
commit b744914fcb76d70761f1b667de95841b3fc80a56
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jan 9 00:36:05 2021 +1100
Add test against Graphene hardened malloc.
commit 6cb52d5bf771f6769b630fce35a8e9b8e433044f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 8 04:49:13 2021 +0000
upstream: make CheckHostIP default to 'no'. It doesn't provide any
perceptible value and makes it much harder for hosts to change host keys,
particularly ones that use IP-based load-balancing.
ok dtucker@
OpenBSD-Commit-ID: 0db98413e82074f78c7d46784b1286d08aee78f0
commit 309b642e1442961b5e57701f095bcd4acd2bfb5f
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jan 8 15:50:41 2021 +1100
Run tests with sudo for better coverage.
commit c336644351fa3c715a08b7a292e309e72792e71e
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jan 8 14:26:32 2021 +1100
Add Ubuntu 16.04 and 20.04 test targets.
commit 4c7af01f9dcc1606dec033e7665a042cb0d8ec52
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 8 02:57:24 2021 +0000
upstream: If a signature operation on a FIDO key fails with a
"incorrect PIN" reason and no PIN was initially requested from the user, then
request a PIN and retry the operation.
This smoothes over a few corner cases including FIDO devices that
require PINs for all hosted credentials, biometric FIDO devices that
fall back to requiring PIN when reading the biometric failed, devices
that don't implement reading credProtect status for downloaded keys
and probably a few more cases that I haven't though of yet.
ok dtucker@
OpenBSD-Commit-ID: 176db8518933d6a5bbf81a2e3cf62447158dc878
commit 64ddd0fe68c4a7acf99b78624f8af45e919cd317
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 8 02:44:14 2021 +0000
upstream: don't try to use timespeccmp(3) directly as a qsort(3)
comparison function - it returns 0/1 and not the -1/0/1 that qsort expectes.
fixes sftp "ls -ltr" under some circumstances.
Based on patch by Masahiro Matsuya via bz3248.
OpenBSD-Commit-ID: 65b5e9f18bb0d10573868c3516de6e5170adb163
commit 599df78f3008cf78af21f8977be3e1dd085f8e2e
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jan 8 02:33:13 2021 +0000
upstream: Update the sntrup761 creation script and generated code:
- remove unneeded header files and typedefs and rely on crypto_api.h - add
defines to map types used to the crypto_api ones instead of typedefs. This
prevents typedef name collisions in -portable. - remove CRYPTO_NAMESPACE
entirely instead of making it a no-op - delete unused functions and make the
remaining ones that aren't exported static.
ok djm@
OpenBSD-Commit-ID: 7b9d0cf3acd5a3c1091da8afe00c904d38cf5783
commit 16448ff529affda7e2a15ee7c3200793abde0759
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 8 02:19:24 2021 +0000
upstream: mention that DisableForwarding is valid in a sshd_config
Match block reported by Fredrik Eriksson in bz3239
OpenBSD-Commit-ID: 3a71c3d84b597f5e43e4b40d5232797daf0993f6
commit 91bac5e95b1b0debf9b2b4f05c20dcfa96b368b9
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Jan 4 21:58:58 2021 +0000
upstream: estructure sntrup761.sh to process all files in a single
list, which will make it easier to reorder. Re-inline int32_MINMAX. ok
tobhe@
OpenBSD-Commit-ID: d145c6c19b08bb93c9e14bfaa7af589d90f144c0
commit 4d96a3ebab2224f17e639a15078e03be1ad3736d
Author: tobhe@openbsd.org <tobhe@openbsd.org>
Date: Sun Jan 3 18:05:21 2021 +0000
upstream: Prevent redefinition of `crypto_int32' error with gcc3.
Fixes compilation on luna88k.
Feedback millert@
Found by and ok aoyama@
OpenBSD-Commit-ID: f305ddfe575a26cc53431af3fde3f4aeebed9ba6
commit a23954eeb930ccc8a66a2710153730769dba31b6
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jan 1 22:00:49 2021 +1100
Undef int32 after sort routines.
This prevents typedef'ing crypto_int32 twice, in sntrup761.c and
crypto_api.h, which some compilers (at least some GCCs) don't accept.
commit 148b8a661c3f93e4b6d049ee902de3d521261fbc
Author: Damien Miller <djm@mindrot.org>
Date: Thu Dec 31 12:47:22 2020 +1100
fix: missing pieces of previous commit
commit 3d999be7b987c848feda718cfcfcdc005ddf670d
Author: tobhe@openbsd.org <tobhe@openbsd.org>
Date: Wed Dec 30 14:13:28 2020 +0000
upstream: Use int64_t for intermediate values in int32_MINMAX to
prevent signed 32-bit integer overflow.
Found by and ok djm@
ok markus@
OpenBSD-Commit-ID: 4f0704768e34cf45fdd792bac4011c6971881bb3
commit 5c1953bf98732da5a76c706714ac066dbfa015ac
Author: Damien Miller <djm@mindrot.org>
Date: Tue Dec 29 12:40:54 2020 +1100
adapt KEX fuzzer to PQ kex change
commit 659864fe81dbc57eeed3769c462679d83e026640
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Dec 29 01:02:15 2020 +0000
upstream: Adapt to replacement of
sntrup4591761x25519-sha512@tinyssh.org with
sntrup761x25519-sha512@openssh.com.
Also test sntrup761x25519-sha512@openssh.com in unittests/kex
OpenBSD-Regress-ID: cfa3506b2b077a9cac1877fb521efd2641b6030c
commit 2c71cec020219d69df84055c59eba5799a1233ec
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Dec 29 00:59:15 2020 +0000
upstream: Update/replace the experimental post-quantim hybrid key
exchange method based on Streamlined NTRU Prime (coupled with X25519).
The previous sntrup4591761x25519-sha512@tinyssh.org method is
replaced with sntrup761x25519-sha512@openssh.com. Per the authors,
sntrup4591761 was replaced almost two years ago by sntrup761.
The sntrup761 implementaion, like sntrup4591761 before it, is public
domain code extracted from the SUPERCOP cryptography benchmark
suite (https://bench.cr.yp.to/supercop.html).
Thanks for Daniel J Bernstein for guidance on algorithm selection.
Patch from Tobias Heider; feedback & ok markus@ and myself
(note this both the updated method and the one that it replaced are
disabled by default)
OpenBSD-Commit-ID: 2bf582b772d81ee24e911bb6f4b2aecfd39338ae
commit 09d070ccc3574ae0d7947d212ed53c7268ef7e1f
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Tue Dec 22 07:40:26 2020 +0000
upstream: tweak the description of KnownHostsCommand in ssh_conf.5,
and add entries for it to the -O list in scp.1 and sftp.1;
ok djm
OpenBSD-Commit-ID: aba31ebea03f38f8d218857f7ce16a500c3e4aff
commit 931c93389a80e32272712459b1102d303844453d
Author: Damien Miller <djm@mindrot.org>
Date: Tue Dec 22 19:43:55 2020 +1100
whitespace at EOL
commit 397b1c4d393f97427283a4717e9015a2bd31b8a5
Author: Damien Miller <djm@mindrot.org>
Date: Tue Dec 22 19:42:37 2020 +1100
whitespace at EOL
commit 33fa3ac547e5349ca34681cce6727b2f933dff0a
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Dec 22 19:21:26 2020 +1100
Improve AIX text.
commit 0f2e21c9dca89598b694932b5b05848380a23ec0
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Dec 22 18:56:54 2020 +1100
Include stdio.h for FILE in misc.h.
Fixes build on at least OpenBSD.
commit 3e9811e57b57ee66b0f70d99d7258da3153b0e8a
Author: Damien Miller <djm@mindrot.org>
Date: Tue Dec 22 18:31:50 2020 +1100
ensure $LOGNAME is set in tests
commit 3eb647cbb34d87a063aa7714256c6e56103fffda
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Dec 22 06:47:24 2020 +0000
upstream: more detail for failing tests
OpenBSD-Regress-ID: c68c0e5a521cad7e7f68e54c54ebf86d6c10ee1d
commit 2873f19570d4d8758be24dbf78332be9a779009b
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Dec 22 06:03:36 2020 +0000
upstream: regress test for KnownHostsCommand
OpenBSD-Regress-ID: ffc77464320b6dabdcfa0a72e0df02659233a38a
commit 0121aa87bab9ad2365de2d07f2832b56d5ff9871
Author: tb@openbsd.org <tb@openbsd.org>
Date: Tue Dec 22 03:05:31 2020 +0000
upstream: Remove lines accidentally left behind in the ProxyJump
parsing fix r1.345.
ok djm
OpenBSD-Commit-ID: fe767c108c8117bea33767b080ff62eef2c55f5c
commit da4bf0db942b5f0278f33238b86235e5813d7a5a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Dec 22 00:15:22 2020 +0000
upstream: add a ssh_config KnownHostsCommand that allows the client
to obtain known_hosts data from a command in addition to the usual files.
The command accepts bunch of %-expansions, including details of the
connection and the offered server host key. Note that the command may
be invoked up to three times per connection (see the manpage for
details).
ok markus@
OpenBSD-Commit-ID: 2433cff4fb323918ae968da6ff38feb99b4d33d0
commit a34e14a5a0071de2036826a00197ce38c8b4ba8b
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Dec 22 00:12:22 2020 +0000
upstream: move subprocess() from auth.c to misc.c
make privilege dropping optional but allow it via callbacks (to avoid
need to link uidswap.c everywhere)
add some other flags (keep environment, disable strict path safety check)
that make this more useful for client-side use.
feedback & ok markus@
OpenBSD-Commit-ID: a80ea9fdcc156f1a18e9c166122c759fae1637bf
commit 649205fe388b56acb3481a1b2461f6b5b7c6efa6
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Dec 21 22:48:41 2020 +0000
upstream: Remove explicit rijndael-cbc@lysator.liu.se test since the
cipher was removed.
OpenBSD-Regress-ID: aa93cddb4ecd9bc21446a79008a1a53050e64f17
commit 03e93c753d7c223063ad8acaf9a30aa511e5f931
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Dec 21 11:09:32 2020 +0000
upstream: Remove the pre-standardization cipher
rijndael-cbc@lysator.liu.se. It is an alias for aes256-cbc which was
standardized in RFC4253 (2006), has been deprecated and disabled by default
since OpenSSH 7.2 (2016) and was only briefly documented in ssh.1 in 2001.
This will reduce the amount of work the cipher/kex regression tests need
to do by a little bit. ok markus@ djm@
OpenBSD-Commit-ID: fb460acc18290a998fd70910b19c29b4e4f199ad
commit a11ca015879eab941add8c6bdaaec7d41107c6f5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 21 09:19:53 2020 +0000
upstream: properly fix ProxyJump parsing; Thanks to tb@ for
pointing out my error (parse_ssh_uri() can return -1/0/1, that I missed).
Reported by Raf Czlonka via bugs@
ok tb@
OpenBSD-Commit-ID: a2991a3794bcaf1ca2b025212cce11cdb5f6b7d6
commit d97fb879724f1670bf55d9adfea7278a93c33ae2
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 21 01:31:06 2020 +0000
upstream: adapt to API change in hostkeys_foreach()/load_hostkeys()
OpenBSD-Regress-ID: dcb468514f32da49a446372453497dc6eeafdbf3
commit bf7eb3c266b7fd4ddda108fcf72b860af2af6406
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Oct 16 14:02:24 2020 +0000
upstream: few more things needs match.c and addrmatch.c now that
log.c calls match_pattern_list()
OpenBSD-Regress-ID: f7c95c76b150d0aeb00a67858b9579b7d1b2db74
commit 2c64f24e27a5e72a7f59e515fc4f4985355237ae
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Dec 21 14:02:56 2020 +1100
Pull in missing rev 1.2.
commit 0f504f592d15d8047e466eb7453067a6880992a8
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Dec 20 23:40:19 2020 +0000
upstream: plumb ssh_conn_info through to sshconnect.c; feedback/ok
markus@
OpenBSD-Commit-ID: e8d14a09cda3f1dc55df08f8a4889beff74e68b0
commit 729b05f59ded35483acef90a6f88aa03eae33b29
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Dec 20 23:38:00 2020 +0000
upstream: allow UserKnownHostsFile=none; feedback and ok markus@
OpenBSD-Commit-ID: c46d515eac94a35a1d50d5fd71c4b1ca53334b48
commit b4c7cd1185c5dc0593d47eafcc1a34fda569dd1d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Dec 20 23:36:51 2020 +0000
upstream: load_hostkeys()/hostkeys_foreach() variants for FILE*
Add load_hostkeys_file() and hostkeys_foreach_file() that accept a
FILE* argument instead of opening the file directly.
Original load_hostkeys() and hostkeys_foreach() are implemented using
these new interfaces.
Add a u_int note field to the hostkey_entry and hostkey_foreach_line
structs that is passed directly from the load_hostkeys() and
hostkeys_foreach() call. This is a lightweight way to annotate results
between different invocations of load_hostkeys().
ok markus@
OpenBSD-Commit-ID: 6ff6db13ec9ee4edfa658b2c38baad0f505d8c20
commit 06fbb386bed666581095cb9cbc7a900e02bfe1b7
Author: tobhe@openbsd.org <tobhe@openbsd.org>
Date: Sat Dec 19 22:09:21 2020 +0000
upstream: Print client kem key with correct length.
ok markus@
OpenBSD-Commit-ID: 91689e14a4fc6c270e265a32d1c8faba63a45755
commit 0ebead6593e2441e4af2735bbe2cd097607cd0d3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Dec 17 23:28:50 2020 +0000
upstream: fix possible error("%s", NULL) on error paths
OpenBSD-Commit-ID: 0b3833c2cb985453ecca1d76803ebb8f3b736a11
commit d060bc7f6e6244f001e658208f53e3e2ecbbd382
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Dec 17 23:26:11 2020 +0000
upstream: refactor client percent_expand() argument passing;
consolidate the common arguments into a single struct and pass that around
instead of using a bunch of globals. ok markus@
OpenBSD-Commit-ID: 035e6d7ca9145ad504f6af5a021943f1958cd19b
commit 43026da035cd266db37df1f723d5575056150744
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Dec 17 23:10:27 2020 +0000
upstream: prepare readconf.c for fuzzing; remove fatal calls and
fix some (one-off) memory leaks; ok markus@
OpenBSD-Commit-ID: 91c6aec57b0e7aae9190de188e9fe8933aad5ec5
commit bef92346c4a808f33216e54d6f4948f9df2ad7c1
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 14 03:13:12 2020 +0000
upstream: use _PATH_SSH_USER_DIR instead of hardcoded .ssh in path
OpenBSD-Commit-ID: 5c1048468813107baa872f5ee33ba51623630e01
commit a5ab499bd2644b4026596fc2cb24a744fa310666
Author: Damien Miller <djm@mindrot.org>
Date: Fri Dec 4 14:01:27 2020 +1100
basic KEX fuzzer; adapted from Markus' unittest
commit 021ff33e383c77b11badd60cec5b141a3e3fa532
Author: Damien Miller <djm@mindrot.org>
Date: Fri Dec 4 13:57:43 2020 +1100
use options that work with recent clang
commit e4d1a0b40add800b6e9352b40c2223e44acc3a45
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Dec 4 02:41:10 2020 +0000
upstream: shuffle a few utility functions into sftp-client.c; from
Jakub Jelen
OpenBSD-Commit-ID: fdeb1aae1f6149b193f12cd2af158f948c514a2a
commit ace12dc64f8e3a2496ca48d36b53cb3c0a090755
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Dec 4 02:29:56 2020 +0000
upstream: make ssh_free(NULL) a no-op
OpenBSD-Commit-ID: 42cb285d94789cefe6608db89c63040ab0a80fa0
commit 3b98b6e27f8a122dbfda9966b1afeb3e371cce91
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Dec 4 02:29:25 2020 +0000
upstream: memleak of DH public bignum; found with libfuzzer
OpenBSD-Commit-ID: 0e913b542c3764b100b1571fdb0d0e5cc086fe97
commit 553b90feedd7da5b90901d73005f86705456d686
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Dec 4 02:27:57 2020 +0000
upstream: fix minor memleak of kex->hostkey_alg on rekex
OpenBSD-Commit-ID: 2c3969c74966d4ccdfeff5e5f0df0791919aef50
commit ac0364b85e66eb53da2f9618f699ba6bd195ceea
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Dec 4 02:27:08 2020 +0000
upstream: typos: s/hex/kex/ in error messages
OpenBSD-Commit-ID: 43a026c9571dd779ec148de1829cf5a6b6651905
commit ee22db7c5885a1d90219202c0695bc621aa0409b
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Dec 4 02:25:13 2020 +0000
upstream: make program name be const
OpenBSD-Commit-ID: ece25680ec637fdf20502721ccb0276691df5384
commit 2bcbf679de838bb77a8bd7fa18e100df471a679c
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Nov 30 05:36:39 2020 +0000
upstream: Ignore comments at the end of config lines in ssh_config,
similar to what we already do for sshd_config. bz#2320, with & ok djm@
OpenBSD-Commit-ID: bdbf9fc5bc72b1a14266f5f61723ed57307a6db4
commit b755264e7d3cdf1de34e18df1af4efaa76a3c015
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sat Nov 28 12:52:32 2020 +0000
upstream: Include cipher.h for declaration of cipher_by_name.
OpenBSD-Commit-ID: ddfebbca03ca0e14e00bbad9d35f94b99655d032
commit 022def7bd16c3426a95e25f57cb259d54468341c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Nov 28 03:27:59 2020 +0000
upstream: check result of strchr() against NULL rather than
searched-for characters; from zhongjubin@huawei.com
OpenBSD-Commit-ID: e6f57de1d4a4d25f8db2d44e8d58d847e247a4fe
commit 57bf03f0217554afb8980f6697a7a0b88658d0a9
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Nov 27 10:12:30 2020 +0000
upstream: Document ssh-keygen -Z, sanity check its argument earlier and
provide a better error message if it's not correct. Prompted by bz#2879, ok
djm@ jmc@
OpenBSD-Commit-ID: 484178a173e92230fb1803fb4f206d61f7b58005
commit 33313ebc1c7135085676db62189e3520341d6b73
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 27 00:49:58 2020 +0000
upstream: Set the specified TOS/DSCP for interactive use prior to
TCP connect. The connection phase of the SSH session is time-sensitive (due
to server side login grace periods) and is frequently interactive (e.g.
entering passwords). The ultimate interactive/bulk TOS/DSCP will be set after
authentication completes.
ok dtucker@
OpenBSD-Commit-ID: f31ab10d9233363a6d2c9996007083ba43a093f1
commit b2bcec13f17ce9174238a704e91d52203e916432
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 27 00:37:10 2020 +0000
upstream: clean up passing of struct passwd from monitor to preauth
privsep process. No longer copy entire struct w/ pointer addresses, but pass
remaining scalar fields explicitly,
Prompted by Yuichiro NAITO, feedback Thorsten Glaser; ok dtucker@
OpenBSD-Commit-ID: 9925df75a56732c43f3663e70dd15ff413ab3e53
commit 19af04e2231155d513e24fdc81fbec2217ae36a6
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Nov 22 22:38:26 2020 +0000
upstream: when loading PKCS#11 keys, include the key fingerprints
and provider/slot information in debug output.
OpenBSD-Commit-ID: 969a089575d0166a9a364a9901bb6a8d9b8a1431
commit 9b9465ea856e15b9e9890b4ecb4110d7106e7766
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Nov 22 22:37:11 2020 +0000
upstream: when mentioning that the host key has changed, don't
report the type because it is ambiguous as to whether it referred to the
known or new host key. bz3216; ok dtucker@
OpenBSD-Commit-ID: 2d5ce4a83dbcf44e340a572e361decad8aab7bad
commit 637017a7dd3281d3f2df804993cc27c30dbfda47
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Nov 25 17:38:46 2020 +1100
Use "=" not "==" in string test.
POSIX says "=" is string comparison and some shells (eg HP-UX) will
complain about "==".
commit 9880f3480f9768897f3b8e714d5317fb993bc5b3
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 20 17:16:51 2020 +1100
Restore correct flags during localtime_r check.
We were restoring the wrong thing CPPFLAGS (we used CFLAGS) for any
platform that doesn't have localtime_r.
commit 41935882f4e82de60dbd6e033eabe79e1b963518
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Nov 20 03:16:56 2020 +0000
upstream: When doing an sftp recursive upload or download of a
read-only directory, ensure that the directory is created with write and
execute permissions in the interim so that we can actually complete the
transfer, then set the directory permission as the final step. (The execute
bit is only likely to be an issue with a non-POSIX server). bz#3222, ok djm@
OpenBSD-Commit-ID: a82606212f2796e31f0e1af94a63355a7ad5d903
commit 0f90440ca70abab947acbd77795e9f130967956c
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 20 13:37:54 2020 +1100
Add new pselect6_time64 syscall on ARM.
This is apparently needed on armhfp/armv7hl. bz#3232, patch from
jjelen at redhat.com.
commit 3a7c46c72b6a1f643b1fc3589cd20d8320c3d9e1
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Nov 20 02:14:16 2020 +0000
upstream: Explicitly initialize all members of the
find_by_key_ctx struct. Initializing a single member should be enough
(the spec says the remainder should be initialized as per the static
rules) but some GCCs warn on this which prevents us testing with -Werror
on those. ok deraadt@ djm@
OpenBSD-Commit-ID: 687126e60a27d30f02614760ef3c3ae4e8d6af28
commit 076cb616b87d1ea1d292973fcd0ba38c08ea6832
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Nov 19 23:05:05 2020 +0000
upstream: draft-ietf-secsh-architecture is now RFC4251.
OpenBSD-Commit-ID: cb0bb58c2711fb5ed519507659be1dcf179ed403
commit 85cceda21f1471548e04111aefe2c4943131c1c8
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Nov 17 11:23:58 2020 +0000
upstream: Specify that the KDF function is bcrypt. Based on github
PR#214 from rafork, ok markus@, mdoc correction jmc@
OpenBSD-Commit-ID: d8f2853e7edbcd483f31b50da77ab80ffa18b4ef
commit 5b9720f9adbd70ba5a994f407fe07a7d016d8d65
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Nov 15 22:34:58 2020 +0000
upstream: revert r1.341; it breaks ProxyJump; reported by sthen@
OpenBSD-Commit-ID: 6ac2f945b26cb86d936eed338f77861d6da8356a
commit 04088725ec9c44880c01799b588cd4ba47b3e8bc
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 13 07:30:44 2020 +0000
upstream: scrub keyboard-interactive authentication prompts coming
from the server through asmprintf() prior to display; suggested by and ok
dtucker@
OpenBSD-Commit-ID: 31fe93367645c37fbfe4691596bf6cf1e3972a58
commit 5442b491d0ee4bb82f6341ad0ee620ef3947f8c5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 13 04:53:12 2020 +0000
upstream: prefix keyboard interactive prompts with (user@host) to
make it easier to determine which connection they are associated with in
cases like scp -3, ProxyJump, etc. bz#3224 ok dtucker
OpenBSD-Commit-ID: 67e6189b04b46c867662f8a6759cf3ecb5f59170
commit 2992e4e7014ac1047062acfdbbf6feb156fef616
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 13 17:56:11 2020 +1100
Remove use of TIME_WITH_SYS_TIME.
It was only set by the recently removed AC_HEADER_TIME macro, replace
with simple inclusions of both sys/time.h and time.h. Should prevent
mis-detection of struct timespec.
commit e3f27006f15abacb7e89fda3f5e9a0bd420b7e38
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 13 14:20:43 2020 +1100
Revert "detect Linux/X32 systems"
This reverts commit 5b56bd0affea7b02b540bdbc4d1d271b0e4fc885.
The approach used was incorrect; discussion in bz#3085
commit e51dc7fab61df36e43f3bc64b673f88d388cab91
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 13 13:22:15 2020 +1100
SELinux has deprecated security_context_t
(it was only ever a char* anyway)
commit b79add37d118276d67f3899987b9f0629c9449c3
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 13 13:43:30 2020 +1100
Remove obsolete AC_HEADER_TIME macro.
AC_HEADER_TIME is marked as obsolete in autoconf-2.70 and as far as I
can tell everything we have that might be old enough to need it doesn't.
commit d5d05cdb3d4efd4a618aa52caab5bec73097c163
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Nov 12 22:56:00 2020 +0000
upstream: when prompting the user to accept a new hostkey, display
any other host names/addresses already associated with the key. E.g.
> The authenticity of host 'test (10.0.0.1)' can't be established.
> ECDSA key fingerprint is SHA256:milU4MODXm8iJQI18wlsbPG7Yup+34fuNNmV08qDnax.
> This host key is known by the following other names/addresses:
> ~/.ssh/known_hosts:1: host.example.org,10.0.0.1
> ~/.ssh/known_hosts:2: [hashed name]
> ~/.ssh/known_hosts:3: [hashed name]
> ~/.ssh/known_hosts:4: host
> ~/.ssh/known_hosts:5: [host]:2222
> Are you sure you want to continue connecting (yes/no/[fingerprint])?
feedback and ok markus@
OpenBSD-Commit-ID: f6f58a77b49f1368b5883b3a1f776447cfcc7ef4
commit 819b44e8b9af6ce18d3ec7505b9f461bf7991a1f
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Nov 12 22:38:57 2020 +0000
upstream: Prevent integer overflow when ridiculously large
ConnectTimeout is specified, capping the effective value (for most platforms)
at 24 days. bz#3229, ok djm@
OpenBSD-Commit-ID: 62d4c4b7b87d111045f8e9f28b5b532d17ac5bc0
commit add926dd1bbe3c4db06e27cab8ab0f9a3d00a0c2
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Nov 11 05:22:32 2020 +0000
upstream: fix logic error that broke URI parsing in ProxyJump
directives; ok dtucker@
OpenBSD-Commit-ID: 96d48839b1704882a0e9a77898f5e14b2d222705
commit 4340dd43928dfe746cb7e75fe920b63c0d909a9a
Author: claudio@openbsd.org <claudio@openbsd.org>
Date: Tue Nov 10 07:46:20 2020 +0000
upstream: Free the previously allocated msg buffer after writing it
out. OK djm@
OpenBSD-Commit-ID: 18c055870fc75e4cb9f926c86c7543e2e21d7fa4
commit fcf429a4c69d30d8725612a55b37181594da8ddf
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Nov 11 12:30:46 2020 +1100
Prevent excessively long username going to PAM.
This is a mitigation for a buffer overflow in Solaris' PAM username
handling (CVE-2020-14871), and is only enabled for Sun-derived PAM
implementations. This is not a problem in sshd itself, it only
prevents sshd from being used as a vector to attack Solaris' PAM.
It does not prevent the bug in PAM from being exploited via some other
PAM application.
Based on github PR#212 from Mike Scott but implemented slightly
differently. ok tim@ djm@
commit 10dce8ff68ef615362cfcab0c0cc33ce524e7682
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Nov 8 23:19:03 2020 +0000
upstream: unbreak; missing NULL check
OpenBSD-Commit-ID: 6613dfab488123f454d348ef496824476b8c11c0
commit d5a0cd4fc430c8eda213a4010a612d4778867cd9
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Nov 8 22:37:24 2020 +0000
upstream: when requesting a security key touch on stderr, inform the
user once the touch has been recorded; requested by claudio@ ok markus@
OpenBSD-Commit-ID: 3b76ee444490e546b9ea7f879e4092ee0d256233
commit 292bcb2479deb27204e3ff796539c003975a5f7a
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Nov 9 00:33:35 2020 +1100
Remove preprocessor directive from log macro calls.
Preprocessor directives inside macro calls, such as the new log macros,
are undefined behaviour and do not work with, eg old GCCs. Put the
entire log call inside the ifdef for OPENSSL_HAS_NISTP521.
commit 71693251b7cbb7dd89aaac18815147124732d0d3
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sun Nov 8 12:10:20 2020 +0000
upstream: Add a comment documenting the source of the moduli group
sizes.
OpenBSD-Commit-ID: aec0725ce607630caaa62682624c6763b350391c
commit 4d94b031ff88b015f0db57e140f481bff7ae1a91
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sun Nov 8 11:46:12 2020 +0000
upstream: Replace WITH_OPENSSL ifdefs in log calls with a macro.
The log calls are themselves now macros, and preprocessor directives inside
macro arguments are undefined behaviour which some compilers (eg old GCCs)
choke on. It also makes the code tidier. ok deraadt@
OpenBSD-Commit-ID: cc12a9029833d222043aecd252d654965c351a69
commit 6d2564b94e51184eb0b73b97d13a36ad50b4f810
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 6 17:11:16 2020 +1100
Fix function body for variadic macro test.
AC_LANG_PROGRAM puts its second argument inside main() so we don't need
to do it ourselves.
commit 586f9bd2f5980e12f8cf0d3c2a761fa63175da52
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 6 16:53:24 2020 +1100
Remove AC_PROC_CC_C99 obsoleted in autoconf 2.70.
Since we only use it to make sure we can handle variadic macros,
explicitly check only for that. with & ok djm@
commit a019e353df04de1b2ca78d91b39c393256044ad7
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 6 13:56:41 2020 +1100
Replace AC_TRY_COMPILE obsoleted in autoconf 2.70.
Replace with the equivalent AC_COMPILE_IFELSE.
commit 771b7795c0ef6a2fb43b4c6c66b615c2085cb9cd
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 6 13:55:33 2020 +1100
Move AC_PROG_CC_C99 to immediately afer AC_PROG_CC.
This puts the related C version selection output in the same place.
commit e5591161f21ab493c6284a85ac3c0710ad94998f
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 6 13:54:17 2020 +1100
AC_CHECK_HEADER() is obsoleted in autoconf 2.70.
Replace with the non-obsoleted AC_CHECK_HEADERS().
commit 05bcd0cadf160fd4826a2284afa7cba6ec432633
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Nov 3 22:53:12 2020 +0000
upstream: fold consecutive '*' wildcards to mitigate combinatorial
explosion of recursive searches; ok dtucker
OpenBSD-Commit-ID: d18bcb39c40fb8a1ab61153db987e7d11dd3792b
commit 7d680448db5858dc76307663f78d0b8d3c2b4a3d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Oct 30 01:50:07 2020 +0000
upstream: print reason in fatal error message when
kex_assemble_namelist() fails
OpenBSD-Commit-ID: a9975ee8db6c98d6f32233d88051b2077ca63dab
commit 95d1109fec7e89ad21f2a97e92bde1305d32a353
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 29 03:13:06 2020 +0000
upstream: fix sshd_config SetEnv directive inside Match blocks; part of
github PR#201 from github user manuelm
OpenBSD-Commit-ID: 9772e3748abff3ad65ae8fc43d026ed569b1d2bc
commit b12b835dc022ba161afe68348e05a83dfbcb1515
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 29 03:01:18 2020 +0000
upstream: fix type of nid in type_bits_valid(); github PR#202 from
github user thingsconnected
OpenBSD-Commit-ID: 769d2b040dec7ab32d323daf54b854dd5dcb5485
commit 1a14c13147618144d1798c36a588397ba9008fcc
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 29 02:52:43 2020 +0000
upstream: whitespace; no code change
OpenBSD-Commit-ID: efefc1c47e880887bdee8cd2127ca93177eaad79
commit 815209abfdd2991fb92ad7d2e33374916cdcbcf4
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 29 02:47:23 2020 +0000
upstream: UpdateHostkeys: fixed/better detection of host keys that
exist under other names and addresses; spotted by and debugged with lots of
help from jca@
OpenBSD-Commit-ID: 5113d7f550bbd48243db1705afbf16b63792d4b7
commit a575cf44e59a65506c67bddb62a712208a7a279c
Author: Duncan Eastoe <duncan.eastoe@att.com>
Date: Wed Oct 21 10:11:10 2020 +0100
session.c: use "denylist" terminology
Follow upstream (6d755706a0059eb9e2d63517f288b75cbc3b4701) language
improvements in this portable-specific code.
commit 33267feaffd5d98aa56d2f0b3a99ec352effe938
Author: Damien Miller <djm@mindrot.org>
Date: Tue Oct 27 16:46:31 2020 +1100
Remove checks for strict POSIX mkdtemp()
We needed a mkdtemp() that accepted template paths that did not
end in XXXXXX a long time ago for KRB4, but that code is long
deprecated. We no longer need to replace mkdtemp() for strictly
following POSIX. ok dtucker@
commit 492d70e18bad5a8c97d05f5eddac817171e88d2c
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Oct 26 00:39:04 2020 +0000
upstream: Minor man page fixes (capitalization, commas) identified by
the manpage-l10n project via bz#3223. feedback deraadt@, ok jmc@
OpenBSD-Commit-ID: ab83af0daf18369244a72daaec6c4a58a9eb7e2c
commit eab2888cfc6cc4e2ef24bd017da9835a0f365f3f
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Oct 19 22:49:23 2020 +0000
upstream: Adapt XMSS to new logging infrastructure. With markus@, ok
djm@.
OpenBSD-Commit-ID: 9c35ec3aa0f710e4e3325187ceff4fa3791686de
commit f7bd11e4941620991f3e727cd0131b01f0311a58
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Oct 19 08:07:08 2020 +0000
upstream: fix SEGV on fatal() errors spotted by dtucker@
OpenBSD-Commit-ID: 75f155a1ac61e364ed00dc379e2c42df81067ce2
commit 7715a3b171049afa1feffb1d5a1245dfac36ce99
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Oct 19 10:54:41 2020 +1100
Use fatal_fr not fatal_r when passing r.
Caught by the PAM -Werror tinderbox build.
commit 816036f142ecd284c12bb3685ae316a68d2ef190
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Oct 18 11:32:01 2020 +0000
upstream: use the new variant log macros instead of prepending
__func__ and appending ssh_err(r) manually; ok markus@
OpenBSD-Commit-ID: 1f14b80bcfa85414b2a1a6ff714fb5362687ace8
commit 9e2c4f64224f68fb84c49b5182e449f94b0dc985
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Oct 18 11:21:59 2020 +0000
upstream: variants of the log methods that append a ssherr.h string
from a supplied error code; ok markus@
OpenBSD-Commit-ID: aed98c4435d48d036ae6740300f6a8357b7cc0bf
commit 28cb0a4b03940d1ee576eb767a81a4113bdc917e
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Oct 18 11:14:27 2020 +0000
upstream: remove a level of macro indirection; ok markus@
OpenBSD-Commit-ID: 0c529d06e902c5d1a6b231e1bec6157f76dc67c9
commit 9cac1db52e6c4961c447910fe02cd68a3b2f9460
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Oct 18 11:13:45 2020 +0000
upstream: add some variant log.h calls that prepend the calling
function name; ok markus@
OpenBSD-Commit-ID: 4be1b2e2455b271ddb7457bc195c5367644f4e48
commit d55dfed34ef6ef1f028d552a90d5f3dba8dd6f7b
Author: Damien Miller <djm@mindrot.org>
Date: Sat Oct 17 22:55:24 2020 +1100
missing header
commit 999d7cb79a3a73d92a6dfbf174c33da0d984c7a2
Author: Damien Miller <djm@mindrot.org>
Date: Sat Oct 17 22:47:52 2020 +1100
sync regress/misc/sk-dummy/fatal.c
commit 3554b4afa38b3483a3302f1be18eaa6f843bb260
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Oct 17 01:28:20 2020 +0000
upstream: make the log functions that exit (sshlogdie(),
sshfatal(), etc) have identical signatures. Makes things a bit more
consistent...
OpenBSD-Commit-ID: bd0ae124733389d7c0042e135c71ee9091362eb9
commit 616029a85ad7529b24bb8c4631d9607c0d6e7afe
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Fri Oct 16 14:34:33 2020 +0000
upstream: add space between macro arg and punctuation;
OpenBSD-Commit-ID: bb81e2ed5a77832fe62ab30a915ae67cda57633e
commit f812a36cee5727147bc897d34ab9af068dd4561e
Author: Damien Miller <djm@mindrot.org>
Date: Sat Oct 17 12:03:34 2020 +1100
check for and require a C99 capable compiler
recent logging changes use __VA_ARGS__.
commit f9ea6515202b59a1e2d5b885cafc1b12eff33016
Author: Damien Miller <djm@mindrot.org>
Date: Sat Oct 17 11:51:20 2020 +1100
logging is now macros, remove function pointers
commit 0f938f998626e8359324f803157cd7c9f8f403e2
Author: Damien Miller <djm@mindrot.org>
Date: Sat Oct 17 11:42:26 2020 +1100
adapt sk-dummy's fatal implementation to changes
commit afbd9ec9e2dbad04834ce7ce53e58740434f32a5
Author: Damien Miller <djm@mindrot.org>
Date: Sat Oct 17 11:33:13 2020 +1100
fix netcat build problem
commit 793b583d097381730adaf6f68bed3c343139a013
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Oct 16 13:26:13 2020 +0000
upstream: LogVerbose keyword for ssh and sshd
Allows forcing maximum debug logging by file/function/line pattern-
lists.
ok markus@
OpenBSD-Commit-ID: c294c25732d1b4fe7e345cb3e044df00531a6356
commit 752250caabda3dd24635503c4cd689b32a650794
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Oct 16 13:24:45 2020 +0000
upstream: revised log infrastructure for OpenSSH
log functions receive function, filename and line number of caller.
We can use this to selectively enable logging via pattern-lists.
ok markus@
OpenBSD-Commit-ID: 51a472610cbe37834ce6ce4a3f0e0b1ccc95a349
commit acadbb3402b70f72f14d9a6930ad41be97c2f9dc
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Oct 16 02:37:12 2020 +0000
upstream: use do_log2 instead of function pointers to different log
functions
OpenBSD-Commit-ID: 88077b826d348c58352a6b394755520f4e484480
commit 95b0bcfd1531d59e056ae8af27bb741391f26ab0
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 14 00:55:17 2020 +0000
upstream: make UpdateHostkeys still more conservative: refuse to
proceed if one of the keys offered by the server is already in known_hosts
under another name. This avoid collisions between address entries for
different host aliases when CheckHostIP=yes
Also, do not attempt to fix known_hosts with incomplete host/ip matches
when there are no new or deprecated hostkeys.
OpenBSD-Commit-ID: 95c19842f7c41f9bd9c92aa6441a278c0fd0c4a3
commit a336ce8c2c55547cc00e0070a18c55f30bb53fb6
Author: kn@openbsd.org <kn@openbsd.org>
Date: Mon Oct 12 08:36:36 2020 +0000
upstream: Zap unused family parameter from ssh_connect_direct()
sshconnect.c r1.241 from 2013 made it unused; found while reading code.
OK djm
OpenBSD-Commit-ID: 219ba6d7f9925d0b7992918612680399d86712b5
commit e545d94b713effab8e6c7dfabbfb76c1d84d7498
Author: Philip Hands <phil@hands.com>
Date: Sun Oct 4 00:15:46 2020 +0200
shift contents of long $() into filter_ids()
This was prompted by the fact that posh does not deal with $()
that contains comments where the comment includes an odd number
of single-quotes. It seems to get befuddled into trying to find
the matching quote.
Regardless, making a function for filtering the unneeded ids
seems much neater than avoiding apostrophes,
so that's what I've done.
SSH-Copy-ID-Upstream: 3dab3366a584427045c8a690a93282f02c09cf24
commit fd360174596047b52aa1cddda74d85012a03ca4b
Author: Philip Hands <phil@hands.com>
Date: Sat Oct 3 23:15:16 2020 +0200
combine if/elif to avoid duplication of the action
SSH-Copy-ID-Upstream: 42aeb1cc53d3f7f6e78edc210fb121fda0834914
commit f7c3a39b016dd77709ecbf18da8282f967b86cd7
Author: Philip Hands <phil@hands.com>
Date: Sat Oct 3 21:45:16 2020 +0200
shellcheck tidyage
SSH-Copy-ID-Upstream: 5b08f840e78ac544288b3983010a1b0585e966fd
commit 108676c3f26be6c873db0dd8754063699908727b
Author: Philip Hands <phil@hands.com>
Date: Sat Oct 3 21:10:03 2020 +0200
tidy up test of $SCRATCH_DIR creation
SSH-Copy-ID-Upstream: 2d8b22d96c105d87743ffe8874887b06f8989b93
commit a9c9e91a82bc1a2cf801b4e3ef27a941dbd27717
Author: Philip Hands <phil@hands.com>
Date: Wed Sep 16 16:13:30 2020 +0200
add -s flag: to install keys via SFTP
This is prompted by:
https://bugzilla.mindrot.org/show_bug.cgi?id=3201
Thanks go to Matthias Blümel for the idea, and the helpful patch, from
which this patch grew.
SSH-Copy-ID-Upstream: f7c76dc64427cd20287a6868f672423b62057614
commit f92424970c02b78852ff149378c7f2616ada4ccf
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Oct 11 22:14:38 2020 +0000
upstream: UpdateHostkeys: check for keys under other names
Stop UpdateHostkeys from automatically removing deprecated keys from
known_hosts files if the same keys exist under a different name or
address to the host that is being connected to.
This avoids UpdateHostkeys from making known_hosts inconsistent in
some cases. For example, multiple host aliases sharing address-based
known_hosts on different lines, or hosts that resolves to multiple
addresses.
ok markus@
OpenBSD-Commit-ID: 6444a705ba504c3c8ccddccd8d1b94aa33bd11c1
commit d98f14b5328922ae3085e07007d820c4f655b57a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Oct 11 22:13:37 2020 +0000
upstream: UpdateHostkeys: better CheckHostIP handling
When preparing to update the known_hosts file, fully check both
entries for both the host and the address (if CheckHostIP enabled)
and ensure that, at the end of the operation, entries for both are
recorded.
Make sure this works with HashKnownHosts too, which requires maintaining
a list of entry-types seen across the whole file for each key.
ok markus@
OpenBSD-Commit-ID: 374dc263103f6b343d9671f87dbf81ffd0d6abdd
commit af5941ae9b013aac12585e84c4cf494f3728982f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Oct 11 22:12:44 2020 +0000
upstream: UpdateHostkeys: better detect manual host entries
Disable UpdateHostkeys if the known_hosts line has more than two
entries in the pattern-list. ssh(1) only writes "host" or "host,ip"
lines so anything else was added by a different tool or by a human.
ok markus@
OpenBSD-Commit-ID: e434828191fb5f3877d4887c218682825aa59820
commit 6247812c76f70b2245f3c23f5074665b3d436cae
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 8 01:15:16 2020 +0000
upstream: don't misdetect comma-separated hostkey names as wildcards;
spotted by naddy@
OpenBSD-Commit-ID: 4b874edfec7fc324a21b130bdb42f912177739ce
commit 67146c7d022a170be3cdad2f5f40259a663fb266
Author: wangxp006 <wangxiaopeng7@huawei.com>
Date: Thu Oct 8 17:49:59 2020 +0800
fix TEST_MALLOC_OPTIONS var
commit 3205eaa3f8883a34fa4559ddef6c90d1067c5cce
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 8 00:31:05 2020 +0000
upstream: clarify conditions for UpdateHostkeys
OpenBSD-Commit-ID: 9cba714cf6aeed769f998ccbe8c483077a618e27
commit e8dfca9bfeff05de87160407fb3e6a5717fa3dcb
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 7 06:38:16 2020 +0000
upstream: remove GlobalKnownHostsFile for this test after
UpdateHostkeys change
OpenBSD-Regress-ID: a940ad79d59343319613ba8fc46b6ef24aa3f8e1
commit 4aa2717d7517cff4bc423a6cfba3a2defb055aea
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 7 02:26:28 2020 +0000
upstream: Disable UpdateHostkeys when hostkey checking fails
If host key checking fails (i.e. a wrong host key is recorded for the
server) and the user elects to continue (via StrictHostKeyChecking=no),
then disable UpdateHostkeys for the session.
reminded by Mark D. Baushke; ok markus@
OpenBSD-Commit-ID: 98b524f121f4252309dd21becd8c4cacb0c6042a
commit 04c06d04475f1f673e9d9743710d194453fe3888
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 7 02:25:43 2020 +0000
upstream: Fix UpdateHostkeys/HashKnownHosts/CheckHostIP bug
When all of UpdateHostkeys, HashKnownHosts and ChechHostIP
were enabled and new host keys were learned, known_hosts IP
entries were not being recorded for new host keys.
reported by matthieu@ ok markus@
OpenBSD-Commit-ID: a654a8290bd1c930aac509e8158cf85e42e49cb7
commit b70e33711291f3081702133175a41cccafc0212a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 7 02:24:51 2020 +0000
upstream: don't UpdateHostkeys when the hostkey is verified by the
GlobalKnownHostsFile file, support only UserKnownHostsFile matches
suggested by Mark D. Baushke; feedback and ok markus@
OpenBSD-Commit-ID: eabb771a6add676c398d38a143a1aff5f04abbb9
commit aa623142e426ca1ab9db77b06dcc9b1b70bd102b
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 7 02:22:23 2020 +0000
upstream: revert kex->flags cert hostkey downgrade back to a plain
key (commitid VtF8vozGOF8DMKVg). We now do this a simpler way that needs less
plumbing.
ok markus@
OpenBSD-Commit-ID: fb92d25b216bff8c136da818ac2221efaadf18ed
commit f4f14e023cafee1cd9ebe4bb0db4029e6e1fafac
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 7 02:20:35 2020 +0000
upstream: simply disable UpdateHostkeys when a certificate
successfully authenticated the host; simpler than the complicated plumbing
via kex->flags we have now.
ok markus@
OpenBSD-Commit-ID: 80e39644eed75717d563a7f177e8117a0e14f42c
commit e79957e877db42c4c68fabcf6ecff2268e53acb5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 7 02:18:45 2020 +0000
upstream: disable UpdateHostkeys by default if VerifyHostKeyDNS is
enabled; suggested by Mark D. Baushke
OpenBSD-Commit-ID: 85a1b88592c81bc85df7ee7787dbbe721a0542bf
commit 3d4c2016bae1a6f14b48c1150a4c79ca4c9968bd
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Oct 6 07:12:04 2020 +0000
upstream: Agent protocol draft is now at rev 4. ok djm@
OpenBSD-Commit-ID: 8c01ea3aae48aab45e01b7421b0fca2dad5e7837
commit af889a40ffc113af9105c03d7b32131eb4372d50
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Oct 4 09:45:01 2020 +0000
upstream: when ordering host key algorithms in the client, consider
the ECDSA key subtype; ok markus@
OpenBSD-Commit-ID: 3097686f853c61ff61772ea35f8b699931392ece
commit 2d39fc9f7e039351daa3d6aead1538ac29258add
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sun Oct 4 03:04:02 2020 +0000
upstream: Allow full range of UIDs and GIDs for sftp chown and
chgrp on 32bit platforms instead of being limited by LONG_MAX. bz#3206,
found by booking00 at sina.cn, ok markus@
OpenBSD-Commit-ID: 373b7bbf1f15ae482d39567ce30d18b51c9229b5
commit 396d32f3a1a16e54df2a76b2a9b237868580dcbe
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Oct 3 09:22:26 2020 +0000
upstream: There are lots of place where we want to redirect stdin,
stdout and/or stderr to /dev/null. Factor all these out to a single
stdfd_devnull() function that allows selection of which of these to redirect.
ok markus@
OpenBSD-Commit-ID: 3033ba5a4c47cacfd5def020d42cabc52fad3099
commit 1286981d08b8429a64613215ce8bff3f6b32488a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Oct 3 08:30:47 2020 +0000
upstream: enable UpdateHostkeys by default when the configuration
has not overridden UserKnownHostsFile; ok markus@ "The timing is perfect"
deraadt@
OpenBSD-Commit-ID: 62df71c9c5242da5763cb473c2a2deefbd0cef60
commit 332f21537293d66508f7342dc643bc7fe45f0f69
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Oct 3 08:12:59 2020 +0000
upstream: disable UpdateHostkeys when a wildcard hostname pattern
is encountered or when a certificate host key is in use. feedback/ok markus@
OpenBSD-Commit-ID: b6e5575af7e6732322be82ec299e09051a5413bd
commit 13cee44ef907824083d89cb9395adbbd552e46c1
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Oct 3 08:11:28 2020 +0000
upstream: record when the host key checking code downgrades a
certificate host key to a plain key. This occurs when the user connects to a
host with a certificate host key but no corresponding CA key configured in
known_hosts; feedback and ok markus@
OpenBSD-Commit-ID: 2ada81853ff9ee7824c62f440bcf4ad62030c901
commit 12ae8f95e2e0c273e9e7ef930b01a028ef796a3f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Oct 3 04:15:06 2020 +0000
upstream: prefer ed25519 signature algorithm variants to ECDSA; ok
markus@
OpenBSD-Commit-ID: 82187926fca96d35a5b5afbc091afa84e0966e5b
commit e5ed753add7aa8eed6b167e44db6240a76404db2
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Oct 3 03:40:38 2020 +0000
upstream: want time.h here too
OpenBSD-Commit-ID: fafee8f1108c64ad8b282f9a1ed5ea830d8c58a7
commit 66bd9fdf8b7762eb6a85cabbb1ae4ed955679f60
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Sat Oct 3 02:18:33 2020 +0000
upstream: split introductory paragraph, and insert ominous words about
the glob issue, which cannot be fully fixed and really requires completely
replacing scp with a completely different subsystem. team effort to find the
right words..
OpenBSD-Commit-ID: 58e1f72d292687f63eb357183036ee242513691c
commit 86cc8ce002ea10e88a4c5d622a8fdfab8a7d261f
Author: Damien Miller <djm@mindrot.org>
Date: Sat Oct 3 13:38:55 2020 +1000
use relative rather than system include here
commit 922cfac5ed5ead9f796f7d39f012dd653dc5c173
Author: Damien Miller <djm@mindrot.org>
Date: Sat Oct 3 13:38:41 2020 +1000
add some openbsd-compat licenses we missed
commit ce941c75ea9cd6c358508a5b206809846c8d9240
Author: Philip Hands <phil@hands.com>
Date: Sat Oct 3 00:20:07 2020 +0200
un-nest $() to make ksh cheerful
commit 18ea5f4b88e303677d2003b95e5cb864b439e442
Author: Philip Hands <phil@hands.com>
Date: Fri Oct 2 21:30:10 2020 +0200
ksh doesn't grok 'local'
and AFAICT it's not actually doing anything useful in the code, so let's
see how things go without it.
commit d9e727dcc04a52caaac87543ea1d230e9e6b5604
Author: Oleg <Fallmay@users.noreply.github.com>
Date: Thu Oct 1 12:09:08 2020 +0300
Fix `EOF: command not found` error in ssh-copy-id
commit a1a856d50c89be3206f320baa4bfb32fff4e826f
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Sep 30 09:11:39 2020 +0000
upstream: Regen moduli.
OpenBSD-Commit-ID: 04967f8c43e9854ac34b917bcd6f5ac96c53a693
commit fa1fe3ead7069d90d3c67d62137ad66acfcc9f48
Author: HARUYAMA Seigo <haruyama@unixuser.org>
Date: Sun Sep 27 20:06:20 2020 +0900
Restore first section title of INSTALL
commit 279261e1ea8150c7c64ab5fe7cb4a4ea17acbb29
Author: Damien Miller <djm@mindrot.org>
Date: Sun Sep 27 17:25:01 2020 +1000
update version numbers
commit 58ca6ab6ff035ed12b5078e3e9c7199fe72c8587
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Sep 27 07:22:05 2020 +0000
upstream: openssh 8.4
OpenBSD-Commit-ID: a29e5b372d2c00e297da8a35a3b87c9beb3b4a58
commit 9bb8a303ce05ff13fb421de991b495930be103c3
Author: Damien Miller <djm@mindrot.org>
Date: Tue Sep 22 10:07:43 2020 +1000
sync with upstream ssh-copy-id rev f0da1a1b7
commit 0a4a5571ada76b1b012bec9cf6ad1203fc19ec8d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Sep 21 07:29:09 2020 +0000
upstream: close stdin when forking after authentication too; ok markus
OpenBSD-Commit-ID: 43db17e4abc3e6b4a7b033aa8cdab326a7cb6c24
commit d14fe25e6c3b89f8af17e2894046164ac3b45688
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Sep 20 23:31:46 2020 +0000
upstream: close stdout/stderr after "ssh -f ..." forking
bz#3137, ok markus
OpenBSD-Commit-ID: e2d83cc4dea1665651a7aa924ad1ed6bcaaab3e2
commit 53a33a0d745179c02108589e1722457ca8ae4372
Author: Damien Miller <djm@mindrot.org>
Date: Sun Sep 20 15:57:09 2020 +1000
.depend
commit 107eb3eeafcd390e1fa7cc7672a05e994d14013e
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Sep 20 05:47:25 2020 +0000
upstream: cap channel input buffer size at 16MB; avoids high memory use
when peer advertises a large window but is slow to consume the data we send
(e.g. because of a slow network)
reported by Pierre-Yves David
fix with & ok markus@
OpenBSD-Commit-ID: 1452771f5e5e768876d3bfe2544e3866d6ade216
commit acfe2ac5fe033e227ad3a56624fbbe4af8b5da04
Author: Damien Miller <djm@mindrot.org>
Date: Fri Sep 18 22:02:53 2020 +1000
libfido2 1.5.0 is recommended
commit 52a03e9fca2d74eef953ddd4709250f365ca3975
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Sep 18 08:16:38 2020 +0000
upstream: handle multiple messages in a single read()
PR#183 by Dennis Kaarsemaker; feedback and ok markus@
OpenBSD-Commit-ID: 8570bb4d02d00cf70b98590716ea6a7d1cce68d1
commit dc098405b2939146e17567a25b08fc6122893cdf
Author: pedro martelletto <pedro@ambientworks.net>
Date: Fri Sep 18 08:57:29 2020 +0200
configure.ac: add missing includes
when testing, make sure to include the relevant header files that
declare the types of the functions used by the test:
- stdio.h for printf();
- stdlib.h for exit();
- string.h for strcmp();
- unistd.h for unlink(), _exit(), fork(), getppid(), sleep().
commit b3855ff053f5078ec3d3c653cdaedefaa5fc362d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Sep 18 05:23:03 2020 +0000
upstream: tweak the client hostkey preference ordering algorithm to
prefer the default ordering if the user has a key that matches the
best-preference default algorithm.
feedback and ok markus@
OpenBSD-Commit-ID: a92dd7d7520ddd95c0a16786a7519e6d0167d35f
commit f93b187ab900c7d12875952cc63350fe4de8a0a8
Author: Damien Miller <djm@mindrot.org>
Date: Fri Sep 18 14:55:48 2020 +1000
control over the colours in gnome-ssh-askpass[23]
Optionally set the textarea colours via $GNOME_SSH_ASKPASS_FG_COLOR and
$GNOME_SSH_ASKPASS_BG_COLOR. These accept the usual three or six digit
hex colours.
commit 9d3d36bdb10b66abd1af42e8655502487b6ba1fa
Author: Damien Miller <djm@mindrot.org>
Date: Fri Sep 18 14:50:38 2020 +1000
focus improvement for gnome-ssh-askpass[23]
When serving a SSH_ASKPASS_PROMPT=none information dialog, ensure
then <enter> doesn't immediately close the dialog. Instead, require an
explicit <tab> to reach the close button, or <esc>.
commit d6f507f37e6c75a899db0ef8224e72797c5563b6
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Sep 16 03:07:31 2020 +0000
upstream: Remove unused buf, last user was removed when switching
to the sshbuf API. Patch from Sebastian Andrzej Siewior.
OpenBSD-Commit-ID: 250fa17f0cec01039cc4abd95917d9746e24c889
commit c3c786c3a0973331ee0922b2c51832a3b8d7f20f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Sep 9 21:57:27 2020 +0000
upstream: For the hostkey confirmation message:
> Are you sure you want to continue connecting (yes/no/[fingerprint])?
compare the fingerprint case sensitively; spotted Patrik Lundin
ok dtucker
OpenBSD-Commit-ID: 73097afee1b3a5929324e345ba4a4a42347409f2
commit f2950baf0bafe6aa20dfe2e8d1ca4b23528df617
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Sep 11 14:45:23 2020 +1000
New config-build-time dependency on automake.
commit 600c1c27abd496372bd0cf83d21a1c119dfdf9a5
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sun Sep 6 21:56:36 2020 +1000
Add aclocal.m4 and config.h.in~ to .gitignore.
aclocal.m4 is now generated by autoreconf.
commit 4bf7e1d00b1dcd3a6b3239f77465c019e61c6715
Author: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
Date: Sat Sep 5 17:50:03 2020 +0200
Quote the definition of OSSH_CHECK_HEADER_FOR_FIELD
autoreconf complains about underquoted definition of
OSSH_CHECK_HEADER_FOR_FIELD after aclocal.m4 has been and now is beeing
recreated.
Quote OSSH_CHECK_HEADER_FOR_FIELD as suggested.
Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
commit a2f3ae386b5f7938ed3c565ad71f30c4f7f010f1
Author: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
Date: Sat Sep 5 17:50:02 2020 +0200
Move the local m4 macros
The `aclocal' step is skipped during `autoreconf' because aclocal.m4 is
present.
Move the current aclocal.m4 which contains local macros into the m4/
folder. With this change the aclocal.m4 will be re-created during
changes to the m4/ macro.
This is needed so the `aclocal' can fetch m4 macros from the system if
they are references in the configure script. This is a prerequisite to
use PKG_CHECK_MODULES.
Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
commit 8372bff3a895b84fd78a81dc39da10928b662f5a
Author: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
Date: Sat Sep 5 17:50:01 2020 +0200
Remove HAVE_MMAP and BROKEN_MMAP
BROKEN_MMAP is no longer defined since commit
1cfd5c06efb12 ("Remove portability support for mmap")
this commit also removed other HAVE_MMAP user. I didn't find anything
that defines HAVE_MMAP. The check does not trigger because compression
on server side is by default COMP_DELAYED (2) so it never triggers.
Remove remaining HAVE_MMAP and BROKEN_MMAP bits.
Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
commit bbf20ac8065905f9cb9aeb8f1df57fcab52ee2fb
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Sep 9 03:10:21 2020 +0000
upstream: adapt to SSH_SK_VERSION_MAJOR crank
OpenBSD-Regress-ID: 0f3e76bdc8f9dbd9d22707c7bdd86051d5112ab8
commit 9afe2a150893b20bdf9eab764978d817b9a7b783
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Aug 28 03:17:13 2020 +0000
upstream: Ensure that address/mask mismatches are flagged at
config-check time. ok djm@
OpenBSD-Regress-ID: 8f5f4c2c0bf00e6ceae7a1755a444666de0ea5c2
commit c76773524179cb654ff838dd43ba1ddb155bafaa
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Sep 9 03:08:01 2020 +0000
upstream: when writing an attestation blob for a FIDO key, record all
the data needed to verify the attestation. Previously we were missing the
"authenticator data" that is included in the signature.
spotted by Ian Haken
feedback Pedro Martelletto and Ian Haken; ok markus@
OpenBSD-Commit-ID: 8439896e63792b2db99c6065dd9a45eabbdb7e0a
commit c1c44eeecddf093a7983bd91e70b446de789b363
Author: pedro martelletto <pedro@ambientworks.net>
Date: Tue Sep 1 17:01:55 2020 +0200
configure.ac: fix libfido2 back-compat
- HAVE_FIDO_CRED_PROD -> HAVE_FIDO_CRED_PROT;
- check for fido_dev_get_touch_begin(), so that
HAVE_FIDO_DEV_GET_TOUCH_BEGIN gets defined.
commit 785f0f315bf7ac5909e988bb1ac3e019fb5e1594
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Aug 31 04:33:17 2020 +0000
upstream: refuse to add verify-required (PINful) FIDO keys to
ssh-agent until the agent supports them properly
OpenBSD-Commit-ID: 125bd55a8df32c87c3ec33c6ebe437673a3d037e
commit 39e88aeff9c7cb6862b37ad1a87a03ebbb38c233
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Aug 31 00:17:41 2020 +0000
upstream: Add RCS IDs to the few files that are missing them; from
Pedro Martelletto
OpenBSD-Commit-ID: 39aa37a43d0c75ec87f1659f573d3b5867e4a3b3
commit 72730249b38a676da94a1366b54a6e96e6928bcb
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Aug 28 03:15:52 2020 +0000
upstream: Check that the addresses supplied to Match Address and
Match LocalAddress are valid when parsing in config-test mode. This will
catch address/mask mismatches before they cause problems at runtime. Found by
Daniel Stocker, ok djm@
OpenBSD-Commit-ID: 2d0b10c69fad5d8fda4c703e7c6804935289378b
commit 2a3a9822311a565a9df48ed3b6a3c972f462bd7d
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Thu Aug 27 12:34:00 2020 +0000
upstream: sentence fix; from pedro martelletto
OpenBSD-Commit-ID: f95b84a1e94e9913173229f3787448eea2f8a575
commit ce178be0d954b210c958bc2b9e998cd6a7aa73a9
Author: Damien Miller <djm@mindrot.org>
Date: Thu Aug 27 20:01:52 2020 +1000
tweak back-compat for older libfido2
commit d6f45cdde031acdf434bbb27235a1055621915f4
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Aug 27 09:46:04 2020 +0000
upstream: debug()-print a little info about FIDO-specific key
fields via "ssh-keygen -vyf /path/key"
OpenBSD-Commit-ID: cf315c4fe77db43947d111b00155165cb6b577cf
commit b969072cc3d62d05cb41bc6d6f3c22c764ed932f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Aug 27 09:43:28 2020 +0000
upstream: skip a bit more FIDO token selection logic when only a
single token is attached.
with Pedro Martelletto
OpenBSD-Commit-ID: e4a324bd9814227ec1faa8cb619580e661cca9ac
commit 744df42a129d7d7db26947b7561be32edac89f88
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Thu Aug 27 06:15:22 2020 +0000
upstream: tweak previous;
OpenBSD-Commit-ID: 92714b6531e244e4da401b2defaa376374e24be7
commit e32479645ce649b444ba5c6e7151304306a09654
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Aug 27 03:55:22 2020 +0000
upstream: adapt to API changes
OpenBSD-Regress-ID: 5f147990cb67094fe554333782ab268a572bb2dd
commit bbcc858ded3fbc46abfa7760e40389e3ca93884c
Author: Damien Miller <djm@mindrot.org>
Date: Thu Aug 27 12:37:12 2020 +1000
degrade semi-gracefully when libfido2 is too old
commit 9cbbdc12cb6a2ab1e9ffe9974cca91d213c185c2
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Aug 27 01:15:36 2020 +0000
upstream: dummy firmware needs to match API version numner crank (for
verify-required resident keys) even though it doesn't implement this feature
OpenBSD-Regress-ID: 86579ea2891e18e822e204413d011b2ae0e59657
commit c1e76c64956b424ba260fd4eec9970e5b5859039
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Aug 27 02:11:09 2020 +0000
upstream: remove unreachable code I forgot to delete in r1.334
OpenBSD-Commit-ID: 9ed6078251a0959ee8deda443b9ae42484fd8b18
commit 0caff05350bd5fc635674c9e051a0322faba5ae3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Aug 27 01:08:45 2020 +0000
upstream: Request PIN ahead of time for certain FIDO actions
When we know that a particular action will require a PIN, such as
downloading resident keys or generating a verify-required key, request
the PIN before attempting it.
joint work with Pedro Martelletto; ok markus@
OpenBSD-Commit-ID: 863182d38ef075bad1f7d20ca485752a05edb727
commit b649b3daa6d4b8ebe1bd6de69b3db5d2c03c9af0
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Aug 27 01:08:19 2020 +0000
upstream: preserve verify-required for resident FIDO keys
When downloading a resident, verify-required key from a FIDO token,
preserve the verify-required in the private key that is written to
disk. Previously we weren't doing that because of lack of support
in the middleware API.
from Pedro Martelletto; ok markus@ and myself
OpenBSD-Commit-ID: 201c46ccdd227cddba3d64e1bdbd082afa956517
commit 642e06d0df983fa2af85126cf4b23440bb2985bf
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Aug 27 01:07:51 2020 +0000
upstream: major rework of FIDO token selection logic
When PINs are in use and multiple FIDO tokens are attached to a host, we
cannot just blast requests at all attached tokens with the PIN specified
as this will cause the per-token PIN failure counter to increment. If
this retry counter hits the token's limit (usually 3 attempts), then the
token will lock itself and render all (web and SSH) of its keys invalid.
We don't want this.
So this reworks the key selection logic for the specific case of
multiple keys being attached. When multiple keys are attached and the
operation requires a PIN, then the user must touch the key that they
wish to use first in order to identify it.
This may require multiple touches, but only if there are multiple keys
attached AND (usually) the operation requires a PIN. The usual case of a
single key attached should be unaffected.
Work by Pedro Martelletto; ok myself and markus@
OpenBSD-Commit-ID: 637d3049ced61b7a9ee796914bbc4843d999a864
commit 801c9f095e6d8b7b91aefd98f5001c652ea13488
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Aug 27 01:07:09 2020 +0000
upstream: support for requiring user verified FIDO keys in sshd
This adds a "verify-required" authorized_keys flag and a corresponding
sshd_config option that tells sshd to require that FIDO keys verify the
user identity before completing the signing/authentication attempt.
Whether or not user verification was performed is already baked into the
signature made on the FIDO token, so this is just plumbing that flag
through and adding ways to require it.
feedback and ok markus@
OpenBSD-Commit-ID: 3a2313aae153e043d57763d766bb6d55c4e276e6
commit 9b8ad93824c682ce841f53f3b5762cef4e7cc4dc
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Aug 27 01:06:18 2020 +0000
upstream: support for user-verified FIDO keys
FIDO2 supports a notion of "user verification" where the user is
required to demonstrate their identity to the token before particular
operations (e.g. signing). Typically this is done by authenticating
themselves using a PIN that has been set on the token.
This adds support for generating and using user verified keys where
the verification happens via PIN (other options might be added in the
future, but none are in common use now). Practically, this adds
another key generation option "verify-required" that yields a key that
requires a PIN before each authentication.
feedback markus@ and Pedro Martelletto; ok markus@
OpenBSD-Commit-ID: 57fd461e4366f87c47502c5614ec08573e6d6a15
commit 1196d7f49d4fbc90f37e550de3056561613b0960
Author: cheloha@openbsd.org <cheloha@openbsd.org>
Date: Wed Aug 12 01:23:45 2020 +0000
upstream: ssh-keyscan(1): simplify conloop() with timercmp(3),
timersub(3); ok djm@
OpenBSD-Commit-ID: a102acb544f840d33ad73d40088adab4a687fa27
commit d0a195c89e26766d3eb8f3e4e2a00ebc98b57795
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Aug 11 09:49:57 2020 +0000
upstream: let ssh_config(5)'s AddKeysToAgent keyword accept a time
limit for keys in addition to its current flag options. Time-limited keys
will automatically be removed from ssh-agent after their expiry time has
passed; ok markus@
OpenBSD-Commit-ID: 792e71cacbbc25faab5424cf80bee4a006119f94
commit e9c2002891a7b8e66f4140557a982978f372e5a3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Aug 11 09:45:54 2020 +0000
upstream: let the "Confirm user presence for key ..." ssh-askpass
notification respect $SSH_ASKPASS_REQUIRE; ok markus@
OpenBSD-Commit-ID: 7c1a616b348779bda3b9ad46bf592741f8e206c1
commit eaf8672b1b52db2815a229745f4e4b08681bed6d
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Aug 21 00:04:13 2020 +1000
Remove check for 'ent' command.
It was added in 8d1fd57a9 for measuring entropy of ssh_prng_cmds which
has long since been removed and there are no other references to it.
commit 05c215de8d224e094a872d97d45f37f60c06206b
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Aug 17 21:34:32 2020 +1000
Wrap stdint.h include in ifdef HAVE_STDINT_H.
commit eaf2765efe8bc74feba85c34295d067637fc6635
Author: Damien Miller <djm@mindrot.org>
Date: Mon Aug 10 13:24:09 2020 +1000
sync memmem.c with OpenBSD
commit ed6bef77f5bb5b8f9ca2914478949e29f2f0a780
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Aug 7 17:12:16 2020 +1000
Always send any PAM account messages.
If the PAM account stack reaturns any messages, send them to the user
not just if the check succeeds. bz#2049, ok djm@
commit a09e98dcae1e26f026029b7142b0e0d10130056f
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Aug 7 15:37:37 2020 +1000
Output test debug logs on failure.
commit eb122b1eebe58b29a83a507ee814cbcf8aeded1b
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Aug 7 15:11:42 2020 +1000
Add ability to specify exact test target.
commit c2ec7a07f8caabb4d8e00c66e7cd46bf2cd1e922
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Aug 7 14:21:15 2020 +1000
Document --without-openssl and --without-zlib.
commit 651bb3a31949bbdc3a78b2ede95a77bce0c72984
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Aug 7 14:15:11 2020 +1000
Add without-openssl without-zlib test target.
commit 9499f2bb01dc1032ae155999b2d7764b9491341f
Author: Stefan Schindler <dns2utf8@estada.ch>
Date: Wed Aug 5 19:00:52 2020 +0200
Add CI with prepare script
* Only use heimdal kerberos implementation
* Fetch yubico/libfido2 (see: https://github.com/Yubico/libfido2)
* Add one target for
* all features
* each feature alone
* no features
commit ea1f649046546a860f68b97ddc3015b7e44346ca
Author: Damien Miller <djm@mindrot.org>
Date: Wed Aug 5 08:58:57 2020 +1000
support NetBSD's utmpx.ut_ss address field
bz#960, ok dtucker
commit 32c63e75a70a0ed9d6887a55fcb0e4531a6ad617
Author: Damien Miller <djm@mindrot.org>
Date: Tue Aug 4 14:59:21 2020 +1000
wrap a declaration in the same ifdefs as its use
avoids warnings on NetBSD
commit c9e3be9f4b41fda32a2a0138d54c7a6b563bc94d
Author: Damien Miller <djm@mindrot.org>
Date: Tue Aug 4 14:58:46 2020 +1000
undef TAILQ_CONCAT and friends
Needed for NetBSD. etc that supply these macros
commit 2d8a3b7e8b0408dfeb933ac5cfd3a58f5bac49af
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Aug 3 02:53:51 2020 +0000
upstream: ensure that certificate extensions are lexically sorted.
Previously if the user specified a custom extension then the everything would
be in order except the custom ones. bz3198 ok dtucker markus
OpenBSD-Commit-ID: d97deb90587b06cb227c66ffebb2d9667bf886f0
commit a8732d74cb8e72f0c6366015687f1e649f60be87
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Aug 3 02:43:41 2020 +0000
upstream: allow -A to explicitly enable agent forwarding in scp and
sftp. The default remains to not forward an agent, even when ssh_config
enables it. ok jmc dtucker markus
OpenBSD-Commit-ID: 36cc526aa3b0f94e4704b8d7b969dd63e8576822
commit ab9105470a83ed5d8197959a1b1f367399958ba1
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Mon Aug 3 02:42:49 2020 +0000
upstream: clang -Wimplicit-fallthrough does not recognise /*
FALLTHROUGH */ comments, which is the style we currently use, and gives too
many boring warnings. ok djm
OpenBSD-Commit-ID: 07b5031e9f49f2b69ac5e85b8da4fc9e393992a0
commit ced327b9fb78c94d143879ef4b2a02cbc5d38690
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jul 31 04:19:37 2020 +0000
upstream: Also compare username when checking for JumpHost loops.
bz#3057, ok djm@
OpenBSD-Commit-ID: 9bbc1d138adb34c54f3c03a15a91f75dbf418782
commit ae7527010c44b3376b85d036a498f136597b2099
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jul 31 15:19:04 2020 +1000
Remove AC_REVISION.
It hasn't been useful since we switched to git in 2014. ok djm@
commit 89fc3f414be0ce4e8008332a9739a7d721269e50
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jul 28 19:40:30 2020 +1000
Use argv in OSSH_CHECK_CFLAG_COMPILE test.
configure.ac is not detecting -Wextra in compilers that implement the
option. The problem is that -Wextra implies -Wunused-parameter, and the
C excerpt used by aclocal.m4 does not use argv. Patch from pedro at
ambientworks.net, ok djm@
commit 62c81ef531b0cc7ff655455dd34f5f0c94f48e82
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Jul 20 22:12:07 2020 +1000
Skip ECDSA-SK webauthn test when built w/out ECC
commit 3ec9a6d7317236a9994887d8bd5d246af403a00d
Author: Damien Miller <djm@mindrot.org>
Date: Mon Jul 20 13:09:25 2020 +1000
Add ssh-sk-helper and manpage to RPM spec file
Based on patch from Fabio Pedretti
commit a2855c048b3f4b17d8787bd3f24232ec0cd79abe
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jul 17 07:09:24 2020 +0000
upstream: Add %k to the TOKENs for Match Exec for consistency with
the other keywords that recently got %k.
OpenBSD-Commit-ID: 1857d1c40f270cbc254fca91e66110641dddcfdb
commit 69860769fa9f4529d8612ec055ae11912f7344cf
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Fri Jul 17 05:59:05 2020 +0000
upstream: fix macro slip in previous;
OpenBSD-Commit-ID: 624e47ab209450ad9ad5c69f54fa69244de5ed9a
commit 40649bd0822883b684183854b16d0b8461d5697b
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jul 17 07:10:24 2020 +0000
upstream: Add test for '%k' (HostKeyAlias) TOKEN.
OpenBSD-Regress-ID: 8ed1ba1a811790031aad3fcea860a34ad7910456
commit 6736fe680704a3518cb4f3f8f6723b00433bd3dd
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jul 17 03:26:58 2020 +0000
upstream: Add tests for expansions on UserKnownHostsFile.
OpenBSD-Regress-ID: bccf8060306c841bbcceb1392644f906a4d6ca51
commit 287dc6396e0f9cb2393f901816dbd7f2a7dfbb5f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jul 17 03:51:32 2020 +0000
upstream: log error message for process_write() write failures
OpenBSD-Commit-ID: f733d7b3b05e3c68967dc18dfe39b9e8fad29851
commit 8df5774a42d2eaffe057bd7f293fc6a4b1aa411c
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jul 17 03:43:42 2020 +0000
upstream: Add a '%k' TOKEN that expands to the effective HostKey of
the destination. This allows, eg, keeping host keys in individual files
using "UserKnownHostsFile ~/.ssh/known_hosts.d/%k". bz#1654, ok djm@, jmc@
(man page bits)
OpenBSD-Commit-ID: 7084d723c9cc987a5c47194219efd099af5beadc
commit c4f239944a4351810fd317edf408bdcd5c0102d9
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jul 17 03:23:10 2020 +0000
upstream: Add %-TOKEN, environment variable and tilde expansion to
UserKnownHostsFile, allowing the file to be automagically split up in the
configuration (eg bz#1654). ok djm@, man page parts jmc@
OpenBSD-Commit-ID: 7e1b406caf147638bb51558836a72d6cc0bd1b18
commit dbaaa01daedb423c38124a72c471982fb08a16fb
Author: solene@openbsd.org <solene@openbsd.org>
Date: Wed Jul 15 07:50:46 2020 +0000
upstream: - Add [-a rounds] in ssh-keygen man page and usage() -
Reorder parameters list in the first usage() case - Sentence rewording
ok dtucker@
jmc@ noticed usage() missed -a flag too
OpenBSD-Commit-ID: f06b9afe91cc96f260b929a56e9930caecbde246
commit 69924a92c3af7b99a7541aa544a2334ec0fb092c
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Wed Jul 15 05:40:05 2020 +0000
upstream: start sentence with capital letter;
OpenBSD-Commit-ID: ab06581d51b2b4cc1b4aab781f7f3cfa56cad973
commit 5b56bd0affea7b02b540bdbc4d1d271b0e4fc885
Author: Damien Miller <djm@mindrot.org>
Date: Fri Jul 17 13:15:50 2020 +1000
detect Linux/X32 systems
This is a frankenstein monster of AMD64 instructions/calling conventions
but with a 4GB address space. Allegedly deprecated but people still run
into it causing weird sandbox failures, e.g. bz#3085
commit 9c9ddc1391d6af8d09580a2424ab467d0a5df3c7
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Jul 15 06:43:16 2020 +0000
upstream: Fix previous by calling the correct function.
OpenBSD-Regress-ID: 821cdd1dff9c502cceff4518b6afcb81767cad5a
commit f1a4798941b4372bfe5e46f1c0f8672fe692d9e4
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Jul 15 05:36:50 2020 +0000
upstream: Update test to match recent change in match.c
OpenBSD-Regress-ID: 965bda1f95f09a765050707340c73ad755f41167
commit d7e71be4fd57b7c7e620d733cdf2333b27bfa924
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Jul 15 15:30:43 2020 +1000
Adjust portable code to match changes in 939d787d,
commit fec89f32a84fd0aa1afc81deec80a460cbaf451a
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Jul 15 04:27:34 2020 +0000
upstream: Add default for number of rounds (-a). ok djm@
OpenBSD-Commit-ID: cb7e9aa04ace01a98e63e4bd77f34a42ab169b15
commit aaa8b609a7b332be836cd9a3b782422254972777
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jul 14 23:57:01 2020 +0000
upstream: allow some additional control over the use of ssh-askpass
via $SSH_ASKPASS_REQUIRE, including force-enable/disable. bz#69 ok markus@
OpenBSD-Commit-ID: 3a1e6cbbf6241ddc4405c4246caa2c249f149eb2
commit 6368022cd4dd508671c4999a59ec5826df098530
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Tue Jul 7 02:47:21 2020 +0000
upstream: correct recently broken comments
OpenBSD-Commit-ID: 964d9a88f7de1d0eedd3f8070b43fb6e426351f1
commit 6d755706a0059eb9e2d63517f288b75cbc3b4701
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Jul 5 23:59:45 2020 +0000
upstream: some language improvements; ok markus
OpenBSD-Commit-ID: 939d787d571b4d5da50b3b721fd0b2ac236acaa8
commit b0c1e8384d5e136ebdf895d1434aea7dd8661a1c
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Jul 3 10:12:26 2020 +0000
upstream: update setproctitle after re-exec; ok djm
OpenBSD-Commit-ID: bc92d122f9184ec2a9471ade754b80edd034ce8b
commit cd119a5ec2bf0ed5df4daff3bd14f8f7566dafd3
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Jul 3 10:11:33 2020 +0000
upstream: keep ignoring HUP after fork+exec; ok djm
OpenBSD-Commit-ID: 7679985a84ee5ceb09839905bb6f3ddd568749a2
commit 8af4a743693ccbea3e15fc9e93edbeb610fa94f4
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Jul 3 10:10:17 2020 +0000
upstream: don't exit the listener on send_rexec_state errors; ok
djm
OpenBSD-Commit-ID: 57cbd757d130d3f45b7d41310b3a15eeec137d5c
commit 03da4c2b70468f04ed1c08518ea0a70e67232739
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Jul 15 04:55:47 2020 +0000
upstream: Use $OBJ to find key files. Fixes test when run on an obj
directory (on OpenBSD) or out of tree (in Portable).
OpenBSD-Regress-ID: 938fa8ac86adaa527d64a305bd2135cfbb1c0a17
commit 73f20f195ad18f1cf633eb7d8be95dc1b6111eea
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jul 4 23:11:23 2020 +1000
Wrap stdint.h in ifdef HAVE_STDINT_H.
commit aa6fa4bf3023fa0e5761cd8f4b2cd015d2de74dd
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jul 3 07:25:18 2020 +0000
upstream: put back the mux_ctx memleak fix, but only for channels of
type SSH_CHANNEL_MUX_LISTENER; Specifically SSH_CHANNEL_MUX_PROXY channels
should not have this structure freed.
OpenBSD-Commit-ID: f3b213ae60405f77439e2b06262f054760c9d325
commit d8195914eb43b20b13381f4e5a74f9f8a14f0ded
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jul 3 07:17:35 2020 +0000
upstream: revert r1.399 - the lifetime of c->mux_ctx is more complex;
simply freeing it here causes other problems
OpenBSD-Commit-ID: c6fee8ca94e2485faa783839541962be2834c5ed
commit 20b5fab9f773b3d3c7f06cb15b8f69a2c081ee80
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jul 3 07:02:37 2020 +0000
upstream: avoid tilde_expand_filename() in expanding ~/.ssh/rc - if
sshd is in chroot mode, the likely absence of a password database will cause
tilde_expand_filename() to fatal; ok dtucker@
OpenBSD-Commit-ID: e20aee6159e8b79190d18dba1513fc1b7c8b7ee1
commit c8935081db35d73ee6355999142fa0776a2af912
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jul 3 06:46:41 2020 +0000
upstream: when redirecting sshd's log output to a file, undo this
redirection after the session child process is forked(); ok dtucker@
OpenBSD-Commit-ID: 6df86dd653c91f5bc8ac1916e7680d9d24690865
commit 183c4aaef944af3a1a909ffa01058c65bac55748
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jul 3 06:29:57 2020 +0000
upstream: start ClientAliveInterval bookkeeping before first pass
through select() loop; fixed theoretical case where busy sshd may ignore
timeouts from client; inspired by and ok dtucker
OpenBSD-Commit-ID: 96bfc4b1f86c7da313882a84755b2b47eb31957f
commit 6fcfd303d67f16695198cf23d109a988e40eefb6
Author: Damien Miller <djm@mindrot.org>
Date: Fri Jul 3 15:28:27 2020 +1000
add check for fido_cred_set_prot() to configure
commit f11b23346309e4d5138e733a49321aedd6eeaa2f
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jul 3 05:09:06 2020 +0000
upstream: Only reset the serveralive check when we receive traffic from
the server and ignore traffic from a port forwarding client, preventing a
client from keeping a connection alive when it should be terminated. Based
on a patch from jxraynor at gmail.com via openssh-unix-dev and bz#2265, ok
djm@
OpenBSD-Commit-ID: a941a575a5cbc244c0ef5d7abd0422bbf02c2dcd
commit adfdbf1211914b631c038f0867a447db7b519937
Author: Damien Miller <djm@mindrot.org>
Date: Fri Jul 3 15:15:15 2020 +1000
sync sys-queue.h with OpenBSD upstream
needed for TAILQ_CONCAT
commit 1b90ddde49e2ff377204082b6eb130a096411dc1
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jul 3 05:08:41 2020 +0000
upstream: fix memory leak of mux_ctx; patch from Sergiy Lozovsky
via bz3189 ok dtucker
OpenBSD-Commit-ID: db249bd4526fd42d0f4f43f72f7b8b7705253bde
commit 55ef3e9cbd5b336bd0f89205716924886fcf86de
Author: markus@openbsd.org <markus@openbsd.org>
Date: Wed Jul 1 16:28:31 2020 +0000
upstream: free kex in ssh_packet_close; ok djm semarie
OpenBSD-Commit-ID: dbc181e90d3d32fd97b10d75e68e374270e070a2
commit e1c401109b61f7dbc199b5099933d579e7fc5dc9
Author: bket@openbsd.org <bket@openbsd.org>
Date: Sat Jun 27 13:39:09 2020 +0000
upstream: Replace TAILQ concatenation loops with TAILQ_CONCAT
OK djm@
OpenBSD-Commit-ID: 454b40e09a117ddb833794358970a65b14c431ef
commit 14beca57ac92d62830c42444c26ba861812dc837
Author: semarie@openbsd.org <semarie@openbsd.org>
Date: Fri Jun 26 11:26:01 2020 +0000
upstream: backout 1.293 fix kex mem-leak in ssh_packet_close at markus
request
the change introduced a NULL deref in sshpkt_vfatal() (uses of ssh->kex after
calling ssh_packet_clear_keys())
OpenBSD-Commit-ID: 9c9a6721411461b0b1c28dc00930d7251a798484
commit 598c3a5e3885080ced0d7c40fde00f1d5cdbb32b
Author: Damien Miller <djm@mindrot.org>
Date: Fri Jun 26 16:07:12 2020 +1000
document a PAM spec problem in a frustrated comment
commit 976c4f86286d52a0cb2aadf4a095d379c0da752e
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 26 05:42:16 2020 +0000
upstream: avoid spurious error message when ssh-keygen creates files
outside ~/.ssh; with dtucker@
OpenBSD-Commit-ID: ac0c662d44607e00ec78c266ee60752beb1c7e08
commit 32b2502a9dfdfded1ccdc1fd6dc2b3fe41bfc205
Author: Damien Miller <djm@mindrot.org>
Date: Fri Jun 26 15:30:06 2020 +1000
missing ifdef SELINUX; spotted by dtucker
commit e073106f370cdd2679e41f6f55a37b491f0e82fe
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 26 05:12:21 2020 +0000
upstream: regress test for ssh-add -d; ok dtucker@
OpenBSD-Regress-ID: 3a2e044be616afc7dd4f56c100179e83b33d8abf
commit c809daaa1bad6b1c305b0e0b5440360f32546c84
Author: markus@openbsd.org <markus@openbsd.org>
Date: Wed Jun 24 15:16:23 2020 +0000
upstream: add test for mux w/-Oproxy; ok djm
OpenBSD-Regress-ID: 764d5c696e2a259f1316a056e225e50023abb027
commit 3d06ff4bbd3dca8054c238d2a94c0da563ef7eee
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 26 05:16:38 2020 +0000
upstream: handle EINTR in waitfd() and timeout_connect() helpers;
bz#3071; ok dtucker@
OpenBSD-Commit-ID: 08fa87be50070bd8b754d9b1ebb1138d7bc9d8ee
commit fe2ec0b9c19adeab0cd9f04b8152dc17f31c31e5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 26 05:04:07 2020 +0000
upstream: allow "ssh-add -d -" to read keys to be deleted from
stdin bz#3180; ok dtucker@
OpenBSD-Commit-ID: 15c7f10289511eb19fce7905c9cae8954e3857ff
commit a3e0c376ffc11862fa3568b28188bd12965973e1
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 26 05:03:36 2020 +0000
upstream: constify a few things; ok dtucker (as part of another
diff)
OpenBSD-Commit-ID: 7c17fc987085994d752304bd20b1ae267a9bcdf6
commit 74344c3ca42c3f53b00b025daf09ae7f6aa38076
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jun 26 05:02:03 2020 +0000
upstream: Defer creation of ~/.ssh by ssh(1) until we attempt to
write to it so we don't leave an empty .ssh directory when it's not needed.
Use the same function to replace the code in ssh-keygen that does the same
thing. bz#3156, ok djm@
OpenBSD-Commit-ID: 59c073b569be1a60f4de36f491a4339bc4ae870f
commit c9e24daac6324fcbdba171392c325bf9ccc3c768
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jun 26 04:45:11 2020 +0000
upstream: Expand path to ~/.ssh/rc rather than relying on it
being relative to the current directory, so that it'll still be found if the
shell startup changes its directory. Since the path is potentially longer,
make the cmd buffer that uses it dynamically sized. bz#3185, with & ok djm@
OpenBSD-Commit-ID: 36e33ff01497af3dc8226d0c4c1526fc3a1e46bf
commit 07f5f369a25e228a7357ef6c57205f191f073d99
Author: markus@openbsd.org <markus@openbsd.org>
Date: Wed Jun 24 15:12:09 2020 +0000
upstream: fix kex mem-leak in ssh_packet_close; ok djm
OpenBSD-Commit-ID: e2e9533f393620383afd0b68ef435de8d5e8abe4
commit e35995088cd6691a712bfd586bae8084a3a922ba
Author: markus@openbsd.org <markus@openbsd.org>
Date: Wed Jun 24 15:10:38 2020 +0000
upstream: fix ssh -O proxy w/mux which got broken by no longer
making ssh->kex optional in packet.c revision 1.278 ok djm@
OpenBSD-Commit-ID: 2b65df04a064c2c6277359921d2320c90ab7d917
commit 250246fef22b87a54a63211c60a2def9be431fbd
Author: markus@openbsd.org <markus@openbsd.org>
Date: Wed Jun 24 15:09:53 2020 +0000
upstream: support loading big sshd_config files w/o realloc; ok
djm
OpenBSD-Commit-ID: ba9238e810074ac907f0cf8cee1737ac04983171
commit 89b54900ac61986760452f132bbe3fb7249cfdac
Author: markus@openbsd.org <markus@openbsd.org>
Date: Wed Jun 24 15:08:53 2020 +0000
upstream: allow sshd_config longer than 256k; ok djm
OpenBSD-Commit-ID: 83f40dd5457a64c1d3928eb4364461b22766beb3
commit e3fa6249e6d9ceb57c14b04dd4c0cfab12fa7cd5
Author: markus@openbsd.org <markus@openbsd.org>
Date: Wed Jun 24 15:07:33 2020 +0000
upstream: only call sshkey_xmss_init() once for KEY_XMSS_CERT; ok
djm
OpenBSD-Commit-ID: d0002ffb7f20f538b014d1d0735facd5a81ff096
commit 37f2da069c0619f2947fb92785051d82882876d7
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Jun 22 23:44:27 2020 +0000
upstream: some clarifying comments
OpenBSD-Commit-ID: 5268479000fd97bfa30ab819f3517139daa054a2
commit b659319a5bc9e8adf3c4facc51f37b670d2a7426
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Mon Jun 22 06:37:38 2020 +0000
upstream: updated argument name for -P in first synopsis was
missed in previous;
OpenBSD-Commit-ID: 8d84dc3050469884ea91e29ee06a371713f2d0b7
commit 02a9222cbce7131d639984c2f6c71d1551fc3333
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Mon Jun 22 06:36:40 2020 +0000
upstream: supply word missing in previous;
OpenBSD-Commit-ID: 16a38b049f216108f66c8b699aa046063381bd23
commit 5098b3b6230852a80ac6cef5d53a785c789a5a56
Author: Damien Miller <djm@mindrot.org>
Date: Mon Jun 22 16:54:02 2020 +1000
missing files for webauthn/sshsig unit test
commit 354535ff79380237924ac8fdc98f8cdf83e67da6
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Jun 22 06:00:06 2020 +0000
upstream: add support for verification of webauthn sshsig signature,
and example HTML/JS to generate webauthn signatures in SSH formats (also used
to generate the testdata/* for the test).
OpenBSD-Regress-ID: dc575be5bb1796fdf4b8aaee0ef52a6671a0f6fb
commit bb52e70fa5330070ec9a23069c311d9e277bbd6f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Jun 22 05:58:35 2020 +0000
upstream: Add support for FIDO webauthn (verification only).
webauthn is a standard for using FIDO keys in web browsers. webauthn
signatures are a slightly different format to plain FIDO signatures - this
support allows verification of these. Feedback and ok markus@
OpenBSD-Commit-ID: ab7e3a9fb5782d99d574f408614d833379e564ad
commit 64bc121097f377142f1387ffb2df7592c49935af
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Jun 22 05:56:23 2020 +0000
upstream: refactor ECDSA-SK verification a little ahead of adding
support for FIDO webauthn signature verification support; ok markus@
OpenBSD-Commit-ID: c9f478fd8e0c1bd17e511ce8694f010d8e32043e
commit 12848191f8fe725af4485d3600e0842d92f8637f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Jun 22 05:54:10 2020 +0000
upstream: support for RFC4648 base64url encoding; ok markus
OpenBSD-Commit-ID: 0ef22c55e772dda05c112c88412c0797fec66eb4
commit 473b4af43db12127137c7fc1a10928313f5a16d2
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Jun 22 05:53:26 2020 +0000
upstream: better terminology for permissions; feedback & ok markus@
OpenBSD-Commit-ID: ff2a71803b5ea57b83cc3fa9b3be42b70e462fb9
commit fc270baf264248c3ee3050b13a6c8c0919e6559f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Jun 22 05:52:05 2020 +0000
upstream: better terminology for permissions; feedback & ok markus@
OpenBSD-Commit-ID: ffb220b435610741dcb4de0e7fc68cbbdc876d2c
commit 00531bb42f1af17ddabea59c3d9c4b0629000d27
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jun 19 07:21:42 2020 +0000
upstream: Correct synopsis and usage for the options accepted when
passing a command to ssh-agent. ok jmc@
OpenBSD-Commit-ID: b36f0679cb0cac0e33b361051b3406ade82ea846
commit b4556c8ad7177e379f0b60305a0cd70f12180e7c
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jun 19 19:22:00 2020 +1000
Add OPENBSD ORIGINAL marker to bcrypt_pbkdf.
commit 1babb8bb14c423011ca34c2f563bb1c51c8fbf1d
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jun 19 19:10:47 2020 +1000
Extra brackets around sizeof() in bcrypt.
Prevents following warning from clang 10:
bcrypt_pbkdf.c:94:40: error: expression does not compute the number of
elements in this array; element type is ´uint32_tÂ[...]
place parentheses around the ´sizeof(uint64_t)´ expression to
silence this warning
commit 9e065729592633290e5ddb6852792913b2286545
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jun 19 18:47:56 2020 +1000
Add includes.h to new test.
Fixes warnings eg "´bounded´ attribute directive ignor" from gcc.
commit e684b1ea365e070433f282a3c1dabc3e2311ce49
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jun 19 18:38:39 2020 +1000
Skip OpenSSL specific tests w/out OpenSSL.
Allows unit tests to pass when configure'ed --without-openssl.
commit 80610e97a76407ca982e62fd051c9be03622fe7b
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jun 19 17:15:27 2020 +1000
Hook sshsig tests up to Portable Makefiles.
commit 5dba1fcabacaab46693338ec829b42a1293d1f52
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jun 19 05:07:09 2020 +0000
upstream: Test that ssh-agent exits when running as as subprocess
of a specified command (ie "ssh-agent command"). Would have caught bz#3181.
OpenBSD-Regress-ID: 895b4765ba5153eefaea3160a7fe08ac0b6db8b3
commit 68e8294f6b04f9590ea227e63d3e129398a49e27
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 19 04:34:21 2020 +0000
upstream: run sshsig unit tests
OpenBSD-Regress-ID: 706ef17e2b545b64873626e0e35553da7c06052a
commit 5edfa1690e9a75048971fd8775f7c16d153779db
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 19 04:32:09 2020 +0000
upstream: basic unit test for sshsig.[ch], including FIDO keys
verification only so far
OpenBSD-Regress-ID: fb1f946c8fc59206bc6a6666e577b5d5d7e45896
commit e95c0a0e964827722d29b4bc00d5c0ff4afe0ed2
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 19 03:48:49 2020 +0000
upstream: basic unit test for FIDO kep parsing
OpenBSD-Regress-ID: 8089b88393dd916d7c95422b442a6fd4cfe00c82
commit 7775819c6de3e9547ac57b87c7dd2bfd28cefcc5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jun 18 23:34:19 2020 +0000
upstream: check public host key matches private; ok markus@ (as
part of previous diff)
OpenBSD-Commit-ID: 65a4f66436028748b59fb88b264cb8c94ce2ba63
commit c514f3c0522855b4d548286eaa113e209051a6d2
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jun 18 23:33:38 2020 +0000
upstream: avoid spurious "Unable to load host key" message when
sshd can load a private key but no public counterpart; with & ok markus@
OpenBSD-Commit-ID: 0713cbdf9aa1ff8ac7b1f78b09ac911af510f81b
commit 7fafaeb5da365f4a408fec355dac04a774f27193
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 12 05:26:37 2020 +0000
upstream: correct RFC number; from HARUYAMA Seigo via GH PR191
OpenBSD-Commit-ID: 8d03b6c96ca98bfbc23d3754c3c33e1fe0852e10
commit 3a7f654d5bcb20df24a134b6581b0d235da4564a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 5 06:18:07 2020 +0000
upstream: unbreak "sshd -ddd" - close of config passing fd happened too
early. ok markus@
OpenBSD-Commit-ID: 49346e945c6447aca3e904e65fc400128d2f8ed0
commit 3de02be39e5c0c2208d9682a3844991651620fcc
Author: Andreas Schwab <schwab@suse.de>
Date: Mon May 25 11:10:44 2020 +0200
Add support for AUDIT_ARCH_RISCV64
commit ea547eb0329c2f8da77a4ac05f6c330bd49bdaab
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 5 03:25:35 2020 +0000
upstream: make sshbuf_putb(b, NULL) a no-op
OpenBSD-Commit-ID: 976fdc99b500e347023d430df372f31c1dd128f7
commit 69796297c812640415c6cea074ea61afc899cbaa
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 5 03:24:36 2020 +0000
upstream: make sshbuf_dump() args const
OpenBSD-Commit-ID: b4a5accae750875d665b862504169769bcf663bd
commit 670428895739d1f79894bdb2457891c3afa60a59
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 5 03:24:16 2020 +0000
upstream: wrap long line
OpenBSD-Commit-ID: ed405a12bd27bdc9c52e169bc5ff3529b4ebbbb2
commit 2f648cf222882719040906722b3593b01df4ad1a
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jun 5 03:15:26 2020 +0000
upstream: Correct historical comment: provos@ modified OpenSSH to
work with SSLeay (very quickly replaced by OpenSSL) not SSL in general. ok
deraadt, historical context markus@
OpenBSD-Commit-ID: 7209e07a2984b50411ed8ca5a4932da5030d2b90
commit 56548e4efcc3e3e8093c2eba30c75b23e561b172
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Jun 3 08:23:18 2020 +0000
upstream: Import regenerated moduli file.
OpenBSD-Commit-ID: 52ff0e3205036147b2499889353ac082e505ea54
commit 8da801f585dd9c534c0cbe487a3b1648036bf2fb
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jun 5 13:20:10 2020 +1000
Test fallthrough in OSSH_CHECK_CFLAG_COMPILE.
clang 10's -Wimplicit-fallthrough does not understand /* FALLTHROUGH */
comments and we don't use the __attribute__((fallthrough)) that it's
looking for. This has the effect of turning off -Wimplicit-fallthrough
where it does not currently help (particularly with -Werror). ok djm@
commit 049297de975b92adcc2db77e3fb7046c0e3c695d
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Jun 3 08:23:18 2020 +0000
upstream: Import regenerated moduli file.
OpenBSD-Commit-ID: 52ff0e3205036147b2499889353ac082e505ea54
commit b458423a38a3140ac022ffcffcb332609faccfe3
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Jun 1 07:11:38 2020 +0000
upstream: Remove now-unused proto_spec and associated definitions.
ok djm@
OpenBSD-Commit-ID: 2e2b18e3aa6ee22a7b69c39f2d3bd679ec35c362
commit 5ad3c3a33ef038b55a14ebd31faeeec46073db2c
Author: millert@openbsd.org <millert@openbsd.org>
Date: Fri May 29 21:22:02 2020 +0000
upstream: Fix error message on close(2) and add printf format
attributes. From Christos Zoulas, OK markus@
OpenBSD-Commit-ID: 41523c999a9e3561fcc7082fd38ea2e0629ee07e
commit 712ac1efb687a945a89db6aa3e998c1a17b38653
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri May 29 11:17:56 2020 +0000
upstream: Make dollar_expand variadic and pass a real va_list to
vdollar_percent_expand. Fixes build error on arm64 spotted by otto@.
OpenBSD-Commit-ID: 181910d7ae489f40ad609b4cf4a20f3d068a7279
commit 837ffa9699a9cba47ae7921d2876afaccc027133
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri May 29 20:39:00 2020 +1000
Omit ToS setting if we don't have IPV6_TCLASS too.
Fixes tests on old BSDs.
commit f85b118d2150847cc333895296bc230e367be6b5
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri May 29 09:02:44 2020 +0000
upstream: Pass a NULL instead of zeroed out va_list from
dollar_expand. The original intent was in case there's some platform where
va_list is not a pointer equivalent, but on i386 this chokes on the memset.
This unbreaks that build, but will require further consideration.
OpenBSD-Commit-ID: 7b90afcd8e1137a1d863204060052aef415baaf7
commit ec1d50b01c84ff667240ed525f669454c4ebc8e9
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Fri May 29 05:48:39 2020 +0000
upstream: remove a stray .El;
OpenBSD-Commit-ID: 58ddfe6f8a15fe10209db6664ecbe7896f1d167c
commit 058674a62ffe33f01d871d46e624bc2a2c22d91f
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri May 29 04:32:26 2020 +0000
upstream: Add regression and unit tests for ${ENV} style
environment variable expansion in various keywords (bz#3140). ok djm@
OpenBSD-Regress-ID: 4d9ceb95d89365b7b674bc26cf064c15a5bbb197
commit 0b15892fc47d6840eba1291a6be9be1a70bc8972
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri May 29 01:21:35 2020 +0000
upstream: Unit test for convtime. ok djm@
OpenBSD-Regress-ID: cec4239efa2fc4c7062064f07a847e1cbdbcd5dd
commit 188e332d1c8f9f24e5b6659e9680bf083f837df9
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri May 29 05:37:03 2020 +0000
upstream: mention that wildcards are processed in lexical order;
bz#3165
OpenBSD-Commit-ID: 8856f3d1612bd42e9ee606d89386cae456dd165c
commit 4a1b46e6d032608b7ec00ae51c4e25b82f460b05
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri May 29 04:25:40 2020 +0000
upstream: Allow some keywords to expand shell-style ${ENV}
environment variables on the client side. The supported keywords are
CertificateFile, ControlPath, IdentityAgent and IdentityFile, plus
LocalForward and RemoteForward when used for Unix domain socket paths. This
would for example allow forwarding of Unix domain socket paths that change at
runtime. bz#3140, ok djm@
OpenBSD-Commit-ID: a4a2e801fc2d4df2fe0e58f50d9c81b03822dffa
commit c9bab1d3a9e183cef3a3412f57880a0374cc8cb2
Author: Damien Miller <djm@mindrot.org>
Date: Fri May 29 14:49:16 2020 +1000
depend
commit 0b0d219313bf9239ca043f20b1a095db0245588f
Author: sobrado <sobrado@openbsd.org>
Date: Thu Sep 3 23:06:28 2015 +0000
partial sync of regress/netcat.c with upstream
synchronize synopsis and usage.
commit 0f04c8467f589f85a523e19fd684c4f6c4ed9482
Author: chl <chl@openbsd.org>
Date: Sun Jul 26 19:12:28 2015 +0000
partial sync of regress/netcat.c with upstream
remove unused variable
ok tedu@
commit d6a81050ace2630b06c3c6dd39bb4eef5d1043f8
Author: tobias <tobias@openbsd.org>
Date: Thu Mar 26 21:22:50 2015 +0000
partial sync of regress/netcat.c with upstream
The code in socks.c writes multiple times in a row to a socket. If the socket becomes invalid between these calls (e.g. connection closed), write will throw SIGPIPE. With this patch, SIGPIPE is ignored so we can handle write's -1 return value (errno will be EPIPE). Ultimately, it leads to program exit, too -- but with nicer error message. :)
with input by and ok djm
commit bf3893dddd35e16def04bf48ed2ee1ad695b8f82
Author: tobias <tobias@openbsd.org>
Date: Thu Mar 26 10:36:03 2015 +0000
partial sync of regress/netcat.c with upstream
Check for short writes in fdpass(). Clean up while at it.
ok djm
commit e18435fec124b4c08eb6bbbbee9693dc04f4befb
Author: jca <jca@openbsd.org>
Date: Sat Feb 14 22:40:22 2015 +0000
partial sync of regress/netcat.c with upstream
Support for nc -T on IPv6 addresses.
ok sthen@
commit 4c607244054a036ad3b2449a6cb4c15feb846a76
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri May 29 03:14:02 2020 +0000
upstream: fix compilation on !HAVE_DLOPEN platforms; stub function
was not updated to match API change. From Dale Rahn via beck@ ok markus@
OpenBSD-Commit-ID: 2b8d054afe34c9ac85e417dae702ef981917b836
commit 224418cf55611869a4ace1b8b07bba0dff77a9c3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri May 29 03:11:54 2020 +0000
upstream: fix exit status for downloading of FIDO resident keys;
from Pedro Martelletto, ok markus@
OpenBSD-Commit-ID: 0da77dc24a1084798eedd83c39a002a9d231faef
commit 1001dd148ed7c57bccf56afb40cb77482ea343a6
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri May 29 01:20:46 2020 +0000
upstream: Fix multiplier in convtime when handling seconds after
other units. bz#3171, spotted by ronf at timeheart.net, ok djm@.
OpenBSD-Commit-ID: 95b7a848e1083974a65fbb6ccb381d438e1dd5be
commit 7af1e92cd289b7eaa9a683e9a6f2fddd98f37a01
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed May 27 22:37:53 2020 +0000
upstream: fix Include before Match in sshd_config; bz#3122 patch
from Jakub Jelen
OpenBSD-Commit-ID: 1b0aaf135fe6732b5d326946042665dd3beba5f4
commit 0a9a611619b0a1fecd0195ec86a9885f5d681c84
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed May 27 21:59:11 2020 +0000
upstream: Do not call process_queued_listen_addrs() for every
included file from sshd_config; patch from Jakub Jelen
OpenBSD-Commit-ID: 0ff603d6f06a7fab4881f12503b53024799d0a49
commit 16ea1fdbe736648f79a827219134331f8d9844fb
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed May 27 21:25:18 2020 +0000
upstream: fix crash in recallocarray when deleting SendEnv
variables; spotted by & ok sthen@
OpenBSD-Commit-ID: b881e8e849edeec5082b5c0a87d8d7cff091a8fd
commit 47adfdc07f4f8ea0064a1495500244de08d311ed
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed May 27 22:35:19 2020 +0000
upstream: two new tests for Include in sshd_config, checking whether
Port directives are processed correctly and handling of Include directives
that appear before Match. Both tests currently fail. bz#3122 and bz#3169 -
patch from Jakub Jelen
OpenBSD-Regress-ID: 8ad5a4a385a63f0a1c59c59c763ff029b45715df
commit 47faad8f794516c33864d866aa1b55d88416f94c
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed May 27 23:26:23 2020 +1000
Document that libfido2 >= 1.4.0 is needed.
commit 4be563994c0cbe9856e7dd3078909f41beae4a9c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue May 26 01:59:46 2020 +0000
upstream: fix memleak of signature; from Pedro Martelletto
OpenBSD-Commit-ID: d0a6eb07e77c001427d738b220dd024ddc64b2bb
commit 0c111eb84efba7c2a38b2cc3278901a0123161b9
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue May 26 01:26:58 2020 +0000
upstream: Restrict ssh-agent from signing web challenges for FIDO
keys.
When signing messages in ssh-agent using a FIDO key that has an
application string that does not start with "ssh:", ensure that the
message being signed is one of the forms expected for the SSH protocol
(currently pubkey authentication and sshsig signatures).
This prevents ssh-agent forwarding on a host that has FIDO keys
attached granting the ability for the remote side to sign challenges
for web authentication using those keys too.
Note that the converse case of web browsers signing SSH challenges is
already precluded because no web RP can have the "ssh:" prefix in the
application string that we require.
ok markus@
OpenBSD-Commit-ID: 9ab6012574ed0352d2f097d307f4a988222d1b19
commit 9c5f64b6cb3a68b99915202d318b842c6c76cf14
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue May 26 01:09:05 2020 +0000
upstream: improve logging for MaxStartups connection throttling:
have sshd log when it starts and stops throttling and periodically while in
this state. bz#3055 ok markus@
OpenBSD-Commit-ID: 2e07a09a62ab45d790d3d2d714f8cc09a9ac7ab9
commit 756c6f66aee83a5862a6f936a316f761532f3320
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue May 26 01:06:52 2020 +0000
upstream: add fmt_timeframe() (from bgpd) to format a time
interval in a human- friendly format. Switch copyright for this file from BSD
to MIT to make it easier to add Henning's copyright for this function. ok
markus@
OpenBSD-Commit-ID: 414a831c662df7e68893e5233e86f2cac081ccf9
commit 2a63ce5cd6d0e782783bf721462239b03757dd49
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon May 18 04:29:35 2020 +0000
upstream: avoid possible NULL deref; from Pedro Martelletto
OpenBSD-Commit-ID: e6099c3fbb70aa67eb106e84d8b43f1fa919b721
commit 4b307faf2fb0e63e51a550b37652f7f972df9676
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri May 15 08:34:03 2020 +0000
upstream: sshd listener must not block if reexecd sshd exits
in write(2) on config_s[0] if the forked child exits early before finishing
recv_rexec_state (e.g. with fatal()) because config_s[1] stays open in the
parent. this prevents the parent from accepting new connections. ok djm,
deraadt
OpenBSD-Commit-ID: 92ccfeb939ccd55bda914dc3fe84582158c4a9ef
commit af8b16fb2cce880341c0ee570ceb0d84104bdcc0
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri May 15 03:57:33 2020 +0000
upstream: fix off-by-one error that caused sftp downloads to make
one more concurrent request that desired. This prevented using sftp(1) in
unpipelined request/response mode, which is useful when debugging. Patch from
Stephen Goetze in bz#3054
OpenBSD-Commit-ID: 41b394ebe57037dbc43bdd0eef21ff0511191f28
commit d7d753e2979f2d3c904b03a08d30856cd2a6e892
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Wed May 13 22:38:41 2020 +0000
upstream: we are still aiming for pre-C99 ...
OpenBSD-Commit-ID: a240fc9cbe60bc4e6c3d24d022eb4ab01fe1cb38
commit 2ad7b7e46408dbebf2a4efc4efd75a9544197d57
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed May 13 10:08:02 2020 +0000
upstream: Enable credProtect extension when generating a resident
key.
The FIDO 2.1 Client to Authenticator Protocol introduced a "credProtect"
feature to better protect resident keys. This option allows (amone other
possibilities) requiring a PIN prior to all operations that may retrieve
the key handle.
Patch by Pedro Martelletto; ok djm and markus
OpenBSD-Commit-ID: 013bc06a577dcaa66be3913b7f183eb8cad87e73
commit 1e70dc3285fc9b4f6454975acb81e8702c23dd89
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed May 13 09:57:17 2020 +0000
upstream: always call fido_init(); previous behaviour only called
fido_init() when SK_DEBUG was defined. Harmless with current libfido2, but
this isn't guaranteed in the future.
OpenBSD-Commit-ID: c7ea20ff2bcd98dd12015d748d3672d4f01f0864
commit f2d84f1b3fa68d77c99238d4c645d0266fae2a74
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed May 13 09:55:57 2020 +0000
upstream: preserve group/world read permission on known_hosts
file across runs of "ssh-keygen -Rf /path". The old behaviour was to remove
all rights for group/other. bz#3146 ok dtucker@
OpenBSD-Commit-ID: dc369d0e0b5dd826430c63fd5f4b269953448a8a
commit 05a651400da6fbe12296c34e3d3bcf09f034fbbf
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed May 13 09:52:41 2020 +0000
upstream: when ordering the hostkey algorithms to request from a
server, prefer certificate types if the known_hosts files contain a key
marked as a @cert-authority; bz#3157 ok markus@
OpenBSD-Commit-ID: 8f194573e5bb7c01b69bbfaabc68f27c9fa5e0db
commit 829451815ec207e14bd54ff5cf7e22046816f042
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue May 12 01:41:32 2020 +0000
upstream: fix non-ASCII quote that snuck in; spotted by Gabriel
Kihlman
OpenBSD-Commit-ID: 04bcde311de2325d9e45730c744c8de079b49800
commit 5a442cec92c0efd6fffb4af84bf99c70af248ef3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon May 11 02:11:29 2020 +0000
upstream: clarify role of FIDO tokens in multi-factor
authentictation; mostly from Pedro Martelletto
OpenBSD-Commit-ID: fbe05685a1f99c74b1baca7130c5a03c2df7c0ac
commit ecb2c02d994b3e21994f31a70ff911667c262f1f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri May 8 05:13:14 2020 +0000
upstream: fix compilation with DEBUG_KEXDH; bz#3160 ok dtucker@
OpenBSD-Commit-ID: 832e771948fb45f2270e8b8895aac36d176ba17a
commit 3ab6fccc3935e9b778ff52f9c8d40f215d58e01d
Author: Damien Miller <djm@mindrot.org>
Date: Thu May 14 12:22:09 2020 +1000
prefer ln to cp for temporary copy of sshd
I saw failures on the reexec fallback test on Darwin 19.4 where
fork()ed children of a process that had it's executable removed
would instantly fail. Using ln to preserve the inode avoids this.
commit f700d316c6b15a9cfbe87230d2dca81a5d916279
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed May 13 15:24:51 2020 +1000
Actually skip pty tests when needed.
commit 08ce6b2210f46f795e7db747809f8e587429dfd2
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed May 13 13:56:45 2020 +1000
Skip building sk-dummy library if no SK support.
commit 102d106bc2e50347d0e545fad6ff5ce408d67247
Author: Damien Miller <djm@mindrot.org>
Date: Wed May 13 12:08:34 2020 +1000
explicitly manage .depend and .depend.bak
Bring back removal of .depend to give the file a known state before
running makedepend, but manually move aside the current .depend file
and restore it as .depend.bak afterwards so the stale .depend check
works as expected.
commit 83a6dc6ba1e03b3fa39d12a8522b8b0e68dd6390
Author: Damien Miller <djm@mindrot.org>
Date: Wed May 13 12:03:42 2020 +1000
make depend
commit 7c0bbed967abed6301a63e0267cc64144357a99a
Author: Damien Miller <djm@mindrot.org>
Date: Wed May 13 12:01:10 2020 +1000
revert removal of .depend before makedepend
Commit 83657eac4 started removing .depend before running makedepend
to reset the contents of .depend to a known state. Unfortunately
this broke the depend-check step as now .depend.bak would only ever
be created as an empty file.
ok dtucker
commit 58ad004acdcabf3b9f40bc3aaa206b25d998db8c
Author: Damien Miller <djm@mindrot.org>
Date: Tue May 12 12:58:46 2020 +1000
prepare for 8.3 release
commit 4fa9e048c2af26beb7dc2ee9479ff3323e92a7b5
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri May 8 21:50:43 2020 +1000
Ensure SA_SIGNAL test only signals itself.
When the test's child signals its parent and it exits the result of
getppid changes. On Ubuntu 20.04 this results in the ppid being that
of the GDM session, causing it to exit. Analysis and testing from pedro
at ambientworks.net
commit dc2da29aae76e170d22f38bb36f1f5d1edd5ec2b
Author: Damien Miller <djm@mindrot.org>
Date: Fri May 8 13:31:53 2020 +1000
sync config.guess/config.sub with latest versions
ok dtucker@
commit a8265bd64c14881fc7f4fa592f46dfc66b911f17
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed May 6 20:58:01 2020 +0000
upstream: openssh-8.3; ok deraadt@
OpenBSD-Commit-ID: c8831ec88b9c750f5816aed9051031fb535d22c1
commit 955854cafca88e0cdcd3d09ca1ad4ada465364a1
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed May 6 20:57:38 2020 +0000
upstream: another case where a utimes() failure could make scp send
a desynchronising error; reminded by Aymeric Vincent ok deraadt markus
OpenBSD-Commit-ID: 2ea611d34d8ff6d703a7a8bf858aa5dbfbfa7381
commit 59d531553fd90196946743da391f3a27cf472f4e
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu May 7 15:34:12 2020 +1000
Check if -D_REENTRANT is needed for localtime_r.
On at least HP-UX 11.11, the localtime_r declararation is behind
ifdef _REENTRANT. Check for and add if needed.
commit c13403e55de8cdbb9da628ed95017b1d4c0f205f
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue May 5 11:32:43 2020 +1000
Skip security key tests if ENABLE_SK not set.
commit 4da393f87cd52d788c84112ee3f2191c9bcaaf30
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri May 1 04:03:14 2020 +0000
upstream: sure enough, some of the test data that we though were in
new format were actually in the old format; fix from Michael Forney
OpenBSD-Regress-ID: a41a5c43a61b0f0b1691994dbf16dfb88e8af933
commit 15bfafc1db4c8792265ada9623a96f387990f732
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri May 1 04:00:29 2020 +0000
upstream: make mktestdata.sh generate old/new format keys that we
expect. This script was written before OpenSSH switched to new-format private
keys by default and was never updated to the change (until now) From Michael
Forney
OpenBSD-Regress-ID: 38cf354715c96852e5b71c2393fb6e7ad28b7ca7
commit 7882d2eda6ad3eb82220a85294de545d20ef82db
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri May 1 03:58:02 2020 +0000
upstream: portability fix for sed that always emil a newline even
if the input does not contain one; from Michael Forney
OpenBSD-Regress-ID: 9190c3ddf0d2562ccc02c4a95fce0e392196bfc7
commit 8074f9499e454df0acdacea33598858a1453a357
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri May 1 03:36:25 2020 +0000
upstream: remove obsolete RSA1 test keys; spotted by Michael Forney
OpenBSD-Regress-ID: 6384ba889594e217d166908ed8253718ab0866da
commit c697e46c314aa94574af0d393d80f23e0ebc9748
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat May 2 18:34:47 2020 +1000
Update .depend.
commit 83657eac42941f270c4b02b2c46d9a21f616ef99
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat May 2 18:29:40 2020 +1000
Remove use of tail for 'make depend'.
Not every tail supports +N and we can do with out it so just remove it.
Prompted by mforney at mforney.org.
commit d25d630d24c5a1c64d4e646510e79dc22d6d7b88
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat May 2 07:19:43 2020 +0000
upstream: we have a sshkey_save_public() function to save public keys;
use it and save a bunch of redundant code.
Patch from loic AT venez.fr; ok markus@ djm@
OpenBSD-Commit-ID: f93e030a0ebcd0fd9054ab30db501ec63454ea5f
commit e9dc9863723e111ae05e353d69df857f0169544a
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri May 1 18:32:25 2020 +1000
Use LONG_LONG_MAX and friends if available.
If we don't have LLONG_{MIN,MAX} but do have LONG_LONG_{MIN,MAX}
then use those instead. We do calculate these values in configure,
but it turns out that at least one compiler (old HP ANSI C) can't
parse "-9223372036854775808LL" without mangling it. (It can parse
"-9223372036854775807LL" which is presumably why its limits.h defines
LONG_LONG_MIN as the latter minus 1.)
Fixes rekey test when compiled with the aforementioned compiler.
commit aad87b88fc2536b1ea023213729aaf4eaabe1894
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri May 1 06:31:42 2020 +0000
upstream: when receving a file in sink(), be careful to send at
most a single error response after the file has been opened. Otherwise the
source() and sink() can become desyncronised. Reported by Daniel Goujot,
Georges-Axel Jaloyan, Ryan Lahfa, and David Naccache.
ok deraadt@ markus@
OpenBSD-Commit-ID: 6c14d233c97349cb811a8f7921ded3ae7d9e0035
commit 31909696c4620c431dd55f6cd15db65c4e9b98da
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri May 1 06:28:52 2020 +0000
upstream: expose vasnmprintf(); ok (as part of other commit) markus
deraadt
OpenBSD-Commit-ID: 2e80cea441c599631a870fd40307d2ade5a7f9b5
commit 99ce9cefbe532ae979744c6d956b49f4b02aff82
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri May 1 04:23:11 2020 +0000
upstream: avoid NULL dereference when attempting to convert invalid
ssh.com private keys using "ssh-keygen -i"; spotted by Michael Forney
OpenBSD-Commit-ID: 2e56e6d26973967d11d13f56ea67145f435bf298
commit 6c6072ba8b079e6f5caa38b011a6f4570c14ed38
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri May 1 15:09:26 2020 +1000
See if SA_RESTART signals will interrupt select().
On some platforms (at least older HP-UXes such as 11.11, possibly others)
setting SA_RESTART on signal handers will cause it to not interrupt
select(), at least for calls that do not specify a timeout. Try to
detect this and if found, don't use SA_RESTART.
POSIX says "If SA_RESTART has been set for the interrupting signal, it
is implementation-dependent whether select() restarts or returns with
[EINTR]" so this behaviour is within spec.
commit 90a0b434ed41f9c505662dba8782591818599cb3
Author: Damien Miller <djm@mindrot.org>
Date: Fri May 1 13:55:03 2020 +1000
fix reversed test
commit c0dfd18dd1c2107c73d18f70cd164f7ebd434b08
Author: Damien Miller <djm@mindrot.org>
Date: Fri May 1 13:29:16 2020 +1000
wrap sha2.h inclusion in #ifdef HAVE_SHA2_H
commit a01817a9f63dbcbbc6293aacc4019993a4cdc7e3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Apr 28 04:59:29 2020 +0000
upstream: adapt dummy FIDO middleware to API change; ok markus@
OpenBSD-Regress-ID: 8bb84ee500c2eaa5616044314dd0247709a1790f
commit 261571ddf02ea38fdb5e4a97c69ee53f847ca5b7
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Thu Apr 30 18:28:37 2020 +0000
upstream: tweak previous; ok markus
OpenBSD-Commit-ID: 41895450ce2294ec44a5713134491cc31f0c09fd
commit 5de21c82e1d806d3e401b5338371e354b2e0a66f
Author: markus@openbsd.org <markus@openbsd.org>
Date: Thu Apr 30 17:12:20 2020 +0000
upstream: bring back debug() removed in rev 1.74; noted by pradeep
kumar
OpenBSD-Commit-ID: 8d134d22ab25979078a3b48d058557d49c402e65
commit ea14103ce9a5e13492e805f7e9277516ff5a4273
Author: markus@openbsd.org <markus@openbsd.org>
Date: Thu Apr 30 17:07:10 2020 +0000
upstream: run the 2nd ssh with BatchMode for scp -3
OpenBSD-Commit-ID: 77994fc8c7ca02d88e6d0d06d0f0fe842a935748
commit 59d2de956ed29aa5565ed5e5947a7abdb27ac013
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Apr 28 04:02:29 2020 +0000
upstream: when signing a challenge using a FIDO toke, perform the
hashing in the middleware layer rather than in ssh code. This allows
middlewares that call APIs that perform the hashing implicitly (including
Microsoft's AFAIK). ok markus@
OpenBSD-Commit-ID: c9fc8630aba26c75d5016884932f08a5a237f37d
commit c9d10dbc0ccfb1c7568bbb784f7aeb7a0b5ded12
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sun Apr 26 09:38:14 2020 +0000
upstream: Fix comment typo. Patch from mforney at mforney.org.
OpenBSD-Commit-ID: 3565f056003707a5e678e60e03f7a3efd0464a2b
commit 4d2c87b4d1bde019cdd0f00552fcf97dd8b39940
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sat Apr 25 06:59:36 2020 +0000
upstream: We've standardized on memset over bzero, replace a couple
that had slipped in. ok deraadt markus djm.
OpenBSD-Commit-ID: f5be055554ee93e6cc66b0053b590bef3728dbd6
commit 7f23f42123d64272a7b00754afa6b0841d676691
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri May 1 12:21:58 2020 +1000
Include sys/byteorder.h for htons and friends.
These are usually in netinet/in.h but on HP-UX they are not defined if
_XOPEN_SOURCE_EXTENDED is set. Only needed for netcat in the regression
tests.
commit d27cba58c972d101a5de976777e518f34ac779cb
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri May 1 09:21:52 2020 +1000
Fix conditional for openssl-based chacha20.
Fixes warnings or link errors when building against older OpenSSLs.
ok djm
commit 20819b962dc1467cd6fad5486a7020c850efdbee
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Apr 24 15:07:55 2020 +1000
Error out if given RDomain if unsupported.
If the config contained 'RDomain %D' on a platform that did not support
it, the error would not be detected until runtime resulting in a broken
sshd. Detect this earlier and error out if found. bz#3126, based on a
patch from jjelen at redhat.com, tweaks and ok djm@
commit 2c1690115a585c624eed2435075a93a463a894e2
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Apr 24 03:33:21 2020 +0000
upstream: Fix incorrect error message for "too many known hosts files."
bz#3149, patch from jjelen at redhat.com.
OpenBSD-Commit-ID: e0fcb07ed5cf7fd54ce340471a747c24454235e5
commit 3beb7276e7a8aedd3d4a49f9c03b97f643448c92
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Apr 24 02:19:40 2020 +0000
upstream: Remove leave_non_blocking() which is now dead code
because nothing sets in_non_blocking_mode any more. Patch from
michaael.meeks at collabora.com, ok djm@
OpenBSD-Commit-ID: c403cefe97a5a99eca816e19cc849cdf926bd09c
commit 8654e3561772f0656e7663a0bd6a1a8cb6d43300
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Thu Apr 23 21:28:09 2020 +0000
upstream: ce examples of "Ar arg Ar arg" with "Ar arg arg" and
stop the spread;
OpenBSD-Commit-ID: af0e952ea0f5e2019c2ce953ed1796eca47f0705
commit 67697e4a8246dd8423e44b8785f3ee31fee72d07
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Apr 24 11:10:18 2020 +1000
Update .depend.
commit d6cc76176216fe3fac16cd20d148d75cb9c50876
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Apr 22 14:07:00 2020 +1000
Mailing list is now closed to non-subscribers.
While there, add a reference to the bugzilla. ok djm@
commit cecde6a41689d0ae585ec903b190755613a6de79
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Apr 22 12:09:40 2020 +1000
Put the values from env vars back.
This merges the values from the recently removed environment into make's
command line arguments since we actually need those.
commit 300c4322b92e98d3346efa0aec1c094c94d0f964
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Apr 22 11:33:15 2020 +1000
Pass configure's egrep through to test-exec.sh.
Use it to create a wrapper function to call it from tests. Fixes the
keygen-comment test on platforms with impoverished default egrep (eg
Solaris).
commit c8d9796cfe046f00eb8b2096d2b7028d6a523a84
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Apr 22 10:56:44 2020 +1000
Remove unneeded env vars from t-exec invocation.
commit 01d4cdcd4514e99a4b6eb9523cd832bbf008d1d7
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Apr 21 23:14:58 2020 +0000
upstream: Backslash '$' at then end of string. Prevents warning on
some shells.
OpenBSD-Regress-ID: 5dc27ab624c09d34078fd326b10e38c1ce9c741f
commit 8854724ccefc1fa16f10b37eda2e759c98148caa
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Apr 21 18:27:23 2020 +1000
Sync rev 1.49.
Prevent infinite for loop since i went from ssize_t to size_t. Patch from
eagleoflqj via OpenSSH github PR#178, ok djm@, feedback & ok millert@
commit d00d07b6744d3b4bb7aca46c734ecd670148da23
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Apr 20 04:44:47 2020 +0000
upstream: regression test for printing of private key fingerprints and
key comments, mostly by loic AT venez.fr (slightly tweaked for portability)
ok dtucker@
OpenBSD-Regress-ID: 8dc6c4feaf4fe58b6d634cd89afac9a13fd19004
commit a98d5ba31e5e7e01317352f85fa63b846a960f8c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Apr 20 04:43:57 2020 +0000
upstream: fix a bug I introduced in r1.406: when printing private key
fingerprint of old-format key, key comments were not being displayed. Spotted
by loic AT venez.fr, ok dtucker
OpenBSD-Commit-ID: 2d98e4f9eb168eea733d17e141e1ead9fe26e533
commit 32f2d0aad42c15e19bd3b07496076ca891573a58
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 17 07:16:07 2020 +0000
upstream: repair private key fingerprint printing to also print
comment after regression caused by my recent pubkey loading refactor.
Reported by loic AT venez.fr, ok dtucker@
OpenBSD-Commit-ID: f8db49acbee6a6ccb2a4259135693b3cceedb89e
commit 094dd513f4b42e6a3cebefd18d1837eb709b4d99
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 17 07:15:11 2020 +0000
upstream: refactor out some duplicate private key loading code;
based on patch from loic AT venez.fr, ok dtucker@
OpenBSD-Commit-ID: 5eff2476b0d8d0614924c55e350fb7bb9c84f45e
commit 4e04f46f248f1708e39b900b76c9693c820eff68
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Fri Apr 17 06:12:41 2020 +0000
upstream: add space beteen macro arg and punctuation;
OpenBSD-Commit-ID: c93a6cbb4bf9468fc4c13e64bc1fd4efee201a44
commit 44ae009a0112081d0d541aeaa90088bedb6f21ce
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 17 04:27:03 2020 +0000
upstream: auth2-pubkey r1.89 changed the order of operations to
checking AuthorizedKeysFile first and falling back to AuthorizedKeysCommand
if no key was found in a file. Document this order here; bz3134
OpenBSD-Commit-ID: afce0872cbfcfc1d4910ad7722e50f792a1dce12
commit f96f17f920f38ceea6f3c5cb0b075c46b8929fdc
Author: Damien Miller <djm@mindrot.org>
Date: Fri Apr 17 14:07:15 2020 +1000
sys/sysctl.h is only used on OpenBSD
so change the preprocessor test used to include it to check
__OpenBSD__, matching the code that uses the symbols it declares.
commit 54688e937a69c7aebef8a3d50cbd4c6345bab2ca
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 17 03:38:47 2020 +0000
upstream: fix reversed test that caused IdentitiesOnly=yes to not
apply to keys loaded from a PKCS11Provider; bz3141, ok dtucker@
OpenBSD-Commit-ID: e3dd6424b94685671fe84c9b9dbe352fb659f677
commit 267cbc87b5b6e78973ac4d3c7a6f807ed226928c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 17 03:34:42 2020 +0000
upstream: mention that /etc/hosts.equiv and /etc/shosts.equiv are
not considered for HostbasedAuthentication when the target user is root;
bz3148
OpenBSD-Commit-ID: fe4c1256929e53f23af17068fbef47852f4bd752
commit c90f72d29e84b4a2709078bf5546a72c29a65177
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 17 03:30:05 2020 +0000
upstream: make IgnoreRhosts a tri-state option: "yes" ignore
rhosts/shosts, "no" allow rhosts/shosts or (new) "shosts-only" to allow
.shosts files but not .rhosts. ok dtucker@
OpenBSD-Commit-ID: d08d6930ed06377a80cf53923c1955e9589342e9
commit 321c7147079270f3a154f91b59e66219aac3d514
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 17 03:23:13 2020 +0000
upstream: allow the IgnoreRhosts directive to appear anywhere in a
sshd_config, not just before any Match blocks; bz3148, ok dtucker@
OpenBSD-Commit-ID: e042467d703bce640b1f42c5d1a62bf3825736e8
commit ca5403b085a735055ec7b7cdcd5b91f2662df94c
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Sat Apr 11 20:20:09 2020 +0000
upstream: add space between macro arg and punctuation;
OpenBSD-Commit-ID: e579e4d95eef13059c30931ea1f09ed8296b819c
commit 8af0244d7b4a65eed2e62f9c89141c7c8e63f09d
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Apr 15 10:58:02 2020 +1000
Add sys/syscall.h for syscall numbers.
In some architecture/libc configurations we need to explicitly include
sys/syscall.h for the syscall number (__NR_xxx) definitions. bz#3085,
patch from blowfist at xroutine.net.
commit 3779b50ee952078018a5d9e1df20977f4355df17
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Apr 11 10:16:11 2020 +0000
upstream: Refactor private key parsing. Eliminates a fair bit of
duplicated code and fixes oss-fuzz#20074 (NULL deref) caused by a missing key
type check in the ECDSA_CERT parsing path.
feedback and ok markus@
OpenBSD-Commit-ID: 4711981d88afb7196d228f7baad9be1d3b20f9c9
commit b6a4013647db67ec622c144a9e05dd768f1966b3
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Apr 10 00:54:03 2020 +0000
upstream: Add tests for TOKEN expansion of LocalForward and
RemoteForward.
OpenBSD-Regress-ID: 90fcbc60d510eb114a2b6eaf4a06ff87ecd80a89
commit abc3e0a5179c13c0469a1b11fe17d832abc39999
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Apr 6 09:43:55 2020 +0000
upstream: Add utf8.c for asmprintf used by krl.c
OpenBSD-Regress-ID: 433708d11165afdb189fe635151d21659dd37a37
commit 990687a0336098566c3a854d23cce74a31ec6fe2
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Apr 10 00:52:07 2020 +0000
upstream: Add TOKEN percent expansion to LocalFoward and RemoteForward
when used for Unix domain socket forwarding. Factor out the code for the
config keywords that use the most common subset of TOKENS into its own
function. bz#3014, ok jmc@ (man page bits) djm@
OpenBSD-Commit-ID: bffc9f7e7b5cf420309a057408bef55171fd0b97
commit 2b13d3934d5803703c04803ca3a93078ecb5b715
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Apr 8 00:10:37 2020 +0000
upstream: let sshkey_try_load_public() load public keys from the
unencrypted envelope of private key files if not sidecar public key file is
present.
ok markus@
OpenBSD-Commit-ID: 252a0a580e10b9a6311632530d63b5ac76592040
commit d01f39304eaab0352793b490a25e1ab5f59a5366
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Apr 8 00:09:24 2020 +0000
upstream: simplify sshkey_try_load_public()
ok markus@
OpenBSD-Commit-ID: 05a5d46562aafcd70736c792208b1856064f40ad
commit f290ab0833e44355fc006e4e67b92446c14673ef
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Apr 8 00:08:46 2020 +0000
upstream: add sshkey_parse_pubkey_from_private_fileblob_type()
Extracts a public key from the unencrypted envelope of a new-style
OpenSSH private key.
ok markus@
OpenBSD-Commit-ID: 44d7ab446e5e8c686aee96d5897b26b3939939aa
commit 8d514eea4ae089626a55e11c7bc1745c8d9683e4
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Apr 8 00:07:19 2020 +0000
upstream: simplify sshkey_parse_private_fileblob_type()
Try new format parser for all key types first, fall back to PEM
parser only for invalid format errors.
ok markus@
OpenBSD-Commit-ID: 0173bbb3a5cface77b0679d4dca0e15eb5600b77
commit 421169d0e758351b105eabfcebf42378ebf17217
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Apr 8 00:05:59 2020 +0000
upstream: check private key type against requested key type in
new-style private decoding; ok markus@
OpenBSD-Commit-ID: 04d44b3a34ce12ce5187fb6f6e441a88c8c51662
commit 6aabfb6d22b36d07f584cba97f4cdc4363a829da
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Apr 8 00:04:32 2020 +0000
upstream: check that pubkey in private key envelope matches actual
private key
(this public key is currently unusued)
ok markus@
OpenBSD-Commit-ID: 634a60b5e135d75f48249ccdf042f3555112049c
commit c0f5b2294796451001fd328c44f0d00f1114eddf
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Apr 8 00:01:52 2020 +0000
upstream: refactor private key parsing a little
Split out the base64 decoding and private section decryption steps in
to separate functions. This will make the decryption step easier to fuzz
as well as making it easier to write a "load public key from new-format
private key" function.
ok markus@
OpenBSD-Commit-ID: 7de31d80fb9062aa01901ddf040c286b64ff904e
commit 8461a5b3db34ed0b5a4a18d82f64fd5ac8693ea8
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Apr 6 20:54:34 2020 +1000
Include openssl-compat.h before checking ifdefs.
Fixes problem where unsuitable chacha20 code in libressl would be used
unintentionally.
commit 931c50c5883a9910ea1ae9a371e4e815ec56b035
Author: Damien Miller <djm@mindrot.org>
Date: Mon Apr 6 10:04:56 2020 +1000
fix inverted test for LibreSSL version
commit d1d5f728511e2338b7c994968d301d8723012264
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sat Apr 4 23:04:41 2020 +0000
upstream: Indicate if we're using a cached key in trace output.
OpenBSD-Regress-ID: 409a7b0e59d1272890fda507651c0c3d2d3c0d89
commit a398251a4627367c78bc483c70c2ec973223f82c
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sun Apr 5 08:43:57 2020 +1000
Use /usr/bin/xp4g/id if necessary.
Solaris' native "id" doesn't support the options we use but the one
in /usr/bin/xp4g does, so use that instead.
commit db0fdd48335b5b01114f78c1a73a195235910f81
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sat Apr 4 22:14:26 2020 +0000
upstream: Some platforms don't have "hostname -s", so use cut to trim
short hostname instead.
OpenBSD-Regress-ID: ebcf36a6fdf287c9336b0d4f6fc9f793c05307a7
commit e7e59a9cc8eb7fd5944ded28f4d7e3ae0a5fdecd
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Apr 3 07:53:10 2020 +0000
upstream: Compute hash locally and re-enable %C tests.
OpenBSD-Regress-ID: 94d1366e8105274858b88a1f9ad2e62801e49770
commit abe2b245b3ac6c4801e99bc0f13289cd28211e22
Author: Damien Miller <djm@mindrot.org>
Date: Fri Apr 3 17:25:46 2020 +1100
prefer libcrypto chacha20-poly1305 where possible
commit bc5c5d01ad668981f9e554e62195383bc12e8528
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Apr 3 05:43:11 2020 +0000
upstream: Temporarily remove tests for '%C' since the hash contains the
local hostname and it doesn't work on any machine except mine... spotted by
djm@
OpenBSD-Regress-ID: 2d4c3585b9fcbbff14f4a5a5fde51dbd0d690401
commit 81624026989654955a657ebf2a1fe8b9994f3c87
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 3 06:07:57 2020 +0000
upstream: r1.522 deleted one too many lines; repair
OpenBSD-Commit-ID: 1af8851fd7a99e4a887b19aa8f4c41a6b3d25477
commit 668cb3585ce829bd6e34d4a962c489bda1d16370
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Fri Apr 3 05:53:52 2020 +0000
upstream: sort -N and add it to usage();
OpenBSD-Commit-ID: 5b00e8db37c2b0a54c7831fed9e5f4db53ada332
commit 338ccee1e7fefa47f3d128c2541e94c5270abe0c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 3 05:48:57 2020 +0000
upstream: avoid another compiler warning spotted in -portable
OpenBSD-Commit-ID: 1d29c51ac844b287c4c8bcaf04c63c7d9ba3b8c7
commit 9f8a42340bd9af86a99cf554dc39ecdf89287544
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 3 04:07:48 2020 +0000
upstream: this needs utf8.c too
OpenBSD-Regress-ID: 445040036cec714d28069a20da25553a04a28451
commit 92115ea7c3a834374720c350841fc729e7d5c8b2
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Apr 3 03:14:03 2020 +0000
upstream: Add percent_expand test for 'Match Exec'.
OpenBSD-Regress-ID: a41c14fd6a0b54d66aa1e9eebfb9ec962b41232f
commit de34a440276ae855c38deb20f926d46752c62c9d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 3 04:43:24 2020 +0000
upstream: fix format string (use %llu for uint64, not %lld). spotted by
Darren and his tinderbox tests
OpenBSD-Commit-ID: 3b4587c3d9d46a7be9bdf028704201943fba96c2
commit 9cd40b829a5295cc81fbea8c7d632b2478db6274
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 3 04:34:15 2020 +0000
upstream: Add a flag to re-enable verbose output when in batch
mode; requested in bz3135; ok dtucker
OpenBSD-Commit-ID: 5ad2ed0e6440562ba9c84b666a5bbddc1afe2e2b
commit 6ce51a5da5d333a44e7c74c027f3571f70c39b24
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 3 04:32:21 2020 +0000
upstream: chacha20-poly1305 AEAD using libcrypto EVP_chacha20
Based on patch from Yuriy M. Kaminskiy. ok + lots of assistance along the
way at a2k20 tb@
OpenBSD-Commit-ID: 5e08754c13d31258bae6c5e318cc96219d6b10f0
commit eba523f0a130f1cce829e6aecdcefa841f526a1a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 3 04:27:03 2020 +0000
upstream: make Chacha20-POLY1305 context struct opaque; ok tb@ as
part of a larger diff at a2k20
OpenBSD-Commit-ID: a4609b7263284f95c9417ef60ed7cdbb7bf52cfd
commit ebd29e90129cf18fedfcfe1de86e324228669295
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 3 04:06:26 2020 +0000
upstream: fix debug statement
OpenBSD-Commit-ID: 42c6edeeda5ce88b51a20d88c93be3729ce6b916
commit 7b4d8999f2e1a0cb7b065e3efa83e6edccfc7d82
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 3 04:03:51 2020 +0000
upstream: the tunnel-forwarding vs ExitOnForwardFailure fix that I
committed earlier had an off-by-one. Fix this and add some debugging that
would have made it apparent sooner.
OpenBSD-Commit-ID: 082f8f72b1423bd81bbdad750925b906e5ac6910
commit eece243666d44ceb710d004624c5c7bdc05454bc
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Apr 3 03:12:11 2020 +0000
upstream: %C expansion just added to Match Exec should include
remote user not local user.
OpenBSD-Commit-ID: 80f1d976938f2a55ee350c11d8b796836c8397e2
commit d5318a784d016478fc8da90a38d9062c51c10432
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Apr 3 02:33:31 2020 +0000
upstream: Add regression test for percent expansions where possible.
OpenBSD-Regress-ID: 7283be8b2733ac1cbefea3048a23d02594485288
commit 663e84bb53de2a60e56a44d538d25b8152b5c1cc
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 3 02:40:32 2020 +0000
upstream: make failures when establishing "Tunnel" forwarding terminate
the connection when ExitOnForwardFailure is enabled; bz3116; ok dtucker
OpenBSD-Commit-ID: ef4b4808de0a419c17579b1081da768625c1d735
commit ed833da176611a39d3376d62154eb88eb440d31c
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Apr 3 02:27:12 2020 +0000
upstream: Make with config keywords support which
percent_expansions more consistent. - %C is moved into its own function and
added to Match Exec. - move the common (global) options into a macro. This
is ugly but it's the least-ugly way I could come up with. - move
IdentityAgent and ForwardAgent percent expansion to before the config dump
to make it regression-testable. - document all of the above
ok jmc@ for man page bits, "makes things less terrible" djm@ for the rest.
OpenBSD-Commit-ID: 4b65664bd6d8ae2a9afaf1a2438ddd1b614b1d75
commit 6ec7457171468da2bbd908b8cd63d298b0e049ea
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 3 02:26:56 2020 +0000
upstream: give ssh-keygen the ability to dump the contents of a
binary key revocation list: ssh-keygen -lQf /path bz#3132; ok dtucker
OpenBSD-Commit-ID: b76afc4e3b74ab735dbde4e5f0cfa1f02356033b
commit af628b8a6c3ef403644d83d205c80ff188c97f0c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Apr 3 02:25:21 2020 +0000
upstream: add allocating variant of the safe utf8 printer; ok
dtucker as part of a larger diff
OpenBSD-Commit-ID: 037e2965bd50eacc2ffb49889ecae41552744fa0
commit d8ac9af645f5519ac5211e9e1e4dc1ed00e9cced
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Mar 16 02:17:02 2020 +0000
upstream: Cast lifetime to u_long for comparison to prevent unsigned
comparison warning on 32bit arches. Spotted by deraadt, ok djm.
OpenBSD-Commit-ID: 7a75b2540bff5ab4fa00b4d595db1df13bb0515a
commit 0eaca933ae08b0a515edfccd5cc4a6b667034813
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Mar 14 20:58:46 2020 +1100
Include fido.h when checking for fido/credman.h.
It's required for fido_dev_t, otherwise configure fails with
when given --with-security-key-builtin.
commit c7c099060f82ffe6a36d8785ecf6052e12fd92f0
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Mar 13 03:18:45 2020 +0000
upstream: some more speeling mistakes from
OpenBSD-Regress-ID: 02471c079805471c546b7a69d9ab1d34e9a57443
commit 1d89232a4aa97fe935cd60b8d24d75c2f70d56c5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Mar 13 04:16:27 2020 +0000
upstream: improve error messages for some common PKCS#11 C_Login
failure cases; based on patch from Jacob Hoffman-Andrews in bz3130; ok
dtucker
OpenBSD-Commit-ID: b8b849621b4a98e468942efd0a1c519c12ce089e
commit 5becbec023f2037394987f85ed7f74b9a28699e0
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Mar 13 04:01:56 2020 +0000
upstream: use sshpkt_fatal() for kex_exchange_identification()
errors. This ensures that the logged errors are consistent with other
transport- layer errors and that the relevant IP addresses are logged. bz3129
ok dtucker@
OpenBSD-Commit-ID: 2c22891f0b9e1a6cd46771cedbb26ac96ec2e6ab
commit eef88418f9e5e51910af3c5b23b5606ebc17af55
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Mar 13 03:24:49 2020 +0000
upstream: Don't clear alarm timers in listening sshd. Previously
these timers were used for regenerating the SSH1 ephemeral host keys but
those are now gone so there's no need to clear the timers either. ok
deraadt@
OpenBSD-Commit-ID: 280d2b885e4a1ce404632e8cc38fcb17be7dafc0
commit d081f017c20a3564255873ed99fd7d024cac540f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Mar 13 03:17:07 2020 +0000
upstream: spelling errors in comments; no code change from
OpenBSD-Commit-ID: 166ea64f6d84f7bac5636dbd38968592cb5eb924
commit c084a2d040f160bc2b83f13297e3e3ca3f5dbac6
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Mar 13 03:12:17 2020 +0000
upstream: when downloading FIDO2 resident keys from a token, don't
prompt for a PIN until the token has told us that it needs one. Avoids
double-prompting on devices that implement on-device authentication (e.g. a
touchscreen PIN pad on the Trezor Model T). ok dtucker@
OpenBSD-Commit-ID: 38b78903dd4422d7d3204095a31692fb69130817
commit 955c4cf4c6a1417c28d4e1040702c4d9bf63645b
Author: Damien Miller <djm@mindrot.org>
Date: Fri Mar 13 14:30:16 2020 +1100
sync fnmatch.c with upstream to fix another typo
commit 397f217e8640e75bb719a8e87111b4bd848fb3df
Author: Damien Miller <djm@mindrot.org>
Date: Fri Mar 13 14:24:23 2020 +1100
another spelling error in comment
commit def31bc5427579ec3f7f2ce99f2da1338fdc0c9f
Author: Damien Miller <djm@mindrot.org>
Date: Fri Mar 13 14:23:07 2020 +1100
spelling mistakes
from https://fossies.org/linux/misc/openssh-8.2p1.tar.gz/codespell.html
commit 8bdc3bb7cf4c82c3344cfcb82495a43406e87e83
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:29:54 2020 +0000
upstream: fix relative includes in sshd_config; ok djm
OpenBSD-Commit-ID: fa29b0da3c93cbc3a1d4c6bcd58af43c00ffeb5b
commit e32ef97a56ae03febfe307688858badae3a70e5a
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:29:14 2020 +0000
upstream: fix use-after-free in do_download_sk; ok djm
OpenBSD-Commit-ID: 96b49623d297797d4fc069f1f09e13c8811f8863
commit 5732d58020309364bf31fa125354e399361006db
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:28:50 2020 +0000
upstream: do not leak oprincipals; ok djm
OpenBSD-Commit-ID: 4691d9387eab36f8fda48f5d8009756ed13a7c4c
commit 8fae395f34c2c52cdaf9919aa261d1848b4bb00b
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:28:27 2020 +0000
upstream: initialize seconds for debug message; ok djm
OpenBSD-Commit-ID: 293fbefe6d00b4812a180ba02e26170e4c855b81
commit 46e5c4c8ffcd1569bcd5d04803abaa2ecf3e4cff
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:27:50 2020 +0000
upstream: correct return code; ok djm
OpenBSD-Commit-ID: 319d09e3b7f4b2bc920c67244d9ff6426b744810
commit 31c39e7840893f1bfdcbe4f813b20d1d7e69ec3e
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:27:15 2020 +0000
upstream: principalsp is optional, pubkey required; ok djm
OpenBSD-Commit-ID: 2cc3ea5018c28ed97edaccd7f17d2cc796f01024
commit e26a31757c5df2f58687cb9a4853d1418f39728e
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:26:21 2020 +0000
upstream: remove unused variables in ssh-pkcs11-helper; ok djm
OpenBSD-Commit-ID: 13e572846d0d1b28f1251ddd2165e9cf18135ae1
commit 1b378c0d982d6ab522eda634b0e88cf1fca5e352
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:25:48 2020 +0000
upstream: return correct error in sshsk_ed25519_sig; ok djm
OpenBSD-Commit-ID: 52bf733df220303c260fee4f165ec64b4a977625
commit fbff605e637b068061ab6784ff03e3874890c092
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:25:12 2020 +0000
upstream: fix possible null-deref in check_key_not_revoked; ok
djm
OpenBSD-Commit-ID: 80855e9d7af42bb6fcc16c074ba69876bfe5e3bf
commit bc30b446841fc16e50ed6e75c56ccfbd37b9f281
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:24:39 2020 +0000
upstream: ssh_fetch_identitylist() returns the return value from
ssh_request_reply() so we should also check against != 0 ok djm
OpenBSD-Commit-ID: 28d0028769d03e665688c61bb5fd943e18614952
commit 7b4f70ddeb59f35283d77d8d9c834ca58f8cf436
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:23:17 2020 +0000
upstream: sshkey_cert_check_authority requires reason to be set;
ok djm
OpenBSD-Commit-ID: 6f7a6f19540ed5749763c2f9530c0897c94aa552
commit 05efe270df1e925db0af56a806d18b5063db4b6d
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:21:28 2020 +0000
upstream: passphrase depends on kdfname, not ciphername (possible
null-deref); ok djm
OpenBSD-Commit-ID: 0d39668edf5e790b5837df4926ee1141cec5471c
commit 1ddf5682f3992bdacd29164891abb71a19c2cf61
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:20:44 2020 +0000
upstream: consistently check packet_timeout_ms against 0; ok djm
OpenBSD-Commit-ID: e8fb8cb2c96c980f075069302534eaf830929928
commit 31f1ee54968ad84eb32375e4412e0318766b586b
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:20:02 2020 +0000
upstream: initialize cname in case ai_canonname is NULL or too
long; ok djm
OpenBSD-Commit-ID: c27984636fdb1035d1642283664193e91aab6e37
commit a6134b02b5264b2611c8beae98bb392329452bba
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:19:21 2020 +0000
upstream: fix uninitialized pointers for forward_cancel; ok djm
OpenBSD-Commit-ID: 612778e6d87ee865d0ba97d0a335f141cee1aa37
commit 16d4f9961c75680aab374dee762a5baa0ad507af
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:16:21 2020 +0000
upstream: exit on parse failures in input_service_request; ok djm
OpenBSD-Commit-ID: 6a7e1bfded26051d5aa893c030229b1ee6a0d5d2
commit 5f25afe5216ba7f8921e04f79aa4ca0624eca820
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:15:38 2020 +0000
upstream: fix null-deref on calloc failure; ok djm
OpenBSD-Commit-ID: a313519579b392076b7831ec022dfdefbec8724a
commit ff2acca039aef16a15fce409163df404858f7aa5
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:15:04 2020 +0000
upstream: exit if ssh_krl_revoke_key_sha256 fails; ok djm
OpenBSD-Commit-ID: 0864ad4fe8bf28ab21fd1df766e0365c11bbc0dc
commit 31c860a0212af2d5b6a129e3e8fcead51392ee1d
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:14:13 2020 +0000
upstream: pkcs11_register_provider: return < 0 on error; ok djm
OpenBSD-Commit-ID: cfc8321315b787e4d40da4bdb2cbabd4154b0d97
commit 15be29e1e3318737b0768ca37d5b4a3fbe868ef0
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:13:29 2020 +0000
upstream: sshsig: return correct error, fix null-deref; ok djm
OpenBSD-Commit-ID: 1d1af7cd538b8b23e621cf7ab84f11e7a923edcd
commit 6fb6f186cb62a6370fba476b6a03478a1e95c30d
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:12:55 2020 +0000
upstream: vasnmprintf allocates str and returns -1; ok djm
OpenBSD-Commit-ID: dae4c9e83d88471bf3b3f89e3da7a107b44df11c
commit 714e1cbca17daa13f4f98978cf9e0695d4b2e0a4
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Mar 6 18:11:10 2020 +0000
upstream: sshpkt_fatal() does not return; ok djm
OpenBSD-Commit-ID: 7dfe847e28bd78208eb227b37f29f4a2a0929929
commit 9b47bd7b09d191991ad9e0506bb66b74bbc93d34
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Feb 28 01:07:28 2020 +0000
upstream: no-touch-required certificate option should be an
extension, not a critical option.
OpenBSD-Commit-ID: 626b22c5feb7be8a645e4b9a9bef89893b88600d
commit dd992520bed35387fc010239abe1bdc0c2665e38
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Feb 28 01:06:05 2020 +0000
upstream: better error message when trying to use a FIDO key
function and SecurityKeyProvider is empty
OpenBSD-Commit-ID: e56602c2ee8c82f835d30e4dc8ee2e4a7896be24
commit b81e66dbe0345aef4717911abcb4f589fff33a0a
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Feb 27 02:32:37 2020 +0000
upstream: Drop leading space from line count that was confusing
ssh-keygen's screen mode.
OpenBSD-Commit-ID: 3bcae7a754db3fc5ad3cab63dd46774edb35b8ae
commit d5ba1c03278eb079438bb038266d80d7477d49cb
Author: jsg@openbsd.org <jsg@openbsd.org>
Date: Wed Feb 26 13:40:09 2020 +0000
upstream: change explicit_bzero();free() to freezero()
While freezero() returns early if the pointer is NULL the tests for
NULL in callers are left to avoid warnings about passing an
uninitialised size argument across a function boundry.
ok deraadt@ djm@
OpenBSD-Commit-ID: 2660fa334fcc7cd05ec74dd99cb036f9ade6384a
commit 9e3220b585c5be19a7431ea4ff8884c137b3a81c
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Feb 26 11:46:51 2020 +0000
upstream: Have sftp reject "-1" in the same way as ssh(1) and
scp(1) do instead of accepting and silently ignoring it since protocol 1
support has been removed. Spotted by shivakumar2696 at gmail.com, ok
deraadt@
OpenBSD-Commit-ID: b79f95559a1c993214f4ec9ae3c34caa87e9d5de
commit ade8e67bb0f07b12e5e47e7baeafbdc898de639f
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Feb 26 01:31:47 2020 +0000
upstream: Remove obsolete XXX comment. ok deraadt@
OpenBSD-Commit-ID: bc462cc843947feea26a2e21c750b3a7469ff01b
commit 7eb903f51eba051d7f65790bab92a28970ac1ccc
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Feb 24 04:27:58 2020 +0000
upstream: Fix typo. Patch from itoama at live.jp via github PR#173.
OpenBSD-Commit-ID: 5cdaafab38bbdea0d07e24777d00bfe6f972568a
commit b2491c289dd1b557a18a2aca04eeff5c157fc5ef
Author: Nico Kadel-Garcia <nkadel@gmail.com>
Date: Sat Oct 12 17:51:01 2019 -0400
Switch %define to %global for redhat/openssh.spec
commit b18dcf6cca7c7aba1cc22e668e04492090ef0255
Author: mkontani <itoama@live.jp>
Date: Fri Feb 21 00:54:49 2020 +0900
fix some typos and sentence
commit 0001576a096f788d40c2c0a39121cff51bf961ad
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Feb 21 00:04:43 2020 +0000
upstream: Fix some typos and an incorrect word in docs. Patch from
itoama at live.jp via github PR#172.
OpenBSD-Commit-ID: 166ee8f93a7201fef431b9001725ab8b269d5874
commit 99ff8fefe4b2763a53778d06b5f74443c8701615
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Feb 20 05:58:08 2020 +0000
upstream: Update moduli generation script to new ssh-keygen
generation and screening command line flags.
OpenBSD-Commit-ID: 5010ff08f7ad92082e87dde098b20f5c24921a8f
commit 700d16f5e534d6de5a3b7105a74a7a6f4487b681
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Feb 20 05:41:51 2020 +0000
upstream: Import regenerated moduli.
OpenBSD-Commit-ID: 7b7b619c1452a459310b0cf4391c5757c6bdbc0f
commit 4753b74ba0f09e4aacdaab5e184cd540352004d5
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Feb 20 16:42:50 2020 +1100
Import regenerated moduli.
commit 11d427162778c18fa42917893a75d178679a2389
Author: HARUYAMA Seigo <haruyama@unixuser.org>
Date: Fri Feb 14 16:14:23 2020 +0900
Fix typos in INSTALL: s/avilable/available/ s/suppports/supports/
commit 264a966216137c9f4f8220fd9142242d784ba059
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Feb 18 08:58:33 2020 +0000
upstream: Ensure that the key lifetime provided fits within the
values allowed by the wire format (u32). Prevents integer wraparound of the
timeout values. bz#3119, ok markus@ djm@
OpenBSD-Commit-ID: 8afe6038b5cdfcf63360788f012a7ad81acc46a2
commit de1f3564cd85915b3002859873a37cb8d31ac9ce
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Feb 18 08:49:49 2020 +0000
upstream: Detect and prevent simple configuration loops when using
ProxyJump. bz#3057, ok djm@
OpenBSD-Commit-ID: 077d21c564c886c98309d871ed6f8ef267b9f037
commit 30144865bfa06b12239cfabc37c45e5ddc369d97
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Sun Feb 16 21:15:43 2020 +0000
upstream: document -F none; with jmc@
OpenBSD-Commit-ID: 0eb93b75473d2267aae9200e02588e57778c84f2
commit 011052de73f3dbc53f50927ccf677266a9ade4f6
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Feb 17 22:55:51 2020 +1100
Remove unused variable warning.
commit 31c9348c5e4e94e9913ec64b3ca6e15f68ba19e5
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Feb 17 22:53:24 2020 +1100
Constify aix_krb5_get_principal_name.
Prevents warning about discarding type qualifiers on AIX.
commit 290c994336a2cfe03c5496bebb6580863f94b232
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Feb 17 22:51:36 2020 +1100
Check if TILDE is already defined and undef.
Prevents redefinition warning on AIX.
commit 41a2e64ae480eda73ee0e809bbe743d203890938
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Feb 17 22:51:00 2020 +1100
Prevent unused variable warning.
commit d4860ec4efd25ba194337082736797fce0bda016
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Feb 17 22:48:50 2020 +1100
Check if getpeereid is actually declared.
Check in sys/socket.h (AIX) and unistd.h (FreeBSD, DragonFLy and OS X).
Prevents undeclared function warning on at least some versions of AIX.
commit 8aa3455b16fddea4c0144a7c4a1edb10ec67dcc8
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Feb 14 00:39:20 2020 +0000
upstream: openssh-8.2
OpenBSD-Commit-ID: 0a1340ff65fad0d84b997ac58dd1b393dec7c19b
commit 72f0ce33f0d5a37f31bad5800d1eb2fbdb732de6
Author: Damien Miller <djm@mindrot.org>
Date: Wed Feb 12 09:28:35 2020 +1100
crank version numbers
commit b763ed05bd1f1f15ae1727c86a4498546bc36ca8
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Feb 11 12:51:24 2020 +1100
Minor documentation update:
- remove duplication of dependency information (it's all in INSTALL).
- SSHFP is now an RFC.
commit 14ccfdb7248e33b1dc8bbac1425ace4598e094cb
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sun Feb 9 11:23:35 2020 +1100
Check if UINT32_MAX is defined before redefining.
commit be075110c735a451fd9d79a864e01e2e0d9f19d2
Author: Damien Miller <djm@mindrot.org>
Date: Fri Feb 7 15:07:27 2020 +1100
typo; reported by Phil Pennock
commit 963d71851e727ffdd2a97fe0898fad61d4a70ba1
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Feb 7 03:57:31 2020 +0000
upstream: sync the description of the $SSH_SK_PROVIDER environment
variable with that of the SecurityKeyProvider ssh/sshd_config(5) directive,
as the latter was more descriptive.
OpenBSD-Commit-ID: 0488f09530524a7e53afca6b6e1780598022552f
commit d4d9e1d40514e2746f9e05335d646512ea1020c6
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Feb 7 03:54:44 2020 +0000
upstream: Add ssh -Q key-sig for all key and signature types.
Teach ssh -Q to accept ssh_config(5) and sshd_config(5) algorithm keywords as
an alias for the corresponding query. Man page help jmc@, ok djm@.
OpenBSD-Commit-ID: 1e110aee3db2fc4bc5bee2d893b7128fd622e0f8
commit fd68dc27864b099b552a6d9d507ca4b83afd6a76
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Feb 7 03:27:54 2020 +0000
upstream: fix two PIN entry bugs on FIDO keygen: 1) it would allow more
than the intended number of prompts (3) and 2) it would SEGV too many
incorrect PINs were entered; based on patch by Gabriel Kihlman
OpenBSD-Commit-ID: 9c0011f28ba8bd8adf2014424b64960333da1718
commit 96bd895a0a0b3a36f81c14db8c91513578fc5563
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Feb 6 22:48:23 2020 +0000
upstream: When using HostkeyAlgorithms to merely append or remove
algorithms from the default set (i.e. HostkeyAlgorithms=+/-...), retain the
default behaviour of preferring those algorithms that have existing keys in
known_hosts; ok markus
OpenBSD-Commit-ID: 040e7fcc38ea00146b5d224ce31ce7a1795ee6ed
commit c7288486731734a864b58d024b1395029b55bbc5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Feb 6 22:46:31 2020 +0000
upstream: expand HostkeyAlgorithms prior to config dump, matching
other algorithm lists; ok markus@
OpenBSD-Commit-ID: a66f0fca8cc5ce30405a2867bc115fff600671d0
commit a6ac5d36efc072b15690c65039754f8e44247bdf
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Thu Feb 6 22:34:58 2020 +0000
upstream: Add Include to the list of permitted keywords after a
Match keyword. ok markus@
OpenBSD-Commit-ID: 342e940538b13dd41e0fa167dc9ab192b9f6e2eb
commit a47f6a6c0e06628eed0c2a08dc31a8923bcc37ba
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Thu Feb 6 22:30:54 2020 +0000
upstream: Replace "security key" with "authenticator" in program
messages.
This replaces "security key" in error/usage/verbose messages and
distinguishes between "authenticator" and "authenticator-hosted key".
ok djm@
OpenBSD-Commit-ID: 7c63800e9c340c59440a054cde9790a78f18592e
commit 849a9b87144f8a5b1771de6c85e44bfeb86be9a9
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Feb 6 11:28:14 2020 +1100
Don't look for UINT32_MAX in inttypes.h
... unless we are actually going to use it. Fixes build on HP-UX
without the potential impact to other platforms of a header change
shortly before release.
commit a2437f8ed0c3be54ddd21630a93c68ebd168286f
Author: Damien Miller <djm@mindrot.org>
Date: Thu Feb 6 12:02:22 2020 +1100
depend
commit 9716e8c4956acdd7b223d1642bfa376e07e7503d
Author: Michael Forney <mforney@mforney.org>
Date: Wed Nov 27 19:17:26 2019 -0800
Fix sha2 MAKE_CLONE no-op definition
The point of the dummy declaration is so that MAKE_CLONE(...) can have
a trailing semicolon without introducing an empty declaration. So,
the macro replacement text should *not* have a trailing semicolon,
just like DEF_WEAK.
commit d596b1d30dc158915a3979fa409d21ff2465b6ee
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Feb 4 09:58:04 2020 +0000
upstream: require FIDO application strings to start with "ssh:"; ok
markus@
OpenBSD-Commit-ID: 94e9c1c066d42b76f035a3d58250a32b14000afb
commit 501f3582438cb2cb1cb92be0f17be490ae96fb23
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Feb 3 23:47:57 2020 +0000
upstream: revert enabling UpdateHostKeys by default - there are still
corner cases we need to address; ok markus
OpenBSD-Commit-ID: ff7ad941bfdc49fb1d8baa95fd0717a61adcad57
commit 072f3b832d2a4db8d9880effcb6c4d0dad676504
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Mon Feb 3 08:15:37 2020 +0000
upstream: use better markup for challenge and write-attestation, and
rejig the challenge text a little;
ok djm
OpenBSD-Commit-ID: 9f351e6da9edfdc907d5c3fdaf2e9ff3ab0a7a6f
commit 262eb05a22cb1fabc3bc1746c220566490b80229
Author: Damien Miller <djm@mindrot.org>
Date: Mon Feb 3 21:22:15 2020 +1100
mention libfido2 in dependencies section
commit ccd3b247d59d3bde16c3bef0ea888213fbd6da86
Author: Damien Miller <djm@mindrot.org>
Date: Mon Feb 3 19:40:12 2020 +1100
add clock_gettime64(2) to sandbox allowed syscalls
bz3093
commit adffbe1c645ad2887ba0b6d24c194aa7a40c5735
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sun Feb 2 09:45:34 2020 +0000
upstream: Output (none) in debug in the case in the CheckHostIP=no case
as suggested by markus@
OpenBSD-Commit-ID: 4ab9117ee5261cbbd1868717fcc3142eea6385cf
commit 58c819096a2167983e55ae686486ce317b69b2d1
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sun Feb 2 09:22:22 2020 +0000
upstream: Prevent possible null pointer deref of ip_str in debug.
OpenBSD-Commit-ID: 37b252e2e6f690efed6682437ef75734dbc8addf
commit 0facae7bc8d3f8f9d02d0f6bed3d163ff7f39806
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Sun Feb 2 07:36:50 2020 +0000
upstream: shuffle the challenge keyword to keep the -O list sorted;
OpenBSD-Commit-ID: 08efad608b790949a9a048d65578fae9ed5845fe
commit 6fb3dd0ccda1c26b06223b87bcd1cab9ec8ec3cc
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Sat Feb 1 06:53:12 2020 +0000
upstream: tweak previous;
OpenBSD-Commit-ID: 0c42851cdc88583402b4ab2b110a6348563626d3
commit 92725d4d3fde675acc0ca040b48f3d0c7be73b7f
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Feb 1 17:25:09 2020 +1100
Use sys-queue.h from compat library.
Fixes build on platforms that don't have sys/queue.h (eg MUSL).
commit 677d0ece67634262b3b96c3cd6410b19f3a603b7
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 31 23:25:08 2020 +0000
upstream: regress test for sshd_config Include directive; from Jakub
Jelen
OpenBSD-Regress-ID: 0d9224de3297c7a5f51ba68d6e3725a2a9345fa4
commit d4f4cdd681ab6408a98419f398b75a55497ed324
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 31 23:13:04 2020 +0000
upstream: whitespace
OpenBSD-Commit-ID: 564cf7a5407ecf5da2d94ec15474e07427986772
commit 245399dfb3ecebc6abfc2ef4ee2e650fa9f6942b
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 31 23:11:25 2020 +0000
upstream: force early logging to stderr if debug_flag (-d) is set;
avoids missing messages from re-exec config passing
OpenBSD-Commit-ID: 02484b8241c1f49010e7a543a7098e6910a8c9ff
commit 7365f28a66d1c443723fbe6f4a2612ea6002901e
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 31 23:08:08 2020 +0000
upstream: mistake in previous: filling the incorrect buffer
OpenBSD-Commit-ID: 862ee84bd4b97b529f64aec5d800c3dcde952e3a
commit c2bd7f74b0e0f3a3ee9d19ac549e6ba89013abaf
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 31 22:42:45 2020 +0000
upstream: Add a sshd_config "Include" directive to allow inclusion
of files. This has sensible semantics wrt Match blocks and accepts glob(3)
patterns to specify the included files. Based on patch by Jakub Jelen in
bz2468; feedback and ok markus@
OpenBSD-Commit-ID: 36ed0e845b872e33f03355b936a4fff02d5794ff
commit ba261a1dd33266168ead4f8f40446dcece4d1600
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Fri Jan 31 22:25:59 2020 +0000
upstream: spelling fix;
OpenBSD-Commit-ID: 3c079523c4b161725a4b15dd06348186da912402
commit 771891a044f763be0711493eca14b6b0082e030f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jan 30 22:25:34 2020 +0000
upstream: document changed default for UpdateHostKeys
OpenBSD-Commit-ID: 25c390b21d142f78ac0106241d13441c4265fd2c
commit d53a518536c552672c00e8892e2aea28f664148c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jan 30 22:19:32 2020 +0000
upstream: enable UpdateKnownHosts=yes if the configuration
specifies only the default known_hosts files, otherwise select
UpdateKnownHosts=ask; ok markus@
OpenBSD-Commit-ID: ab401a5ec4a33d2e1a9449eae6202e4b6d427df7
commit bb63ff844e818d188da4fed3c016e0a4eecbbf25
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Jan 30 18:54:42 2020 +1100
Look in inttypes.h for UINT32_MAX.
Should prevent warnings on at least some AIX versions.
commit afeb6a960da23f0a5cbc4b80cca107c7504e932a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jan 30 07:21:38 2020 +0000
upstream: use sshpkt_fatal() instead of plain fatal() for
ssh_packet_write_poll() failures here too as the former yields better error
messages; ok dtucker@
OpenBSD-Commit-ID: 1f7a6ca95bc2b716c2e948fc1370753be772d8e3
commit 65d6fd0a8a6f31c3ddf0c1192429a176575cf701
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jan 30 07:20:57 2020 +0000
upstream: check the return value of ssh_packet_write_poll() and
call sshpkt_fatal() if it fails; avoid potential busy-loop under some
circumstances. Based on patch by Mike Frysinger; ok dtucker@
OpenBSD-Commit-ID: c79fe5cf4f0cd8074cb6db257c1394d5139408ec
commit dce74eab0c0f9010dc84c62500a17771d0131ff3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jan 30 07:20:05 2020 +0000
upstream: have sshpkt_fatal() save/restore errno before we
potentially call strerror() (via ssh_err()); ok dtucker
OpenBSD-Commit-ID: 5590df31d21405498c848245b85c24acb84ad787
commit 14ef4efe2bf4180e085ea6738fdbebc199458b0c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Jan 29 08:17:49 2020 +0000
upstream: markus suggests a simplification to previous
OpenBSD-Commit-ID: 10bbfb6607ebbb9a018dcd163f0964941adf58de
commit 101ebc3a8cfa78d2e615afffbef9861bbbabf1ff
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Jan 29 07:51:30 2020 +0000
upstream: give more context to UpdateHostKeys messages, mentioning
that the changes are validated by the existing trusted host key. Prompted by
espie@ feedback and ok markus@
OpenBSD-Commit-ID: b3d95f4a45f2692f4143b9e77bb241184dbb8dc5
commit 24c0f752adf9021277a7b0a84931bb5fe48ea379
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jan 28 08:01:34 2020 +0000
upstream: changes to support FIDO attestation
Allow writing to disk the attestation certificate that is generated by
the FIDO token at key enrollment time. These certificates may be used
by an out-of-band workflow to prove that a particular key is held in
trustworthy hardware.
Allow passing in a challenge that will be sent to the card during
key enrollment. These are needed to build an attestation workflow
that resists replay attacks.
ok markus@
OpenBSD-Commit-ID: 457dc3c3d689ba39eed328f0817ed9b91a5f78f6
commit 156bef36f93a48212383235bb8e3d71eaf2b2777
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jan 28 07:24:15 2020 +0000
upstream: disable UpdateHostKeys=ask when in quiet mode; "work for
me" matthieu@
OpenBSD-Commit-ID: 60d7b5eb91accf935ed9852650a826d86db2ddc7
commit ec8a759b4045e54d6b38e690ffee4cbffc53c7b7
Author: Damien Miller <djm@mindrot.org>
Date: Tue Jan 28 12:57:25 2020 +1100
compat for missing IPTOS_DSCP_LE in system headers
commit 4594c7627680c4f41c2ad5fe412e55b7cc79b10c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jan 28 01:49:36 2020 +0000
upstream: make IPTOS_DSCP_LE available via IPQoS directive; bz2986,
based on patch by veegish AT cyberstorm.mu
OpenBSD-Commit-ID: 9902bf4fbb4ea51de2193ac2b1d965bc5d99c425
commit da22216b5db3613325aa7b639f40dc017e4c6f69
Author: markus@openbsd.org <markus@openbsd.org>
Date: Mon Jan 27 20:51:32 2020 +0000
upstream: disable UpdateHostKeys=ask if command is specified; ok
djm@ sthen@
OpenBSD-Commit-ID: e5bcc45eadb78896637d4143d289f1e42c2ef5d7
commit 1e1db0544fdd788e2e3fc21d972a7ccb7de6b4ae
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Jan 26 00:09:50 2020 +0000
upstream: unbreak unittests for recent API / source file changes
OpenBSD-Regress-ID: 075a899a01bbf7781d38bf0b33d8366faaf6d3c0
commit 0d1144769151edf65f74aee9a4c8545c37861695
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sun Jan 26 15:09:15 2020 +1100
Move definition of UINT32_MAX.
This allows us to always define it if needed not just if we also
define the type ourself.
commit f73ab8a811bc874c2fb403012aa8e4bfdcaf5ec7
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Jan 26 00:09:50 2020 +0000
upstream: unbreak unittests for recent API / source file changes
OpenBSD-Regress-ID: 075a899a01bbf7781d38bf0b33d8366faaf6d3c0
commit 0373f9eba2b63455dceedbd3ac3d5dca306789ff
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sun Jan 26 14:09:17 2020 +1100
Include signal.h to prevent redefintion of _NSIG.
commit 638a45b5c1e20a8539100ca44166caad8abf26f8
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sun Jan 26 13:40:51 2020 +1100
Wrap stdint.h in tests inside HAVE_STDINT_H.
commit 74dfc2c859c906eaab1f88a27fd883115ffb928f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Jan 26 00:14:45 2020 +0000
upstream: for UpdateHostKeys, don't report errors for unsupported
key types - just ignore them. spotted by and ok dtucker@
OpenBSD-Commit-ID: 91769e443f6197c983932fc8ae9d39948727d473
commit b59618246c332e251160be0f1e0e88a7d4e2b0ae
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Jan 26 00:13:20 2020 +0000
upstream: downgrade error() for missing subsequent known_hosts
files to debug() as it was intended to be; spotted by dtucker@
OpenBSD-Commit-ID: 18cfea382cb52f2da761be524e309cc3d5354ef9
commit 469df611f778eec5950d556aabfe1d4efc227915
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 23:33:27 2020 +0000
upstream: clarify that BatchMode applies to all interactive prompts
(e.g. host key confirmation) and not just password prompts.
OpenBSD-Commit-ID: 97b001883d89d3fb1620d2e6b747c14a26aa9818
commit de40876c4a5d7c519d3d7253557572fdfc13db76
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 23:28:06 2020 +0000
upstream: tidy headers; some junk snuck into sshbuf-misc.c and
sshbuf-io.c doesn't need SSHBUF_INTERNAL set
OpenBSD-Commit-ID: 27a724d2e0b2619c1a1490f44093bbd73580d9e6
commit 6a107606355fa9547884cad6740e6144a7a7955b
Author: Damien Miller <djm@mindrot.org>
Date: Sun Jan 26 10:28:21 2020 +1100
depend
commit 59d01f1d720ebede4da42882f592d1093dac7adc
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 23:13:09 2020 +0000
upstream: improve the error message for u2f enrollment errors by
making ssh-keygen be solely responsible for printing the error message and
convertint some more common error responses from the middleware to a useful
ssherr.h status code. more detail remains visible via -v of course.
also remove indepedent copy of sk-api.h declarations in sk-usbhid.c
and just include it.
feedback & ok markus@
OpenBSD-Commit-ID: a4a8ffa870d9a3e0cfd76544bcdeef5c9fb1f1bb
commit 99aa8035554ddb976348d2a9253ab3653019728d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 23:02:13 2020 +0000
upstream: factor out reading/writing sshbufs to dedicated
functions; feedback and ok markus@
OpenBSD-Commit-ID: dc09e5f1950b7acc91b8fdf8015347782d2ecd3d
commit 065064fcf455778b0918f783033b374d4ba37a92
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 22:49:38 2020 +0000
upstream: add a comment describing the ranges of channel IDs that
we use; requested by markus@
OpenBSD-Commit-ID: 83a1f09810ffa3a96a55fbe32675b34ba739e56b
commit 69334996ae203c51c70bf01d414c918a44618f8e
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 22:41:01 2020 +0000
upstream: make sshd_config:ClientAliveCountMax=0 disable the
connection killing behaviour, rather than killing the connection after
sending the first liveness test probe (regardless of whether the client was
responsive) bz2627; ok markus
OpenBSD-Commit-ID: 5af79c35f4c9fa280643b6852f524bfcd9bccdaf
commit bf986a9e2792555e0879a3145fa18d2b49436c74
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 22:36:22 2020 +0000
upstream: clarify order of AllowUsers/DenyUsers vs
AllowGroups/DenyGroups; bz1690, ok markus@
OpenBSD-Commit-ID: 5637584ec30db9cf64822460f41b3e42c8f9facd
commit 022ce92fa0daa9d78830baeb2bd2dc3f83c724ba
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 07:17:18 2020 +0000
upstream: when AddKeysToAgent=yes is set and the key contains no
comment, add the key to the agent with the key's path as the comment. bz2564
OpenBSD-Commit-ID: 8dd8ca9340d7017631a27f4ed5358a4cfddec16f
commit 0b813436bbf6546638b10c1fa71f54691bcf5e63
Author: tedu@openbsd.org <tedu@openbsd.org>
Date: Sat Jan 25 07:09:14 2020 +0000
upstream: group14-sha1 is no longer a default algorithm
OpenBSD-Commit-ID: a96f04d5e9c2ff760c6799579dc44f69b4ff431d
commit 3432b6e05d5c583c91c566c5708fed487cec79ac
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 07:02:51 2020 +0000
upstream: reword HashKnownHosts description a little more; some
people found the wording confusing (bz#2560)
OpenBSD-Commit-ID: ac30896598694f07d498828690aecd424c496988
commit f80d7d6aa98d6eddc5df02412efee6db75673d4c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 07:01:00 2020 +0000
upstream: weaken the language for what HashKnownHosts provides with
regards to known_hosts name privacy, it's not practical for this option to
offer any guarantee that hostnames cannot be recovered from a disclosed
known_hosts file (e.g. by brute force).
OpenBSD-Commit-ID: 13f1e3285f8acf7244e9770074296bcf446c6972
commit 846446bf3e7421e6671a4afd074bdf15eecd7832
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 06:40:20 2020 +0000
upstream: the GatewayPorts vs -R listen address selection logic is
still confusing people, so add another comment explaining the special
handling of "localhost"; bz#3258
OpenBSD-Commit-ID: e6bf0f0fbf1c7092bf0dbd9c6eab105970b5b53a
commit 734f2f83f5ff86f2967a99d67be9ce22dd0394dd
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 06:03:10 2020 +0000
upstream: mention that permitopen=/PermitOpen do no name to address
translation; prompted by bz3099
OpenBSD-Commit-ID: 0dda8e54d566b29855e76bebf9cfecce573f5c23
commit e1e97cae19ff07b7a7f7e82556bc048c3c54af63
Author: Damien Miller <djm@mindrot.org>
Date: Sat Jan 25 16:30:22 2020 +1100
include tunnel device path in error message
commit 0ecd20bc9f0b9c7c697c9eb014613516c8f65834
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 04:48:26 2020 +0000
upstream: unrevert this:
> revision 1.217
> date: 2019/11/27 03:34:04; author: dtucker; state: Exp; lines: +5 -7; commitid: wkiMn49XJyjzoJIs;
> Make channel_id u_int32_t and remove unnecessary check and cast that were
> left over from the type conversion. Noted by t-hashida@amiya.co.jp in
> bz#3098, ok markus@ djm@
Darren was right the first time; ok dtucker@ "agreed" markus@
OpenBSD-Commit-ID: 641dd1b99a6bbd85b7160da462ae1be83432c7c8
commit a0c81d2402eedc514b9c9f25ef9604eb0576b86a
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sat Jan 25 02:57:53 2020 +0000
upstream: Move setting $NC into test-exec since it's now used by
multiple tests, and in -portable we use our own local copy to avoid
portability problems.
OpenBSD-Regress-ID: ceb78445fcaac317bec2fc51b3f0d9589048c114
commit e16dfa94f86358033531c4a97dcb51508ef84d49
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jan 25 13:05:42 2020 +1100
Put EC key export inside OPENSSL_HAS_ECC.
Fixes link error when building against an OpenSSL that does not have
ECC.
commit 94a2e5951b374e1a89761ceaff72e66eb1946807
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sat Jan 25 00:27:56 2020 +0000
upstream: Wait a bit longer for the multiplex master to become ready
since on very slow hosts the current delay is not sufficient and the test
will fail.
OpenBSD-Regress-ID: 6d90c7475d67ac3a95610b64af700629ece51a48
commit b2df804f571d77b07059f087b90955ffbc2f67d4
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jan 24 10:08:17 2020 +0000
upstream: Add a connection test for proxycommand. This would have
caught the problem caused by ssh.c rev 1.507 wherein Host and Hostname were
swapped. Prompted by beck@
OpenBSD-Regress-ID: d218500ae6aca4c479c27318fb5b09ebc00f7aae
commit c6f06fd38a257b9fcc7d6760f8fb6d505dccb628
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 00:22:31 2020 +0000
upstream: set UpdateKnownHosts=ask by default; bz#2894; ok
markus@
OpenBSD-Commit-ID: f09cb3177f3a14c96428e14f347e976a8a531fee
commit 7955633a554397bc24913cec9fd7285002935f7e
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 00:21:08 2020 +0000
upstream: allow UpdateKnownHosts=yes to function when multiple
known_hosts files are in use. When updating host keys, ssh will now search
subsequent known_hosts files, but will add new/changed host keys to the first
specified file only. bz#2738
ok markus@
OpenBSD-Commit-ID: 6ded6d878a03e57d5aa20bab9c31f92e929dbc6c
commit e5a278a62ab49dffe96929fa8d8506c6928dba90
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 00:06:48 2020 +0000
upstream: process security key provider via realpath() in agent,
avoids malicious client from being able to cause agent to load arbitrary
libraries into ssh-sk-helper.
reported by puck AT puckipedia.com; ok markus
OpenBSD-Commit-ID: 1086643df1b7eee4870825c687cf0c26a6145d1c
commit 89a8d4525e8edd9958ed3df60cf683551142eae0
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 25 00:03:36 2020 +0000
upstream: expose PKCS#11 key labels/X.509 subjects as comments
Extract the key label or X.509 subject string when PKCS#11 keys
are retrieved from the token and plumb this through to places where
it may be used as a comment.
based on https://github.com/openssh/openssh-portable/pull/138
by Danielle Church
feedback and ok markus@
OpenBSD-Commit-ID: cae1fda10d9e10971dea29520916e27cfec7ca35
commit a8c05c640873621681ab64d2e47a314592d5efa2
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 24 23:56:01 2020 +0000
upstream: tweak proctitle to include sshd arguments, as these are
frequently used to distinguish between multiple independent instances of the
server. New proctitle looks like this:
$ pgrep -lf sshd
12844 sshd: /usr/sbin/sshd -f /etc/ssh/sshd_config [listener] 0 of 10-100 startups
requested by sthen@ and aja@; ok aja@
OpenBSD-Commit-ID: cf235a561c655a3524a82003cf7244ecb48ccc1e
commit 8075fccbd4f70a4371acabcfb47562471ff0de6f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 24 23:54:40 2020 +0000
upstream: add xextendf() to extend a string with a format
(reallocating as necessary). ok aja@ as part of a larger diff
OpenBSD-Commit-ID: 30796b50d330b3e0e201747fe40cdf9aa70a77f9
commit d15c8adf2c6f1a6b4845131074383eb9c3d05c3d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 24 05:33:01 2020 +0000
upstream: minor tweaks to ssh-keygen -Y find-principals:
emit matched principals one per line to stdout rather than as comma-
separated and with a free-text preamble (easy confusion opportunity)
emit "not found" error to stderr
fix up argument testing for -Y operations and improve error message for
unsupported operations
OpenBSD-Commit-ID: 3d9c9a671ab07fc04a48f543edfa85eae77da69c
commit c3368a5d5ec368ef6bdf9971d6330ca0e3bdca06
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 24 00:28:57 2020 +0000
upstream: remove ssh-rsa (SHA1) from the list of allowed CA
signature algorithms ok markus
OpenBSD-Commit-ID: da3481fca8c81e6951f319a86b7be67502237f57
commit 4a41d245d6b13bd3882c8dc058dbd2e2b39a9f67
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 24 00:27:04 2020 +0000
upstream: when signing a certificate with an RSA key, default to
a safe signature algorithm (rsa-sha-512) if not is explicitly specified by
the user; ok markus@
OpenBSD-Commit-ID: e05f638f0be6c0266e1d3d799716b461011e83a9
commit 8dfb6a202c96cdf037c8ce05e53e32e0e0b7b454
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 24 00:00:31 2020 +0000
upstream: allow PEM export of DSA and ECDSA keys; bz3091, patch
from Jakub Jelen ok markus@
OpenBSD-Commit-ID: a58edec8b9f07acab4b962a71a5125830d321b51
commit 72a8bea2d748c8bd7f076a8b39a52082c79ae95f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jan 23 23:31:52 2020 +0000
upstream: ssh-keygen -Y find-principals fixes based on feedback
from Markus:
use "principals" instead of principal, as allowed_signers lines may list
multiple.
When the signing key is a certificate, emit only principals that match
the certificate principal list.
NB. the command -Y name changes: "find-principal" => "find-principals"
ok markus@
OpenBSD-Commit-ID: ab575946ff9a55624cd4e811bfd338bf3b1d0faf
commit 0585b5697201f5d8b32e6f1b0fee7e188268d30d
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jan 24 01:29:23 2020 +0000
upstream: Do not warn about permissions on symlinks.
OpenBSD-Regress-ID: 339d4cbae224bd8743ffad9c3afb0cf3cb66c357
commit 415192348a5737a960f6d1b292a17b64d55b542c
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Jan 23 11:19:12 2020 +0000
upstream: Handle zlib compression being disabled now that it's
optional.
OpenBSD-Regress-ID: 0af4fbc5168e62f89d0350de524bff1cb00e707a
commit fbce7c1a898ae75286349822950682cf46346121
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Jan 23 10:53:04 2020 +0000
upstream: Fix typo in comment.
OpenBSD-Commit-ID: d1d7a6553208bf439378fd1cf686a828aceb353a
commit ba247af8e9e302910e22881ef9d307a8afeef036
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Jan 23 10:19:59 2020 +0000
upstream: When checking for unsafe directories, ignore non-directories
(ie symlinks, where permissions are not relevant).
OpenBSD-Regress-ID: fb6cfc8b022becb62b2dcb99ed3f072b3326e501
commit 74deb7029be4c00810443114aac9308875a81dae
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Jan 23 22:17:24 2020 +1100
zlib is now optional.
commit 633a2af47ee90291aaf93969aeee1e5046074c7c
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Jan 23 22:16:51 2020 +1100
Plumb WITH_ZLIB into configure.
This allows zlib support to be disabled by ./configure --without-zlib.
commit 7f8e66fea8c4e2a910df9067cb7638999b7764d5
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Jan 23 10:24:29 2020 +0000
upstream: Make zlib optional. This adds a "ZLIB" build time option
that allows building without zlib compression and associated options. With
feedback from markus@, ok djm@
OpenBSD-Commit-ID: 44c6e1133a90fd15a3aa865bdedc53bab28b7910
commit 69ac4e33023b379e9a8e9b4b6aeeffa6d1fcf6fa
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jan 23 07:54:04 2020 +0000
upstream: remove trailing period characters from pub/priv key
pathnames - they make them needlessly more difficult to cut and paste without
error; ok markus@ & dtucker@
OpenBSD-Commit-ID: abdcfd1a5723fcac0711feee7665edc66ae2335a
commit 945bf52c3c815d95b1e842ebf6c910c3524bd5bb
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Jan 23 21:06:45 2020 +1100
Fix a couple of mysig_t leftovers.
commit 84226b447d45fe4542613de68c2ca59a890d7c01
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Jan 23 18:55:24 2020 +1100
Remove mysignal wrapper.
We switched the main code to use sigaction(), so the wrapper is no
longer used.
commit 5533c2fb7ef21172fa3708d66b03faa2c6b3d93f
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Thu Jan 23 07:16:38 2020 +0000
upstream: new sentence, new line;
OpenBSD-Commit-ID: b6c3f2f36ec77e99198619b38a9f146655281925
commit 3bf2a6ac791d64046a537335a0f1d5e43579c5ad
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Jan 23 07:10:22 2020 +0000
upstream: Replace all calls to signal(2) with a wrapper around
sigaction(2). This wrapper blocks all other signals during the handler
preventing races between handlers, and sets SA_RESTART which should reduce
the potential for short read/write operations.
OpenBSD-Commit-ID: 5e047663fd77a40d7b07bdabe68529df51fd2519
commit e027c044c796f3a01081a91bee55741204283f28
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jan 23 04:54:34 2020 +0000
upstream: missing header change from previous; spotted by dtucker@
OpenBSD-Commit-ID: 321ce74c0a5bbd0f02fa3f20cb5cf2a952c6b96f
commit 7e1323102b1b04eef391b01e180710a2d408a7ab
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Jan 23 03:42:41 2020 +0000
upstream: Check for and warn about StrictModes permission problems. ok tb@
OpenBSD-Regress-ID: 4841704ccdee50ee7efc6035bc686695c6ac2991
commit 84de1c27f845d15c859db44e7070a46f45504b66
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Jan 23 03:35:07 2020 +0000
upstream: Also test PuTTY chacha20.
OpenBSD-Regress-ID: 7af6a0e8763b05f1f8eee6bca5f31fcb16151040
commit c7ed15a39695ecd5f1f21842d8d9cd22246d4ee2
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Jan 23 03:24:38 2020 +0000
upstream: Also test PuTTY ecdh kex methods.
OpenBSD-Regress-ID: ec4017dce612131842398a03e93007a869c2c133
commit c4b3a128954ee1b7fbcbda167baf8aca1a3d1c84
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Jan 23 02:46:49 2020 +0000
upstream: Remove unsupported algorithms from list of defaults at run
time and remove ifdef and distinct settings for OPENSSL=no case.
This will make things much simpler for -portable where the exact set
of algos depends on the configuration of both OpenSSH and the libcrypto
it's linked against (if any). ok djm@
OpenBSD-Commit-ID: e0116d0183dcafc7a9c40ba5fe9127805c5dfdd2
commit 56cffcc09f8a2e661d2ba02e61364ae6f998b2b1
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jan 23 02:43:48 2020 +0000
upstream: add a new signature operations "find-principal" to look
up the principal associated with a signature from an allowed-signers file.
Work by Sebastian Kinne; ok dtucker@
OpenBSD-Commit-ID: 6f782cc7e18e38fcfafa62af53246a1dcfe74e5d
commit 65cf8730de6876a56595eef296e07a86c52534a6
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Jan 22 07:38:30 2020 +0000
upstream: Ignore whitespace when checking explict fingerprint.
When confirming a host key using the fingerprint itself, ignore leading and
trailing whitespace. ok deraadt@ djm@
OpenBSD-Commit-ID: cafd7f803bbdcd40c3a8f8f1a77747e6b6d8c011
commit 8d3af6ebdf524b34087a0a3ae415b5141ba10572
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Jan 22 07:31:27 2020 +0000
upstream: Increase keyscan timeout from default. On slow hosts 3
concurrent keyscans can hit the default 5 second timeout, so increase to 15
seconds.
OpenBSD-Regress-ID: 16383dec166af369b7fb9948572856f5d544c93f
commit 6c30c9adbeeed09a8a9e7a69974cfa1f1ddd1e9e
Author: tedu@openbsd.org <tedu@openbsd.org>
Date: Wed Jan 22 04:58:23 2020 +0000
upstream: remove diffie-hellman-group14-sha1 from default kex to
see what happens. general mostly ok
OpenBSD-Commit-ID: 216b7b8462d2ef5f4531f26cb2cb839b2153dad9
commit 4a32c0ca44a2dc2a358f69b5d43c08e528b44b39
Author: claudio@openbsd.org <claudio@openbsd.org>
Date: Wed Jan 22 04:51:51 2020 +0000
upstream: For ssh-keygen -lF only add a space after key fingerprint
when there is a comment. This makes copy-paste of fingerprints into ssh
easier. OK djm@
OpenBSD-Commit-ID: fa01d95624f65c1eb4dc7c575d20d77c78010dfd
commit 37d3b736506760e4ebc7fe56255f7b8ea823a00c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Jan 22 04:49:16 2020 +0000
upstream: some __func__ and strerror(errno) here; no functional
change
OpenBSD-Commit-ID: 6c3ddd5f848b99ea560b31d3fba99ceed66cef37
commit e2031b05c74c98b141179ceab13a323cf17d01e5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Jan 22 02:25:21 2020 +0000
upstream: factor out parsing of allowed-signers lines
OpenBSD-Commit-ID: 85ee6aeff608371826019ea85e55bfa87f79d06e
commit 47160e1de8c2f638f0ef41cef42c976417b61778
Author: Damien Miller <djm@mindrot.org>
Date: Wed Jan 22 10:30:13 2020 +1100
unbreak fuzzer support for recent ssh-sk.h changes
commit 70d38c3cfd4550e8ee66cc3bf1b91aa339c91df5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jan 21 22:39:57 2020 +0000
upstream: expose the number of currently-authenticating connections
along with the MaxStartups limit in the proctitle; suggestion from Philipp
Marek, w/ feedback from Craig Miskell ok dtucker@
OpenBSD-Commit-ID: a4a6db2dc1641a5df8eddf7d6652176e359dffb3
commit a78c66d5d2144bd49779bc80a647346bd3d7233d
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Tue Jan 21 12:40:04 2020 +0000
upstream: document the default value of the ControlPersist option;
ok dtucker@ djm@
OpenBSD-Commit-ID: 0788e7f2b5a9d4e36d3d2ab378f73329320fef66
commit b46a6325849e40aa2e4b0d962a6f00f708f6576a
Author: Damien Miller <djm@mindrot.org>
Date: Wed Jan 22 09:28:32 2020 +1100
remove accidental change in f8c11461
commit 80d3bebcab96fe1d177e45906e10db16895da01d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jan 21 11:06:09 2020 +0000
upstream: don't #ifdef out the KRL code when compiling without
libcrypto support; it works just fine and disabling it breaks a few tests. ok
dtucker@
OpenBSD-Commit-ID: 65f6272c4241eb4b04de78b012fe98b2b555ad44
commit f8c11461aa6db168fc5e7eeae448b4cbbf59642a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jan 21 08:06:27 2020 +0000
upstream: pass SSH_SK_HELPER explicitly past $SUDO to avoid it getting
cleared; with dtucker@
OpenBSD-Regress-ID: 03178a0580324bf0dff28f7eac6c3edbc5407f8e
commit b5fcb0ac1cc0ef01aeec1c089146298654ab3ae0
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jan 21 07:07:31 2020 +0000
upstream: check access(ssh-sk-helper, X_OK) to provide friendly
error message for misconfigured helper paths
OpenBSD-Commit-ID: 061bcc262155d12e726305c91394ac0aaf1f8341
commit 56bced43c14dc6fa2bfa1816007e441644105609
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Jan 21 06:09:56 2020 +0000
upstream: Document sntrup4591761x25519-sha512@tinyssh.org. Patch
from jtesta@positronsecurity.com via github PR#151.
OpenBSD-Commit-ID: f3d48168623045c258245c340a5a2af7dbb74edc
commit 4a05d789b86314fef7303824f69defbc6b96ed60
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jan 21 05:56:56 2020 +0000
upstream: fix ssh-keygen not displaying authenticator touch
prompt; reported by jmc@
OpenBSD-Commit-ID: 04d4f582fc194eb3897ebcbfe286c49958ba2859
commit 881aded0389d999375f926051491a944c6d8752b
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jan 21 05:56:27 2020 +0000
upstream: a little more verbosity in sign_and_send_pubkey() debug
messages
OpenBSD-Commit-ID: 6da47a0e6373f6683006f49bc2a516d197655508
commit b715fdc71bbd009d0caff691ab3fc04903c4aee8
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Sat Jan 18 21:16:43 2020 +0000
upstream: one more replacement "(security) key" -> "(FIDO)
authenticator"
OpenBSD-Commit-ID: 031bca03c1d1f878ab929facd561911f1bc68dfd
commit 84911da1beeb6ed258a43468efb316cd39fb6855
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Sat Jan 18 15:45:41 2020 +0000
upstream: undo merge error and replace the term "security key"
again
OpenBSD-Commit-ID: 341749062c089cc360a7877e9ee3a887aecde395
commit e8c06c4ee708720efec12cd1a6f78a3c6d76b7f0
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Fri Jan 17 20:13:47 2020 +0000
upstream: Document loading of resident keys from a FIDO
authenticator.
* Rename -O to -K to keep "-O option" available.
* Document -K.
* Trim usage() message down to synopsis, like all other commands.
ok markus@
OpenBSD-Commit-ID: 015c2c4b28f8e19107adc80351b44b23bca4c78a
commit 0d005d6372a067b59123dec8fc6dc905f2c09e1e
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Tue Jan 14 15:07:30 2020 +0000
upstream: sync ssh-keygen.1 and ssh-keygen's usage() with each
other and reality ok markus@
OpenBSD-Commit-ID: cdf64454f2c3604c25977c944e5b6262a3bcce92
commit b8a4ca2ebfddab862f7eb1ea2a07fb9f70330429
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Sat Jan 11 16:23:10 2020 +0000
upstream: revise the fix for reversed arguments on
expand_proxy_command()
Always put 'host' before 'host_arg' for consistency. ok markus@ djm@
OpenBSD-Commit-ID: 1ba5b25472779f1b1957295fcc6907bb961472a3
commit 57b181eaf2d34fd0a1b51ab30cb6983df784de5a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 10 23:43:26 2020 +0000
upstream: pass the log-on-stderr flag and log level through to
ssh-sk-helper, making debugging a bit easier. ok markus@
OpenBSD-Commit-ID: 2e7aea6bf5770d3f38b7c7bba891069256c5a49a
commit a8bd5fdbdb7581afc7123a042a7cd6ca25357388
Author: Damien Miller <djm@mindrot.org>
Date: Tue Jan 21 12:32:16 2020 +1100
Wrap copy_environment_blacklist() in #ifdef
It's only needed for USE_PAM or HAVE_CYGWIN cases and will cause compiler
warnings otherwise.
commit 10ecc647fc1db8d2dde9f6b9b826b201dfc48b62
Author: Damien Miller <djm@mindrot.org>
Date: Tue Jan 21 12:20:05 2020 +1100
depend
commit b3f7009c9ffa5891283ed96e043001e09934a8d4
Author: Ruben Kerkhof <ruben@rubenkerkhof.com>
Date: Mon Jan 20 11:56:48 2020 +0100
Fix missing prototype warning for copy_environment
This function is only used in this file, and only on Cygwin, so make
it static and hide it behind HAVE_CYGWIN. Prevents missing prototype
warning.
commit 0c428c0e991e2c4fabc48cf5d9b8f84c9412e0c3
Author: Ruben Kerkhof <ruben@rubenkerkhof.com>
Date: Mon Jan 20 13:58:11 2020 +0100
configure.ac: fix ldns test
When running ./configure --with-ldns, if ldns-config cannot be found, we
add -Iyes/include to CPPFLAGS and -Lyes/lib to LDFLAGS. Fix that.
commit 6089abf715e2784751c9f62697e09bb103295b93
Author: Ruben Kerkhof <ruben@rubenkerkhof.com>
Date: Mon Jan 20 12:13:26 2020 +0100
Make sshpam_password_change_required static.
sshpam_password_change_required is only used in auth-pam.c, so make it
static to prevent a mising prototype warning.
commit 5a9b9c82851b7bc219dc3a65962a80803c76c102
Author: Ruben Kerkhof <ruben@rubenkerkhof.com>
Date: Mon Jan 20 12:24:51 2020 +0100
sandbox-darwin.c: fix missing prototypes.
Include the right header just like the other sandbox files.
Fixes missing prototype warnings for ssh_sandbox_* functions.
commit 335dc93526942a650f6c69666b3f6ca44d0a2910
Author: Ruben Kerkhof <ruben@rubenkerkhof.com>
Date: Mon Jan 20 11:09:27 2020 +0100
Fix a few warnings when on Mac OS X.
Include stdlib.h for calloc, malloc, free and setenv.
commit 0488dc2d3050ea1a99ef5cf44afc50ffbf3f1315
Author: Ruben Kerkhof <ruben@rubenkerkhof.com>
Date: Mon Jan 20 10:32:23 2020 +0100
Fix building without openssl.
This fixes the following when there are no openssl headers on the system:
ssh-ecdsa-sk.c:34:10: fatal error: 'openssl/bn.h' file not found
commit e6b7157b4ef29c83ec3a2d1d7c927e4b8898f9bb
Author: Ruben Kerkhof <ruben@rubenkerkhof.com>
Date: Wed Jan 15 16:08:55 2020 +0100
Add config.log to .gitignore
commit 515e10ddf9644010b88cfd7ecf601f4306d42232
Author: Ruben Kerkhof <ruben@rubenkerkhof.com>
Date: Wed Jan 15 16:16:31 2020 +0100
Fix typo in README.md, s/crytpo/crypto/
commit 1af3354aea3c4bfa5b5ecfb5d1ff3ad231c2073c
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Jan 15 16:22:36 2020 +1100
Wrap stdint.h in ifdef HAVE_STDINT_H.
commit 429170f273ce1b0140f8111a45ba69390d98de3a
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jan 14 14:41:47 2020 +1100
Wrap stdint.h inside HAVE_STDINT_H.
commit a0989b60211b6f1c2313e1397c526d883a23a075
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jan 14 14:26:41 2020 +1100
Include compat header for definitions.
commit e0cedcad51fe02683943bf4f1ad2961aa3f35313
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jan 14 09:42:52 2020 +1100
Improve search for 'struct timespec'.
Make struct timespec test consistent with existing timeval test.
Include time.h for timespec in compat header where required.
commit acaf9e058594310001ce64468ed2923dc6323e81
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jan 14 12:43:03 2020 +1100
Update depend to remove rmd160.h.
commit 26b2675b0c3e3efea11a52609073aec01736ec84
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jan 14 07:24:46 2020 +1100
Remove configure test & compat code for ripemd160.
RIPEMD160 support was removed upstream in 2017, however we still had
a configure test and compat code for it, so clean those up now.
commit ed3ad71b17adcd1fb4431d145f53cee1c6a1135e
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jan 9 03:28:38 2020 +0000
upstream: fix reversed arguments on expand_proxy_command(); spotted
by anton@
OpenBSD-Commit-ID: db1c32478a01dfbc9c4db171de0f25907bea5775
commit cd53476383f0cf475f40ba8ac8deb6b76dd5ce4e
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Mon Jan 6 07:43:28 2020 +0000
upstream: put the fido options in a list, and tidy up the text a
little; ok djm
OpenBSD-Commit-ID: 491ce15ae52a88b7a6a2b3b6708a14b4aacdeebb
commit 30f704ebc0e9e32b3d12f5d9e8c1b705fdde2c89
Author: Jeremy Drake <github@jdrake.com>
Date: Fri Oct 11 18:31:05 2019 -0700
Deny (non-fatal) ipc in preauth privsep child.
As noted in openssh/openssh-portable#149, i386 does not have have
_NR_shmget etc. Instead, it has a single ipc syscall (see man 2 ipc,
https://linux.die.net/man/2/ipc). Add this syscall, if present, to the
list of syscalls that seccomp will deny non-fatally.
commit b110cefdfbf5a20f49b774a55062d6ded2fb6e22
Author: Khem Raj <raj.khem@gmail.com>
Date: Tue Jan 7 16:26:45 2020 -0800
seccomp: Allow clock_gettime64() in sandbox.
This helps sshd accept connections on mips platforms with
upcoming glibc ( 2.31 )
commit 3cc60c899a92a469e5118310ba6b74cb57215618
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Jan 6 02:39:30 2020 +0000
upstream: missing else in check_enroll_options()
OpenBSD-Commit-ID: e058fb918fda56ddbbf0bee910101004cec421d4
commit ff5784e2698d6c41e9f39ce4df24968c1beeb2bb
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Jan 6 02:24:28 2020 +0000
upstream: fix error message
OpenBSD-Commit-ID: 1eb52025658eb78ea6223181e552862198d3d505
commit dd2acc8b862c09751621995fba2d5fa6f4e24cc9
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Jan 6 02:07:50 2020 +0000
upstream: adapt sk-dummy to SK API changes
also, make it pull prototypes directly from sk-api.c and #error
if the expected version changes. This will make any future regress
test breakage because of SK API changes much more apparent
OpenBSD-Regress-ID: 79b07055de4feb988e31da71a89051ad5969829d
commit c312ca077cd2a6c15545cd6b4d34ee2f69289174
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Jan 6 02:00:46 2020 +0000
upstream: Extends the SK API to accept a set of key/value options
for all operations. These are intended to future-proof the API a little by
making it easier to specify additional fields for without having to change
the API version for each.
At present, only two options are defined: one to explicitly specify
the device for an operation (rather than accepting the middleware's
autoselection) and another to specify the FIDO2 username that may
be used when generating a resident key. These new options may be
invoked at key generation time via ssh-keygen -O
This also implements a suggestion from Markus to avoid "int" in favour
of uint32_t for the algorithm argument in the API, to make implementation
of ssh-sk-client/helper a little easier.
feedback, fixes and ok markus@
OpenBSD-Commit-ID: 973ce11704609022ab36abbdeb6bc23c8001eabc
commit 2ab335712d084d9ccaf3f53afc3fa9535329da87
Author: beck@openbsd.org <beck@openbsd.org>
Date: Sun Jan 5 16:28:22 2020 +0000
upstream: fix CanonicalizeHostname, broken by rev 1.507
Issue noticed and reported by Pierre-Olivier Martel <pom@apple.com>
ok dtucker@ markus@ djm@
OpenBSD-Commit-ID: 749f3168ec520609c35b0c4e1984e5fa47f16094
commit 69e44ba701b90b0f530d64c3fe4363ea86e50cd3
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Jan 6 09:02:53 2020 +1100
Fix typo: 'you' -> 'your'.
bz#3108 from jmckitrick@gmail.com.
commit 7652a57662969bd5c61448b3843ec6d407ad12be
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Jan 6 08:56:46 2020 +1100
Remove auth-skey.c.
S/Key support was removed in OpenSSH 7.8 but this file was missed.
commit c593cc5e826c9f4ec506e22b629d37cabfaacff9
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Fri Jan 3 07:33:33 2020 +0000
upstream: the download resident keys option is -K (upper) not -k
(lower); ok djm
OpenBSD-Commit-ID: 71dc28a3e1fa7c553844abc508845bcf5766e091
commit ff31f15773ee173502eec4d7861ec56f26bba381
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 3 03:02:26 2020 +0000
upstream: what bozo decided to use 2020 as a future date in a regress
test?
OpenBSD-Regress-ID: 3b953df5a7e14081ff6cf495d4e8d40e153cbc3a
commit 680eb7749a39d0e4d046e66cac4e51e8e3640b75
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jan 3 02:46:19 2020 +0000
upstream: implement recent SK API change to support resident keys
and PIN prompting in the dummy middleware that we use for the tests. Should
fix breakage spotted by dtucker@
OpenBSD-Regress-ID: 379cf9eabfea57aaf7f3f59dafde59889566c484
commit 86834fe6b54ac57b8528c30cf0b27e5cac5b7af7
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Jan 2 13:25:38 2020 +0000
upstream: Update keygen moduli screen test to match recent command
line option change to ssh-keygen(1).
OpenBSD-Regress-ID: 744a72755004377e9669b662c13c6aa9ead8a0c3
commit 9039971887cccd95b209c479296f772a3a93e8e7
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jan 2 22:40:09 2020 +0000
upstream: ability to download FIDO2 resident keys from a token via
"ssh-keygen -K". This will save public/private keys into the current
directory.
This is handy if you move a token between hosts.
feedback & ok markus@
OpenBSD-Commit-ID: d57c1f9802f7850f00a117a1d36682a6c6d10da6
commit 878ba4350d57e905d6bb1865d8ff31bdfe5deab4
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jan 2 22:38:33 2020 +0000
upstream: add sshkey_save_public(), to save a public key; ok
markus@
OpenBSD-Commit-ID: 5d6f96a966d10d7fa689ff9aa9e1d6767ad5a076
commit 3b1382ffd5e71eff78db8cef0f3cada22ff29409
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Mon Dec 30 16:10:00 2019 +0000
upstream: simplify the list for moduli options - no need for
-compact;
OpenBSD-Commit-ID: 6492c72280482c6d072be46236b365cb359fc280
commit 0248ec7c763dee9ff730a589e3d166eac5c74d7c
Author: Damien Miller <djm@mindrot.org>
Date: Thu Jan 2 13:41:31 2020 +1100
ssh-sk-null.cc needs extern "C" {}
commit 5ca4b414effe4b56f0cfe3058c92391aa8a43871
Author: Damien Miller <djm@mindrot.org>
Date: Thu Jan 2 10:56:29 2020 +1100
add dummy ssh-sk API for linking with fuzzers
commit c4b2664be7ba25e4c233315b25212dec29b727ab
Author: Damien Miller <djm@mindrot.org>
Date: Mon Dec 30 21:04:09 2019 +1100
refresh depend
commit 3093d12ff80927cf45da08d9f262a26680fb14ee
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 30 09:49:52 2019 +0000
upstream: Remove the -x option currently used for
FIDO/U2F-specific key flags. Instead these flags may be specified via -O.
ok markus@
OpenBSD-Commit-ID: f23ebde2a8a7e1bf860a51055a711cffb8c328c1
commit ef65e7dbaa8fac3245aa2bfc9f7e09be7cba0d9d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 30 09:25:29 2019 +0000
upstream: document SK API changes in PROTOCOL.u2f
ok markus@
OpenBSD-Commit-ID: 52622363c103a3c4d3d546050480ffe978a32186
commit 43ce96427b76c4918e39af654e2fc9ee18d5d478
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 30 09:24:45 2019 +0000
upstream: translate and return error codes; retry on bad PIN
Define some well-known error codes in the SK API and pass
them back via ssh-sk-helper.
Use the new "wrong PIN" error code to retry PIN prompting during
ssh-keygen of resident keys.
feedback and ok markus@
OpenBSD-Commit-ID: 9663c6a2bb7a0bc8deaccc6c30d9a2983b481620
commit d433596736a2cd4818f538be11fc94783f5c5236
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 30 09:24:03 2019 +0000
upstream: improve some error messages; ok markus@
OpenBSD-Commit-ID: 4ccd8ddabb8df4f995107dd3b7ea58220e93cb81
commit c54cd1892c3e7f268b21e1f07ada9f0d9816ffc0
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 30 09:23:28 2019 +0000
upstream: SK API and sk-helper error/PIN passing
Allow passing a PIN via the SK API (API major crank) and let the
ssh-sk-helper API follow.
Also enhance the ssh-sk-helper API to support passing back an error
code instead of a complete reply. Will be used to signal "wrong PIN",
etc.
feedback and ok markus@
OpenBSD-Commit-ID: a1bd6b0a2421646919a0c139b8183ad76d28fb71
commit 79fe22d9bc2868c5118f032ec1200ac9c2e3aaef
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 30 09:22:49 2019 +0000
upstream: implement loading resident keys in ssh-add
"ssh-add -O" will load resident keys from a FIDO2 token and add them
to a ssh-agent.
feedback and ok markus@
OpenBSD-Commit-ID: 608104ae957a7d65cb84e0a3a26c8f60e0df3290
commit 27753a8e21887d47fe6b5c78a4aed0efe558a850
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 30 09:21:59 2019 +0000
upstream: implement loading of resident keys in ssh-sk-helper
feedback and ok markus@
OpenBSD-Commit-ID: b273c23769ea182c55c4a7b8f9cbd9181722011a
commit 14cea36df397677b8f8568204300ef654114fd76
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 30 09:21:16 2019 +0000
upstream: resident keys support in SK API
Adds a sk_load_resident_keys() function to the security key
API that accepts a security key provider and a PIN and returns
a list of keys.
Implement support for this in the usbhid middleware.
feedback and ok markus@
OpenBSD-Commit-ID: 67e984e4e87f4999ce447a6178c4249a9174eff0
commit 2fe05fcb4a2695f190b4fcf27770b655586ab349
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 30 09:20:36 2019 +0000
upstream: Factor out parsing of struct sk_enroll_response
We'll reuse this for extracting resident keys from a device.
feedback and ok markus@
OpenBSD-Commit-ID: 9bc1efd9c6897eac4df0983746cf6578c1542273
commit 4532bd01d57ee13c3ca881eceac1bf9da96a4d7e
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 30 09:19:52 2019 +0000
upstream: basic support for generating FIDO2 resident keys
"ssh-keygen -t ecdsa-sk|ed25519-sk -x resident" will generate a
device-resident key.
feedback and ok markus@
OpenBSD-Commit-ID: 8e1b3c56a4b11d85047bd6c6c705b7eef4d58431
commit 3e60d18fba1b502c21d64fc7e81d80bcd08a2092
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 30 03:30:09 2019 +0000
upstream: remove single-letter flags for moduli options
Move all moduli generation options to live under the -O flag.
Frees up seven single-letter flags.
NB. this change break existing ssh-keygen commandline syntax for moduli-
related operations. Very few people use these fortunately.
feedback and ok markus@
OpenBSD-Commit-ID: d498f3eaf28128484826a4fcb343612764927935
commit 1e645fe767f27725dc7fd7864526de34683f7daf
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 30 03:28:41 2019 +0000
upstream: prepare for use of ssh-keygen -O flag beyond certs
Move list of available certificate options in ssh-keygen.1 to the
CERTIFICATES section.
Collect options specified by -O but delay parsing/validation of
certificate options until we're sure that we're acting as a CA.
ok markus@
OpenBSD-Commit-ID: 33e6bcc29cfca43606f6fa09bd84b955ee3a4106
commit 20ccd854245c598e2b47cc9f8d4955d645195055
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Fri Dec 27 08:28:44 2019 +0000
upstream: sort -Y internally in the options list, as is already
done in synopsis;
OpenBSD-Commit-ID: 86d033c5764404057616690d7be992e445b42274
commit 5b6c954751dd3677466cda7adb92e4f05446c96c
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Fri Dec 27 08:25:07 2019 +0000
upstream: in the options list, sort -Y and -y;
OpenBSD-Commit-ID: 24c2e6a3aeab6e050a0271ffc73fdff91c10dcaa
commit 141df487ba699cfd1ec3dcd98186e7c956e99024
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Sat Dec 21 20:22:34 2019 +0000
upstream: Replace the term "security key" with "(FIDO)
authenticator".
The polysemous use of "key" was too confusing. Input from markus@.
ok jmc@
OpenBSD-Commit-ID: 12eea973a44c8232af89f86e4269d71ae900ca8f
commit fbd9729d4eadf2f7097b6017156387ac64302453
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Dec 21 02:33:07 2019 +0000
upstream: unit tests for ForwardAgent=/path; from Eric Chiang
OpenBSD-Regress-ID: 24f693f78290b2c17725dab2c614dffe4a88c8da
commit e5b7cf8edca7e843adc125621e1dab14507f430a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 16 02:39:05 2019 +0000
upstream: test security key host keys in addition to user keys
OpenBSD-Regress-ID: 9fb45326106669a27e4bf150575c321806e275b1
commit 40be78f503277bd91c958fa25ea9ef918a2ffd3d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Dec 21 02:19:13 2019 +0000
upstream: Allow forwarding a different agent socket to the path
specified by $SSH_AUTH_SOCK, by extending the existing ForwardAgent option to
accepting an explicit path or the name of an environment variable in addition
to yes/no.
Patch by Eric Chiang, manpage by me; ok markus@
OpenBSD-Commit-ID: 98f2ed80bf34ea54d8b2ddd19ac14ebbf40e9265
commit 416f15372bfb5be1709a0ad1d00ef5d8ebfb9e0e
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Fri Dec 20 20:28:55 2019 +0000
upstream: SSH U2F keys can now be used as host keys. Fix a garden
path sentence. ok markus@
OpenBSD-Commit-ID: 67d7971ca1a020acd6c151426c54bd29d784bd6b
commit 68010acbcfe36167b3eece3115f3a502535f80df
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Dec 20 02:42:42 2019 +0000
upstream: Move always unsupported keywords to be grouped with the other
ones. Move oSecurityProvider to match the order in the OpCodes enum. Patch
from openbsd@academicsolutions.ch, ok djm@
OpenBSD-Commit-ID: 061e4505861ec1e02ba3a63e3d1b3be3cad458ec
commit 8784b02dc49e1c98df4e7aca466be2f652ed4ad1
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Dec 20 02:29:21 2019 +0000
upstream: Remove obsolete opcodes from the configuation enum.
Patch from openbsd@academicsolutions.ch, ok djm@
OpenBSD-Commit-ID: 395c202228872ce8d9044cc08552ac969f51e01b
commit 345be6091bdc9be09c90a937d1320f97c01fab2a
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Dec 20 02:11:38 2019 +0000
upstream: Remove now-obsolete config options from example in
comment. Patch from openbsd@academicsolutions.ch, ok djm@
OpenBSD-Commit-ID: 35862beb0927b1cb0af476ec23cc07f6e3006101
commit ae024b22c4fd68e7f39681d605585889f9511108
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Thu Dec 19 15:09:30 2019 +0000
upstream: Document that security key-hosted keys can act as host
keys.
Update the list of default host key algorithms in ssh_config.5 and
sshd_config.5. Copy the description of the SecurityKeyProvider
option to sshd_config.5.
ok jmc@
OpenBSD-Commit-ID: edadf3566ab5e94582df4377fee3b8b702c7eca0
commit bc2dc091e0ac4ff6245c43a61ebe12c7e9ea0b7f
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Dec 19 03:50:01 2019 +0000
upstream: "Forward security" -> "Forward secrecy" since that's the
correct term. Add "MAC" since we use that acronym in other man pages. ok
naddy@
OpenBSD-Commit-ID: c35529e511788586725fb63bda3459e10738c5f5
commit e905f7260d72bc0e33ef5f10a0db737ff6e77ba7
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Tue Dec 17 16:21:07 2019 +0000
upstream: cut obsolete lists of crypto algorithms from outline of
how SSH works ok markus@ jmc@
OpenBSD-Commit-ID: 8e34973f232ab48c4d4f5d07df48d501708b9160
commit f65cf1163ff01531ae02f3f9210391d0d692f699
Author: tobhe@openbsd.org <tobhe@openbsd.org>
Date: Mon Dec 16 13:58:53 2019 +0000
upstream: strdup may return NULL if memory allocation fails. Use
the safer xstrdup which fatals on allocation failures.
ok markus@
OpenBSD-Commit-ID: 8b608d387120630753cbcb8110e0b019c0c9a0d0
commit 57634bfc5708477826c0be265ddc59b9d83e4886
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Dec 16 03:16:58 2019 +0000
upstream: sort sk-* methods behind their plain key methods cousins
for now
OpenBSD-Commit-ID: c97e22c2b28c0d12ee389b8b4ef5f2ada7908828
commit b8df8fe920e697edcc69c520390b78c3b7ad9d84
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Dec 17 19:46:15 2019 +1100
Mac OS X has PAM too.
commit bf8de8b8251af69b5ce96a8faa69145af156af4d
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Dec 17 19:37:06 2019 +1100
Show portable tarball pattern in example.
commit a19ef613e98141cc37c8acdeebe285b9dbe2531e
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Dec 17 19:35:59 2019 +1100
OpenSSL is now optional.
commit 1a7217ac063e48cf0082895aeee81ed2b8a57191
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Dec 15 18:58:33 2019 +0000
upstream: adapt to ssh-sk-client change
OpenBSD-Regress-ID: 40481999a5928d635ab2e5b029e8239c112005ea
commit a7fc1df246e80bfdabd09b069b91c72f9c578ca8
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Dec 11 18:47:14 2019 +0000
upstream: it's no longer possible to disable privilege separation
in sshd, so don't double the tests' work by trying both off/on
OpenBSD-Regress-ID: d366665466dbd09e9b707305da884be3e7619c68
commit 3145d38ea06820a66c0f5e068f49af14fd2b7ac1
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Dec 15 20:59:23 2019 +0000
upstream: don't treat HostKeyAgent=none as a path either; avoids
spurious warnings from the cfgparse regress test
OpenBSD-Commit-ID: ba49ea7a5c92b8a16cb9c2e975dbb163853afc54
commit 747e25192f436e71dd39e15d65aa32bca967533a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Dec 15 20:57:15 2019 +0000
upstream: do not attempt to find an absolute path for sshd_config
SecurityKeyProvider=internal - unbreaks cfgparse regress test
OpenBSD-Commit-ID: d2ddcf525c0dc3c8339522360c10b3c70f1fd641
commit 9b6e30b96b094ad787511a5b989253e3b8fe1789
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Dec 15 19:47:10 2019 +0000
upstream: allow ssh-keyscan to find security key hostkeys
OpenBSD-Commit-ID: 1fe822a7f714df19a7e7184e3a3bbfbf546811d3
commit 56584cce75f3d20aaa30befc7cbd331d922927f3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Dec 15 18:57:30 2019 +0000
upstream: allow security keys to act as host keys as well as user
keys.
Previously we didn't do this because we didn't want to expose
the attack surface presented by USB and FIDO protocol handling,
but now that this is insulated behind ssh-sk-helper there is
less risk.
ok markus@
OpenBSD-Commit-ID: 77b068dd133b8d87e0f010987bd5131e640ee64c
commit 5af6fd5461bb709304e6979c8b7856c7af921c9e
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Dec 16 13:55:56 2019 +1100
Allow clock_nanosleep_time64 in seccomp sandbox.
Needed on Linux ARM. bz#3100, patch from jjelen@redhat.com.
commit fff8ff6dd580e1a72ba09a6775d185175cdc8d13
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sun Dec 15 18:27:02 2019 +1100
Put SK ECDSA bits inside ifdef OPENSSL_HAS_ECC.
Fixes build when linking against OpenSSLs built with no-ec.
commit 9244990ecdcfa36bb9371058111685b05f201c1e
Author: Damien Miller <djm@mindrot.org>
Date: Sat Dec 14 09:21:46 2019 +1100
remove a bunch of ENABLE_SK #ifdefs
The ssh-sk-helper client API gives us a nice place to disable
security key support when it is wasn't enabled at compile time,
so we don't need to check everywere.
Also, verification of security key signatures can remain enabled
all the time - it has no additional dependencies. So sshd can
accept security key pubkeys in authorized_keys, etc regardless of
the host's support for dlopen, etc.
commit a33ab1688b5c460a7e2a301418241ce1b13b2638
Author: Damien Miller <djm@mindrot.org>
Date: Sat Dec 14 09:15:06 2019 +1100
ssh-sk-client.c needs includes.h
commit 633778d567ad50b63d2a3bca5e1b97d279d236d9
Author: Damien Miller <djm@mindrot.org>
Date: Sat Dec 14 08:40:33 2019 +1100
only link ssh-sk-helper against libfido2
commit 7b47b40b170db4d6f41da0479575f6d99dd7228a
Author: Damien Miller <djm@mindrot.org>
Date: Sat Dec 14 08:20:52 2019 +1100
adapt Makefile to ssh-sk-client everywhere
commit f45f3a8a12e2bee601046b916e6c5cd6eae08048
Author: Damien Miller <djm@mindrot.org>
Date: Sat Dec 14 07:53:11 2019 +1100
fixup
commit d21434766764d5babf99fc3937c19b625c0f6334
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Dec 13 20:16:56 2019 +0000
upstream: actually commit the ssh-sk-helper client code; ok markus
OpenBSD-Commit-ID: fd2ea776a5bbbf4d452989d3c3054cf25a5e0589
commit 611073fb40ecaf4ac65094e403edea3a08deb700
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Dec 13 19:11:14 2019 +0000
upstream: perform security key enrollment via ssh-sk-helper too.
This means that ssh-keygen no longer needs to link against ssh-sk-helper, and
only ssh-sk-helper needs libfido2 and /dev/uhid* access;
feedback & ok markus@
OpenBSD-Commit-ID: 9464233fab95708d2ff059f8bee29c0d1f270800
commit 612b1dd1ec91ffb1e01f58cca0c6eb1d47bf4423
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Dec 13 19:09:37 2019 +0000
upstream: allow sshbuf_put_stringb(buf, NULL); ok markus@
OpenBSD-Commit-ID: 91482c1ada9adb283165d48dafbb88ae91c657bd
commit b52ec0ba3983859514aa7b57d6100fa9759fe696
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Dec 13 19:09:10 2019 +0000
upstream: use ssh-sk-helper for all security key signing operations
This extracts and refactors the client interface for ssh-sk-helper
from ssh-agent and generalises it for use by the other programs.
This means that most OpenSSH tools no longer need to link against
libfido2 or directly interact with /dev/uhid*
requested by, feedback and ok markus@
OpenBSD-Commit-ID: 1abcd3aea9a7460eccfbf8ca154cdfa62f1dc93f
commit c33d46868c3d88e04a92610cdb429094aeeb5847
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Dec 11 22:19:47 2019 +0000
upstream: add a note about the 'extensions' field in the signed
object
OpenBSD-Commit-ID: 67c01e0565b258e0818c1ccfe1f1aeaf9a0d4c7b
commit a62f4e1960691f3aeb1f972e009788b29e2ae464
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Dec 10 23:37:31 2019 +0000
upstream: some more corrections for documentation problems spotted
by Ron Frederick
document certifiate private key format
correct flags type for sk-ssh-ed25519@openssh.com keys
OpenBSD-Commit-ID: fc4e9a1ed7f9f7f9dd83e2e2c59327912e933e74
commit 22d4beb79622fc82d7111ac941269861fc7aef8d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Dec 10 23:21:56 2019 +0000
upstream: loading security keys into ssh-agent used the extension
constraint "sk-provider@openssh.com", not "sk@openssh.com"; spotted by Ron
Frederick
OpenBSD-Commit-ID: dbfba09edbe023abadd5f59c1492df9073b0e51d
commit 75f7f22a43799f6d25dffd9d6683de1601da05a3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Dec 10 22:43:19 2019 +0000
upstream: add security key types to list of keys allowed to act as
CAs; spotted by Ron Frederick
OpenBSD-Commit-ID: 9bb0dfff927b4f7aa70679f983f84c69d45656c3
commit 516605f2d596884cedc2beed6b262716ec76f63d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Dec 10 22:37:20 2019 +0000
upstream: when acting as a CA and using a security key as the CA
key, remind the user to touch they key to authorise the signature.
OpenBSD-Commit-ID: fe58733edd367362f9766b526a8b56827cc439c1
commit c4036fe75ea5a4d03a2a40be1f3660dcbbfa01b2
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Dec 10 22:36:08 2019 +0000
upstream: chop some unnecessary and confusing verbiage from the
security key protocol description; feedback from Ron Frederick
OpenBSD-Commit-ID: 048c9483027fbf9c995e5a51b3ac502989085a42
commit 59175a350fe1091af7528b2971e3273aa7ca7295
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Dec 6 03:06:08 2019 +0000
upstream: fix setting of $SSH_ASKPASS_PROMPT - it shouldn't be set
when asking passphrases, only when confirming the use of a key (i.e. for
ssh-agent keys added with "ssh-add -c keyfile")
OpenBSD-Commit-ID: 6643c82960d9427d5972eb702c917b3b838ecf89
commit 36eaa356d391a23a2d4e3a8aaa0223abc70b9822
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Dec 6 02:55:21 2019 +0000
upstream: bring the __func__
OpenBSD-Commit-ID: 71a3a45b0fe1b8f680ff95cf264aa81f7abbff67
commit 483cc723d1ff3b7fdafc6239348040a608ebc78d
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Sat Nov 30 07:07:59 2019 +0000
upstream: tweak the Nd lines for a bit of consistency; ok markus
OpenBSD-Commit-ID: 876651bdde06bc1e72dd4bd7ad599f42a6ce5a16
commit afffd310360b155df2133d1f5f1ab2f4e939b570
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Dec 11 13:22:06 2019 +1100
Check if memmem is declared in system headers.
If the system (or one of the dependencies) implements memmem but does
not define the header, we would not declare it either resulting in
compiler warnings. Check for declaration explicitly. bz#3102.
commit ad8cd420797695f3b580aea1034b9de60bede9b9
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Dec 11 13:12:01 2019 +1100
Sort depends.
commit 5e3abff39e01817f6866494416f2ada25c316018
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Dec 11 13:09:34 2019 +1100
Sort .depend when rebuilding.
This makes diffs more stable between makedepend implementations.
commit 5df9d1f5c0943367d9b68435f4c82224ce11a73f
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Dec 11 13:06:43 2019 +1100
Update depend to include sk files.
commit 9a967c5bbfca35835165f7d8a6165009f5b21872
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Dec 9 20:25:26 2019 +1100
Describe how to build libcrypto as PIC.
While there, move the OpenSSL 1.1.0g caveat closer to the other version
information.
commit b66fa5da25c4b5b67cf9f0ce7af513f5a6a6a686
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Dec 9 17:23:22 2019 +1100
Recommend running LibreSSL or OpenSSL self-tests.
commit fa7924008e838cded7e8a561356ffe5e06e0ed64
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Dec 6 14:17:26 2019 +1100
Wrap ECC specific bits in ifdef.
Fixes tests when built against an OpenSSL configured with no-ec.
commit 2ff822eabd7d4461743f22d3b9ba35ab76069df5
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 29 20:21:36 2019 +1100
Wrap sha2.h include in ifdef.
Fixes build --without-openssl on at least Fedora.
commit 443848155ffcda65a6077aac118c861b503a093f
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 29 15:10:21 2019 +1100
compile sk-dummy.so with no-PIE version of LDFLAGS
This lets it pick up the -L path to libcrypto for example.
commit 37f5b5346e4cc6a894245aa89d2930649bb7045b
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 29 14:48:46 2019 +1100
includes.h for sk-dummy.c, dummy
commit b218055e59a7c1a1816f7a55ca18e3f3c05d63a4
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 29 12:32:23 2019 +1100
(yet) another x-platform fix for sk-dummy.so
Check for -fPIC support from compiler
Compile libopenbsd-compat -fPIC
Don't mix -fPIE and -fPIC when compiling
commit 0dedb703adcd98d0dbc4479f5f312a2bd3df2850
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 29 11:53:57 2019 +1100
needs includes.h for WITH_OPENSSL
commit ef3853bb94c2c72e7eda0de6cec0bcb1da62058f
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 29 11:52:23 2019 +1100
another attempt at sk-dummy.so working x-platform
include a fatal() implementation to satisfy libopenbsd-compat
clean up .lo and .so files
.gitignore .lo and .so files
commit d46ac56f1cbd5a855a2d5e7309f90d383dcf6431
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 29 00:13:29 2019 +0000
upstream: lots of dependencies go away here with ed25519 no longer
needing the ssh_digest API.
OpenBSD-Regress-ID: 785847ec78cb580d141e29abce351a436d6b5d49
commit 7404b81f25a4a7847380c0f0cf7f1bea5f0a5cd3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 29 00:11:21 2019 +0000
upstream: perform hashing directly in crypto_hash_sha512() using
libcrypto or libc SHA512 functions rather than calling ssh_digest_memory();
avoids many dependencies on ssh code that complicate standalone use of
ed25519, as we want to do in sk-dummy.so
OpenBSD-Commit-ID: 5a3c37593d3ba7add037b587cec44aaea088496d
commit d39a865b7af93a7a9b5a64cf7cf0ef4396c80ba3
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Thu Nov 28 12:24:31 2019 +0000
upstream: improve the text for -A a little; input from naddy and
djm
OpenBSD-Commit-ID: f9cdfb1d6dbb9887c4bf3bb25f9c7a94294c988d
commit 9a0e01bd0c61f553ead96b5af84abd73865847b8
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Thu Nov 28 12:23:25 2019 +0000
upstream: reshuffle the text to read better; input from naddy,
djmc, and dtucker
OpenBSD-Commit-ID: a0b2aca2b67614dda3d6618ea097bf0610c35013
commit 5ca52c0f2e5e7f7d01d8d557b994b5c2087bed00
Author: Damien Miller <djm@mindrot.org>
Date: Thu Nov 28 18:09:07 2019 +1100
$< doesn't work as` I thought; explicily list objs
commit 18e84bfdc5906a73405c3b42d7f840013bbffe34
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Nov 28 05:20:54 2019 +0000
upstream: tweak wording
OpenBSD-Commit-ID: bd002ca1599b71331faca735ff5f6de29e32222e
commit 8ef5bf9d03aa0f047711cff47f5ffbe3b33ff8c9
Author: Damien Miller <djm@mindrot.org>
Date: Thu Nov 28 13:12:30 2019 +1100
missing .SUFFIXES line makes make sad
commit 323da82b8ea993b7f2c5793fd53b4f5ca105d19d
Author: Damien Miller <djm@mindrot.org>
Date: Thu Nov 28 09:53:42 2019 +1100
(hopefully) fix out of tree builds of sk-dummy.so
commit d8b2838c5d19bf409d44ede4d32df8ee47aeb4cd
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Nov 27 22:32:11 2019 +0000
upstream: remove stray semicolon after closing brace of function;
from Michael Forney
OpenBSD-Commit-ID: fda95acb799bb160d15e205ee126117cf33da3a7
commit 6e1d1bbf5a3eca875005e0c87f341a0a03799809
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Nov 27 05:38:43 2019 +0000
upstream: Revert previous commit. The channels code still uses int
in many places for channel ids so the INT_MAX check still makes sense.
OpenBSD-Commit-ID: 532e4b644791b826956c3c61d6ac6da39bac84bf
commit 48989244658b9748b6801034ff4ffbdfc6b1520f
Author: Damien Miller <djm@mindrot.org>
Date: Wed Nov 27 16:03:12 2019 +1100
wire sk-dummy.so into test suite
commit f79364bacaebde4f1c260318ab460fceacace02f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Nov 27 05:00:17 2019 +0000
upstream: use error()+_exit() instead of fatal() to avoid running
cleanup handlers in child process; spotted via weird regress failures in
portable
OpenBSD-Commit-ID: 6902a9bb3987c7d347774444f7979b8a9ba7f412
commit 70ec5e5e2681bcd409a9df94a2fec6f57a750945
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Nov 27 03:34:04 2019 +0000
upstream: Make channel_id u_int32_t and remove unnecessary check
and cast that were left over from the type conversion. Noted by
t-hashida@amiya.co.jp in bz#3098, ok markus@ djm@
OpenBSD-Commit-ID: 3ad105b6a905284e780b1fd7ff118e1c346e90b5
commit ad44ca81bea83657d558aaef5a1d789a9032bac3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Nov 26 23:43:10 2019 +0000
upstream: test FIDO2/U2F key types; ok markus@
OpenBSD-Regress-ID: 367e06d5a260407619b4b113ea0bd7004a435474
commit c6efa8a91af1d4fdb43909a23a0a4ffa012155ad
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Nov 26 23:41:23 2019 +0000
upstream: add dummy security key middleware based on work by
markus@
This will allow us to test U2F/FIDO2 support in OpenSSH without
requiring real hardware.
ok markus@
OpenBSD-Regress-ID: 88b309464b8850c320cf7513f26d97ee1fdf9aae
commit 8635afa1cdc21366d61730d943f3cf61861899c8
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Tue Nov 26 22:42:26 2019 +0000
upstream: tweak previous;
OpenBSD-Commit-ID: a4c097364c75da320f1b291568db830fb1ee4883
commit e0d38ae9bc8c0de421605b9021d8144e4d8ff22b
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Nov 26 03:04:27 2019 +0000
upstream: more debugging; behind DEBUG_SK
OpenBSD-Commit-ID: a978896227118557505999ddefc1f4c839818b60
commit 9281d4311b8abc63b88259f354944c53f9b0b3c7
Author: Damien Miller <djm@mindrot.org>
Date: Mon Nov 25 21:47:49 2019 +1100
unbreak fuzzers for recent security key changes
commit c5f1cc993597fed0a9013743556b1567f476c677
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 25 10:32:35 2019 +0000
upstream: unbreak tests for recent security key changes
OpenBSD-Regress-ID: 2cdf2fcae9962ca4d711338f3ceec3c1391bdf95
commit 64988266820cc90a45a21672be9d762cbde8d34d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 25 06:53:04 2019 +0000
upstream: unbreak after security key support landed
OpenBSD-Regress-ID: 3ab578b0dbeb2aa6d9969b54a9c1bad329c0dcba
commit e65e25c81e22ea622e89a142a303726a3882384f
Author: tb@openbsd.org <tb@openbsd.org>
Date: Thu Nov 21 05:18:47 2019 +0000
upstream: Remove workaround for broken 'openssl rsa -text' output
that was fixed in libcrypto/rsa/rsa_ameth.c r1.24.
ok dtucker inoguchi
OpenBSD-Regress-ID: c260edfac177daa8fcce90141587cf04a95c4f5f
commit 21377ec2a9378579ba4b44a681af7bbca77581f4
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 25 10:23:36 2019 +0000
upstream: redundant test
OpenBSD-Commit-ID: 38fa7806c528a590d91ae560e67bd8b246c2d7a3
commit 664deef95a2e770812533439b8bdd3f3c291ae59
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 25 00:57:51 2019 +0000
upstream: document the "no-touch-required" certificate extension;
ok markus, feedback deraadt
OpenBSD-Commit-ID: 47640122b13f825e9c404ea99803b2372246579d
commit 26cb128b31efdd5395153f4943f5be3eddc07033
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 25 00:57:27 2019 +0000
upstream: Print a key touch reminder when generating a security
key. Most keys require a touch to authorize the operation.
OpenBSD-Commit-ID: 7fe8b23edbf33e1bb81741b9f25e9a63be5f6b68
commit daeaf4136927c2a82af1399022103d67ff03f74a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 25 00:55:58 2019 +0000
upstream: allow "ssh-keygen -x no-touch-required" when generating a
security key keypair to request one that does not require a touch for each
authentication attempt. The default remains to require touch.
feedback deraadt; ok markus@
OpenBSD-Commit-ID: 887e7084b2e89c0c62d1598ac378aad8e434bcbd
commit 2e71263b80fec7ad977e098004fef7d122169d40
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 25 00:54:23 2019 +0000
upstream: add a "no-touch-required" option for authorized_keys and
a similar extension for certificates. This option disables the default
requirement that security key signatures attest that the user touched their
key to authorize them.
feedback deraadt, ok markus
OpenBSD-Commit-ID: f1fb56151ba68d55d554d0f6d3d4dba0cf1a452e
commit 0fddf2967ac51d518e300408a0d7e6adf4cd2634
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 25 00:52:46 2019 +0000
upstream: Add a sshd_config PubkeyAuthOptions directive
This directive has a single valid option "no-touch-required" that
causes sshd to skip checking whether user presence was tested before
a security key signature was made (usually by the user touching the
key).
ok markus@
OpenBSD-Commit-ID: 46e434a49802d4ed82bc0aa38cb985c198c407de
commit b7e74ea072919b31391bc0f5ff653f80b9f5e84f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 25 00:51:37 2019 +0000
upstream: Add new structure for signature options
This is populated during signature verification with additional fields
that are present in and covered by the signature. At the moment, it is
only used to record security key-specific options, especially the flags
field.
with and ok markus@
OpenBSD-Commit-ID: 338a1f0e04904008836130bedb9ece4faafd4e49
commit d2b0f88178ec9e3f11b606bf1004ac2fe541a2c3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 25 00:38:17 2019 +0000
upstream: memleak in error path
OpenBSD-Commit-ID: 93488431bf02dde85a854429362695d2d43d9112
commit e2c0a21ade5e0bd7f0aab08d7eb9457f086681e9
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Nov 22 06:50:30 2019 +0000
upstream: Wait for FD to be readable or writeable during a nonblocking
connect, not just readable. Prevents a timeout when the server doesn't
immediately send a banner (eg multiplexers like sslh) but is also slightly
quicker for other connections since, unlike ssh1, ssh2 doesn't specify
that the client should parse the server banner before sending its own.
Patch from mnissler@chromium.org, ok djm@
OpenBSD-Commit-ID: aba9cd8480d1d9dd31d0ca0422ea155c26c5df1d
commit 2f95d43dc222ce194622b706682e8de07c9cfb42
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Nov 20 16:34:11 2019 +1100
Include openssl compat header.
Fixes warning for ECDSA_SIG_set0 on OpenSSL versions prior to 1.1.
commit a70d92f236576c032a45c39e68ca0d71e958d19d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Nov 19 22:23:19 2019 +0000
upstream: adjust on-wire signature encoding for ecdsa-sk keys to
better match ec25519-sk keys. Discussed with markus@ and Sebastian Kinne
NB. if you are depending on security keys (already?) then make sure you
update both your clients and servers.
OpenBSD-Commit-ID: 53d88d8211f0dd02a7954d3af72017b1a79c0679
commit 26369a5f7d9c4e4ef44a3e04910126e1bcea43d8
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Nov 19 22:21:15 2019 +0000
upstream: a little more information from the monitor when signature
verification fails.
OpenBSD-Commit-ID: e6a30071e0518cac512f9e10be3dc3500e2003f3
commit 4402d6c9b5bf128dcfae2429f1d41cdaa8849b6b
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Tue Nov 19 16:02:32 2019 +0000
upstream: revert previous: naddy pointed out what's meant to
happen. rethink needed...
OpenBSD-Commit-ID: fb0fede8123ea7f725fd65e00d49241c40bd3421
commit 88056f881315233e990e4e04a815f8f96b4674e1
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Tue Nov 19 14:54:47 2019 +0000
upstream: -c and -s do not make sense with -k; reshuffle -k into
the main synopsis/usage; ok djm
OpenBSD-Commit-ID: f881ba253da015398ae8758d973e3390754869bc
commit 2cf262c21f35296c2ff718cfdb52e0473a1c3983
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Mon Nov 18 23:17:48 2019 +0000
upstream: document '$' environment variable expansion for
SecurityKeyProvider; ok djm@
OpenBSD-Commit-ID: 76db507ebd336a573e1cd4146cc40019332c5799
commit f0edda81c5ebccffcce52b182c3033531a1aab71
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Mon Nov 18 23:16:49 2019 +0000
upstream: more missing mentions of ed25519-sk; ok djm@
OpenBSD-Commit-ID: f242e53366f61697dffd53af881bc5daf78230ff
commit 189550f5bc85148e85f4caa1f6b2fc623149a4ee
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Mon Nov 18 16:10:05 2019 +0000
upstream: additional missing stdarg.h includes when built without
WITH_OPENSSL; ok djm@
OpenBSD-Commit-ID: 881f9a2c4e2239849cee8bbf4faec9bab128f55b
commit 723a5369864b338c48d22854bc2bb4ee5c083deb
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Mon Nov 18 16:08:57 2019 +0000
upstream: add the missing WITH_OPENSSL ifdefs after the ED25519-SK
addition; ok djm@
OpenBSD-Commit-ID: a9545e1c273e506cf70e328cbb9d0129b6d62474
commit 478f4f98e4e93ae4ed1a8911dec4e5b75ea10f30
Author: Damien Miller <djm@mindrot.org>
Date: Tue Nov 19 08:52:24 2019 +1100
remove all EC algs from proposals, no just sk ones
ok dtucker@
commit 6a7ef310da100f876a257b7367e3b0766dac3994
Author: Damien Miller <djm@mindrot.org>
Date: Mon Nov 18 22:22:04 2019 +1100
filter PUBKEY_DEFAULT_PK_ALG for ECC algorithms
Remove ECC algorithms from the PUBKEY_DEFAULT_PK_ALG list when
compiling without ECC support in libcrypto.
commit 64f56f1d1af3947a71a4c391f2c08747d19ee591
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Nov 18 09:15:17 2019 +0000
upstream: LibreSSL change the format for openssl rsa -text output from
"publicExponent" to "Exponent" so accept either. with djm.
OpenBSD-Regress-ID: b7e6c4bf700029a31c98be14600d4472fe0467e6
commit 4bfc0503ad94a2a7190686a89649567c20b8534f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 18 06:58:00 2019 +0000
upstream: fix a bug that prevented serialisation of ed25519-sk keys
OpenBSD-Commit-ID: 066682b79333159cac04fcbe03ebd9c8dcc152a9
commit d88205417084f523107fbe1bc92061635cd57fd2
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 18 06:39:36 2019 +0000
upstream: Fix incorrect error message when key certification fails
OpenBSD-Commit-ID: 7771bd77ee73f7116df37c734c41192943a73cee
commit 740c4bc9875cbb4b9fc03fd5eac19df080f20df5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 18 06:39:02 2019 +0000
upstream: fix bug that prevented certification of ed25519-sk keys
OpenBSD-Commit-ID: 64c8cc6f5de2cdd0ee3a81c3a9dee8d862645996
commit 85409cbb505d8c463ab6e2284b4039764c7243de
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 18 06:24:17 2019 +0000
upstream: allow *-sk key types to be turned into certificates
OpenBSD-Commit-ID: cd365ee343934862286d0b011aa77fa739d2a945
commit e2e1283404e06a22ac6135d057199e70dcadb8dd
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 18 04:55:02 2019 +0000
upstream: mention ed25519-sk key/cert types here too; prompted by
jmc@
OpenBSD-Commit-ID: e281977e4a4f121f3470517cbd5e483eee37b818
commit 97dc5d1d82865a7d20f1eb193b5c62ce684024e5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 18 04:50:45 2019 +0000
upstream: mention ed25519-sk in places where it is accepted;
prompted by jmc@
OpenBSD-Commit-ID: 076d386739ebe7336c2137e583bc7a5c9538a442
commit 130664344862a8c7afd3e24d8d36ce40af41a99f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 18 04:34:47 2019 +0000
upstream: document ed25519-sk pubkey, private key and certificate
formats
OpenBSD-Commit-ID: 795a7c1c80315412e701bef90e31e376ea2f3c88
commit 71856e1142fc01628ce53098f8cfc74765464b35
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 18 04:29:50 2019 +0000
upstream: correct order or ecdsa-sk private key fields
OpenBSD-Commit-ID: 4d4a0c13226a79f0080ce6cbe74f73b03ed8092e
commit 93fa2a6649ae3e0626cbff25c985a4573d63e3f2
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 18 04:16:53 2019 +0000
upstream: correct description of fields in pub/private keys (was
missing curve name); spotted by Sebastian Kinne
OpenBSD-Commit-ID: 2a11340dc7ed16200342d384fb45ecd4fcce26e7
commit b497e920b409250309c4abe64229237b8f2730ba
Author: Damien Miller <djm@mindrot.org>
Date: Mon Nov 18 15:05:04 2019 +1100
Teach the GTK2/3 ssh-askpass the new prompt hints
ssh/ssh-agent now sets a hint environment variable $SSH_ASKPASS_PROMPT
when running the askpass program. This is intended to allow the
askpass to vary its UI across the three cases it supports: asking for
a passphrase, confirming the use of a key and (recently) reminding
a user to touch their security key.
This adapts the gnome-ssh-askpass[23] to use these hints. Specifically,
for SSH_ASKPASS_PROMPT=confirm it will skip the text input box and show
only "yes"/"no" buttons. For SSH_ASKPASS_PROMPT=none (used to remind
users to tap their security key), it shows only a "close" button.
Help wanted: adapt the other askpass programs in active use, including
x11-ssh-askpass, lxqt-openssh-askpass, etc.
commit 857f49e91eeae6feb781ef5f5e26c38ca3d953ec
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Nov 18 14:15:26 2019 +1100
Move ifdef OPENSSL_HAS_ECC.
Found by -Wimplicit-fallthrough: one ECC case was not inside the ifdef.
ok djm@
commit 6cf1c40096a79e5eedcf897c7cdb46bb32d4a3ee
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Nov 18 14:14:18 2019 +1100
Enable -Wimplicit-fallthrough if supported
Suggested by djm.
commit 103c51fd5f5ddc01cd6b5c1132e711765b921bf5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Nov 18 01:59:48 2019 +0000
upstream: missing break in getopt switch; spotted by Sebastian Kinne
OpenBSD-Commit-ID: f002dbf14dba5586e8407e90f0141148ade8e8fc
commit 9a1225e8ca2ce1fe809910874935302234399a6d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Nov 16 23:17:20 2019 +0000
upstream: tweak debug message
OpenBSD-Commit-ID: 2bf336d3be0b7e3dd97920d7e7471146a281d2b9
commit 4103a3ec7c68493dbc4f0994a229507e943a86d3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Nov 16 22:42:30 2019 +0000
upstream: a little debug() in the security key interface
OpenBSD-Commit-ID: 4c70300609a5c8b19707207bb7ad4109e963b0e8
commit 05daa211de926f66f50b7380d637f84dc6341574
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Nov 16 22:36:48 2019 +0000
upstream: always use ssh-sk-helper, even for the internal USB HID
support. This avoid the need for a wpath pledge in ssh-agent.
reported by jmc@
OpenBSD-Commit-ID: 19f799c4d020b870741d221335dbfa5e76691c23
commit d431778a561d90131814f986b646299f9af33c8c
Author: markus@openbsd.org <markus@openbsd.org>
Date: Fri Nov 15 15:41:01 2019 +0000
upstream: fix typos in sk_enroll
OpenBSD-Commit-ID: faa9bf779e008b3e64e2eb1344d9b7d83b3c4487
commit af90aec0443ec51e6b2d804cb91771d3905f8a6f
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Fri Nov 15 11:16:28 2019 +0000
upstream: double word;
OpenBSD-Commit-ID: 43d09bafa4ea9002078cb30ca9adc3dcc0b9c2b9
commit fd1a96490cef7f945a1b3b5df4e90c8a1070f425
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 15 06:00:20 2019 +0000
upstream: remove most uses of BN_CTX
We weren't following the rules re BN_CTX_start/BN_CTX_end and the places
we were using it didn't benefit from its use anyway. ok dtucker@
OpenBSD-Commit-ID: ea9ba6c0d2e6f6adfe00b309a8f41842fe12fc7a
commit 39b87104cdd47baf79ef77dc81de62cea07d119f
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 15 18:56:54 2019 +1100
Add wrappers for other ultrix headers.
Wrappers protect against multiple inclusions for headers that don't do
it themselves.
commit 134a74f4e0cf750931f1125beb2a3f40c54c8809
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 15 18:55:13 2019 +1100
Add SSIZE_MAX when we define ssize_t.
commit 9c6d0a3a1ed77989d8c5436d8c3cc6c7045c0197
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 15 17:13:19 2019 +1100
Remove ultrix realpath hack.
commit c63fba5e3472307167850bbd84187186af7fa9f0
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 15 05:37:27 2019 +0000
upstream: unshield security key privkey before attempting signature
in agent. spotted by dtucker@
OpenBSD-Commit-ID: fb67d451665385b8a0a55371231c50aac67b91d2
commit d165bb5396e3f718480e6039ca2cf77f5a2c2885
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Fri Nov 15 05:26:56 2019 +0000
upstream: rewrite c99-ism
OpenBSD-Commit-ID: d0c70cca29cfa7e6d9f7ec1d6d5dabea112499b3
commit 03e06dd0e6e1c0a9f4b4b9de7def8a44dcbf93a7
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Fri Nov 15 05:25:52 2019 +0000
upstream: only clang understands those new -W options
OpenBSD-Commit-ID: d9b910e412d139141b072a905e66714870c38ac0
commit 5c0bc273cba53f822b7d777bbb6c35d160d3b505
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 15 16:08:00 2019 +1100
configure flag to built-in security key support
Require --with-security-key-builtin before enabling the built-in
security key support (and consequent dependency on libfido2).
commit fbcb9a7fa55300b8bd4c18bee024c6104c5a25d7
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 15 16:06:30 2019 +1100
upstream commit
revision 1.48
date: 2019/02/04 16:45:40; author: millert; state: Exp; lines: +16 -17; commitid: cpNtVC7erojNyctw;
Make gl_pathc, gl_matchc and gl_offs size_t in glob_t to match POSIX.
This requires a libc major version bump. OK deraadt@
commit 2cfb11abac85885de0cb888bbeb9a3e4303105ea
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 15 16:05:07 2019 +1100
upstream commit
revision 1.47
date: 2017/05/08 14:53:27; author: millert; state: Exp; lines: +34 -21; commitid: sYfxfyUHAfarP8sE;
Fix exponential CPU use with repeated '*' operators by changing '*'
handling to be interative instead of recursive.
Fix by Yves Orton, ported to OpenBSD glob.c by Ray Lai. OK tb@
commit 228dd595c7882bb9b161dbb7d4dca15c8a5f03f5
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 15 16:04:28 2019 +1100
upstream commit
revision 1.46
date: 2015/12/28 22:08:18; author: mmcc; state: Exp; lines: +5 -9; commitid: 0uXuF2O13NH9q2e1;
Remove NULL-checks before free() and a few related dead assignments.
ok and valuable input from millert@
commit a16f748690139b9f452485d97511ad5e578f59b2
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 15 16:02:43 2019 +1100
upstream commit
revision 1.44
date: 2015/09/14 16:09:13; author: tedu; state: Exp; lines: +3 -5; commitid: iWfSX2BIn0sLw62l;
remove null check before free. from Michael McConville
ok semarie
commit fd37cdeafe25adfcdc752280f535d28de7997ff1
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 15 16:02:27 2019 +1100
upstream commit
revision 1.43
date: 2015/06/13 16:57:04; author: deraadt; state: Exp; lines: +4 -4; commitid: zOUKuqWBdOPOz1SZ;
in glob() initialize the glob_t before the first failure check.
from j@pureftpd.org
ok millert stsp
commit fd62769c3882adea118dccaff80a06009874a2d1
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 15 16:01:20 2019 +1100
upstream commit
revision 1.42
date: 2015/02/05 12:59:57; author: millert; state: Exp; lines: +2 -1; commitid: DTQbfd4poqBW8iSJ;
Include stdint.h, not limits.h to get SIZE_MAX. OK guenther@
commit 2b6cba7ee2b8b36f393be739c860a9d2e5d8eb48
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 15 16:00:07 2019 +1100
upstream commit
revision 1.41
date: 2014/10/08 05:35:27; author: deraadt; state: Exp; lines: +3 -3; commitid: JwTGarRLHQKDgPh2;
obvious realloc -> reallocarray conversion
commit ab3600665387ae34785498558c4409e27f495b0b
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 15 04:12:32 2019 +0000
upstream: don't consult dlopen whitelist for internal security key
provider; spotted by dtucker@
OpenBSD-Commit-ID: bfe5fbd17e4ff95dd85b9212181652b54444192e
commit 19f8ec428db835f68c1cfd63587e9880ccd6486c
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 15 15:08:28 2019 +1100
upstream commit
revision 1.40
date: 2013/09/30 12:02:34; author: millert; state: Exp; lines: +14 -15;
Use PATH_MAX, NAME_MAX and LOGIN_NAME_MAX not MAXPATHNAMELEN,
MAXNAMLEN or MAXLOGNAME where possible. OK deraadt@
commit bb7413db98e418d4af791244660abf6c829783f5
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 15 15:07:30 2019 +1100
upstream commit
revision 1.39
date: 2012/01/20 07:09:42; author: tedu; state: Exp; lines: +4 -4;
the glob stat limit is way too low. bump to 2048.
while here, failed stats should count against the limit too.
ok deraadt sthen stsp
commit 01362cf7cb979525c014714e2bccf799a46e772e
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 15 03:41:57 2019 +0000
upstream: U2F tokens may return FIDO_ERR_USER_PRESENCE_REQUIRED when
probed to see if they own a key handle. Handle this case so the find_device()
look can work for them. Reported by Michael Forney
OpenBSD-Commit-ID: 2ccd5b30a6ddfe4dba228b7159bf168601bd9166
commit cf62307bc9758105913dcb91b418e4968ac2244d
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 15 14:01:00 2019 +1100
Add libfido2 to INSTALL.
commit 69fbda1894349d1f420c842dfcbcc883239d1aa7
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 15 13:42:15 2019 +1100
libcrypto is now optional.
commit 45ffa369886e37930776d7c15dd8b973242d6ecc
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 15 02:38:07 2019 +0000
upstream: show the "please touch your security key" notifier when
using the (default) build-in security key support.
OpenBSD-Commit-ID: 4707643aaa7124501d14e92d1364b20f312a6428
commit 49dc9fa928d77807c53bdc2898db7fb515fe5eb3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 15 02:37:24 2019 +0000
upstream: close the "touch your security key" notifier on the error
path too
OpenBSD-Commit-ID: c7628bf80505c1aefbb1de7abc8bb5ee51826829
commit 22a82712e89bf17c27427aeba15795fb4011a0c2
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 15 02:20:06 2019 +0000
upstream: correct function name in debug message
OpenBSD-Commit-ID: 2482c99d2ce448f39282493050f8a01e3ffc39ab
commit 018e2902a65c22faded215a7c588492c948f108c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 15 00:32:40 2019 +0000
upstream: follow existing askpass logic for security key notifier:
fall back to _PATH_SSH_ASKPASS_DEFAULT if no $SSH_ASKPASS environment
variable is set.
OpenBSD-Commit-ID: cda753726b13fb797bf7a9f7a0b3022d9ade4520
commit 575d0042a94997c1eeb86a6dcfb30b3c7bdbcba3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Nov 14 21:56:52 2019 +0000
upstream: remove debugging goop that snuck in to last commit
OpenBSD-Commit-ID: 8ea4455a2d9364a0a04f9e4a2cbfa4c9fcefe77e
commit 63a5b24f2dbdc9a4bf2182ac3db26731ddc617e8
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 15 11:21:26 2019 +1100
don't fatal if libfido2 not found
spotted by dtucker@
commit 129952a81c00c332721b4ba3ede868c720ad7f4e
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 15 11:17:12 2019 +1100
correct object dependency
commit 6bff9521ab9a9f7396d635755c342b72373bb4f9
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Nov 14 21:27:29 2019 +0000
upstream: directly support U2F/FIDO2 security keys in OpenSSH by
linking against the (previously external) USB HID middleware. The dlopen()
capability still exists for alternate middlewares, e.g. for Bluetooth, NFC
and test/debugging.
OpenBSD-Commit-ID: 14446cf170ac0351f0d4792ba0bca53024930069
commit 4f5e331cb8e11face3025aa6578662dde489c3ad
Author: markus@openbsd.org <markus@openbsd.org>
Date: Wed Nov 13 22:00:21 2019 +0000
upstream: in order to be able to figure out the number of
signatures left on a shielded key, we need to transfer the number of
signatures left from the private to the public key. ok djm@
OpenBSD-Commit-ID: 8a5d0d260aeace47d372695fdae383ce9b962574
commit dffd02e297e6c2a4e86775f293eb1b0ff01fb3df
Author: markus@openbsd.org <markus@openbsd.org>
Date: Wed Nov 13 20:25:45 2019 +0000
upstream: fix check for sig_s; noted by qsa at qualys.com
OpenBSD-Commit-ID: 34198084e4afb424a859f52c04bb2c9668a52867
commit fc173aeb1526d4268db89ec5dfebaf8750dd26cd
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Nov 13 11:25:11 2019 +0000
upstream: When clients get denied by MaxStartups, send a
noification prior to the SSH2 protocol banner according to RFC4253 section
4.2. ok djm@ deraadt@ markus@
OpenBSD-Commit-ID: e5dabcb722d54dea18eafb336d50b733af4f9c63
commit bf219920b70cafbf29ebc9890ef67d0efa54e738
Author: markus@openbsd.org <markus@openbsd.org>
Date: Wed Nov 13 07:53:10 2019 +0000
upstream: fix shield/unshield for xmss keys: - in ssh-agent we need
to delay the call to shield until we have received key specific options. -
when serializing xmss keys for shield we need to deal with all optional
components (e.g. state might not be loaded). ok djm@
OpenBSD-Commit-ID: cc2db82524b209468eb176d6b4d6b9486422f41f
commit 40598b85d72a509566b7b2a6d57676c7231fed34
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Wed Nov 13 05:42:26 2019 +0000
upstream: remove size_t gl_pathc < 0 test, it is invalid. the
return value from glob() is sufficient. discussed with djm
OpenBSD-Commit-ID: c91203322db9caaf7efaf5ae90c794a91070be3c
commit 72687c8e7c38736e3e64e833ee7aa8f9cd9efed1
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Wed Nov 13 04:47:52 2019 +0000
upstream: stdarg.h required more broadly; ok djm
OpenBSD-Commit-ID: b5b15674cde1b54d6dbbae8faf30d47e6e5d6513
commit 1e0b248d47c96be944868a735553af8482300a07
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Nov 14 16:08:17 2019 +1100
Put sshsk_sign call inside ifdef ENABLE_SK.
Fixes build against OpenSSL configured without ECC.
commit 546274a6f89489d2e6be8a8b62f2bb63c87a61fd
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Nov 13 23:27:31 2019 +1100
Remove duplicate __NR_clock_nanosleep
commit b1c82f4b8adf3f42476d8a1f292df33fb7aa1a56
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Nov 13 23:19:35 2019 +1100
seccomp: Allow clock_nanosleep() in sandbox.
seccomp: Allow clock_nanosleep() to make OpenSSH working with latest
glibc. Patch from Jakub Jelen <jjelen@redhat.com> via bz #3093.
commit 2b523d23804c13cb68db135b919fcf312c42b580
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Nov 13 11:56:56 2019 +1100
Include stdarg.h for va_list in xmalloc.h.
commit 245dcbdca5374296bdb9c48be6e24bdf6b1c0af7
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Nov 13 11:19:26 2019 +1100
Put headers inside ifdef _AIX.
Prevents compile errors due to missing definitions (eg va_list) on
non-AIX platforms.
commit a4cc579c6ad2b2e54bdd6cc0d5e12c2288113a56
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Nov 13 10:41:41 2019 +1100
Fix comment in match_usergroup_pattern_list.
Spotted by balu.gajjala@gmail.com via bz#3092.
commit fccff339cab5aa66f2554e0188b83f980683490b
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Nov 12 22:38:19 2019 +0000
upstream: allow an empty attestation certificate returned by a
security key enrollment - these are possible for tokens that only offer self-
attestation. This also needs support from the middleware.
ok markus@
OpenBSD-Commit-ID: 135eeeb937088ef6830a25ca0bbe678dfd2c57cc
commit e44bb61824e36d0d181a08489c16c378c486a974
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Nov 12 22:36:44 2019 +0000
upstream: security keys typically need to be tapped/touched in
order to perform a signature operation. Notify the user when this is expected
via the TTY (if available) or $SSH_ASKPASS if we can.
ok markus@
OpenBSD-Commit-ID: 0ef90a99a85d4a2a07217a58efb4df8444818609
commit 4671211068441519011ac0e38c588317f4157ba1
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Nov 12 22:35:02 2019 +0000
upstream: pass SSH_ASKPASS_PROMPT hint to y/n key confirm too
OpenBSD-Commit-ID: 08d46712e5e5f1bad0aea68e7717b7bec1ab8959
commit 5d1c1590d736694f41b03e686045f08fcae20d62
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Nov 12 22:34:20 2019 +0000
upstream: dd API for performing one-shot notifications via tty or
SSH_ASKPASS
OpenBSD-Commit-ID: 9484aea33aff5b62ce3642bf259546c7639f23f3
commit 166927fd410823eec8a7b2472463db51e0e6fef5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Nov 12 22:32:48 2019 +0000
upstream: add xvasprintf()
OpenBSD-Commit-ID: e5e3671c05c121993b034db935bce1a7aa372247
commit 782093ec6cf64cc6c4078410093359869ea9329f
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Nov 13 09:08:55 2019 +1100
Remove leftover if statement from sync.
commit b556cc3cbf0c43f073bb41bba4e92ca709a1ec13
Author: markus@openbsd.org <markus@openbsd.org>
Date: Tue Nov 12 19:34:40 2019 +0000
upstream: remove extra layer for ed25519 signature; ok djm@
OpenBSD-Commit-ID: 7672d9d0278b4bf656a12d3aab0c0bfe92a8ae47
commit 3fcf69ace19e75cf9dcd7206f396adfcb29611a8
Author: markus@openbsd.org <markus@openbsd.org>
Date: Tue Nov 12 19:34:00 2019 +0000
upstream: check sig_r and sig_s for ssh-sk keys; ok djm
OpenBSD-Commit-ID: 1a1e6a85b5f465d447a3800f739e35c5b74e0abc
commit 2c55744a56de0ffc81fe445a1e7fc5cd308712b3
Author: markus@openbsd.org <markus@openbsd.org>
Date: Tue Nov 12 19:33:08 2019 +0000
upstream: enable ed25519 support; ok djm
OpenBSD-Commit-ID: 1a399c5b3ef15bd8efb916110cf5a9e0b554ab7e
commit fd1a3b5e38721b1d69aae2d9de1a1d9155dfa5c7
Author: markus@openbsd.org <markus@openbsd.org>
Date: Tue Nov 12 19:32:30 2019 +0000
upstream: update sk-api to version 2 for ed25519 support; ok djm
OpenBSD-Commit-ID: 77aa4d5b6ab17987d8a600907b49573940a0044a
commit 7c32b51edbed5bd57870249c0a45dffd06be0002
Author: markus@openbsd.org <markus@openbsd.org>
Date: Tue Nov 12 19:31:45 2019 +0000
upstream: implement sshsk_ed25519_assemble(); ok djm
OpenBSD-Commit-ID: af9ec838b9bc643786310b5caefc4ca4754e68c6
commit fe05a36dc0ea884c8c2395d53d804fe4f4202b26
Author: markus@openbsd.org <markus@openbsd.org>
Date: Tue Nov 12 19:31:18 2019 +0000
upstream: implement sshsk_ed25519_inner_sig(); ok djm
OpenBSD-Commit-ID: f422d0052c6d948fe0e4b04bc961f37fdffa0910
commit e03a29e6554cd0c9cdbac0dae53dd79e6eb4ea47
Author: markus@openbsd.org <markus@openbsd.org>
Date: Tue Nov 12 19:30:50 2019 +0000
upstream: rename sshsk_ecdsa_sign() to sshsk_sign(); ok djm
OpenBSD-Commit-ID: 1524042e09d81e54c4470d7bfcc0194c5b46fe19
commit bc7b5d6187de625c086b5f639b25bbad17bbabfc
Author: markus@openbsd.org <markus@openbsd.org>
Date: Tue Nov 12 19:30:21 2019 +0000
upstream: factor out sshsk_ecdsa_inner_sig(); ok djm@
OpenBSD-Commit-ID: 07e41997b542f670a15d7e2807143fe01efef584
commit cef84a062db8cfeece26f067235dc440f6992c17
Author: markus@openbsd.org <markus@openbsd.org>
Date: Tue Nov 12 19:29:54 2019 +0000
upstream: factor out sshsk_ecdsa_assemble(); ok djm@
OpenBSD-Commit-ID: 2313761a3a84ccfe032874d638d3c363e0f14026
commit 7c096c456f33f3d2682736d4735cc10e790276e9
Author: markus@openbsd.org <markus@openbsd.org>
Date: Tue Nov 12 19:29:24 2019 +0000
upstream: implement ssh-ed25519-sk verification; ok djm@
OpenBSD-Commit-ID: 37906d93948a1e3d237c20e713d6ca8fbf7d13f6
commit ba5fb02bed1e556d0ce7b1740ae8a5f87b737491
Author: Damien Miller <djm@mindrot.org>
Date: Wed Nov 13 08:48:30 2019 +1100
ignore ssh-sk-helper
commit 78c96498947f711141f493a40d202c482cc59438
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Mon Nov 11 19:53:37 2019 +0000
upstream: skip demanding -fstack-protector-all on hppa. we never
wrote a stack protector for reverse-stack architectures, and i don't think
anyone else did either. a warning per compiled file is just annoying.
OpenBSD-Commit-ID: 14806a59353152f843eb349e618abbf6f4dd3ada
commit aa1c9e37789f999979fe59df74ce5c8424861ac8
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 8 03:54:02 2019 +0000
upstream: duplicate 'x' character in getopt(3) optstring
OpenBSD-Commit-ID: 64c81caa0cb5798de3621eca16b7dd22e5d0d8a7
commit aa4c640dc362816d63584a16e786d5e314e24390
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Thu Nov 7 08:38:38 2019 +0000
upstream: Fill in missing man page bits for U2F security key support:
Mention the new key types, the ~/.ssh/id_ecdsa_sk file, ssh's
SecurityKeyProvider keyword, the SSH_SK_PROVIDER environment variable,
and ssh-keygen's new -w and -x options.
Copy the ssh-sk-helper man page from ssh-pkcs11-helper with minimal
substitutions.
ok djm@
OpenBSD-Commit-ID: ef2e8f83d0c0ce11ad9b8c28945747e5ca337ac4
commit b236b27d6dada7f0542214003632b4e9b7aa1380
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sun Nov 3 00:10:43 2019 +1100
Put sftp-realpath in libssh.a
and remove it from the specific binary targets.
commit 382c18c20cdcec45b5d21ff25b4a5e0df91a68c4
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sun Nov 3 00:09:21 2019 +1100
statfs might be defined in sys/mount.h.
eg on old NetBSDs.
commit 03ffc0951c305c8e3b5fdc260d65312a57f8f7ea
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Nov 2 23:25:01 2019 +1100
Put stdint.h inside ifdef HAVE_STDINT_H.
commit 19cb64c4b42d4312ce12091fd9436dbd6898998c
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Nov 2 22:45:44 2019 +1100
Rebuild .depend.
commit 3611bfe89b92ada5914526d8ff0919aeb967cfa7
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Nov 2 22:42:05 2019 +1100
Define __BSD_VISIBLE in fnmatch.h.
.. since we use symbols defined only when it is when using the compat
fnmatch.
commit f5cc5816aaddb8eca3cba193f53e99d6a0b37d05
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Nov 2 16:39:38 2019 +1100
Only enable U2F if OpenSSL supports ECC.
This requires moving the U2F bits to below the OpenSSL parts so we have
the required information. ok djm@
commit ad38406fc95fa223b0ef2edf8ff50508f8ab1cb6
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Fri Nov 1 12:10:43 2019 +0000
upstream: fix miscellaneous text problems; ok djm@
OpenBSD-Commit-ID: 0cbf411a14d8fa0b269b69cbb1b4fc0ca699fe9f
commit 9cac151c2dc76b8e5b727b2fa216f572e372170f
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 1 18:26:07 2019 +1100
Add flags needed to build and work on Ultrix.
commit 0e3c5bc50907d2058407641b5a3581b7eda91b7e
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 1 18:24:29 2019 +1100
Hook up fnmatch for platforms that don't have it.
commit b56dbfd9d967e5b6ce7be9f81f206112e19e1030
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 1 18:17:42 2019 +1100
Add missing bracket in realpath macro.
commit 59ccb56f15e5e530e7c1b5a0b361749d8c6217d5
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 1 17:32:47 2019 +1100
Import fnmatch.c from OpenBSD.
commit 79d46de9fbea0f3c0e8ae7cf84effaba089071b0
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 1 15:22:32 2019 +1100
Use sftp_realpath if no native realpath.
commit bb4f003ed8c5f61ec74a66bcedc8ab19bf5b35c4
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 1 15:06:16 2019 +1100
Configure flags for haiku from haikuports.
Should build with the default flags with ./configure
commit 4332b4fe49360679647a8705bc08f4e81323f6b4
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 1 03:54:33 2019 +0000
upstream: fix a race condition in the SIGCHILD handler that could turn
in to a kill(-1); bz3084, reported by Gao Rui, ok dtucker@
OpenBSD-Commit-ID: ac2742e04a69d4c34223505b6a32f6d686e18896
commit 03f9205f0fb49ea2507eacc143737a8511ae5a4e
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 1 14:49:25 2019 +1100
conditionalise SK sign/verify on ENABLE_SK
Spotted by Darren and his faux-Vax
commit 5eb7b9563ff818e17de24231bf2d347d9db302c5
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 1 14:41:07 2019 +1100
Add prototype for localtime_r if needed.
commit d500b59a825f6a58f2abf7b04eb1992d81e45d58
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Nov 1 13:42:12 2019 +1100
Check if IP_TOS is defined before using.
commit 764d51e04460ec0da12e05e4777bc90c116accb9
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 1 13:34:49 2019 +1100
autoconf pieces for U2F support
Mostly following existing logic for PKCS#11 - turning off support
when either libcrypto or dlopen(3) are unavailable.
commit 45f17a159acfc5a8e450bfbcc2cffe72950ed7a3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 1 02:32:05 2019 +0000
upstream: remove duplicate PUBKEY_DEFAULT_PK_ALG on !WITH_OPENSSL path
OpenBSD-Commit-ID: 95a7cafad2a4665d57cabacc28031fabc0bea9fc
commit db8d13f7925da7337df87248995c533e111637ec
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 1 02:06:52 2019 +0000
upstream: more additional source files
OpenBSD-Regress-ID: 8eaa25fb901594aee23b76eda99dca5b8db94c6f
commit f89c5df65dd307739ff22319c2cf847d3b0c5ab4
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 1 02:04:25 2019 +0000
upstream: additional source files here too
OpenBSD-Regress-ID: 8809f8e1c8f7459e7096ab6b58d8e56cb2f483fd
commit 02275afa1ecbfbd39f27d34c97090e76bec232ec
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 1 02:03:27 2019 +0000
upstream: additional source files here too
OpenBSD-Regress-ID: 09297e484327f911fd353489518cceaa0c1b95ce
commit dfc8f01b9886c7999e6e20acf3f7492cb8c80796
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 1 01:57:59 2019 +0000
upstream: adapt to extra sshkey_sign() argument and additional
dependencies
OpenBSD-Regress-ID: 7a25604968486c4d6f81d06e8fbc7d17519de50e
commit afa59e26eeb44a93f36f043f60b936eaddae77c4
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Nov 1 01:55:41 2019 +0000
upstream: skip security-key key types for tests until we have a
dummy U2F middleware to use.
OpenBSD-Regress-ID: 37200462b44334a4ad45e6a1f7ad1bd717521a95
commit de871e4daf346a712c78fa4ab8f18b231a47cb85
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Fri Nov 1 00:52:35 2019 +0000
upstream: sort;
OpenBSD-Commit-ID: 8264b0be01ec5a60602bd50fd49cc3c81162ea16
commit 2aae149a34b1b5dfbef423d3b7999a96818969bb
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 31 21:37:33 2019 +0000
upstream: undo debugging bits that shouldn't have been committed
OpenBSD-Commit-ID: 4bd5551b306df55379afe17d841207990eb773bf
commit 3420e0464bd0e8fedcfa5fd20ad37bdc740ad5b4
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 1 09:24:58 2019 +1100
depend
commit b923a90abc7bccb11a513dc8b5c0f13a0ea9682c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 31 21:28:27 2019 +0000
upstream: fix -Wshadow warning
OpenBSD-Commit-ID: 3441eb04f872a00c2483c11a5f1570dfe775103c
commit 9a14c64c38fc14d0029f1c7bc70cf62cc7f0fdf9
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 31 21:23:19 2019 +0000
upstream: Refactor signing - use sshkey_sign for everything,
including the new U2F signatures.
Don't use sshsk_ecdsa_sign() directly, instead make it reachable via
sshkey_sign() like all other signature operations. This means that
we need to add a provider argument to sshkey_sign(), so most of this
change is mechanically adding that.
Suggested by / ok markus@
OpenBSD-Commit-ID: d5193a03fcfa895085d91b2b83d984a9fde76c8c
commit 07da39f71d36fb547749a5b16aa8892e621a7e4a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 31 21:22:01 2019 +0000
upstream: ssh-agent support for U2F/FIDO keys
feedback & ok markus@
OpenBSD-Commit-ID: bb544a44bc32e45d2ec8bf652db2046f38360acb
commit eebec620c9519c4839d781c4d5b6082152998f82
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 31 21:20:38 2019 +0000
upstream: ssh AddKeysToAgent support for U2F/FIDO keys
feedback & ok markus@
OpenBSD-Commit-ID: ac08e45c7f995fa71f8d661b3f582e38cc0a2f91
commit 486164d060314a7f8bca2a00f53be9e900c5e74d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 31 21:19:56 2019 +0000
upstream: ssh-add support for U2F/FIDO keys
OpenBSD-Commit-ID: 7f88a5181c982687afedf3130c6ab2bba60f7644
commit b9dd14d3091e31fb836f69873d3aa622eb7b4a1c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 31 21:19:14 2019 +0000
upstream: add new agent key constraint for U2F/FIDO provider
feedback & ok markus@
OpenBSD-Commit-ID: d880c380170704280b4003860a1744d286c7a172
commit 884416bdb10468f1252e4d7c13d51b43dccba7f6
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 31 21:18:28 2019 +0000
upstream: ssh client support for U2F/FIDO keys
OpenBSD-Commit-ID: eb2cfa6cf7419a1895e06e398ea6d41516c5b0bc
commit 01a0670f69c5b86e471e033b92145d6c7cc77c58
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 31 21:17:49 2019 +0000
upstream: Separate myproposal.h userauth pubkey types
U2F/FIDO keys are not supported for host authentication, so we need
a separate list for user keys.
feedback & ok markus@
OpenBSD-Commit-ID: 7fe2e6ab85f9f2338866e5af8ca2d312abbf0429
commit 23f38c2d8cda3fad24e214e1f0133c42435b54ee
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 31 21:17:09 2019 +0000
upstream: ssh-keygen support for generating U2F/FIDO keys
OpenBSD-Commit-ID: 6ce04f2b497ac9dd8c327f76f1e6c724fb1d1b37
commit ed3467c1e16b7396ff7fcf12d2769261512935ec
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 31 21:16:20 2019 +0000
upstream: U2F/FIDO middleware interface
Supports enrolling (generating) keys and signatures.
feedback & ok markus@
OpenBSD-Commit-ID: 73d1dd5939454f9c7bd840f48236cba41e8ad592
commit 02bb0768a937e50bbb236efc2bbdddb1991b1c85
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 31 21:15:14 2019 +0000
upstream: Initial infrastructure for U2F/FIDO support
Key library support: including allocation, marshalling public/private
keys and certificates, signature validation.
feedback & ok markus@
OpenBSD-Commit-ID: a17615ba15e0f7932ac4360cb18fc9a9544e68c7
commit 57ecc10628b04c384cbba2fbc87d38b74cd1199d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Oct 31 21:14:17 2019 +0000
upstream: Protocol documentation for U2F/FIDO keys in OpenSSH
OpenBSD-Commit-ID: 8f3247317c2909870593aeb306dff848bc427915
commit f4fdcd2b7a2bbf5d8770d44565173ca5158d4dcb
Author: Damien Miller <djm@mindrot.org>
Date: Fri Nov 1 08:36:16 2019 +1100
Missing unit test files
commit 1bcd1169c5221688418fa38606e9c69055b72451
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Oct 29 19:45:03 2019 +1100
Add implementation of localtime_r.
commit 2046ed16c1202431b0307674c33a123a113e8297
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Oct 29 07:47:27 2019 +0000
upstream: Signal handler cleanup: remove leftover support for
unreliable signals and now-unneeded save and restore of errno. ok deraadt@
markus@
OpenBSD-Commit-ID: 01dd8a1ebdd991c8629ba1f5237283341a93cd88
commit 70fc9a6ca4dd33cb2dd400a4dad5db9683a3d284
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Tue Oct 22 08:50:35 2019 +0000
upstream: fixes from lucas;
OpenBSD-Commit-ID: 4c4bfd2806c5bbc753788ffe19c5ee13aaf418b2
commit 702368aa4381c3b482368257ac574a87b5a80938
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Oct 22 07:06:35 2019 +0000
upstream: Import regenerated moduli file.
OpenBSD-Commit-ID: 58ec755be4e51978ecfee73539090eb68652a987
commit 5fe81da22652f8caa63e9e3a1af519a85d36337e
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Oct 28 21:19:47 2019 +1100
Fix ifdefs to not mask needed bits.
commit 7694e9d2fb5785bbdd0920dce7a160bd79feaf00
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Oct 28 17:05:36 2019 +1100
Only use RLIMIT_NOFILE if it's defined.
commit d561b0b2fa2531b4cc3bc70a7d657c6485c9fd0b
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Oct 28 16:09:04 2019 +1100
Make sure we have struct statfs before using.
commit 2912596aecfcf48e5115c7a906d1e664f7717a4b
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Oct 28 16:06:59 2019 +1100
Define UINT32_MAX if needed.
commit 7169e31121e8c8cc729b55154deb722ae495b316
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Oct 28 16:00:45 2019 +1100
Move utimensat definition into timespec section.
Since utimensat uses struct timespec, move it to the section where we
define struct timespec when needed.
commit 850ec1773d656cbff44d78a79e369dc262ce5853
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Oct 28 15:57:22 2019 +1100
Wrap OpenSSL bits in WITH_OPENSSL.
commit 6fc7e1c6fec3ba589869ae98e968c0e5e2e4695b
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Oct 28 15:53:25 2019 +1100
Wrap poll.h includes in HAVE_POLL_H.
commit 9239a18f96905cc1a353e861e33af093652f24e7
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Oct 24 14:39:49 2019 +1100
Add a function call stackprotector tests.
Including a function call in the test programs for the gcc stack
protector flag tests exercises more of the compiler and makes it more
likely it'll detect problems.
commit b9705393be4612fd5e29d0cd8e7cf2b66ed19eb7
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Oct 22 18:09:22 2019 +1100
Import regenerated moduli file.
commit 76ed2199491397e0f9902ade80d5271e4a9b2630
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 16 06:05:39 2019 +0000
upstream: potential NULL dereference for revoked hostkeys; reported
by krishnaiah bommu
OpenBSD-Commit-ID: 35ff685e7cc9dd2e3fe2e3dfcdcb9bc5c79f6506
commit 6500c3bc71bf4fe14972c1177e6b93f1164d07a4
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 16 06:03:30 2019 +0000
upstream: free buf before return; reported by krishnaiah bommu
OpenBSD-Commit-ID: 091bb23a6e913af5d4f72c50030b53ce1cef4de1
commit d7d116b6d9e6cb79cc235e9801caa683d3db3181
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Oct 14 06:00:02 2019 +0000
upstream: memleak in error path; spotted by oss-fuzz, ok markus@
OpenBSD-Commit-ID: d6ed260cbbc297ab157ad63931802fb1ef7a4266
commit 9b9e3ca6945351eefb821ff783a4a8e6d9b98b9a
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Oct 11 14:12:16 2019 +1100
Re-add SA_RESTART to mysignal.
This makes mysignal implement reliable BSD semantics according to
Stevens' APUE. This was first attempted in 2001 but was reverted
due to problems with HP-UX 10.20 and select() and possibly grantpt().
Modern systems should be fine with it, but if any current platforms have
a problem with it now we can disable it just for those. ok djm@
commit 0bd312a362168c1eae3cd6b3889395a78e6fd0f8
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Oct 10 09:42:03 2019 +1100
Fix ifdef typo for declaration of memmem.
Fixes build on IRIX. bz#3081.
commit 01ce1cd402d5eecde2bba35b67e08f5b266b37fd
Author: Abhishek Arya <inferno@chromium.org>
Date: Tue Oct 8 20:19:18 2019 -0700
Update README.md
commit 1ba130ac8fb2884307f658126f04578f8aef409e
Author: Damien Miller <djm@mindrot.org>
Date: Wed Oct 9 13:49:35 2019 +1100
add a fuzzer for private key parsing
commit cdf1d0a9f5d18535e0a18ff34860e81a6d83aa5c
Author: Damien Miller <djm@mindrot.org>
Date: Wed Oct 9 11:31:03 2019 +1100
prepare for 8.1 release
commit 3b4e56d740b74324e2d7542957cad5a11518f455
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 9 00:04:57 2019 +0000
upstream: openssh-8.1
OpenBSD-Commit-ID: 3356bb34e2aa287f0e6d6773c9ae659dc680147d
commit 29e0ecd9b4eb3b9f305e2240351f0c59cad9ef81
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 9 00:04:42 2019 +0000
upstream: fix an unreachable integer overflow similar to the XMSS
case, and some other NULL dereferences found by fuzzing.
fix with and ok markus@
OpenBSD-Commit-ID: 0f81adbb95ef887ce586953e1cb225fa45c7a47b
commit a546b17bbaeb12beac4c9aeed56f74a42b18a93a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 9 00:02:57 2019 +0000
upstream: fix integer overflow in XMSS private key parsing.
Reported by Adam Zabrocki via SecuriTeam's SSH program.
Note that this code is experimental and not compiled by default.
ok markus@
OpenBSD-Commit-ID: cd0361896d15e8a1bac495ac583ff065ffca2be1
commit c2cc25480ba36ab48c1a577bebb12493865aad87
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Oct 8 22:40:39 2019 +0000
upstream: Correct type for end-of-list sentinel; fixes initializer
warnings on some platforms. ok deraadt.
OpenBSD-Commit-ID: a990dbc2dac25bdfa07e79321349c73fd991efa2
commit e827aedf8818e75c0016b47ed8fc231427457c43
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Oct 7 23:10:38 2019 +0000
upstream: reversed test yielded incorrect debug message
OpenBSD-Commit-ID: 78bb512d04cfc238adb2c5b7504ac93eecf523b3
commit 8ca491d29fbe26e5909ce22b344c0a848dc28d55
Author: Damien Miller <djm@mindrot.org>
Date: Tue Oct 8 17:05:57 2019 +1100
depend
commit 86a0323374cbd404629e75bb320b3fa1c16aaa6b
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Oct 9 09:36:06 2019 +1100
Make MAKE_CLONE no-op macro more correct.
Similar to the previous change to DEF_WEAK, some compilers don't like
the empty statement, so convert into a no-op function prototype.
commit cfc1897a2002ec6c4dc879b24e8b3153c87ea2cf
Author: Damien Miller <djm@mindrot.org>
Date: Wed Oct 9 09:06:35 2019 +1100
wrap stdint.h include in HAVE_STDINT_H
make the indenting a little more consistent too..
Fixes Solaris 2.6; reported by Tom G. Christensen
commit 13b3369830a43b89a503915216a23816d1b25744
Author: Damien Miller <djm@mindrot.org>
Date: Tue Oct 8 15:32:02 2019 +1100
avoid "return (value)" in void-declared function
spotted by Tim Rice; ok dtucker
commit 0c7f8d2326d812b371f7afd63aff846973ec80a4
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Oct 8 14:44:50 2019 +1100
Make DEF_WEAK more likely to be correct.
Completely nop-ing out DEF_WEAK leaves an empty statemment which some
compilers don't like. Replace with a no-op function template. ok djm@
commit b1e79ea8fae9c252399677a28707661d85c7d00c
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sun Oct 6 11:49:50 2019 +0000
upstream: Instead of running sed over the whole log to remove CRs,
remove them only where it's needed (and confuses test(1) on at least OS X in
portable).
OpenBSD-Regress-ID: a6ab9b4bd1d33770feaf01b2dfb96f9e4189d2d0
commit 8dc7d6b75a7f746fdd056acd41dffc0a13557a4c
Author: Eduardo Barretto <ebarretto@linux.vnet.ibm.com>
Date: Tue May 9 13:33:30 2017 -0300
Enable specific ioctl call for EP11 crypto card (s390)
The EP11 crypto card needs to make an ioctl call, which receives an
specific argument. This crypto card is for s390 only.
Signed-off-by: Eduardo Barretto <ebarretto@linux.vnet.ibm.com>
commit 07f2c7f34951c04d2cd796ac6c80e47c56c4969e
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Oct 4 04:31:59 2019 +0000
upstream: fix memory leak in error path; bz#3074 patch from
krishnaiah.bommu@intel.com, ok dtucker
OpenBSD-Commit-ID: d031853f3ecf47b35a0669588f4d9d8e3b307b3c
commit b7fbc75e119170f4d15c94a7fda4a1050e0871d6
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Oct 4 04:13:39 2019 +0000
upstream: space
OpenBSD-Commit-ID: 350648bcf00a2454e7ef998b7d88e42552b348ac
commit 643ab68c79ac1644f4a31e36928c2bfc8a51db3c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Oct 4 03:39:19 2019 +0000
upstream: more sshsig regress tests: check key revocation, the
check-novalidate signature test mode and signing keys in ssh-agent.
From Sebastian Kinne (slightly tweaked)
OpenBSD-Regress-ID: b39566f5cec70140674658cdcedf38752a52e2e2
commit 714031a10bbe378a395a93cf1040f4ee1451f45f
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Oct 4 03:26:58 2019 +0000
upstream: Check for gmtime failure in moduli generation. Based on
patch from krishnaiah.bommu@intel.com, ok djm@
OpenBSD-Commit-ID: 4c6a4cde0022188ac83737de08da0e875704eeaa
commit 6918974405cc28ed977f802fd97a9c9a9b2e141b
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Thu Oct 3 17:07:50 2019 +0000
upstream: use a more common options order in SYNOPSIS and sync
usage(); while here, no need for Bk/Ek;
ok dtucker
OpenBSD-Commit-ID: 38715c3f10b166f599a2283eb7bc14860211bb90
commit feff96b7d4c0b99307f0459cbff128aede4a8984
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 2 09:50:50 2019 +0000
upstream: thinko in previous; spotted by Mantas
=?UTF-8?q?=20Mikul=C4=97nas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
OpenBSD-Commit-ID: ffa3f5a45e09752fc47d9041e2203ee2ec15b24d
commit b5a89eec410967d6b712665f8cf0cb632928d74b
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 2 08:07:13 2019 +0000
upstream: make signature format match PROTOCO
=?UTF-8?q?=20as=20a=20string,=20not=20raw=20bytes.=20Spotted=20by=20Manta?=
=?UTF-8?q?s=20Mikul=C4=97nas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
OpenBSD-Commit-ID: 80fcc6d52893f80c6de2bedd65353cebfebcfa8f
commit dc6f81ee94995deb11bbf7e19801022c5f6fd90a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 2 08:05:50 2019 +0000
upstream: ban empty namespace strings for s
=?UTF-8?q?shsig;=20spotted=20by=20Mantas=20Mikul=C4=97nas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
OpenBSD-Commit-ID: 7c5bcf40bed8f4e826230176f4aa353c52aeb698
commit fa5bd8107e0e2b3e1e184f55d0f9320c119f65f0
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Oct 2 14:30:55 2019 +1000
Put ssherr.h back as it's actually needed.
commit 3ef92a657444f172b61f92d5da66d94fa8265602
Author: Lonnie Abelbeck <lonnie@abelbeck.com>
Date: Tue Oct 1 09:05:09 2019 -0500
Deny (non-fatal) shmget/shmat/shmdt in preauth privsep child.
New wait_random_seeded() function on OpenSSL 1.1.1d uses shmget, shmat, and shmdt
in the preauth codepath, deny (non-fatal) in seccomp_filter sandbox.
commit edd1d3a6261aecbf9a55944fd7be1db83571b46e
Author: Damien Miller <djm@mindrot.org>
Date: Wed Oct 2 10:54:28 2019 +1000
remove duplicate #includes
Prompted by Jakub Jelen
commit 13c508dfed9f25e6e54c984ad00a74ef08539e70
Author: Damien Miller <djm@mindrot.org>
Date: Wed Oct 2 10:51:15 2019 +1000
typo in comment
commit d0c3ac427f6c52b872d6617421421dd791664445
Author: djm@openbsd.org <djm@openbsd.org>
Date: Wed Oct 2 00:42:30 2019 +0000
upstream: remove some duplicate #includes
OpenBSD-Commit-ID: ed6827ab921eff8027669848ef4f70dc1da4098c
commit 084682786d9275552ee93857cb36e43c446ce92c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Oct 1 10:22:53 2019 +0000
upstream: revert unconditional forced login implemented in r1.41 of
ssh-pkcs11.c; r1.45 added a forced login as a fallback for cases where the
token returns no objects and this is less disruptive for users of tokens
directly in ssh (rather than via ssh-agent) and in ssh-keygen
bz3006, patch from Jakub Jelen; ok markus
OpenBSD-Commit-ID: 33d6df589b072094384631ff93b1030103b3d02e
commit 6c91d42cce3f055917dc3fd2c305dfc5b3b584b3
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Sun Sep 29 16:31:57 2019 +0000
upstream: group and sort single letter options; ok deraadt
OpenBSD-Commit-ID: e1480e760a2b582f79696cdcff70098e23fc603f
commit 3b44bf39ff4d7ef5d50861e2e9dda62d2926d2fe
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Fri Sep 27 20:03:24 2019 +0000
upstream: fix the DH-GEX text in -a; because this required a comma,
i added a comma to the first part, for balance...
OpenBSD-Commit-ID: 2c3464e9e82a41e8cdfe8f0a16d94266e43dbb58
commit 3e53ef28fab53094e3b19622ba0e9c3d5fe71273
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Tue Sep 24 12:50:46 2019 +0000
upstream: identity_file[] should be PATH_MAX, not the arbitrary
number 1024
OpenBSD-Commit-ID: e775f94ad47ce9ab37bd1410d7cf3b7ea98b11b7
commit 90d4b2541e8c907793233d9cbd4963f7624f4174
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Fri Sep 20 18:50:58 2019 +0000
upstream: new sentence, new line;
OpenBSD-Commit-ID: c35ca5ec07be460e95e7406af12eee04a77b6698
commit fbec7dba01b70b49ac47f56031310865dff86200
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Sep 30 18:01:12 2019 +1000
Include stdio.h for snprintf.
Patch from vapier@gentoo.org.
commit 0a403bfde71c4b82147473298d3a60b4171468bd
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Sep 30 14:11:42 2019 +1000
Add SKIP_LTESTS for skipping specific tests.
commit 4d59f7a5169c451ebf559aedec031ac9da2bf80c
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Sep 27 05:25:12 2019 +0000
upstream: Test for empty result in expected bits. Remove CRs from log
as they confuse tools on some platforms. Re-enable the 3des-cbc test.
OpenBSD-Regress-ID: edf536d4f29fc1ba412889b37247a47f1b49d250
commit 7c817d129e2d48fc8a6f7965339313023ec45765
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Sep 27 15:26:22 2019 +1000
Re-enable dhgex test.
Since we've added larger fallback groups to dh.c this test will pass
even if there is no moduli file installed on the system.
commit c1e0a32fa852de6d1c82ece4f76add0ab0ca0eae
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Sep 24 21:17:20 2019 +1000
Add more ToS bits, currently only used by netcat.
commit 5a273a33ca1410351cb484af7db7c13e8b4e8e4e
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Sep 19 15:41:23 2019 +1000
Privsep is now required.
commit 8aa2aa3cd4d27d14e74b247c773696349472ef20
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Sep 16 03:23:02 2019 +0000
upstream: Allow testing signature syntax and validity without verifying
that a signature came from a trusted signer. To discourage accidental or
unintentional use, this is invoked by the deliberately ugly option name
"check-novalidate"
from Sebastian Kinne
OpenBSD-Commit-ID: cea42c36ab7d6b70890e2d8635c1b5b943adcc0b
commit 7047d5afe3103f0f07966c05b810682d92add359
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Sep 13 04:52:34 2019 +0000
upstream: clarify that IdentitiesOnly also applies to the default
~/.ssh/id_* keys; bz#3062
OpenBSD-Commit-ID: 604be570e04646f0f4a17026f8b2aada6a585dfa
commit b36ee3fcb2f1601693b1b7fd60dd6bd96006ea75
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Sep 13 04:36:43 2019 +0000
upstream: Plug mem leaks on error paths, based in part on github
pr#120 from David Carlier. ok djm@.
OpenBSD-Commit-ID: c57adeb1022a8148fc86e5a88837b3b156dbdb7e
commit 2aefdf1aef906cf7548a2e5927d35aacb55948d4
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Sep 13 04:31:19 2019 +0000
upstream: whitespace
OpenBSD-Commit-ID: 57a71dd5f4cae8d61e0ac631a862589fb2bfd700
commit fbe24b142915331ceb2a3a76be3dc5b6d204fddf
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Sep 13 04:27:35 2019 +0000
upstream: allow %n to be expanded in ProxyCommand strings
From Zachary Harmany via github.com/openssh/openssh-portable/pull/118
ok dtucker@
OpenBSD-Commit-ID: 7eebf1b7695f50c66d42053d352a4db9e8fb84b6
commit 2ce1d11600e13bee0667d6b717ffcc18a057b821
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Sep 13 04:07:42 2019 +0000
upstream: clarify that ConnectTimeout applies both to the TCP
connection and to the protocol handshake/KEX. From Jean-Charles Longuet via
Github PR140
OpenBSD-Commit-ID: ce1766abc6da080f0d88c09c2c5585a32b2256bf
commit df780114278f406ef7cb2278802a2660092fff09
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Sep 9 02:31:19 2019 +0000
upstream: Fix potential truncation warning. ok deraadt.
OpenBSD-Commit-ID: d87b7e3a94ec935e8194e7fce41815e22804c3ff
commit ec0e6243660bf2df30c620a6a0d83eded376c9c6
Author: Damien Miller <djm@mindrot.org>
Date: Fri Sep 13 13:14:39 2019 +1000
memleak of buffer in sshpam_query
coverity report via Ed Maste; ok dtucker@
commit c17e4638e5592688264fc0349f61bfc7b4425aa5
Author: Damien Miller <djm@mindrot.org>
Date: Fri Sep 13 13:12:42 2019 +1000
explicitly test set[ug]id() return values
Legacy !_POSIX_SAVED_IDS path only; coverity report via Ed Maste
ok dtucker@
commit 91a2135f32acdd6378476c5bae475a6e7811a6a2
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Fri Sep 6 14:45:34 2019 +0000
upstream: Allow prepending a list of algorithms to the default set
by starting the list with the '^' character, e.g.
HostKeyAlgorithms ^ssh-ed25519
Ciphers ^aes128-gcm@openssh.com,aes256-gcm@openssh.com
ok djm@ dtucker@
OpenBSD-Commit-ID: 1e1996fac0dc8a4b0d0ff58395135848287f6f97
commit c8bdd2db77ac2369d5cdee237656f266c8f41552
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Sep 6 07:53:40 2019 +0000
upstream: key conversion should fail for !openssl builds, not fall
through to the key generation code
OpenBSD-Commit-ID: b957436adc43c4941e61d61958a193a708bc83c9
commit 823f6c37eb2d8191d45539f7b6fa877a4cb4ed3d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Sep 6 06:08:11 2019 +0000
upstream: typo in previous
OpenBSD-Commit-ID: 7c3b94110864771a6b80a0d8acaca34037c3c96e
commit 6a710d3e06fd375e2c2ae02546b9541c488a2cdb
Author: Damien Miller <djm@mindrot.org>
Date: Sun Sep 8 14:48:11 2019 +1000
needs time.h for --without-openssl
commit f61f29afda6c71eda26effa54d3c2e5306fd0833
Author: Damien Miller <djm@mindrot.org>
Date: Sat Sep 7 19:25:00 2019 +1000
make unittests pass for no-openssl case
commit 105e1c9218940eb53473f55a9177652d889ddbad
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Sep 6 05:59:41 2019 +0000
upstream: avoid compiling certain files that deeply depend on
libcrypto when WITH_OPENSSL isn't set
OpenBSD-Commit-ID: 569f08445c27124ec7c7f6c0268d844ec56ac061
commit 670104b923dd97b1c06c0659aef7c3e52af571b2
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Sep 6 05:23:55 2019 +0000
upstream: fixes for !WITH_OPENSSL compilation; ok dtucker@
OpenBSD-Commit-ID: 7fd68eaa9e0f7482b5d4c7e8d740aed4770a839f
commit be02d7cbde3d211ec2ed2320a1f7d86b2339d758
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Sep 6 04:53:27 2019 +0000
upstream: lots of things were relying on libcrypto headers to
transitively include various system headers (mostly stdlib.h); include them
explicitly
OpenBSD-Commit-ID: 5b522f4f2d844f78bf1cc4f3f4cc392e177b2080
commit d05aaaaadcad592abfaa44540928e0c61ef72ebb
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Sep 6 03:30:42 2019 +0000
upstream: remove leakmalloc reference; we used this early when
refactoring but not since
OpenBSD-Commit-ID: bb28ebda8f7c490b87b37954044a6cdd43a7eb2c
commit 1268f0bcd8fc844ac6c27167888443c8350005eb
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Sep 6 04:24:06 2019 +0000
upstream: Check for RSA support before using it for the user key,
otherwise use ed25519 which is supported when built without OpenSSL.
OpenBSD-Regress-ID: 3d23ddfe83c5062f00ac845d463f19a2ec78c0f7
commit fd7a2dec652b9efc8e97f03f118f935dce732c60
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Sep 6 14:07:10 2019 +1000
Provide explicit path to configure-check.
On some platforms (at least OpenBSD) make won't search VPATH for target
files, so building out-of-tree will fail at configure-check. Provide
explicit path. ok djm@
commit 00865c29690003b4523cc09a0e104724b9f911a4
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Sep 6 01:58:50 2019 +0000
upstream: better error code for bad arguments; inspired by
OpenBSD-Commit-ID: dfc263b6041de7f0ed921a1de0b81ddebfab1e0a
commit afdf27f5aceb4973b9f5308f4310c6e3fd8db1fb
Author: Damien Miller <djm@mindrot.org>
Date: Thu Sep 5 21:38:40 2019 +1000
revert config.h/config.h.in freshness checks
turns out autoreconf and configure don't touch some files if their content
doesn't change, so the mtime can't be relied upon in a makefile rule
commit a97609e850c57bd2cc2fe7e175fc35cb865bc834
Author: Damien Miller <djm@mindrot.org>
Date: Thu Sep 5 20:54:39 2019 +1000
extend autoconf freshness test
make it cover config.h.in and config.h separately
commit 182297c10edb21c4856c6a38326fd04d81de41a5
Author: Damien Miller <djm@mindrot.org>
Date: Thu Sep 5 20:34:54 2019 +1000
check that configure/config.h is up to date
Ensure they are newer than the configure.ac / aclocal.m4 source
commit 7d6034bd020248e9fc0f8c39c71c858debd0d0c1
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Sep 5 10:05:51 2019 +0000
upstream: if a PKCS#11 token returns no keys then try to login and
refetch them. Based on patch from Jakub Jelen; bz#2430 ok markus@
OpenBSD-Commit-ID: ab53bd6ddd54dd09e54a8bfbed1a984496f08b43
commit 76f09bd95917862101b740afb19f4db5ccc752bf
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Sep 5 09:35:19 2019 +0000
upstream: sprinkle in some explicit errors here, otherwise the
percolate all the way up to dispatch_run_fatal() and lose all meaninful
context
to help with bz#3063; ok dtucker@
OpenBSD-Commit-ID: 5b2da83bb1c4a3471444b7910b2120ae36438a0a
commit 0ea332497b2b2fc3995f72f6bafe9d664c0195b3
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Sep 5 09:25:13 2019 +0000
upstream: only send ext_info for KEX_INITIAL; bz#2929 ok dtucker
OpenBSD-Commit-ID: 00f5c6062f6863769f5447c6346f78c05d2e4a63
commit f23d91f9fa7f6f42e70404e000fac88aebfe3076
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Thu Sep 5 05:47:23 2019 +0000
upstream: macro fix; ok djm
OpenBSD-Commit-ID: e891dd6c7996114cb32f0924cb7898ab55efde6e
commit 8b57337c1c1506df2bb9f039d0628a6de618566b
Author: Damien Miller <djm@mindrot.org>
Date: Thu Sep 5 15:46:39 2019 +1000
update fuzzing makefile to more recent clang
commit ae631ad77daf8fd39723d15a687cd4b1482cbae8
Author: Damien Miller <djm@mindrot.org>
Date: Thu Sep 5 15:45:32 2019 +1000
fuzzer for sshsig allowed_signers option parsing
commit 69159afe24120c97e5ebaf81016c85968afb903e
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Sep 5 05:42:59 2019 +0000
upstream: memleak on error path; found by libfuzzer
OpenBSD-Commit-ID: 34d44cb0fb5bdb5fcbc6b02b804e71b20a7a5fc7
commit bab6feb01f9924758ca7129dba708298a53dde5f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Sep 5 04:55:32 2019 +0000
upstream: expose allowed_signers options parsing code in header for
fuzzing
rename to make more consistent with philosophically-similar auth
options parsing API.
OpenBSD-Commit-ID: 0c67600ef04187f98e2912ca57b60c22a8025b7c
commit 4f9d75fbafde83d428e291516f8ce98e6b3a7c4b
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Wed Sep 4 20:31:15 2019 +0000
upstream: Call comma-separated lists as such to clarify semantics.
Options such as Ciphers take values that may be a list of ciphers; the
complete list, not indiviual elements, may be prefixed with a dash or plus
character to remove from or append to the default list, respectively.
Users might read the current text as if each elment took an optional prefix,
so tweak the wording from "values" to "list" to prevent such ambiguity for
all options supporting these semantics.
Fix instances missed in first commit. ok jmc@ kn@
OpenBSD-Commit-ID: 7112522430a54fb9f15a7a26d26190ed84d5e417
commit db1e6f60f03641b2d17e0ab062242609f4ed4598
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Wed Sep 4 05:56:54 2019 +0000
upstream: tweak previous;
OpenBSD-Commit-ID: 0abd728aef6b5b35f6db43176aa83b7e3bf3ce27
commit 0f44e5956c7c816f6600f2a47be4d7bb5a8d711d
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Tue Sep 3 20:51:49 2019 +0000
upstream: repair typo and editing mishap
OpenBSD-Commit-ID: d125ab720ca71ccf9baf83e08ddc8c12a328597e
commit f4846dfc6a79f84bbc6356ae3184f142bacedc24
Author: Damien Miller <djm@mindrot.org>
Date: Thu Sep 5 11:09:28 2019 +1000
Fuzzer harness for sshsig
commit b08a6bc1cc7750c6f8a425d1cdbd86552fffc637
Author: Damien Miller <djm@mindrot.org>
Date: Tue Sep 3 18:45:42 2019 +1000
oops; missed including the actual file
commit 1a72c0dd89f09754df443c9576dde624a17d7dd0
Author: Damien Miller <djm@mindrot.org>
Date: Tue Sep 3 18:44:10 2019 +1000
portability fixes for sshsig
commit 6d6427d01304d967e58544cf1c71d2b4394c0522
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Sep 3 08:37:45 2019 +0000
upstream: regress test for sshsig; feedback and ok markus@
OpenBSD-Regress-ID: 74c0974f2cdae8d9599b9d76a09680bae55d8a8b
commit 59650f0eaf65115afe04c39abfb93a4fc994ec55
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Sep 3 08:37:06 2019 +0000
upstream: only add plain keys to prevent any certs laying around
from confusing the test.
OpenBSD-Regress-ID: b8f1508f822bc560b98dea910e61ecd76f34100f
commit d637c4aee6f9b5280c13c020d7653444ac1fcaa5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Sep 3 08:35:27 2019 +0000
upstream: sshsig tweaks and improvements from and suggested by
Markus
ok markus/me
OpenBSD-Commit-ID: ea4f46ad5a16b27af96e08c4877423918c4253e9
commit 2a9c9f7272c1e8665155118fe6536bebdafb6166
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Sep 3 08:34:19 2019 +0000
upstream: sshsig: lightweight signature and verification ability
for OpenSSH
This adds a simple manual signature scheme to OpenSSH.
Signatures can be made and verified using ssh-keygen -Y sign|verify
Signatures embed the key used to make them. At verification time, this
is matched via principal name against an authorized_keys-like list
of allowed signers.
Mostly by Sebastian Kinne w/ some tweaks by me
ok markus@
OpenBSD-Commit-ID: 2ab568e7114c933346616392579d72be65a4b8fb
commit 5485f8d50a5bc46aeed829075ebf5d9c617027ea
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Sep 3 08:32:11 2019 +0000
upstream: move authorized_keys option parsing helpsers to misc.c
and make them public; ok markus@
OpenBSD-Commit-ID: c18bcb2a687227b3478377c981c2d56af2638ea2
commit f8df0413f0a057b6a3d3dd7bd8bc7c5d80911d3a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Sep 3 08:31:20 2019 +0000
upstream: make get_sigtype public as sshkey_get_sigtype(); ok
markus@
OpenBSD-Commit-ID: 01f8cdbec63350490d2249f41112c5780d1cfbb8
commit dd8002fbe63d903ffea5be7b7f5fc2714acab4a0
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Sep 3 08:30:47 2019 +0000
upstream: move advance_past_options to authfile.c and make it
public; ok markus@
OpenBSD-Commit-ID: edda2fbba2c5b1f48e60f857a2010479e80c5f3c
commit c72d78ccbe642e08591a626e5de18381489716e0
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Sep 3 08:29:58 2019 +0000
upstream: move skip_space() to misc.c and make it public; ok
markus@
OpenBSD-Commit-ID: caa77e8a3b210948e29ad3e28c5db00852961eae
commit 06af3583f46e2c327fdd44d8a95b8b4e8dfd8db5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Sep 3 08:29:15 2019 +0000
upstream: authfd: add function to check if key is in agent
This commit adds a helper function which allows the caller to
check if a given public key is present in ssh-agent.
work by Sebastian Kinne; ok markus@
OpenBSD-Commit-ID: d43c5826353e1fdc1af71eb42961b30782c7bd13
commit 2ab5a8464870cc4b29ddbe849bbbc255729437bf
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Sep 3 08:28:30 2019 +0000
upstream: fix memleak in ssh_free_identitylist(); ok markus@
OpenBSD-Commit-ID: aa51f77ae2c5330a1f61b2d22933f24a443f9abf
commit 85443f165b4169b2a448b3e24bc1d4dc5b3156a4
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Sep 3 08:27:52 2019 +0000
upstream: factor out confirm_overwrite(); ok markus@
OpenBSD-Commit-ID: 304e95381b39c774c8fced7e5328b106a3ff0400
commit 9a396e33685633581c67d5ad9664570ef95281f2
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Sep 2 23:46:46 2019 +0000
upstream: constify an argument
OpenBSD-Commit-ID: 724bafc9f993746ad4303e95bede2c030de6233b
commit b52c0c2e64988277a35a955a474d944967059aeb
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Sep 2 00:19:25 2019 +0000
upstream: downgrade PKCS#11 "provider returned no slots" warning
from log level error to debug. This is common when attempting to enumerate
keys on smartcard readers with no cards plugged in. bz#3058 ok dtucker@
OpenBSD-Commit-ID: bb8839ddeb77c271390488af1b771041d43e49c6
commit 0713322e18162463c5ab5ddfb9f935055ca775d8
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Sep 1 23:47:32 2019 +0000
upstream: print comment when printing pubkey from private
bz#3052; ok dtucker
OpenBSD-Commit-ID: a91b2a8d5f1053d34d7fce44523c53fb534ba914
commit 368f1cc2fbd6ad10c66bc1b67c2c04aebf8a04a8
Author: Damien Miller <djm@mindrot.org>
Date: Mon Sep 2 10:28:42 2019 +1000
fixed test in OSX closefrom() replacement
from likan_999.student AT sina.com
commit 6b7c53498def19a14dd9587bf521ab6dbee8988f
Author: Damien Miller <djm@mindrot.org>
Date: Mon Sep 2 10:22:02 2019 +1000
retain Solaris PRIV_FILE_LINK_ANY in sftp-server
Dropping this privilege removes the ability to create hard links to
files owned by other users. This is required for the legacy sftp rename
operation.
bz#3036; approach ok Alex Wilson (the original author of the Solaris
sandbox/pledge replacement code)
commit e50f808712393e86d69e42e9847cdf8d473412d7
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Aug 30 05:08:28 2019 +0000
upstream: Use ed25519 for most hostkey rotation tests since it's
supported even when built without OpenSSL. Use RSA for the secondary type
test if supported, otherwise skip it. Fixes this test for !OpenSSL builds.
OpenBSD-Regress-ID: 101cb34a84fd974c623bdb2e496f25a6e91be109
commit 5e4796c47dd8d6c38fb2ff0b3e817525fed6040d
Author: bluhm@openbsd.org <bluhm@openbsd.org>
Date: Thu Aug 22 21:47:27 2019 +0000
upstream: Test did not compile due to missing symbols. Add source
sshbuf-misc.c to regress as it was done in ssh make file. from Moritz Buhl
OpenBSD-Regress-ID: 9e1c23476bb845f3cf3d15d9032da3ed0cb2fcf5
commit e0e7e3d0e26f2c30697e6d0cfc293414908963c7
Author: Damien Miller <djm@mindrot.org>
Date: Fri Aug 30 14:26:19 2019 +1000
tweak warning flags
Enable -Wextra if compiler supports it
Set -Wno-error=format-truncation if available to prevent expected
string truncations in openbsd-compat from breaking -Werror builds
commit 28744182cf90e0073b76a9e98de58a47e688b2c4
Author: Damien Miller <djm@mindrot.org>
Date: Fri Aug 30 13:21:38 2019 +1000
proc_pidinfo()-based closefrom() for OS X
Refactor closefrom() to use a single brute-force close() loop fallback.
Based on patch from likan_999.student@sina.com in bz#3049. ok dtucker@
commit dc2ca588144f088a54febebfde3414568dc73d5f
Author: kn@openbsd.org <kn@openbsd.org>
Date: Fri Aug 16 11:16:32 2019 +0000
upstream: Call comma-separated lists as such to clarify semantics
Options such as Ciphers take values that may be a list of ciphers; the
complete list, not indiviual elements, may be prefixed with a dash or plus
character to remove from or append to the default list respectively.
Users might read the current text as if each elment took an optional prefix,
so tweak the wording from "values" to "list" to prevent such ambiguity for
all options supporting this semantics (those that provide a list of
available elements via "ssh -Q ...").
Input and OK jmc
OpenBSD-Commit-ID: 4fdd175b0e5f5cb10ab3f26ccc38a93bb6515d57
commit c4736f39e66729ce2bf5b06ee6b391e092b48f47
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Aug 16 06:35:27 2019 +0000
upstream: include sshbuf-misc.c in SRCS_BASE
OpenBSD-Commit-ID: 99dd10e72c04e93849981d43d64c946619efa474
commit d0e51810f332fe44ebdba41113aacf319d35f5a5
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Aug 24 15:12:11 2019 +1000
Fix pasto in fallback code.
There is no parameter called "pathname", it should simply be "path".
bz#3059, patch from samuel at cendio.se.
commit e83c989bfd9fc9838b7dfb711d1dc6da81814045
Author: Damien Miller <djm@mindrot.org>
Date: Fri Aug 23 10:19:30 2019 +1000
use SC_ALLOW_ARG_MASK to limit mmap protections
Restrict to PROT_(READ|WRITE|NONE), i.e. exclude PROT_EXEC
commit f6906f9bf12c968debec3671bbf19926ff8a235b
Author: Damien Miller <djm@mindrot.org>
Date: Fri Aug 23 10:08:48 2019 +1000
allow mprotect(2) with PROT_(READ|WRITE|NONE) only
Used by some hardened heap allocators. Requested by Yegor
Timoshenko in https://github.com/openssh/openssh-portable/pull/142
commit e3b6c966b79c3ea5d51b923c3bbdc41e13b96ea0
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Aug 16 06:13:15 2019 +0000
upstream: switch percent_expand() to use sshbuf instead of a limited
fixed buffer; ok markus@
OpenBSD-Commit-ID: 3f9ef20bca5ef5058b48c1cac67c53b9a1d15711
commit 9ab5b9474779ac4f581d402ae397f871ed16b383
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Aug 9 05:05:54 2019 +0000
upstream: produce a useful error message if the user's shell is set
incorrectly during "match exec" processing. bz#2791 reported by Dario
Bertini; ok dtucker
OpenBSD-Commit-ID: cf9eddd6a6be726cb73bd9c3936f3888cd85c03d
commit 8fdbc7247f432578abaaca1b72a0dbf5058d67e5
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Aug 9 04:24:03 2019 +0000
upstream: Change description of TCPKeepAlive from "inactive" to
"unresponsive" to clarify what it checks for. Patch from jblaine at
kickflop.net via github pr#129, ok djm@.
OpenBSD-Commit-ID: 3682f8ec7227f5697945daa25d11ce2d933899e9
commit 7afc45c3ed72672690014dc432edc223b23ae288
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Aug 8 08:02:57 2019 +0000
upstream: Allow the maximimum uint32 value for the argument passed to
-b which allows better error messages from later validation. bz#3050, ok
djm@
OpenBSD-Commit-ID: 10adf6876b2401b3dc02da580ebf67af05861673
commit c31e4f5fb3915c040061981a67224de7650ab34b
Author: naddy@openbsd.org <naddy@openbsd.org>
Date: Mon Aug 5 21:45:27 2019 +0000
upstream: Many key types are supported now, so take care to check
the size restrictions and apply the default size only to the matching key
type. tweak and ok dtucker@
OpenBSD-Commit-ID: b825de92d79cc4cba19b298c61e99909488ff57e
commit 6b39a7b49ebacec4e70e24bfc8ea2f11057aac22
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Mon Aug 5 11:50:33 2019 +0000
upstream: Remove now-redundant perm_ok arg since
sshkey_load_private_type will now return SSH_ERR_KEY_BAD_PERMISSIONS in that
case. Patch from jitendra.sharma at intel.com, ok djm@
OpenBSD-Commit-ID: 07916a17ed0a252591b71e7fb4be2599cb5b0c77
commit d46075b923bf25e6f25959a3f5b458852161cb3e
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Aug 5 21:36:48 2019 +1000
Fix mem leak in unit test.
Patch from jitendra.sharma at intel.com.
commit c4ffb72593c08921cf9291bc05a5ef1d0aaa6891
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Aug 2 01:41:24 2019 +0000
upstream: fix some memleaks in test_helper code
bz#3037 from Jitendra Sharma
OpenBSD-Regress-ID: 71440fa9186f5842a65ce9a27159385c6cb6f751
commit 6e76e69dc0c7712e9ac599af34bd091b0e7dcdb5
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Aug 2 01:23:19 2019 +0000
upstream: typo; from Christian Hesse
OpenBSD-Commit-ID: 82f6de7438ea7ee5a14f44fdf5058ed57688fdc3
commit 49fa065a1bfaeb88a59abdfa4432d3b9c35b0655
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jul 30 05:04:49 2019 +0000
upstream: let sshbuf_find/cmp take a void* for the
search/comparison argument, instead of a u_char*. Saves callers needing to
cast.
OpenBSD-Commit-ID: d63b69b7c5dd570963e682f758f5a47b825605ed
commit 7adf6c430d6fc17901e167bc0789d31638f5c2f8
Author: mestre@openbsd.org <mestre@openbsd.org>
Date: Wed Jul 24 08:57:00 2019 +0000
upstream: When using a combination of a Yubikey+GnuPG+remote
forwarding the gpg-agent (and options ControlMaster+RemoteForward in
ssh_config(5)) then the codepath taken will call mux_client_request_session
-> mm_send_fd -> sendmsg(2). Since sendmsg(2) is not allowed in that codepath
then pledge(2) kills the process.
The solution is to add "sendfd" to pledge(2), which is not too bad considering
a little bit later we reduce pledge(2) to only "stdio proc tty" in that
codepath.
Problem reported and diff provided by Timothy Brown <tbrown at freeshell.org>
OK deraadt@
OpenBSD-Commit-ID: 7ce38b6542bbec00e441595d0a178e970a9472ac
commit 0e2fe18acc1da853a9120c2e9af68e8d05e6503e
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Jul 23 23:06:57 2019 +0000
upstream: Fix typo in CASignatureAlgorithms wherein what should be
a comma is a dot. Patch from hnj2 via github pr#141.
OpenBSD-Commit-ID: 01f5a460438ff1af09aab483c0a70065309445f0
commit e93ffd1a19fc47c49d68ae2fb332433690ecd389
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Jul 29 16:04:01 2019 +1000
Report success of individual tests as well as all.
This puts the "all tests passed" message back at the end where the
test harnesses can find it.
commit 2ad5b36b18bddf2965fe60384c29b3f1d451b4ed
Author: Damien Miller <djm@mindrot.org>
Date: Mon Jul 29 09:49:23 2019 +1000
convert to UTF-8; from Mike Frysinger
commit d31e7c937ba0b97534f373cf5dea34675bcec602
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jul 26 04:22:21 2019 +0000
upstream: Restrict limit-keytype to types supported by build. This
means we have to skip a couple tests when only one key type is supported.
OpenBSD-Regress-ID: 22d05befb9c7ce21ce8dc22acf1ffe9e2ef2e95e
commit 0967a233b8a28907ae8a4a6773c89f21d2ace11b
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Jul 25 18:36:28 2019 +1000
Remove override disabling DH-GEX.
The DH-GEX override doesn't work when build without OpenSSL, and
we'll prefer curve25519 these days, removing the need for it.
commit 061407efc19b41ab4a7485e5adcff2a12befacdb
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Jul 25 09:17:35 2019 +0000
upstream: Only use supported key types during KRL test, preferring
ed25519 since it's supported by both OpenSSL and non-OpenSSL builds.
OpenBSD-Regress-ID: 9f2bb3eadd50fcc8245b1bd8fd6f0e53602f71aa
commit 47f8ff1fa5b76790c1d785815fd13ee6009f8012
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Jul 25 08:48:11 2019 +0000
upstream: Switch keys-command test from rsa to ed25519 since it's
supported for both OpenSSL and non-OpenSSL builds.
OpenBSD-Regress-ID: 174be4be876edd493e4a5c851e5bc579885e7a0a
commit 1e94afdfa8df774ab7dd3bad52912b636dc31bbd
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Jul 25 08:28:15 2019 +0000
upstream: Make certificate tests work with the supported key
algorithms. Allows tests to pass when built without OpenSSL.
OpenBSD-Regress-ID: 617169a6dd9d06db3697a449d9a26c284eca20fc
commit 26bf693661a48b97b6023f702b2af643676ac21a
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Jul 23 13:49:14 2019 +0000
upstream: Construct list of key types to test based on the types
supported by the binaries.
OpenBSD-Regress-ID: fcbd115efacec8ab0ecbdb3faef79ac696cb1d62
commit 773c55b3d1230e8f7714a1b33873c37b85049c74
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Jul 23 13:32:48 2019 +0000
upstream: Only use DSA key type in tests if binaries support it.
OpenBSD-Regress-ID: 770e31fe61dc33ed8eea9c04ce839b33ddb4dc96
commit 159e987a54d92ccd73875e7581ffc64e8927a715
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Jul 24 14:21:19 2019 +1000
Split test targets further.
Splits test into file-tests, t-exec, unit and interop-tests and their
respective dependencies. Should allow running any set individually
without having to build the other dependencies that are not needed
for that specific test.
commit 520d4550a2470106d63e30079bb05ce82f3a4f7d
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Jul 24 11:20:18 2019 +1000
Add lib dependencies for regress binary targets.
commit 4e8d0dd78d5f6142841a07dc8b8c6b4730eaf587
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Jul 24 00:12:51 2019 +1000
Make "unit" a dependency of "test".
commit 4317b2a0480e293e58ba115e47b49d3a384b6568
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jul 23 23:24:47 2019 +1000
upstream rev 1.28: fix comment typo.
commit e0055af2bd39fdb44566ff6594147664e1fac8b8
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jul 23 23:06:22 2019 +1000
Split regress-binaries into two targets.
Split the binaries for the unit tests out into a regress-unit-binaries
target, and add a dependency on it for only the unit tests. This allows
us to run the integration tests only ("make t-exec") without building
the unit tests, which allows us to run a subset of the tests when
building --without-openssl without trying (and failing) to build the
unit tests.
This means there are two targets for "unit" which I *think* is valid
(it works in testing, and makedepend will generate Makefiles of this
form)a but I could be wrong.
commit 7cdf9fdcf11aaaa98c2bd22c92882ea559e772ad
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Jul 23 08:19:29 2019 +0000
upstream: Skip DH group generation test if binaries don't support
DH-GEX.
OpenBSD-Regress-ID: 7c918230d969ecf7656babd6191a74526bffbffd
commit 3a3eab8bb0da3d2f0f32cb85a1a268bcca6e4d69
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Jul 23 07:55:29 2019 +0000
upstream: Only test conversion of key types supported by the
binaries.
OpenBSD-Regress-ID: e3f0938a0a7407e2dfbb90abc3ec979ab6e8eeea
commit 7e66b7d98c6e3f48a1918c3e1940c9b11b10ec63
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Jul 23 07:39:43 2019 +0000
upstream: Only add ssh-dss to allowed key types if it's supported
by the binary.
OpenBSD-Regress-ID: 395a54cab16e9e4ece9aec047ab257954eebd413
commit fd0684b319e664d8821dc4ca3026126dfea3ccf4
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jul 23 22:36:39 2019 +1000
Remove sys/cdefs.h include.
It's not needed on -portable (that's handled by includes.h) and not all
platforms have it.
commit 9634ffbf29b3c2493e69d10b37077b09a8cbf5ff
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jul 23 22:25:44 2019 +1000
Add headers to prevent warnings w/out OpenSSL.
commit 2ea60312e1c08dea88982fec68244f89a40912ff
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jul 23 22:11:50 2019 +1000
Include stdlib.h for free() and calloc().
commit 11cba2a4523fda447e2554ea457484655bedc831
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jul 23 21:51:22 2019 +1000
Re-apply portability changes to current sha2.{c,h}.
Rather than attempt to apply 14 years' worth of changes to OpenBSD's sha2
I imported the current versions directly then re-applied the portability
changes. This also allowed re-syncing digest-libc.c against upstream.
commit 09159594a3bbd363429ee6fafde57ce77986dd7c
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jul 23 20:27:51 2019 +1000
Import current sha2.c and sha2.h from OpenBSD.
These are not changed from their original state, the next commit will
re-apply the portable changes.
commit 2e6035b900cc9d7432d95084e03993d1b426f812
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jul 23 08:11:22 2019 +1000
Rename valgrind "errors" to "failures".
When valgrind is enabled, test-exec.sh counts the number of invocations
that valgrind detects failures in, not the total number of errors detected.
This makes the name to be more accurate.
commit e82c9bb9ffa65725cc2e03ea81cb79ce3387f66b
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jul 19 18:51:18 2019 +1000
Skip running sftp-chroot under Valgrind.
commit 41e22c2e05cb950b704945ac9408f6109c9b7848
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sat Jul 20 09:50:58 2019 +0000
upstream: Remove the sleeps and thus races from the forwarding
test. They were originally required to work with Protocol 1, but now we can
use ssh -N and the control socket without the sleeps. While there, suppress
output fro the control exit commands.
OpenBSD-Regress-ID: 4c51a1d651242f12c90074c18c61008a74c1c790
commit 0423043c5e54293f4dd56041304fd0046c317be9
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sat Jul 20 09:37:31 2019 +0000
upstream: Allow SLEEPTIME to be overridden.
OpenBSD-Regress-ID: 1596ab168729954be3d219933b2d01cc93687e76
commit d466b6a5cfba17a83c7aae9f584ab164e2ece0a1
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sat Jul 20 09:14:40 2019 +0000
upstream: Move sleep time into a variable so that we can increase
it for platforms or configurations that are much slower then usual.
OpenBSD-Regress-ID: 88586cabc800062c260d0b876bdcd4ca3f58a872
commit b4a7c9d2b5f928e0b902b580d35dc8b244a3aae0
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jul 19 03:45:44 2019 +0000
upstream: add regression tests for scp for out-of-destination path file
creation by Harry Sintonen via Jakub Jelen in bz3007
OpenBSD-Regress-ID: 01ae5fbc6ce400b2df5a84dc3152a9e31f354c07
commit bca0582063f148c7ddf409ec51435a5a726bee4c
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jul 19 03:38:01 2019 +0000
upstream: Accept the verbose flag when searching for host keys in known
hosts (i.e. "ssh-keygen -vF host") to print the matching host's random- art
signature too. bz#3003 "amusing, pretty" deraadt@
OpenBSD-Commit-ID: 686221a5447d6507f40a2ffba5393984d889891f
commit 5299a09fa2879a068af200c91028fcfa9283c0f0
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jul 19 13:50:25 2019 +1000
Revert one dependency per line change.
It turns out that having such a large number of lines in the .depend
file will cause the memory usage of awk during AC_SUBST to blow up on at
least NetBSD's awk, causing configure to fail.
commit 01dddb231f23b4a7b616f9d33a0b9d937f9eaf0e
Author: Damien Miller <djm@mindrot.org>
Date: Fri Jul 19 13:19:19 2019 +1000
fix SIGWINCH delivery of Solaris for mux sessions
Remove PRIV_PROC_SESSION which was limiting ability to send SIGWINCH
signals to other sessions. bz#3030; report and fix from Darren Moffat
commit 05500af21d27c1a3ddac232b018cc23da7b1ee95
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jul 19 13:20:03 2019 +1000
Force dependencies one per line.
Force makedepend to output one dependency per line, which will make
reading diffs against it much easier. ok djm@
commit b5bc5d016bbb83eb7f8e685390044e78b1ea1427
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jul 19 13:18:07 2019 +1000
make depend.
commit 65333f7454365fe40f7367630e7dd10903b9d99e
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jul 19 13:16:11 2019 +1000
Show when skipping valgrind for a test.
commit fccb7eb3436da8ef3dcd22e5936ba1abc7ae6730
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jul 19 10:41:56 2019 +1000
Enable connect-privsep test with valgrind.
connect-privsep seems to work OK with valgrind now so don't skip
valgrind on it.
commit d7423017265c5ae6d0be39340feb6c9f016b1f71
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jul 19 07:43:07 2019 +1000
Show valgrind results and error counts.
commit 22b9b3e944880db906c6ac5527c4228bd92b293a
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Jul 18 13:40:12 2019 +1000
Fix format string integer type in error message.
commit ed46a0c0705895834d3f47a46faa89c2a71b760a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jul 18 13:26:00 2019 +0000
upstream: fix off-by-one in sshbuf_dtob64() base64 wrapping that could
cause extra newlines to be appended at the end of the base64 text (ugly, but
harmless). Found and fixed by Sebastian Kinne
OpenBSD-Commit-ID: 9fe290bd68f706ed8f986a7704ca5a2bd32d7b68
commit a192021fedead23c375077f92346336d531f8cad
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Jul 18 11:09:38 2019 +1000
Fail tests if Valgrind enabled and reports errors.
Also dump the failing valgrind report to stdout (not the cleanest
solution, but better than nothing).
commit d1c491ecb939ee10b341fa7bb6205dff19d297e5
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu Jul 18 10:17:54 2019 +1000
Allow low-priv tests to write to pipe dir.
When running regression tests with Valgrind and SUDO, the low-priv agent
tests need to be able to create pipes in the appropriate directory.
commit 8a5bb3e78191cc206f970c26d2a26c949971e91a
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed Jul 17 21:24:55 2019 +1000
Put valgrind vgdb files to a specific directory.
Valgrind by default puts vgdb files and pipes under /tmp, however it
is not always able to clean them up, which can cause test failures when
there's a pid/file collision. Using a specific directory ensures that
we can clean up and start clean.
commit f8829fe57fb0479d6103cfe1190095da3c032c6d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jul 16 22:16:49 2019 +0000
upstream: adapt to sshbuf_dtob64() change
OpenBSD-Regress-ID: 82374a83edf0955fd1477169eee3f5d6467405a6
commit 1254fcbb2f005f745f2265016ee9fa52e16d37b0
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Jul 16 03:21:54 2019 +0000
upstream: Remove ssh1 files from CLEANFILES since ssh1 no longer
supported.
OpenBSD-Regress-ID: 5b9ae869dc669bac05939b4a2fdf44ee067acfa0
commit 9dc81a5adabc9a7d611ed2e63fbf4c85d43b15c6
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Jul 16 02:09:29 2019 +0000
upstream: Update names of host key files in CLEANFILES to match
recent changes to the tests.
OpenBSD-Regress-ID: 28743052de3acf70b06f18333561497cd47c4ecf
commit e44e4ad1190db22ed407a79f32a8cff5bcd2b815
Author: Damien Miller <djm@mindrot.org>
Date: Tue Jul 16 23:26:53 2019 +1000
depend
commit 16dd8b2c78a0de106c7429e2a294d203f6bda3c7
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jul 16 13:18:39 2019 +0000
upstream: remove mostly vestigal uuencode.[ch]; moving the only unique
functionality there (wrapping of base64-encoded data) to sshbuf functions;
feedback and ok markus@
OpenBSD-Commit-ID: 4dba6735d88c57232f6fccec8a08bdcfea44ac4c
commit 45478898f9590b5cc8bc7104e573b84be67443b0
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jul 16 09:20:23 2019 +1000
Hook memmem compat code into build.
This fixes builds on platforms that don't have it (at least old DragonFly,
probably others).
commit c7bd4617293a903bd3fac3394a7e72d439af49a5
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Jul 16 09:07:18 2019 +1000
Import memmem.c from OpenBSD.
commit 477e2a3be8b10df76e8d76f0427b043280d73d68
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Jul 15 13:12:02 2019 +0000
upstream: unit tests for sshbuf_cmp() and sshbuf_find(); ok markus
OpenBSD-Regress-ID: b52d36bc3ab6dc158c1e59a9a4735f821cf9e1fd
commit eb0d8e708a1f958aecd2d6e2ff2450af488d4c2a
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Jul 15 13:16:29 2019 +0000
upstream: support PKCS8 as an optional format for storage of
private keys, enabled via "ssh-keygen -m PKCS8" on operations that save
private keys to disk.
The OpenSSH native key format remains the default, but PKCS8 is a
superior format to PEM if interoperability with non-OpenSSH software
is required, as it may use a less terrible KDF (IIRC PEM uses a single
round of MD5 as a KDF).
adapted from patch by Jakub Jelen via bz3013; ok markus
OpenBSD-Commit-ID: 027824e3bc0b1c243dc5188504526d73a55accb1
commit e18a27eedccb024acb3cd9820b650a5dff323f01
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon Jul 15 13:11:38 2019 +0000
upstream: two more bounds-checking sshbuf counterparts to common
string operations: sshbuf_cmp() (bcmp-like) and sshbuf_find() (memmem like)
feedback and ok markus@
OpenBSD-Commit-ID: fd071ec2485c7198074a168ff363a0d6052a706a
commit bc551dfebb55845537b1095cf3ccd01640a147b7
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Jul 15 12:52:45 2019 +1000
Clear valgrind-out dir to prevent collisions.
commit 5db9ba718e983661a9114ae1418f6e412d1f52d5
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Jul 15 12:02:27 2019 +1000
Allow agent tests to write to valgrind dir.
commit 121e48fa5305f41f0477d9908e3d862987a68a84
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Jul 14 23:33:19 2019 +0000
upstream: unit tests for sshbuf_peek/poke bounds-checked random access
functions. ok markus@
OpenBSD-Regress-ID: 034c4284b1da6b12e25c762a6b958efacdafbaef
commit 101d164723ffbc38f8036b6f3ea3bfef771ba250
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Jul 14 23:32:27 2019 +0000
upstream: add some functions to perform random-access read/write
operations inside buffers with bounds checking. Intended to replace manual
pointer arithmetic wherever possible.
feedback and ok markus@
OpenBSD-Commit-ID: 91771fde7732738f1ffed078aa5d3bee6d198409
commit 7250879c72d28275a53f2f220e49646c3e42ef18
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jul 12 04:08:39 2019 +0000
upstream: include SHA2-variant RSA key algorithms in KEX proposal;
allows ssh-keyscan to harvest keys from servers that disable olde SHA1
ssh-rsa. bz#3029 from Jakub Jelen
OpenBSD-Commit-ID: 9f95ebf76a150c2f727ca4780fb2599d50bbab7a
commit a0876bd994cab9ba6e47ba2a163a4417c7597487
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jul 12 03:56:21 2019 +0000
upstream: print explicit "not modified" message if a file was
requested for resumed download but was considered already complete.
bz#2978 ok dtucker
OpenBSD-Commit-ID: f32084b26a662f16215ee4ca4a403d67e49ab986
commit b9b0f2ac9625933db53a35b1c1ce423876630558
Author: tb@openbsd.org <tb@openbsd.org>
Date: Wed Jul 10 07:04:27 2019 +0000
upstream: Fix a typo and make <esc><right> move right to the
closest end of a word just like <esc><left> moves left to the closest
beginning of a word.
ok djm
OpenBSD-Commit-ID: 6afe01b05ed52d8b12eb1fda6e9af5afb5e198ee
commit 8729498a5d239980a91d32f031b34e8c58c52f62
Author: Damien Miller <djm@mindrot.org>
Date: Wed Jul 10 09:43:19 2019 +1000
fix typo that prevented detection of Linux VRF
Reported by hexiaowen AT huawei.com
commit 5b2b79ff7c057ee101518545727ed3023372891d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Tue Jul 9 04:15:00 2019 +0000
upstream: cap the number of permiopen/permitlisten directives we're
willing to parse on a single authorized_keys line; ok deraadt@
OpenBSD-Commit-ID: a43a752c2555d26aa3fc754805a476f6e3e30f46
commit eb0b51dac408fadd1fd13fa6d726ab8fdfcc4152
Author: Darren Tucker <dtucker@dtucker.net>
Date: Mon Jul 8 17:27:26 2019 +1000
Move log.h include inside ifdefs.
Fixes build on some other platforms that don't have va_list immediately
available (eg NetBSD).
commit 43702f8e6fa22a258e25c4dd950baaae0bc656b7
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jul 6 23:07:04 2019 +1000
Include log.h for debug() and friends.
Should fix some compiler warnings on IRIX (bz#3032).
commit 53a6ebf1445a857f5e487b18ee5e5830a9575149
Author: Damien Miller <djm@mindrot.org>
Date: Mon Jul 8 13:44:32 2019 +1000
sftp-realpath.c needs includes.h
commit 4efe1adf05ee5d3fce44320fcff68735891f4ee6
Author: Damien Miller <djm@mindrot.org>
Date: Mon Jul 8 13:38:39 2019 +1000
remove realpath() compat replacement
We shipped a BSD implementation of realpath() because sftp-server
depended on its behaviour.
OpenBSD is now moving to a more strictly POSIX-compliant realpath(2),
so sftp-server now unconditionally requires its own BSD-style realpath
implementation. As such, there is no need to carry another independant
implementation in openbsd-compat.
ok dtucker@
commit 696fb4298e80f2ebcd188986a91b49af3b7ca14c
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sun Jul 7 01:05:00 2019 +0000
upstream: Remove some set but never used variables. ok daraadt@
OpenBSD-Commit-ID: 824baf9c59afc66a4637017e397b9b74a41684e7
commit 156e9e85e92b46ca90226605d9eff49e8ec31b22
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Fri Jul 5 12:35:40 2019 +0000
upstream: still compile uuencode.c, unbreaks build
OpenBSD-Commit-ID: 5ea3d63ab972691f43e9087ab5fd8376d48e898f
commit cec9ee527a12b1f6c2e0a1c155fec64a38d71cf6
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jul 5 07:32:01 2019 +0000
upstream: revert header removal that snuck into previous
OpenBSD-Commit-ID: 3919cdd58989786660b8269b325646ef8856428e
commit 569b650f93b561c09c655f83f128e1dfffe74101
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jul 5 04:55:40 2019 +0000
upstream: add a local implementation of BSD realpath() for
sftp-server use ahead of OpenBSD's realpath changing to match POSIX;
ok deraadt@ (thanks for snaps testing)
OpenBSD-Commit-ID: 4f8cbf7ed8679f6237264301d104ecec64885d55
commit b8e2b797362526437e0642a6c2f2970d794f2561
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jul 6 13:13:57 2019 +1000
Add prototype for strnlen to prevent warnings.
commit 4c3e00b1ed7e596610f34590eb5d54ee50d77878
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jul 6 13:02:34 2019 +1000
Cast *ID types to unsigned long when printing.
UID and GID types vary by platform so cast to u_long and use %lu when
printing them to prevent warnings.
commit 2753521e899f30d1d58b5da0b4e68fde6fcf341e
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jul 6 12:54:43 2019 +1000
Add prototype for compat strndup.(bz#3032).
commit 01a1e21cd55d99293c8ff8ed7c590f2ee440da43
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jul 6 12:00:41 2019 +1000
Add missing bracket in EGD seeding code.
When configured --with-prngd-socket the code had a missing bracket after
an API change. Fix that and a couple of warnings. bz#3032 , from
ole.weidner at protonmail.ch
commit e187b1d4607392cf2c19243afe0d0311a4ff3591
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jul 5 04:19:39 2019 +0000
upstream: Add (recently added) rsa_oldfmt to CLEANFILES.
OpenBSD-Regress-ID: 405beda94e32aa6cc9c80969152fab91f7c54bd3
commit 74b541bfabdcb57c1683cd9b3f1d1f4d5e41563e
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jul 5 04:12:46 2019 +0000
upstream: Adapt the PuTTY/Conch tests to new key names.
A recent regress change (2a9b3a2ce411d16cda9c79ab713c55f65b0ec257 in
portable) broke the PuTTY and Twisted Conch interop tests, because the
key they want to use is now called ssh-rsa rather than rsa. Adapt the
tests to the new file names. bz#3020, patch from cjwatson at debian.org.
OpenBSD-Regress-ID: fd342a37db4d55aa4ec85316f73082c8eb96e64e
commit de08335a4cfaa9b7081e94ea4a8b7153c230546d
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jul 5 04:03:13 2019 +0000
upstream: Add a sleep to allow forwards to come up.
Currently when the multiplex client requests a forward it returns
once the request has been sent but not necessarily when the forward
is up. This causes intermittent text failures due to this race,
so add some sleeps to mitigate this until we can fix it properly.
OpenBSD-Regress-ID: 384c7d209d2443d25ea941d7f677e932621fb253
commit 4d249284729f864faa2e8f3e015f9a41b674544a
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jul 5 14:58:57 2019 +1000
Remove nc stderr redirection to resync w/OpenBSD.
commit c5cfa90e03432181ffcc7ad3f9f815179bd0c626
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jul 5 13:21:45 2019 +1000
Do not fatal on failed lookup of group "tty".
Some platforms (eg AIX and Cygwin) do not have a "tty" group. In those
cases we will fall back to making the tty device the user's primary
group, so do not fatal if the group lookup fails. ok djm@
commit 8b4cc4bdc8a70bf209a274fa2b2a49c1e3c8d8a2
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Thu Jul 4 16:20:10 2019 +0000
upstream: fatal() if getgrnam() cannot find "tty"
OpenBSD-Commit-ID: d148c1c052fa0ed7d105b5428b5c1bab91630048
commit 48cccc275c6a1e91d3f80fdb0dc0d5baf529aeca
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Thu Jul 4 16:16:51 2019 +0000
upstream: stat() returns precisely -1 to indicate error
OpenBSD-Commit-ID: 668e8d022ed4ab847747214f64119e5865365fa1
commit 8142fcaf9ed8ff66252deecbfd29fc59d5f2df4f
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Wed Jul 3 03:24:02 2019 +0000
upstream: snprintf/vsnprintf return < 0 on error, rather than -1.
OpenBSD-Commit-ID: a261c421140a0639bb2b66bbceca72bf8239749d
commit 4d28fa78abce2890e136281950633fae2066cc29
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Fri Jun 28 13:35:04 2019 +0000
upstream: When system calls indicate an error they return -1, not
some arbitrary value < 0. errno is only updated in this case. Change all
(most?) callers of syscalls to follow this better, and let's see if this
strictness helps us in the future.
OpenBSD-Commit-ID: 48081f00db7518e3b712a49dca06efc2a5428075
commit e8c974043c1648eab0ad67a7ba6a3e444fe79d2d
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Fri Jun 28 05:44:09 2019 +0000
upstream: asprintf returns -1, not an arbitrary value < 0. Also
upon error the (very sloppy specification) leaves an undefined value in *ret,
so it is wrong to inspect it, the error condition is enough. discussed a
little with nicm, and then much more with millert until we were exasperated
OpenBSD-Commit-ID: 29258fa51edf8115d244b9d4b84028487bf8923e
commit 1b2d55d15c6240c15a1e1cf4203b82e54a766272
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Fri Jun 28 01:23:50 2019 +0000
upstream: oops, from asou
OpenBSD-Commit-ID: 702e765d1639b732370d8f003bb84a1c71c4d0c6
commit 5cdbaa78fcb718c39af4522d98016ad89d065427
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Thu Jun 27 18:03:37 2019 +0000
upstream: Some asprintf() calls were checked < 0, rather than the
precise == -1. ok millert nicm tb, etc
OpenBSD-Commit-ID: caecf8f57938685c04f125515b9f2806ad408d53
commit b2e3e57be4a933d9464bccbe592573725765486f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Thu Jun 27 06:29:35 2019 +0000
upstream: fix NULL deference (bzero) on err
=?UTF-8?q?or=20path=20added=20in=20last=20commit;=20spotted=20by=20Reynir?=
=?UTF-8?q?=20Bj=C3=B6rnsson?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
ok deraadt@ markus@ tb@
OpenBSD-Commit-ID: b11b084bcc551b2c630560eb08618dd501027bbd
commit 58ceacdcbaebefc77d120712de55c6fc6aa32bb1
Author: Jitendra Sharma <jitendra.sharma@intel.com>
Date: Fri Jun 21 09:54:17 2019 +0530
Update README doc to include missing test cases
Readme regress document is missing various individual tests,
which are supported currently. Update README to
include those test cases.
commit 7959330a554051b5587f8af3fec0c2c0d5820f64
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Jun 26 22:29:43 2019 +0000
upstream: Remove unneeded unlink of xauthfile o
=?UTF-8?q?n=20error=20path.=20=20From=20Erik=20Sj=C3=B6lund=20via=20githu?=
=?UTF-8?q?b,=20ok=20djm@=20deraadt@?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
OpenBSD-Commit-ID: 62a4893cf83b29a4bbfedc40e7067c25c203e632
commit 8de52eb224143783a49f9bddd9ab7800022a8276
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sun Jun 23 12:21:46 2019 +0000
upstream: fix mismatch proto/decl from key shielding change; spotted
via oss-fuzz
OpenBSD-Commit-ID: 1ea0ba05ded2c5557507bd844cd446e5c8b5b3b7
commit 1dfadb9b57c2985c95838a0292d1c2f6a501896e
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 21 04:21:45 2019 +0000
upstream: adapt for key shielding API changes (const removal)
OpenBSD-Regress-ID: 298890bc52f0cd09dba76dc1022fabe89bc0ded6
commit 4f7a56d5e02e3d04ab69eac1213817a7536d0562
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 21 04:21:04 2019 +0000
upstream: Add protection for private keys at rest in RAM against
speculation and memory sidechannel attacks like Spectre, Meltdown, Rowhammer
and Rambleed. This change encrypts private keys when they are not in use with
a symmetic key that is derived from a relatively large "prekey" consisting of
random data (currently 16KB).
Attackers must recover the entire prekey with high accuracy before
they can attempt to decrypt the shielded private key, but the current
generation of attacks have bit error rates that, when applied
cumulatively to the entire prekey, make this unlikely.
Implementation-wise, keys are encrypted "shielded" when loaded and then
automatically and transparently unshielded when used for signatures or
when being saved/serialised.
Hopefully we can remove this in a few years time when computer
architecture has become less unsafe.
been in snaps for a bit already; thanks deraadt@
ok dtucker@ deraadt@
OpenBSD-Commit-ID: 19767213c312e46f94b303a512ef8e9218a39bd4
commit 4cd6b12cc9c10bf59c8b425041f3ea5091285a0f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 21 03:19:59 2019 +0000
upstream: print the correct AuthorizedPrincipalsCommand rather than
an uninitialised variable; spotted by dtucker@
OpenBSD-Commit-ID: 02802018784250f68202f01c8561de82e17b0638
commit 5f68ab436b0e01751d564e9a9041e6ac3673e45a
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Wed Jun 19 20:12:44 2019 +0000
upstream: from tim: - for reput, it is remote-path which is
optional, not local-path - sync help
from deraadt:
- prefer -R and undocument -r (but add a comment for future editors)
from schwarze:
- prefer -p and undocument -P (as above. the comment was schwarze's too)
more:
- add the -f flag to reput and reget
- sort help (i can;t remember who suggested this originally)
djm and deraadt were ok with earlier versions of this;
tim and schwarze ok
OpenBSD-Commit-ID: 3c699b53b46111f5c57eed4533f132e7e58bacdd
commit 99bcbbc77fbd5a5027031f42a5931b21b07c947e
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 14 04:03:48 2019 +0000
upstream: check for convtime() refusing to accept times that
resolve to LONG_MAX Reported by Kirk Wolf bz2977; ok dtucker
OpenBSD-Regress-ID: 15c9fe87be1ec241d24707006a31123d3a3117e0
commit e5cccb2410247c9b8151b9510a876abdf5424b24
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Sun Apr 28 22:53:26 2019 +0000
upstream: Add unit tests for user@host and URI parsing.
OpenBSD-Regress-ID: 69d5b6f278e04ed32377046f7692c714c2d07a68
commit 0bb7e38834e3f9886302bbaea630a6b0f8cfb520
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Apr 18 18:57:16 2019 +0000
upstream: Add tests for sshd -T -C with Match.
OpenBSD-Regress-ID: d4c34916fe20d717692f10ef50b5ae5a271c12c7
commit 73eb6cef41daba0359c1888e4756108d41b4e819
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sun Jun 16 12:55:27 2019 +1000
Include stdio.h for vsnprintf.
Patch from mforney at mforney.org.
commit adcaf40fd0a180e6cb5798317fdf479b52e3c09a
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jun 8 09:07:04 2019 +1000
upstream rev 1.27: fix integer overflow.
Cast bitcount to u_in64_t before bit shifting to prevent integer overflow
on 32bit platforms which cause incorrect results when adding a block
>=512M in size. sha1 patch from ante84 at gmail.com via openssh github,
sha2 with djm@, ok tedu@
commit 7689048e6103d3c34cba24ac5aeea7bf8405d19a
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jun 8 09:06:06 2019 +1000
upstream rev 1.25: add DEF_WEAK.
Wrap blowfish, sha*, md5, and rmd160 so that internal calls go direct
ok deraadt@
commit 55f3153393ac7e072a4b4b21b194864460d8f44a
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jun 8 09:02:24 2019 +1000
upstream rev 1.25: add sys/types.h
commit 10974f986fa842a3a3a693e3d5761072540002b4
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jun 8 09:01:14 2019 +1000
upstream: Use explicit_bzero instead of memset
in hash Final and End functions. OK deraadt@ djm@
commit cb8f56570f70b00abae4267d4bcce2bfae7dfff6
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 14 04:13:58 2019 +0000
upstream: slightly more instructive error message when the user
specifies multiple -J options on the commandline. bz3015 ok dtucker@
OpenBSD-Commit-ID: 181c15a65cac3b575819bc8d9a56212c3c748179
commit 2317ce4b0ed7d8c4b0c684e2d47bff5006bd1178
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 14 03:51:47 2019 +0000
upstream: process agent requests for RSA certificate private keys using
correct signature algorithm when requested. Patch from Jakub Jelen in bz3016
ok dtucker markus
OpenBSD-Commit-ID: 61f86efbeb4a1857a3e91298c1ccc6cf49b79624
commit c95b90d40170473825904be561b1eafba354f376
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 14 03:39:59 2019 +0000
upstream: for public key authentication, check AuthorizedKeysFiles
files before consulting AuthorizedKeysCommand; ok dtucker markus
OpenBSD-Commit-ID: 13652998bea5cb93668999c39c3c48e8429db8b3
commit a5a53914989ddd3521b6edc452bc3291784a4f4f
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri Jun 14 03:28:19 2019 +0000
upstream: if passed a bad fd, log what it was
OpenBSD-Commit-ID: 582e2bd05854e49365195b58989b68ac67f09140
commit 7349149da1074d82b71722338e05b6a282f126cc
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Wed Jun 12 11:31:50 2019 +0000
upstream: Hostname->HostName cleanup; from lauri tirkkonen ok
dtucker
OpenBSD-Commit-ID: 4ade73629ede63b691f36f9a929f943d4e7a44e4
commit 76af9c57387243556d38935555c227d0b34062c5
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Wed Jun 12 05:53:21 2019 +0000
upstream: deraadt noticed some inconsistency in the way we denote
the "Hostname" and "X11UseLocalhost" keywords; this makes things consistent
(effectively reversing my commit of yesterday);
ok deraadt markus djm
OpenBSD-Commit-ID: 255c02adb29186ac91dcf47dfad7adb1b1e54667
commit d1bbfdd932db9b9b799db865ee1ff50060dfc895
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Tue Jun 11 13:39:40 2019 +0000
upstream: consistent lettering for "HostName" keyword; from lauri
tirkkonen
OpenBSD-Commit-ID: 0c267a1257ed7482b13ef550837b6496e657d563
commit fc0340f7c4ee29bfb12bd1de9f99defa797e16b4
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jun 8 00:10:59 2019 +1000
Typo fixes in error messages.
Patch from knweiss at gmail.com via github pull req #97 (portable-
specific parts).
commit 4b7dd22b02b64b1ededd3c0e98a6e7ae21e31d38
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jun 7 14:18:48 2019 +0000
upstream: Typo and spelling fixes in comments and error messages.
Patch from knweiss at gmail.com via -portable.
OpenBSD-Commit-ID: 2577465442f761a39703762c4f87a8dfcb918b4b
commit 130ef0695e1731392ca33831939fe89e8b70cc17
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jun 8 00:47:07 2019 +1000
Include missed bits from previous sync.
commit 25e3bccbaa63d27b9d5e09c123f1eb28594d2bd6
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Jun 7 03:47:12 2019 +0000
upstream: Check for user@host when parsing sftp target. This
allows user@[1.2.3.4] to work without a path in addition to with one.
bz#2999, ok djm@
OpenBSD-Commit-ID: d989217110932490ba8ce92127a9a6838878928b
commit 0323d9b619d512f80c57575b810a05791891f657
Author: otto@openbsd.org <otto@openbsd.org>
Date: Thu Jun 6 05:13:13 2019 +0000
upstream: Replace calls to ssh_malloc_init() by a static init of
malloc_options. Prepares for changes in the way malloc is initialized. ok
guenther@ dtucker@
OpenBSD-Commit-ID: 154f4e3e174f614b09f792d4d06575e08de58a6b
commit c586d2d3129265ea64b12960c379d634bccb6535
Author: djm@openbsd.org <djm@openbsd.org>
Date: Fri May 31 03:20:07 2019 +0000
upstream: fix ssh-keysign fd handling problem introduced in r1.304
caused by a typo (STDIN_FILENO vs STDERR_FILENO)
OpenBSD-Commit-ID: 57a0b4be7bef23963afe24150e24bf014fdd9cb0
commit 410b231aa41ff830b2f5b09b5aaf5e5cdc1ab86b
Author: lum@openbsd.org <lum@openbsd.org>
Date: Wed May 29 08:30:26 2019 +0000
upstream: Make the standard output messages of both methods of
changing a key pair's comments (using -c and -C) more applicable to both
methods. ok and suggestions djm@ dtucker@
OpenBSD-Commit-ID: b379338118109eb36e14a65bc0a12735205b3de6
commit 2b3402dc9f1d9b0df70291b424f36e436cdfa7e0
Author: Darren Tucker <dtucker@dtucker.net>
Date: Sat Jun 8 00:03:07 2019 +1000
Always clean up before and after utimensat test.
commit 182898192d4b720e4faeafd5b39c2cfb3b92aa21
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jun 7 23:47:37 2019 +1000
Update utimensat test.
POSIX specifies that when given a symlink, AT_SYMLINK_NOFOLLOW should
update the symlink and not the destination. The compat code doesn't
have a way to do this, so where possible it fails instead of following a
symlink when explicitly asked not to. Instead of checking for an explicit
failure, check that it does not update the destination, which both the
real and compat implmentations should honour.
Inspired by github pull req #125 from chutzpah at gentoo.org.
commit d220b675205185e0b4d6b6524acc2e5c599ef0e2
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Jun 7 14:26:54 2019 +1000
Have pthread_create return errno on failure.
According to POSIX, pthread_create returns the failure reason in
the non-zero function return code so make the fork wrapper do that.
Matches previous change.
commit 1bd4f7f25f653e0cadb2e6f25d79bc3c35c6aa4d
Author: Elliott Hughes <enh@google.com>
Date: Thu Apr 25 13:36:27 2019 -0700
pthread_create(3) returns positive values on failure.
Found by inspection after finding similar bugs in other code used by
Android.
commit b3a77b25e5f7880222b179431a74fad76d2cf60c
Author: Harald Freudenberger <freude@linux.ibm.com>
Date: Fri May 24 10:11:15 2019 +0200
allow s390 specific ioctl for ecc hardware support
Adding another s390 specific ioctl to be able to support ECC hardware
acceleration to the sandbox seccomp filter rules.
Now the ibmca openssl engine provides elliptic curve cryptography
support with the help of libica and CCA crypto cards. This is done via
jet another ioctl call to the zcrypt device driver and so there is a
need to enable this on the openssl sandbox.
Code is s390 specific and has been tested, verified and reviewed.
Please note that I am also the originator of the previous changes in
that area. I posted these changes to Eduardo and he forwarded the
patches to the openssl community.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Joerg Schmidbauer <jschmidb@de.ibm.com>
commit 2459df9aa11820f8092a8651aeb381af7ebbccb1
Author: Sorin Adrian Savu <sorin25@users.noreply.github.com>
Date: Sun May 26 21:50:08 2019 +0300
openssl-devel is obsoleted by libssl-devel
openssl-devel is no longer installable via the cygwin setup and
it's hidden by default, so you can't see the replacement very easy.
commit 85ceb0e64bff672558fc87958cd548f135c83cdd
Author: jmc@openbsd.org <jmc@openbsd.org>
Date: Mon May 20 06:01:59 2019 +0000
upstream: tweak previous;
OpenBSD-Commit-ID: 42f39f22f53cfcb913bce401ae0f1bb93e08dd6c
commit 30615295609f5c57b3137b3021fe63bfa45c1985
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon May 20 00:25:55 2019 +0000
upstream: embiggen format buffer size for certificate serial number so
that it will fit a full 64 bit integer. bz#3012 from Manoel Domingues Junior
OpenBSD-Commit-ID: a51f3013056d05b976e5af6b978dcb9e27bbc12b
commit 476e3551b2952ef73acc43d995e832539bf9bc4d
Author: djm@openbsd.org <djm@openbsd.org>
Date: Mon May 20 00:20:35 2019 +0000
upstream: When signing certificates with an RSA key, default to
using the rsa-sha2-512 signature algorithm. Certificates signed by RSA keys
will therefore be incompatible with OpenSSH < 7.2 unless the default is
overridden.
Document the ability of the ssh-keygen -t flag to override the
signature algorithm when signing certificates, and the new default.
ok deraadt@
OpenBSD-Commit-ID: 400c9c15013978204c2cb80f294b03ae4cfc8b95
commit 606077ee1e77af5908431d003fb28461ef7be092
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri May 17 13:14:12 2019 +1000
Add no-op implementation of pam_putenv.
Some platforms such as HP-UX do not have pam_putenv. Currently the
calls are ifdef'ed out, but a new one was recently added. Remove the
ifdefs and add a no-op implementation. bz#3008, ok djm.
commit 1ac98be8724c9789d770ddb8e7f0dbf1b55e05a0
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri May 17 12:42:17 2019 +1000
Use the correct macro for SSH_ALLOWED_CA_SIGALGS.
commit 97370f6c2c3b825f8c577b7e6c00b1a98d30a6cf
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri May 17 10:54:51 2019 +1000
Fix building w/out ECC.
Ifdef out ECC specific code so that that it'll build against an OpenSSL
configured w/out ECC. With & ok djm@
commit 633703babf8d9a88da85f23b800e1b88dec7cdbd
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri May 17 10:50:29 2019 +1000
Conditionalize ECDH methods in CA algos.
When building against an OpenSSL configured without ECC, don't include
those algos in CASignatureAlgorithms. ok djm@
commit 5c8d14c512f5d413095b22bdba08a6bb990f1e97
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu May 16 08:47:27 2019 +0000
upstream: Move a variable declaration to the block where it's used
to make things a little tidier for -portable.
OpenBSD-Commit-ID: 616379861be95619e5358768b7dee4793e2f3a75
commit a1d29cc36a5e6eeabc935065a8780e1ba5b67014
Author: deraadt@openbsd.org <deraadt@openbsd.org>
Date: Wed May 15 04:43:31 2019 +0000
upstream: When doing the fork+exec'ing for ssh-keysign, rearrange
the socket into fd3, so as to not mistakenly leak other fd forward
accidentally. ok djm
OpenBSD-Commit-ID: 24cc753f5aa2c6a7d0fbf62766adbc75cd785296
commit db7606d4a62fee67b0cb2f32dfcbd7b3642bfef5
Author: schwarze@openbsd.org <schwarze@openbsd.org>
Date: Tue May 14 12:47:17 2019 +0000
upstream: Delete some .Sx macros that were used in a wrong way.
Part of a patch from Stephen Gregoratto <dev at sgregoratto dot me>.
OpenBSD-Commit-ID: 15501ed13c595f135e7610b1a5d8345ccdb513b7
commit cb4accb1233865d9151f8a50cc5f0c61a3fd4077
Author: florian@openbsd.org <florian@openbsd.org>
Date: Fri May 10 18:55:17 2019 +0000
upstream: For PermitOpen violations add the remote host and port to
be able to find out from where the request was comming.
Add the same logging for PermitListen violations which where not
logged at all.
Pointed out by Robert Kisteleki (robert AT ripe.net)
input markus
OK deraadt
OpenBSD-Commit-ID: 8a7d0f1b7175504c0d1dca8d9aca1588b66448c8
commit cd16aceec148d55088fc8df6be88335578d85258
Author: Darren Tucker <dtucker@dtucker.net>
Date: Thu May 16 07:53:20 2019 +1000
Add OpenSSL 1.1.1 to the supported list.
Clarify the language around prngd and egd.
commit 6fd4aa2aafbce90acb11a328ca0aa0696cb01c6b
Author: Darren Tucker <dtucker@dtucker.net>
Date: Wed May 15 16:19:14 2019 +1000
Fix typo in man page formatter selector.
commit 285546b73e2c172565c992a695927ac8cf3b4cc6
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri May 10 15:04:42 2019 +1000
Use "doc" man page format if mandoc present.
Previously configure would not select the "doc" man page format if
mandoc was present but nroff was not. This checks for mandoc first
and removes a now-superflous AC_PATH_PROG. Based on a patch from
vehk at vehk.de and feedback from schwarze at usta.de.
commit 62dd70613b77b229f53db3cc1c3e8a206fa2b582
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri May 3 06:06:30 2019 +0000
upstream: Use the correct (according to POSIX) format for
left-justification in snmprintf. bz#3002, patch from velemas at gmail.com, ok
markus@.
OpenBSD-Commit-ID: 65d252b799be0cc8f68b6c47cece0a57bb00fea7
commit 62be1ffe5ffc68cfaac183320503c00a8c72e0b1
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri May 3 04:11:00 2019 +0000
upstream: Free channel objects on exit path. Patch from markus at
blueflash.cc, ok deraadt
OpenBSD-Commit-ID: dbe4db381603909482211ffdd2b48abd72169117
commit 1c554a5d94b9de6bd5374e2992a5662746cc39ba
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri May 3 03:27:38 2019 +0000
upstream: Free host on exit path. Patch from markus at
blueflash.cc, ok djm@
OpenBSD-Commit-ID: c54e9945d93c4ce28350d8b9fa8b71f744ef2b5a
commit 99043bd64e5e0f427173f4fa83ef25a4676624a3
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri May 3 03:25:18 2019 +0000
upstream: Wrap XMSS including in ifdef. Patch from markus at
blueflash.cc, ok djm
OpenBSD-Commit-ID: e3b34fc35cf12d33bde91ac03633210a3bc0f8b5
commit 8fcfb7789c43a19d24162a7a4055cd09ee951b34
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Apr 26 08:37:17 2019 +0000
upstream: Import regenerated moduli.
OpenBSD-Commit-ID: db6375fc302e3bdf07d96430c63c991b2c2bd3ff
commit 3a7db919d5dd09f797971b3cf8ee301767459774
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Tue Apr 23 11:56:41 2019 +0000
upstream: Use the LogLevel typdef instead of int where appropriate. Patch from Markus Schmidt via openssh-unix-dev, ok markus@
OpenBSD-Commit-ID: 4c0f0f458e3da7807806b35e3eb5c1e8403c968a
commit d7c6e38b87efab1f140745fd8b1106b82e6e4a68
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Fri Apr 19 05:47:44 2019 +0000
upstream: Document new default RSA key size. From
sebastiaanlokhorst at gmail.com via bz#2997.
OpenBSD-Commit-ID: bdd62ff5d4d649d2147904e91bf7cefa82fe11e1
commit e826bbcafe26dac349a8593da5569e82faa45ab8
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Apr 18 18:56:16 2019 +0000
upstream: When running sshd -T, assume any attibute not provided by
-C does not match, which allows it to work when sshd_config contains a Match
directive with or without -C. bz#2858, ok djm@
OpenBSD-Commit-ID: 1a701f0a33e3bc96753cfda2fe0b0378520b82eb
commit 5696512d7ad57e85e89f8011ce8dec617be686aa
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Apr 18 07:32:56 2019 +0000
upstream: Remove crc32.{c,h} which were only used by the now-gone
SSH1 protocol. Patch from yumkam at gmail.com, ok deraadt.
OpenBSD-Commit-ID: cceda5876c5ba6b4d8abcd52335329198cee3240
commit 34e87fb5d9ce607f5701ab4c31d837ad8133e2d1
Author: Darren Tucker <dtucker@dtucker.net>
Date: Tue Apr 30 12:27:57 2019 +1000
Remove unused variables from RLIMIT_NOFILE test.
commit 35e82e62c1ef53cfa457473a4c4d957d6197371a
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Apr 26 18:38:27 2019 +1000
Import regenerated moduli.
commit 5590f53f99219e95dc23b0ebd220f19a6f46b101
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Apr 26 18:22:10 2019 +1000
Whitespace resync w/OpenBSD.
Patch from markus at blueflash.cc via openssh-unix-dev.
commit b7b8334914fb9397a6725f3b5d2de999b0bb69ac
Author: Darren Tucker <dtucker@dtucker.net>
Date: Fri Apr 26 18:06:34 2019 +1000
Don't install duplicate STREAMS modules on Solaris
Check if STREAMS modules are already installed on pty before installing
since when compiling with XPG>=4 they will likely be installed already.
Prevents hangs and duplicate lines on the terminal. bz#2945 and bz#2998,
patch from djm@
commit fd0fa130ecf06d7d092932adcd5d77f1549bfc8d
Author: Damien Miller <djm@mindrot.org>
Date: Thu Apr 18 08:52:57 2019 +1000
makedepend
-
-commit 5de397a876b587ba05a9169237deffdc71f273b0
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Apr 5 11:29:51 2019 -0700
-
- second thoughts: leave README in place
-
- A number of contrib/* files refer to the existing README so let's leave
- it in place for release and add the new markdown version in parallel.
-
- I'll get rid of README after release.
-
-commit 5d3127d9274519b25ed10e320f45045ba8d7f3be
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Apr 5 11:29:31 2019 -0700
-
- Revert "rewrite README"
-
- This reverts commit 9444d82678cb7781820da4d1c23b3c2b9fb1e12f.
-
-commit 9444d82678cb7781820da4d1c23b3c2b9fb1e12f
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Apr 5 11:21:48 2019 -0700
-
- rewrite README
-
- Include basic build instructions and comments on commonly-used build-
- time flags, links to the manual pages and other resources.
-
- Now in Markdown format for better viewing on github, etc.
-
-commit a924de0c4908902433813ba205bee1446bd1a157
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Apr 5 03:41:52 2019 +1100
-
- update versions
-
-commit 312dcee739bca5d6878c536537b2a8a497314b75
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Apr 3 15:48:45 2019 +0000
-
- upstream: openssh-8.0
-
- OpenBSD-Commit-ID: 5aafdf218679dab982fea20771afd643be9a127b
-
-commit 885bc114692046d55e2a170b932bdc0092fa3456
-Author: Damien Miller <djm@mindrot.org>
-Date: Thu Apr 4 02:47:40 2019 +1100
-
- session: Do not use removed API
-
- from Jakub Jelen
-
-commit 9d7b2882b0c9a5e9bf8312ce4075bf178e2b98be
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Mar 29 11:31:40 2019 +0000
-
- upstream: when logging/fataling on error, include a bit more detail
-
- than just the function name and the error message
-
- OpenBSD-Commit-ID: dd72d7eba2215fcb89be516c378f633ea5bcca9f
-
-commit 79a87d32783d6c9db40af8f35e091d9d30365ae7
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Apr 3 06:27:45 2019 +1100
-
- Remove "struct ssh" from sys_auth_record_login.
-
- It's not needed, and is not available from the call site in loginrec.c
- Should only affect AIX, spotted by Kevin Brott.
-
-commit 138c0d52cdc90f9895333b82fc57d81cce7a3d90
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Apr 2 18:21:35 2019 +1100
-
- Adapt custom_failed_login to new prototype.
-
- Spotted by Kevin Brott.
-
-commit a0ca4009ab2f0b1007ec8ab6864dbf9b760a8ed5
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Apr 1 20:07:23 2019 +1100
-
- Add includes.h for compat layer.
-
- Should fix build on AIX 7.2.
-
-commit 00991151786ce9b1d577bdad1f83a81d19c8236d
-Author: Tim Rice <tim@multitalents.net>
-Date: Sun Mar 31 22:14:22 2019 -0700
-
- Stop USL compilers for erroring with "integral constant expression expected"
-
-commit 43f47ebbdd4037b569c23b8f4f7981f53b567f1d
-Author: Tim Rice <tim@multitalents.net>
-Date: Sun Mar 31 19:22:19 2019 -0700
-
- Only use O_NOFOLLOW in fchownat and fchmodat if defined
-
-commit 342d6e51589b184c337cccfc4c788b60ff8b3765
-Author: Jakub Jelen <jjelen@redhat.com>
-Date: Fri Mar 29 12:29:41 2019 +0100
-
- Adjust softhsm2 path on Fedora Linux for regress
-
- The SoftHSM lives in Fedora in /usr/lib64/pkcs11/libsofthsm2.so
-
-commit f5abb05f8c7358dacdcb866fe2813f6d8efd5830
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Mar 28 09:26:14 2019 +1100
-
- Only use O_NOFOLLOW in utimensat if defined.
-
- Fixes build on systems that don't have it (Solaris <=9) Found by
- Tom G. Christensen.
-
-commit 786cd4c1837fdc3fe7b4befe54a3f37db7df8715
-Author: Corinna Vinschen <vinschen@redhat.com>
-Date: Wed Mar 27 18:18:21 2019 +0100
-
- drop old Cygwin considerations
-
- - Cygwin supports non-DOS characters in filenames
- - Cygwin does not support Windows XP anymore
-
- Signed-off-by: Corinna Vinschen <vinschen@redhat.com>
-
-commit 21da87f439b48a85b951ef1518fe85ac0273e719
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Mar 27 09:29:14 2019 +0000
-
- upstream: fix interaction between ClientAliveInterval and RekeyLimit
-
- that could cause connection to close incorrectly; Report and patch from Jakub
- Jelen in bz#2757; ok dtucker@ markus@
-
- OpenBSD-Commit-ID: 17229a8a65bd8e6c2080318ec2b7a61e1aede3fb
-
-commit 4f0019a9afdb4a94d83b75e82dbbbe0cbe826c56
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Mar 25 22:34:52 2019 +0000
-
- upstream: Fix authentication failures when "AuthenticationMethods
-
- any" in a Match block overrides a more restrictive global default.
-
- Spotted by jmc@, ok markus@
-
- OpenBSD-Commit-ID: a90a4fe2ab81d0eeeb8fdfc21af81f7eabda6666
-
-commit d6e5def308610f194c0ec3ef97a34a3e9630e190
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Mar 25 22:33:44 2019 +0000
-
- upstream: whitespace
-
- OpenBSD-Commit-ID: 106e853ae8a477e8385bc53824d3884a8159db07
-
-commit 26e0cef07b04479537c971dec898741df1290fe5
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Mar 25 16:19:44 2019 +0000
-
- upstream: Expand comment to document rationale for default key
-
- sizes. "seems worthwhile" deraadt.
-
- OpenBSD-Commit-ID: 72e5c0983d7da1fb72f191870f36cb58263a2456
-
-commit f47269ea67eb4ff87454bf0d2a03e55532786482
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Mar 25 15:49:00 2019 +0000
-
- upstream: Increase the default RSA key size to 3072 bits. Based on
-
- the estimates from NIST Special Publication 800-57, 3k bits provides security
- equivalent to 128 bits which is the smallest symmetric cipher we enable by
- default. ok markus@ deraadt@
-
- OpenBSD-Commit-ID: 461dd32ebe808f88f4fc3ec74749b0e6bef2276b
-
-commit 62949c5b37af28d8490d94866e314a76be683a5e
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Fri Mar 22 20:58:34 2019 +0000
-
- upstream: full stop in the wrong place;
-
- OpenBSD-Commit-ID: 478a0567c83553a2aebf95d0f1bd67ac1b1253e4
-
-commit 1b1332b5bb975d759a50b37f0e8bc8cfb07a0bb0
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Sat Mar 16 19:14:21 2019 +0000
-
- upstream: benno helped me clean up the tcp forwarding section;
-
- OpenBSD-Commit-ID: d4bec27edefde636fb632b7f0b7c656b9c7b7f08
-
-commit 2aee9a49f668092ac5c9d34e904ef7a9722e541d
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Fri Mar 8 17:24:43 2019 +0000
-
- upstream: fix use-after-free in ssh-pkcs11; found by hshoexer w/AFL
-
- OpenBSD-Commit-ID: febce81cca72b71f70513fbee4ff52ca050f675c
-
-commit 9edbd7821e6837e98e7e95546cede804dac96754
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Mar 14 10:17:28 2019 +1100
-
- Fix build when configured --without-openssl.
-
- ok djm@
-
-commit 825ab32f0d04a791e9d19d743c61ff8ed9b4d8e5
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Mar 14 08:51:17 2019 +1100
-
- On Cygwin run sshd as SYSTEM where possible.
-
- Seteuid now creates user token using S4U. We don't create a token
- from scratch anymore, so we don't need the "Create a process token"
- privilege. The service can run under SYSTEM again...
-
- ...unless Cygwin is running on Windows Vista or Windows 7 in the
- WOW64 32 bit emulation layer. It turns out that WOW64 on these systems
- didn't implement MsV1_0 S4U Logon so we still need the fallback
- to NtCreateToken for these systems.
-
- Signed-off-by: Corinna Vinschen <vinschen@redhat.com>
-
-commit a212107bfdf4d3e870ab7a443e4d906e5b9578c3
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Mar 13 10:49:16 2019 +1100
-
- Replace alloca with xcalloc.
-
- The latter checks for memory exhaustion and integer overflow and may be
- at a less predictable place. Sanity check by vinschen at redhat.com, ok
- djm@
-
-commit daa7505aadca68ba1a2c70cbdfce423208eb91ee
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Mar 12 09:19:19 2019 +1100
-
- Use Cygwin-specific matching only for users+groups.
-
- Patch from vinschen at redhat.com, updated a little by me.
-
-commit fd10cf027b56f9aaa80c9e3844626a05066589a4
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Mar 6 22:14:23 2019 +0000
-
- upstream: Move checks for lists of users or groups into their own
-
- function. This is a no-op on OpenBSD but will make things easier in
- -portable, eg on systems where these checks should be case-insensitive. ok
- djm@
-
- OpenBSD-Commit-ID: 8bc9c8d98670e23f8eaaaefe29c1f98e7ba0487e
-
-commit ab5fee8eb6a011002fd9e32b1597f02aa8804a25
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Mar 6 21:06:59 2019 +0000
-
- upstream: Reset last-seen time when sending a keepalive. Prevents
-
- sending two keepalives successively and prematurely terminating connection
- when ClientAliveCount=1. While there, collapse two similar tests into one.
- ok markus@
-
- OpenBSD-Commit-ID: 043670d201dfe222537a2a4bed16ce1087de5ddd
-
-commit c13b74530f9f1d9df7aeae012004b31b2de4438e
-Author: naddy@openbsd.org <naddy@openbsd.org>
-Date: Tue Mar 5 16:17:12 2019 +0000
-
- upstream: PKCS#11 support is no longer limited to RSA; ok benno@
-
- kn@
-
- OpenBSD-Commit-ID: 1a9bec64d530aed5f434a960e7515a3e80cbc826
-
-commit e9552d6043db7cd170ac6ba1b4d2c7a5eb2c3201
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Mar 1 03:29:32 2019 +0000
-
- upstream: in ssh_set_newkeys(), mention the direction that we're
-
- keying in debug messages. Previously it would be difficult to tell which
- direction it was talking about
-
- OpenBSD-Commit-ID: c2b71bfcceb2a7389b9d0b497fb2122a406a522d
diff --git a/Makefile.in b/Makefile.in
index e3cd296cabb0..b749206dd4e7 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,734 +1,775 @@
# uncomment if you run a non bourne compatible shell. Ie. csh
#SHELL = @SH@
AUTORECONF=autoreconf
prefix=@prefix@
exec_prefix=@exec_prefix@
bindir=@bindir@
sbindir=@sbindir@
libexecdir=@libexecdir@
datadir=@datadir@
datarootdir=@datarootdir@
mandir=@mandir@
mansubdir=@mansubdir@
sysconfdir=@sysconfdir@
piddir=@piddir@
srcdir=@srcdir@
top_srcdir=@top_srcdir@
+abs_top_srcdir=@abs_top_srcdir@
DESTDIR=
VPATH=@srcdir@
SSH_PROGRAM=@bindir@/ssh
ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass
SFTP_SERVER=$(libexecdir)/sftp-server
SSH_KEYSIGN=$(libexecdir)/ssh-keysign
SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
SSH_SK_HELPER=$(libexecdir)/ssh-sk-helper
PRIVSEP_PATH=@PRIVSEP_PATH@
SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
STRIP_OPT=@STRIP_OPT@
TEST_SHELL=@TEST_SHELL@
PATHS= -DSSHDIR=\"$(sysconfdir)\" \
-D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \
-D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" \
-D_PATH_SFTP_SERVER=\"$(SFTP_SERVER)\" \
-D_PATH_SSH_KEY_SIGN=\"$(SSH_KEYSIGN)\" \
-D_PATH_SSH_PKCS11_HELPER=\"$(SSH_PKCS11_HELPER)\" \
-D_PATH_SSH_SK_HELPER=\"$(SSH_SK_HELPER)\" \
-D_PATH_SSH_PIDDIR=\"$(piddir)\" \
-D_PATH_PRIVSEP_CHROOT_DIR=\"$(PRIVSEP_PATH)\"
CC=@CC@
LD=@LD@
CFLAGS=@CFLAGS@
CFLAGS_NOPIE=@CFLAGS_NOPIE@
CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@
PICFLAG=@PICFLAG@
LIBS=@LIBS@
K5LIBS=@K5LIBS@
GSSLIBS=@GSSLIBS@
SSHDLIBS=@SSHDLIBS@
LIBEDIT=@LIBEDIT@
LIBFIDO2=@LIBFIDO2@
AR=@AR@
AWK=@AWK@
RANLIB=@RANLIB@
INSTALL=@INSTALL@
SED=@SED@
XAUTH_PATH=@XAUTH_PATH@
LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@
LDFLAGS_NOPIE=-L. -Lopenbsd-compat/ @LDFLAGS_NOPIE@
EXEEXT=@EXEEXT@
MANFMT=@MANFMT@
MKDIR_P=@MKDIR_P@
.SUFFIXES: .lo
TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT)
XMSS_OBJS=\
ssh-xmss.o \
sshkey-xmss.o \
xmss_commons.o \
xmss_fast.o \
xmss_hash.o \
xmss_hash_address.o \
xmss_wots.o
LIBOPENSSH_OBJS=\
ssh_api.o \
ssherr.o \
sshbuf.o \
sshkey.o \
sshbuf-getput-basic.o \
sshbuf-misc.o \
sshbuf-getput-crypto.o \
krl.o \
bitmap.o \
${XMSS_OBJS}
LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
authfd.o authfile.o \
canohost.o channels.o cipher.o cipher-aes.o cipher-aesctr.o \
cipher-ctr.o cleanup.o \
compat.o fatal.o hostfile.o \
log.o match.o moduli.o nchan.o packet.o \
readpass.o ttymodes.o xmalloc.o addr.o addrmatch.o \
atomicio.o dispatch.o mac.o misc.o utf8.o \
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 \
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 \
hmac.o sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o \
kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
kexgexc.o kexgexs.o \
kexsntrup761x25519.o sntrup761.o kexgen.o \
sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \
sshbuf-io.o
SKOBJS= ssh-sk-client.o
SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
sshconnect.o sshconnect2.o mux.o $(SKOBJS)
SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \
audit.o audit-bsm.o audit-linux.o platform.o \
sshpty.o sshlogin.o servconf.o serverloop.o \
auth.o auth2.o auth-options.o session.o \
auth2-chall.o groupaccess.o \
auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \
auth2-none.o auth2-passwd.o auth2-pubkey.o \
monitor.o monitor_wrap.o auth-krb5.o \
auth2-gss.o gss-serv.o gss-serv-krb5.o \
loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
srclimit.o 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)
SCP_OBJS= scp.o progressmeter.o
SSHADD_OBJS= ssh-add.o $(SKOBJS)
SSHAGENT_OBJS= ssh-agent.o ssh-pkcs11-client.o $(SKOBJS)
SSHKEYGEN_OBJS= ssh-keygen.o sshsig.o $(SKOBJS)
SSHKEYSIGN_OBJS=ssh-keysign.o readconf.o uidswap.o $(SKOBJS)
P11HELPER_OBJS= ssh-pkcs11-helper.o ssh-pkcs11.o $(SKOBJS)
SKHELPER_OBJS= ssh-sk-helper.o ssh-sk.o sk-usbhid.o
SSHKEYSCAN_OBJS=ssh-keyscan.o $(SKOBJS)
SFTPSERVER_OBJS=sftp-common.o sftp-server.o sftp-server-main.o
SFTP_OBJS= sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o
MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out ssh-sk-helper.8.out sshd_config.5.out ssh_config.5.out
MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 ssh-sk-helper.8 sshd_config.5 ssh_config.5
MANTYPE = @MANTYPE@
CONFIGFILES=sshd_config.out ssh_config.out moduli.out
CONFIGFILES_IN=sshd_config ssh_config moduli
PATHSUBS = \
-e 's|/etc/ssh/ssh_config|$(sysconfdir)/ssh_config|g' \
-e 's|/etc/ssh/ssh_known_hosts|$(sysconfdir)/ssh_known_hosts|g' \
-e 's|/etc/ssh/sshd_config|$(sysconfdir)/sshd_config|g' \
-e 's|/usr/libexec|$(libexecdir)|g' \
-e 's|/etc/shosts.equiv|$(sysconfdir)/shosts.equiv|g' \
-e 's|/etc/ssh/ssh_host_key|$(sysconfdir)/ssh_host_key|g' \
-e 's|/etc/ssh/ssh_host_ecdsa_key|$(sysconfdir)/ssh_host_ecdsa_key|g' \
-e 's|/etc/ssh/ssh_host_dsa_key|$(sysconfdir)/ssh_host_dsa_key|g' \
-e 's|/etc/ssh/ssh_host_rsa_key|$(sysconfdir)/ssh_host_rsa_key|g' \
-e 's|/etc/ssh/ssh_host_ed25519_key|$(sysconfdir)/ssh_host_ed25519_key|g' \
-e 's|/var/run/sshd.pid|$(piddir)/sshd.pid|g' \
-e 's|/etc/moduli|$(sysconfdir)/moduli|g' \
-e 's|/etc/ssh/moduli|$(sysconfdir)/moduli|g' \
-e 's|/etc/ssh/sshrc|$(sysconfdir)/sshrc|g' \
-e 's|/usr/X11R6/bin/xauth|$(XAUTH_PATH)|g' \
-e 's|/var/empty|$(PRIVSEP_PATH)|g' \
-e 's|/usr/bin:/bin:/usr/sbin:/sbin|@user_path@|g'
FIXPATHSCMD = $(SED) $(PATHSUBS)
FIXALGORITHMSCMD= $(SHELL) $(srcdir)/fixalgorithms $(SED) \
@UNSUPPORTED_ALGORITHMS@
all: configure-check $(CONFIGFILES) $(MANPAGES) $(TARGETS)
$(LIBSSH_OBJS): Makefile.in config.h
$(SSHOBJS): Makefile.in config.h
$(SSHDOBJS): Makefile.in config.h
configure-check: $(srcdir)/configure
$(srcdir)/configure: configure.ac $(srcdir)/m4/*.m4
@echo "ERROR: configure is out of date; please run ${AUTORECONF} (and configure)" 1>&2
@exit 1
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
LIBCOMPAT=openbsd-compat/libopenbsd-compat.a
$(LIBCOMPAT): always
(cd openbsd-compat && $(MAKE))
always:
libssh.a: $(LIBSSH_OBJS)
$(AR) rv $@ $(LIBSSH_OBJS)
$(RANLIB) $@
ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS)
$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(GSSLIBS)
sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS)
$(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS)
scp$(EXEEXT): $(LIBCOMPAT) libssh.a $(SCP_OBJS)
$(LD) -o $@ $(SCP_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHADD_OBJS)
$(LD) -o $@ $(SSHADD_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHAGENT_OBJS)
$(LD) -o $@ $(SSHAGENT_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHKEYGEN_OBJS)
$(LD) -o $@ $(SSHKEYGEN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHKEYSIGN_OBJS)
$(LD) -o $@ $(SSHKEYSIGN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a $(P11HELPER_OBJS)
$(LD) -o $@ $(P11HELPER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
ssh-sk-helper$(EXEEXT): $(LIBCOMPAT) libssh.a $(SKHELPER_OBJS)
$(LD) -o $@ $(SKHELPER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) $(LIBFIDO2)
ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHKEYSCAN_OBJS)
$(LD) -o $@ $(SSHKEYSCAN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a $(SFTPSERVER_OBJS)
$(LD) -o $@ $(SFTPSERVER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
sftp$(EXEEXT): $(LIBCOMPAT) libssh.a $(SFTP_OBJS)
$(LD) -o $@ $(SFTP_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT)
# test driver for the loginrec code - not built by default
logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o
$(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS)
$(MANPAGES): $(MANPAGES_IN)
if test "$(MANTYPE)" = "cat"; then \
manpage=$(srcdir)/`echo $@ | sed 's/\.[1-9]\.out$$/\.0/'`; \
else \
manpage=$(srcdir)/`echo $@ | sed 's/\.out$$//'`; \
fi; \
if test "$(MANTYPE)" = "man"; then \
$(FIXPATHSCMD) $${manpage} | $(FIXALGORITHMSCMD) | \
$(AWK) -f $(srcdir)/mdoc2man.awk > $@; \
else \
$(FIXPATHSCMD) $${manpage} | $(FIXALGORITHMSCMD) > $@; \
fi
$(CONFIGFILES): $(CONFIGFILES_IN)
conffile=`echo $@ | sed 's/.out$$//'`; \
$(FIXPATHSCMD) $(srcdir)/$${conffile} > $@
# fake rule to stop make trying to compile moduli.o into a binary "moduli.o"
moduli:
echo
clean: regressclean
rm -f *.o *.lo *.a $(TARGETS) logintest config.cache config.log
rm -f *.out core survey
rm -f regress/check-perm$(EXEEXT)
rm -f regress/mkdtemp$(EXEEXT)
rm -f regress/unittests/test_helper/*.a
rm -f regress/unittests/test_helper/*.o
- rm -f regress/unittests/sshbuf/*.o
- rm -f regress/unittests/sshbuf/test_sshbuf$(EXEEXT)
- rm -f regress/unittests/sshkey/*.o
- rm -f regress/unittests/sshkey/test_sshkey$(EXEEXT)
- rm -f regress/unittests/sshsig/*.o
- rm -f regress/unittests/sshsig/test_sshsig$(EXEEXT)
+ rm -f regress/unittests/authopt/*.o
+ rm -f regress/unittests/authopt/test_authopt$(EXEEXT)
rm -f regress/unittests/bitmap/*.o
rm -f regress/unittests/bitmap/test_bitmap$(EXEEXT)
rm -f regress/unittests/conversion/*.o
rm -f regress/unittests/conversion/test_conversion$(EXEEXT)
rm -f regress/unittests/hostkeys/*.o
rm -f regress/unittests/hostkeys/test_hostkeys$(EXEEXT)
rm -f regress/unittests/kex/*.o
rm -f regress/unittests/kex/test_kex$(EXEEXT)
rm -f regress/unittests/match/*.o
rm -f regress/unittests/match/test_match$(EXEEXT)
+ rm -f regress/unittests/misc/*.o
+ rm -f regress/unittests/misc/test_misc$(EXEEXT)
+ rm -f regress/unittests/sshbuf/*.o
+ rm -f regress/unittests/sshbuf/test_sshbuf$(EXEEXT)
+ rm -f regress/unittests/sshkey/*.o
+ rm -f regress/unittests/sshkey/test_sshkey$(EXEEXT)
+ rm -f regress/unittests/sshsig/*.o
+ rm -f regress/unittests/sshsig/test_sshsig$(EXEEXT)
rm -f regress/unittests/utf8/*.o
rm -f regress/unittests/utf8/test_utf8$(EXEEXT)
rm -f regress/misc/sk-dummy/*.o
rm -f regress/misc/sk-dummy/*.lo
rm -f regress/misc/sk-dummy/sk-dummy.so
(cd openbsd-compat && $(MAKE) clean)
distclean: regressclean
rm -f *.o *.a $(TARGETS) logintest config.cache config.log
rm -f *.out core opensshd.init openssh.xml
rm -f Makefile buildpkg.sh config.h config.status
rm -f survey.sh openbsd-compat/regress/Makefile *~
rm -rf autom4te.cache
rm -f regress/check-perm
rm -f regress/mkdtemp
rm -f regress/unittests/test_helper/*.a
rm -f regress/unittests/test_helper/*.o
- rm -f regress/unittests/sshbuf/*.o
- rm -f regress/unittests/sshbuf/test_sshbuf
- rm -f regress/unittests/sshkey/*.o
- rm -f regress/unittests/sshkey/test_sshkey
- rm -f regress/unittests/sshsig/*.o
- rm -f regress/unittests/sshsig/test_sshsig
+ rm -f regress/unittests/authopt/*.o
+ rm -f regress/unittests/authopt/test_authopt
rm -f regress/unittests/bitmap/*.o
rm -f regress/unittests/bitmap/test_bitmap
rm -f regress/unittests/conversion/*.o
rm -f regress/unittests/conversion/test_conversion
rm -f regress/unittests/hostkeys/*.o
rm -f regress/unittests/hostkeys/test_hostkeys
rm -f regress/unittests/kex/*.o
rm -f regress/unittests/kex/test_kex
rm -f regress/unittests/match/*.o
rm -f regress/unittests/match/test_match
+ rm -f regress/unittests/misc/*.o
+ rm -f regress/unittests/misc/test_misc
+ rm -f regress/unittests/sshbuf/*.o
+ rm -f regress/unittests/sshbuf/test_sshbuf
+ rm -f regress/unittests/sshkey/*.o
+ rm -f regress/unittests/sshkey/test_sshkey
+ rm -f regress/unittests/sshsig/*.o
+ rm -f regress/unittests/sshsig/test_sshsig
rm -f regress/unittests/utf8/*.o
rm -f regress/unittests/utf8/test_utf8
(cd openbsd-compat && $(MAKE) distclean)
if test -d pkg ; then \
rm -fr pkg ; \
fi
veryclean: distclean
rm -f configure config.h.in *.0
cleandir: veryclean
mrproper: veryclean
realclean: veryclean
catman-do:
@for f in $(MANPAGES_IN) ; do \
base=`echo $$f | sed 's/\..*$$//'` ; \
echo "$$f -> $$base.0" ; \
$(MANFMT) $$f | cat -v | sed -e 's/.\^H//g' \
>$$base.0 ; \
done
depend: depend-rebuild
rm -f .depend.bak
depend-rebuild:
mv .depend .depend.old
rm -f config.h .depend
touch config.h .depend
makedepend -w1000 -Y. -f .depend *.c 2>/dev/null
(echo '# Automatically generated by makedepend.'; \
echo '# Run "make depend" to rebuild.'; sort .depend ) >.depend.tmp
mv .depend.tmp .depend
rm -f .depend.bak
mv .depend.old .depend.bak
rm -f config.h
depend-check: depend-rebuild
cmp .depend .depend.bak || (echo .depend stale && exit 1)
distprep: catman-do depend-check
$(AUTORECONF)
-rm -rf autom4te.cache .depend.bak
install: $(CONFIGFILES) $(MANPAGES) $(TARGETS) install-files install-sysconf host-key check-config
install-nokeys: $(CONFIGFILES) $(MANPAGES) $(TARGETS) install-files install-sysconf
install-nosysconf: $(CONFIGFILES) $(MANPAGES) $(TARGETS) install-files
check-config:
-$(DESTDIR)$(sbindir)/sshd -t -f $(DESTDIR)$(sysconfdir)/sshd_config
install-files:
$(MKDIR_P) $(DESTDIR)$(bindir)
$(MKDIR_P) $(DESTDIR)$(sbindir)
$(MKDIR_P) $(DESTDIR)$(mandir)/$(mansubdir)1
$(MKDIR_P) $(DESTDIR)$(mandir)/$(mansubdir)5
$(MKDIR_P) $(DESTDIR)$(mandir)/$(mansubdir)8
$(MKDIR_P) $(DESTDIR)$(libexecdir)
$(MKDIR_P) -m 0755 $(DESTDIR)$(PRIVSEP_PATH)
$(INSTALL) -m 0755 $(STRIP_OPT) ssh$(EXEEXT) $(DESTDIR)$(bindir)/ssh$(EXEEXT)
$(INSTALL) -m 0755 $(STRIP_OPT) scp$(EXEEXT) $(DESTDIR)$(bindir)/scp$(EXEEXT)
$(INSTALL) -m 0755 $(STRIP_OPT) ssh-add$(EXEEXT) $(DESTDIR)$(bindir)/ssh-add$(EXEEXT)
$(INSTALL) -m 0755 $(STRIP_OPT) ssh-agent$(EXEEXT) $(DESTDIR)$(bindir)/ssh-agent$(EXEEXT)
$(INSTALL) -m 0755 $(STRIP_OPT) ssh-keygen$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT)
$(INSTALL) -m 0755 $(STRIP_OPT) ssh-keyscan$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT)
$(INSTALL) -m 0755 $(STRIP_OPT) sshd$(EXEEXT) $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
$(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
$(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
$(INSTALL) -m 0755 $(STRIP_OPT) ssh-sk-helper$(EXEEXT) $(DESTDIR)$(SSH_SK_HELPER)$(EXEEXT)
$(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT)
$(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
$(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
$(INSTALL) -m 644 scp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
$(INSTALL) -m 644 ssh-add.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
$(INSTALL) -m 644 ssh-agent.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1
$(INSTALL) -m 644 ssh-keygen.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1
$(INSTALL) -m 644 ssh-keyscan.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1
$(INSTALL) -m 644 moduli.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/moduli.5
$(INSTALL) -m 644 sshd_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/sshd_config.5
$(INSTALL) -m 644 ssh_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/ssh_config.5
$(INSTALL) -m 644 sshd.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8
$(INSTALL) -m 644 sftp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1
$(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
$(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
install-sysconf:
$(MKDIR_P) $(DESTDIR)$(sysconfdir)
@if [ ! -f $(DESTDIR)$(sysconfdir)/ssh_config ]; then \
$(INSTALL) -m 644 ssh_config.out $(DESTDIR)$(sysconfdir)/ssh_config; \
else \
echo "$(DESTDIR)$(sysconfdir)/ssh_config already exists, install will not overwrite"; \
fi
@if [ ! -f $(DESTDIR)$(sysconfdir)/sshd_config ]; then \
$(INSTALL) -m 644 sshd_config.out $(DESTDIR)$(sysconfdir)/sshd_config; \
else \
echo "$(DESTDIR)$(sysconfdir)/sshd_config already exists, install will not overwrite"; \
fi
@if [ ! -f $(DESTDIR)$(sysconfdir)/moduli ]; then \
if [ -f $(DESTDIR)$(sysconfdir)/primes ]; then \
echo "moving $(DESTDIR)$(sysconfdir)/primes to $(DESTDIR)$(sysconfdir)/moduli"; \
mv "$(DESTDIR)$(sysconfdir)/primes" "$(DESTDIR)$(sysconfdir)/moduli"; \
else \
$(INSTALL) -m 644 moduli.out $(DESTDIR)$(sysconfdir)/moduli; \
fi ; \
else \
echo "$(DESTDIR)$(sysconfdir)/moduli already exists, install will not overwrite"; \
fi
host-key: ssh-keygen$(EXEEXT)
@if [ -z "$(DESTDIR)" ] ; then \
./ssh-keygen -A; \
fi
host-key-force: ssh-keygen$(EXEEXT) ssh$(EXEEXT)
./ssh-keygen -t dsa -f $(DESTDIR)$(sysconfdir)/ssh_host_dsa_key -N ""
./ssh-keygen -t rsa -f $(DESTDIR)$(sysconfdir)/ssh_host_rsa_key -N ""
./ssh-keygen -t ed25519 -f $(DESTDIR)$(sysconfdir)/ssh_host_ed25519_key -N ""
if ./ssh -Q key | grep ecdsa >/dev/null ; then \
./ssh-keygen -t ecdsa -f $(DESTDIR)$(sysconfdir)/ssh_host_ecdsa_key -N ""; \
fi
uninstallall: uninstall
-rm -f $(DESTDIR)$(sysconfdir)/ssh_config
-rm -f $(DESTDIR)$(sysconfdir)/sshd_config
-rmdir $(DESTDIR)$(sysconfdir)
-rmdir $(DESTDIR)$(bindir)
-rmdir $(DESTDIR)$(sbindir)
-rmdir $(DESTDIR)$(mandir)/$(mansubdir)1
-rmdir $(DESTDIR)$(mandir)/$(mansubdir)8
-rmdir $(DESTDIR)$(mandir)
-rmdir $(DESTDIR)$(libexecdir)
uninstall:
-rm -f $(DESTDIR)$(bindir)/ssh$(EXEEXT)
-rm -f $(DESTDIR)$(bindir)/scp$(EXEEXT)
-rm -f $(DESTDIR)$(bindir)/ssh-add$(EXEEXT)
-rm -f $(DESTDIR)$(bindir)/ssh-agent$(EXEEXT)
-rm -f $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT)
-rm -f $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT)
-rm -f $(DESTDIR)$(bindir)/sftp$(EXEEXT)
-rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
-rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
-rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
-rm -f $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
-rm -f $(DESTDIR)$(SSH_SK_HELPER)$(EXEEXT)
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-sk-helper.8
regress-prep:
$(MKDIR_P) `pwd`/regress/unittests/test_helper
- $(MKDIR_P) `pwd`/regress/unittests/sshbuf
- $(MKDIR_P) `pwd`/regress/unittests/sshkey
- $(MKDIR_P) `pwd`/regress/unittests/sshsig
+ $(MKDIR_P) `pwd`/regress/unittests/authopt
$(MKDIR_P) `pwd`/regress/unittests/bitmap
$(MKDIR_P) `pwd`/regress/unittests/conversion
$(MKDIR_P) `pwd`/regress/unittests/hostkeys
$(MKDIR_P) `pwd`/regress/unittests/kex
$(MKDIR_P) `pwd`/regress/unittests/match
+ $(MKDIR_P) `pwd`/regress/unittests/misc
+ $(MKDIR_P) `pwd`/regress/unittests/sshbuf
+ $(MKDIR_P) `pwd`/regress/unittests/sshkey
+ $(MKDIR_P) `pwd`/regress/unittests/sshsig
$(MKDIR_P) `pwd`/regress/unittests/utf8
$(MKDIR_P) `pwd`/regress/misc/sk-dummy
[ -f `pwd`/regress/Makefile ] || \
ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile
REGRESSLIBS=libssh.a $(LIBCOMPAT)
regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c $(REGRESSLIBS)
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/modpipe.c \
$(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
regress/setuid-allowed$(EXEEXT): $(srcdir)/regress/setuid-allowed.c $(REGRESSLIBS)
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/setuid-allowed.c \
$(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
regress/netcat$(EXEEXT): $(srcdir)/regress/netcat.c $(REGRESSLIBS)
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/netcat.c \
$(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
regress/check-perm$(EXEEXT): $(srcdir)/regress/check-perm.c $(REGRESSLIBS)
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/check-perm.c \
$(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
regress/mkdtemp$(EXEEXT): $(srcdir)/regress/mkdtemp.c $(REGRESSLIBS)
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/mkdtemp.c \
$(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
UNITTESTS_TEST_HELPER_OBJS=\
regress/unittests/test_helper/test_helper.o \
regress/unittests/test_helper/fuzz.o
regress/unittests/test_helper/libtest_helper.a: ${UNITTESTS_TEST_HELPER_OBJS}
$(AR) rv $@ $(UNITTESTS_TEST_HELPER_OBJS)
$(RANLIB) $@
UNITTESTS_TEST_SSHBUF_OBJS=\
regress/unittests/sshbuf/tests.o \
regress/unittests/sshbuf/test_sshbuf.o \
regress/unittests/sshbuf/test_sshbuf_getput_basic.o \
regress/unittests/sshbuf/test_sshbuf_getput_crypto.o \
regress/unittests/sshbuf/test_sshbuf_misc.o \
regress/unittests/sshbuf/test_sshbuf_fuzz.o \
regress/unittests/sshbuf/test_sshbuf_getput_fuzz.o \
regress/unittests/sshbuf/test_sshbuf_fixed.o
regress/unittests/sshbuf/test_sshbuf$(EXEEXT): ${UNITTESTS_TEST_SSHBUF_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_SSHBUF_OBJS) \
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
UNITTESTS_TEST_SSHKEY_OBJS=\
regress/unittests/sshkey/test_fuzz.o \
regress/unittests/sshkey/tests.o \
regress/unittests/sshkey/common.o \
regress/unittests/sshkey/test_file.o \
regress/unittests/sshkey/test_sshkey.o \
$(SKOBJS)
regress/unittests/sshkey/test_sshkey$(EXEEXT): ${UNITTESTS_TEST_SSHKEY_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_SSHKEY_OBJS) \
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
UNITTESTS_TEST_SSHSIG_OBJS=\
sshsig.o \
regress/unittests/sshsig/tests.o \
$(SKOBJS)
regress/unittests/sshsig/test_sshsig$(EXEEXT): ${UNITTESTS_TEST_SSHSIG_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_SSHSIG_OBJS) \
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
UNITTESTS_TEST_BITMAP_OBJS=\
regress/unittests/bitmap/tests.o
regress/unittests/bitmap/test_bitmap$(EXEEXT): ${UNITTESTS_TEST_BITMAP_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_BITMAP_OBJS) \
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
+UNITTESTS_TEST_AUTHOPT_OBJS=\
+ regress/unittests/authopt/tests.o \
+ auth-options.o \
+ $(SKOBJS)
+
+regress/unittests/authopt/test_authopt$(EXEEXT): \
+ ${UNITTESTS_TEST_AUTHOPT_OBJS} \
+ regress/unittests/test_helper/libtest_helper.a libssh.a
+ $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_AUTHOPT_OBJS) \
+ regress/unittests/test_helper/libtest_helper.a \
+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
+
UNITTESTS_TEST_CONVERSION_OBJS=\
regress/unittests/conversion/tests.o
regress/unittests/conversion/test_conversion$(EXEEXT): \
${UNITTESTS_TEST_CONVERSION_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_CONVERSION_OBJS) \
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
UNITTESTS_TEST_KEX_OBJS=\
regress/unittests/kex/tests.o \
regress/unittests/kex/test_kex.o \
$(SKOBJS)
regress/unittests/kex/test_kex$(EXEEXT): ${UNITTESTS_TEST_KEX_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_KEX_OBJS) \
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
UNITTESTS_TEST_HOSTKEYS_OBJS=\
regress/unittests/hostkeys/tests.o \
regress/unittests/hostkeys/test_iterate.o \
$(SKOBJS)
regress/unittests/hostkeys/test_hostkeys$(EXEEXT): \
${UNITTESTS_TEST_HOSTKEYS_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_HOSTKEYS_OBJS) \
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
UNITTESTS_TEST_MATCH_OBJS=\
regress/unittests/match/tests.o
regress/unittests/match/test_match$(EXEEXT): \
${UNITTESTS_TEST_MATCH_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_MATCH_OBJS) \
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
+UNITTESTS_TEST_MISC_OBJS=\
+ regress/unittests/misc/tests.o \
+ regress/unittests/misc/test_parse.o \
+ regress/unittests/misc/test_expand.o \
+ regress/unittests/misc/test_convtime.o \
+ regress/unittests/misc/test_argv.o
+
+regress/unittests/misc/test_misc$(EXEEXT): \
+ ${UNITTESTS_TEST_MISC_OBJS} \
+ regress/unittests/test_helper/libtest_helper.a libssh.a
+ $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_MISC_OBJS) \
+ regress/unittests/test_helper/libtest_helper.a \
+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
+
UNITTESTS_TEST_UTF8_OBJS=\
regress/unittests/utf8/tests.o
regress/unittests/utf8/test_utf8$(EXEEXT): \
${UNITTESTS_TEST_UTF8_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_UTF8_OBJS) \
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
# These all need to be compiled -fPIC, so they are treated differently.
SK_DUMMY_OBJS=\
regress/misc/sk-dummy/sk-dummy.lo \
regress/misc/sk-dummy/fatal.lo \
ed25519.lo hash.lo ge25519.lo fe25519.lo sc25519.lo verify.lo
SK_DUMMY_LIBRARY=@SK_DUMMY_LIBRARY@
.c.lo: Makefile.in config.h
$(CC) $(CFLAGS_NOPIE) $(PICFLAG) $(CPPFLAGS) -c $< -o $@
regress/misc/sk-dummy/sk-dummy.so: $(SK_DUMMY_OBJS)
$(CC) $(CFLAGS) $(CPPFLAGS) -fPIC -shared -o $@ $(SK_DUMMY_OBJS) \
-L. -Lopenbsd-compat -lopenbsd-compat $(LDFLAGS_NOPIE) $(LIBS)
regress-binaries: regress-prep $(LIBCOMPAT) \
regress/modpipe$(EXEEXT) \
regress/setuid-allowed$(EXEEXT) \
regress/netcat$(EXEEXT) \
regress/check-perm$(EXEEXT) \
regress/mkdtemp$(EXEEXT) \
$(SK_DUMMY_LIBRARY)
regress-unit-binaries: regress-prep $(REGRESSLIBS) \
- regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \
- regress/unittests/sshkey/test_sshkey$(EXEEXT) \
- regress/unittests/sshsig/test_sshsig$(EXEEXT) \
+ regress/unittests/authopt/test_authopt$(EXEEXT) \
regress/unittests/bitmap/test_bitmap$(EXEEXT) \
regress/unittests/conversion/test_conversion$(EXEEXT) \
regress/unittests/hostkeys/test_hostkeys$(EXEEXT) \
regress/unittests/kex/test_kex$(EXEEXT) \
regress/unittests/match/test_match$(EXEEXT) \
+ regress/unittests/misc/test_misc$(EXEEXT) \
+ regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \
+ regress/unittests/sshkey/test_sshkey$(EXEEXT) \
+ regress/unittests/sshsig/test_sshsig$(EXEEXT) \
regress/unittests/utf8/test_utf8$(EXEEXT) \
tests: file-tests t-exec interop-tests unit
echo all tests passed
unit: regress-unit-binaries
BUILDDIR=`pwd`; \
cd $(srcdir)/regress || exit $$?; \
$(MAKE) \
.OBJDIR="$${BUILDDIR}/regress" \
.CURDIR="`pwd`" \
+ OBJ="$${BUILDDIR}/regress" \
$@ && echo $@ tests passed
interop-tests t-exec file-tests: regress-prep regress-binaries $(TARGETS)
BUILDDIR=`pwd`; \
cd $(srcdir)/regress || exit $$?; \
EGREP='@EGREP@' \
$(MAKE) \
.OBJDIR="$${BUILDDIR}/regress" \
.CURDIR="`pwd`" \
BUILDDIR="$${BUILDDIR}" \
OBJ="$${BUILDDIR}/regress/" \
PATH="$${BUILDDIR}:$${PATH}" \
TEST_ENV=MALLOC_OPTIONS="@TEST_MALLOC_OPTIONS@" \
TEST_MALLOC_OPTIONS="@TEST_MALLOC_OPTIONS@" \
TEST_SSH_SCP="$${BUILDDIR}/scp" \
TEST_SSH_SSH="$${BUILDDIR}/ssh" \
TEST_SSH_SSHD="$${BUILDDIR}/sshd" \
TEST_SSH_SSHAGENT="$${BUILDDIR}/ssh-agent" \
TEST_SSH_SSHADD="$${BUILDDIR}/ssh-add" \
TEST_SSH_SSHKEYGEN="$${BUILDDIR}/ssh-keygen" \
TEST_SSH_SSHPKCS11HELPER="$${BUILDDIR}/ssh-pkcs11-helper" \
TEST_SSH_SSHKEYSCAN="$${BUILDDIR}/ssh-keyscan" \
TEST_SSH_SFTP="$${BUILDDIR}/sftp" \
TEST_SSH_PKCS11_HELPER="$${BUILDDIR}/ssh-pkcs11-helper" \
TEST_SSH_SK_HELPER="$${BUILDDIR}/ssh-sk-helper" \
TEST_SSH_SFTPSERVER="$${BUILDDIR}/sftp-server" \
+ TEST_SSH_MODULI_FILE="$(abs_top_srcdir)/moduli" \
TEST_SSH_PLINK="plink" \
TEST_SSH_PUTTYGEN="puttygen" \
TEST_SSH_CONCH="conch" \
TEST_SSH_IPV6="@TEST_SSH_IPV6@" \
TEST_SSH_UTF8="@TEST_SSH_UTF8@" \
TEST_SSH_ECC="@TEST_SSH_ECC@" \
TEST_SHELL="${TEST_SHELL}" \
EXEEXT="$(EXEEXT)" \
$@ && echo all $@ passed
compat-tests: $(LIBCOMPAT)
(cd openbsd-compat/regress && $(MAKE))
regressclean:
if [ -f regress/Makefile ] && [ -r regress/Makefile ]; then \
(cd regress && $(MAKE) clean) \
fi
survey: survey.sh ssh
@$(SHELL) ./survey.sh > survey
@echo 'The survey results have been placed in the file "survey" in the'
@echo 'current directory. Please review the file then send with'
@echo '"make send-survey".'
send-survey: survey
mail portable-survey@mindrot.org <survey
package: $(CONFIGFILES) $(MANPAGES) $(TARGETS)
if [ "@MAKE_PACKAGE_SUPPORTED@" = yes ]; then \
sh buildpkg.sh; \
fi
# @DEPEND@
diff --git a/README b/README
index 0f87812a6388..99fe347738ca 100644
--- a/README
+++ b/README
@@ -1,52 +1,52 @@
-See https://www.openssh.com/releasenotes.html#8.5p1 for the release notes.
+See https://www.openssh.com/releasenotes.html#8.6p1 for the release notes.
Please read https://www.openssh.com/report.html for bug reporting
instructions and note that we do not use Github for bug reporting or
patch/pull-request management.
This is the port of OpenBSD's excellent OpenSSH[0] to Linux and other
Unices.
OpenSSH is based on the last free version of Tatu Ylonen's sample
implementation with all patent-encumbered algorithms removed (to
external libraries), all known security bugs fixed, new features
reintroduced and many other clean-ups. OpenSSH has been created by
Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo de Raadt,
and Dug Song. It has a homepage at https://www.openssh.com/
This port consists of the re-introduction of autoconf support, PAM
support, EGD/PRNGD support and replacements for OpenBSD library
functions that are (regrettably) absent from other unices. This port
has been best tested on AIX, Cygwin, HP-UX, Linux, MacOS/X,
FreeBSD, NetBSD, OpenBSD, OpenServer, Solaris and UnixWare.
This version actively tracks changes in the OpenBSD CVS repository.
The PAM support is now more functional than the popular packages of
commercial ssh-1.2.x. It checks "account" and "session" modules for
all logins, not just when using password authentication.
There is now several mailing lists for this port of OpenSSH. Please
refer to https://www.openssh.com/list.html for details on how to join.
Please send bug reports and patches to https://bugzilla.mindrot.org or
the mailing list openssh-unix-dev@mindrot.org. To mitigate spam, the
list only allows posting from subscribed addresses. Code contribution
are welcomed, but please follow the OpenBSD style guidelines[1].
Please refer to the INSTALL document for information on dependencies and
how to install OpenSSH on your system.
Damien Miller <djm@mindrot.org>
Miscellania -
This version of OpenSSH is based upon code retrieved from the OpenBSD CVS
repository which in turn was based on the last free sample implementation
released by Tatu Ylonen.
References -
[0] https://www.openssh.com/
[1] https://man.openbsd.org/style.9
diff --git a/addrmatch.c b/addrmatch.c
index 3215c653d36a..b0dc096804db 100644
--- a/addrmatch.c
+++ b/addrmatch.c
@@ -1,169 +1,169 @@
-/* $OpenBSD: addrmatch.c,v 1.16 2021/01/09 11:58:50 dtucker Exp $ */
+/* $OpenBSD: addrmatch.c,v 1.17 2021/04/03 06:18:40 djm Exp $ */
/*
* Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include "addr.h"
#include "match.h"
#include "log.h"
/*
* Match "addr" against list pattern list "_list", which may contain a
* mix of CIDR addresses and old-school wildcards.
*
* If addr is NULL, then no matching is performed, but _list is parsed
* and checked for well-formedness.
*
* Returns 1 on match found (never returned when addr == NULL).
* Returns 0 on if no match found, or no errors found when addr == NULL.
* Returns -1 on negated match found (never returned when addr == NULL).
* Returns -2 on invalid list entry.
*/
int
addr_match_list(const char *addr, const char *_list)
{
char *list, *cp, *o;
struct xaddr try_addr, match_addr;
u_int masklen, neg;
int ret = 0, r;
if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
debug2_f("couldn't parse address %.100s", addr);
return 0;
}
if ((o = list = strdup(_list)) == NULL)
return -1;
while ((cp = strsep(&list, ",")) != NULL) {
neg = *cp == '!';
if (neg)
cp++;
if (*cp == '\0') {
ret = -2;
break;
}
/* Prefer CIDR address matching */
r = addr_pton_cidr(cp, &match_addr, &masklen);
if (r == -2) {
debug2_f("inconsistent mask length for "
"match network \"%.100s\"", cp);
ret = -2;
break;
} else if (r == 0) {
if (addr != NULL && addr_netmatch(&try_addr,
- &match_addr, masklen) == 0) {
+ &match_addr, masklen) == 0) {
foundit:
if (neg) {
ret = -1;
break;
}
ret = 1;
}
continue;
} else {
/* If CIDR parse failed, try wildcard string match */
if (addr != NULL && match_pattern(addr, cp) == 1)
goto foundit;
}
}
free(o);
return ret;
}
/*
* Match "addr" against list CIDR list "_list". Lexical wildcards and
* negation are not supported. If "addr" == NULL, will verify structure
* of "_list".
*
* Returns 1 on match found (never returned when addr == NULL).
* Returns 0 on if no match found, or no errors found when addr == NULL.
* Returns -1 on error
*/
int
addr_match_cidr_list(const char *addr, const char *_list)
{
char *list, *cp, *o;
struct xaddr try_addr, match_addr;
u_int masklen;
int ret = 0, r;
if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
debug2_f("couldn't parse address %.100s", addr);
return 0;
}
if ((o = list = strdup(_list)) == NULL)
return -1;
while ((cp = strsep(&list, ",")) != NULL) {
if (*cp == '\0') {
error_f("empty entry in list \"%.100s\"", o);
ret = -1;
break;
}
/*
* NB. This function is called in pre-auth with untrusted data,
* so be extra paranoid about junk reaching getaddrino (via
* addr_pton_cidr).
*/
/* Stop junk from reaching getaddrinfo. +3 is for masklen */
if (strlen(cp) > INET6_ADDRSTRLEN + 3) {
error_f("list entry \"%.100s\" too long", cp);
ret = -1;
break;
}
#define VALID_CIDR_CHARS "0123456789abcdefABCDEF.:/"
if (strspn(cp, VALID_CIDR_CHARS) != strlen(cp)) {
error_f("list entry \"%.100s\" contains invalid "
"characters", cp);
ret = -1;
}
/* Prefer CIDR address matching */
r = addr_pton_cidr(cp, &match_addr, &masklen);
if (r == -1) {
error("Invalid network entry \"%.100s\"", cp);
ret = -1;
break;
} else if (r == -2) {
error("Inconsistent mask length for "
"network \"%.100s\"", cp);
ret = -1;
break;
} else if (r == 0 && addr != NULL) {
if (addr_netmatch(&try_addr, &match_addr,
masklen) == 0)
ret = 1;
continue;
}
}
free(o);
return ret;
}
diff --git a/audit-bsm.c b/audit-bsm.c
index 0ba16c72c820..ccfcf6f7fc68 100644
--- a/audit-bsm.c
+++ b/audit-bsm.c
@@ -1,454 +1,455 @@
/*
* TODO
*
* - deal with overlap between this and sys_auth_allowed_user
* sys_auth_record_login and record_failed_login.
*/
/*
* Copyright 1988-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/* #pragma ident "@(#)bsmaudit.c 1.1 01/09/17 SMI" */
#include "includes.h"
#if defined(USE_BSM_AUDIT)
#include <sys/types.h>
#include <errno.h>
#include <netdb.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#ifdef BROKEN_BSM_API
#include <libscf.h>
#endif
#include "ssh.h"
#include "log.h"
#include "hostfile.h"
#include "auth.h"
#include "xmalloc.h"
#ifndef AUE_openssh
# define AUE_openssh 32800
#endif
#include <bsm/audit.h>
#include <bsm/libbsm.h>
#include <bsm/audit_uevents.h>
#include <bsm/audit_record.h>
#include <locale.h>
#if defined(HAVE_GETAUDIT_ADDR)
#define AuditInfoStruct auditinfo_addr
#define AuditInfoTermID au_tid_addr_t
#define SetAuditFunc(a,b) setaudit_addr((a),(b))
#define SetAuditFuncText "setaudit_addr"
#define AUToSubjectFunc au_to_subject_ex
#define AUToReturnFunc(a,b) au_to_return32((a), (int32_t)(b))
#else
#define AuditInfoStruct auditinfo
#define AuditInfoTermID au_tid_t
#define SetAuditFunc(a,b) setaudit(a)
#define SetAuditFuncText "setaudit"
#define AUToSubjectFunc au_to_subject
#define AUToReturnFunc(a,b) au_to_return((a), (u_int)(b))
#endif
#ifndef cannot_audit
extern int cannot_audit(int);
#endif
extern void aug_init(void);
extern void aug_save_auid(au_id_t);
extern void aug_save_uid(uid_t);
extern void aug_save_euid(uid_t);
extern void aug_save_gid(gid_t);
extern void aug_save_egid(gid_t);
extern void aug_save_pid(pid_t);
extern void aug_save_asid(au_asid_t);
extern void aug_save_tid(dev_t, unsigned int);
extern void aug_save_tid_ex(dev_t, u_int32_t *, u_int32_t);
extern int aug_save_me(void);
extern int aug_save_namask(void);
extern void aug_save_event(au_event_t);
extern void aug_save_sorf(int);
extern void aug_save_text(char *);
extern void aug_save_text1(char *);
extern void aug_save_text2(char *);
extern void aug_save_na(int);
extern void aug_save_user(char *);
extern void aug_save_path(char *);
extern int aug_save_policy(void);
extern void aug_save_afunc(int (*)(int));
extern int aug_audit(void);
extern int aug_na_selected(void);
extern int aug_selected(void);
extern int aug_daemon_session(void);
#ifndef HAVE_GETTEXT
# define gettext(a) (a)
#endif
extern Authctxt *the_authctxt;
static AuditInfoTermID ssh_bsm_tid;
#ifdef BROKEN_BSM_API
/* For some reason this constant is no longer defined
in Solaris 11. */
#define BSM_TEXTBUFSZ 256
#endif
/* Below is the low-level BSM interface code */
/*
* aug_get_machine is only required on IPv6 capable machines, we use a
* different mechanism in audit_connection_from() for IPv4-only machines.
* getaudit_addr() is only present on IPv6 capable machines.
*/
#if defined(HAVE_AUG_GET_MACHINE) || !defined(HAVE_GETAUDIT_ADDR)
-extern int aug_get_machine(char *, u_int32_t *, u_int32_t *);
+extern int aug_get_machine(char *, u_int32_t *, u_int32_t *);
#else
static int
aug_get_machine(char *host, u_int32_t *addr, u_int32_t *type)
{
struct addrinfo *ai;
struct sockaddr_in *in4;
struct sockaddr_in6 *in6;
int ret = 0, r;
if ((r = getaddrinfo(host, NULL, NULL, &ai)) != 0) {
error("BSM audit: getaddrinfo failed for %.100s: %.100s", host,
r == EAI_SYSTEM ? strerror(errno) : gai_strerror(r));
return -1;
}
switch (ai->ai_family) {
case AF_INET:
in4 = (struct sockaddr_in *)ai->ai_addr;
*type = AU_IPv4;
memcpy(addr, &in4->sin_addr, sizeof(struct in_addr));
break;
#ifdef AU_IPv6
case AF_INET6:
in6 = (struct sockaddr_in6 *)ai->ai_addr;
*type = AU_IPv6;
memcpy(addr, &in6->sin6_addr, sizeof(struct in6_addr));
break;
#endif
default:
error("BSM audit: unknown address family for %.100s: %d",
host, ai->ai_family);
ret = -1;
}
freeaddrinfo(ai);
return ret;
}
#endif
#ifdef BROKEN_BSM_API
/*
In Solaris 11 the audit daemon has been moved to SMF. In the process
they simply dropped getacna() from the API, since it read from a now
non-existent config file. This function re-implements getacna() to
read from the SMF repository instead.
*/
int
getacna(char *auditstring, int len)
{
scf_handle_t *handle = NULL;
scf_property_t *property = NULL;
scf_value_t *value = NULL;
int ret = 0;
+ /*
+ * The man page for getacna on Solaris 10 states we should return -2
+ * in case of error and set errno to indicate the error. We don't
+ * bother with errno here, though, since the only use of this function
+ * below doesn't check for errors anyway.
+ */
handle = scf_handle_create(SCF_VERSION);
if (handle == NULL)
- return -2; /* The man page for getacna on Solaris 10 states
- we should return -2 in case of error and set
- errno to indicate the error. We don't bother
- with errno here, though, since the only use
- of this function below doesn't check for errors
- anyway.
- */
+ return -2;
ret = scf_handle_bind(handle);
if (ret == -1)
- return -2;
+ return -2;
property = scf_property_create(handle);
if (property == NULL)
- return -2;
+ return -2;
ret = scf_handle_decode_fmri(handle,
- "svc:/system/auditd:default/:properties/preselection/naflags",
- NULL, NULL, NULL, NULL, property, 0);
+ "svc:/system/auditd:default/:properties/preselection/naflags",
+ NULL, NULL, NULL, NULL, property, 0);
if (ret == -1)
- return -2;
+ return -2;
value = scf_value_create(handle);
if (value == NULL)
- return -2;
+ return -2;
ret = scf_property_get_value(property, value);
if (ret == -1)
- return -2;
+ return -2;
ret = scf_value_get_astring(value, auditstring, len);
if (ret == -1)
- return -2;
+ return -2;
scf_value_destroy(value);
scf_property_destroy(property);
scf_handle_destroy(handle);
return 0;
}
#endif
/*
* Check if the specified event is selected (enabled) for auditing.
* Returns 1 if the event is selected, 0 if not and -1 on failure.
*/
static int
selected(char *username, uid_t uid, au_event_t event, int sf)
{
int rc, sorf;
char naflags[512];
struct au_mask mask;
mask.am_success = mask.am_failure = 0;
if (uid < 0) {
/* get flags for non-attributable (to a real user) events */
rc = getacna(naflags, sizeof(naflags));
if (rc == 0)
(void) getauditflagsbin(naflags, &mask);
} else
rc = au_user_mask(username, &mask);
sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE;
return(au_preselect(event, &mask, sorf, AU_PRS_REREAD));
}
static void
bsm_audit_record(int typ, char *string, au_event_t event_no)
{
int ad, rc, sel;
uid_t uid = -1;
gid_t gid = -1;
pid_t pid = getpid();
AuditInfoTermID tid = ssh_bsm_tid;
if (the_authctxt != NULL && the_authctxt->valid) {
uid = the_authctxt->pw->pw_uid;
gid = the_authctxt->pw->pw_gid;
}
rc = (typ == 0) ? 0 : -1;
sel = selected(the_authctxt->user, uid, event_no, rc);
debug3("BSM audit: typ %d rc %d \"%s\"", typ, rc, string);
if (!sel)
return; /* audit event does not match mask, do not write */
debug3("BSM audit: writing audit new record");
ad = au_open();
(void) au_write(ad, AUToSubjectFunc(uid, uid, gid, uid, gid,
pid, pid, &tid));
(void) au_write(ad, au_to_text(string));
(void) au_write(ad, AUToReturnFunc(typ, rc));
#ifdef BROKEN_BSM_API
- /* The last argument is the event modifier flags. For
- some seemingly undocumented reason it was added in
- Solaris 11. */
+ /*
+ * The last argument is the event modifier flags. For some seemingly
+ * undocumented reason it was added in Solaris 11.
+ */
rc = au_close(ad, AU_TO_WRITE, event_no, 0);
#else
rc = au_close(ad, AU_TO_WRITE, event_no);
#endif
if (rc < 0)
error("BSM audit: %s failed to write \"%s\" record: %s",
__func__, string, strerror(errno));
}
static void
bsm_audit_session_setup(void)
{
int rc;
struct AuditInfoStruct info;
au_mask_t mask;
if (the_authctxt == NULL) {
error("BSM audit: session setup internal error (NULL ctxt)");
return;
}
if (the_authctxt->valid)
info.ai_auid = the_authctxt->pw->pw_uid;
else
info.ai_auid = -1;
info.ai_asid = getpid();
mask.am_success = 0;
mask.am_failure = 0;
(void) au_user_mask(the_authctxt->user, &mask);
info.ai_mask.am_success = mask.am_success;
info.ai_mask.am_failure = mask.am_failure;
info.ai_termid = ssh_bsm_tid;
rc = SetAuditFunc(&info, sizeof(info));
if (rc < 0)
error("BSM audit: %s: %s failed: %s", __func__,
SetAuditFuncText, strerror(errno));
}
static void
bsm_audit_bad_login(const char *what)
{
char textbuf[BSM_TEXTBUFSZ];
if (the_authctxt->valid) {
(void) snprintf(textbuf, sizeof (textbuf),
gettext("invalid %s for user %s"),
what, the_authctxt->user);
bsm_audit_record(4, textbuf, AUE_openssh);
} else {
(void) snprintf(textbuf, sizeof (textbuf),
gettext("invalid user name \"%s\""),
the_authctxt->user);
bsm_audit_record(3, textbuf, AUE_openssh);
}
}
/* Below is the sshd audit API code */
void
audit_connection_from(const char *host, int port)
{
AuditInfoTermID *tid = &ssh_bsm_tid;
char buf[1024];
if (cannot_audit(0))
return;
debug3("BSM audit: connection from %.100s port %d", host, port);
/* populate our terminal id structure */
#if defined(HAVE_GETAUDIT_ADDR)
tid->at_port = (dev_t)port;
aug_get_machine((char *)host, &(tid->at_addr[0]), &(tid->at_type));
snprintf(buf, sizeof(buf), "%08x %08x %08x %08x", tid->at_addr[0],
tid->at_addr[1], tid->at_addr[2], tid->at_addr[3]);
debug3("BSM audit: iptype %d machine ID %s", (int)tid->at_type, buf);
#else
/* this is used on IPv4-only machines */
tid->port = (dev_t)port;
tid->machine = inet_addr(host);
snprintf(buf, sizeof(buf), "%08x", tid->machine);
debug3("BSM audit: machine ID %s", buf);
#endif
}
void
audit_run_command(const char *command)
{
/* not implemented */
}
void
audit_session_open(struct logininfo *li)
{
/* not implemented */
}
void
audit_session_close(struct logininfo *li)
{
/* not implemented */
}
void
audit_event(struct ssh *ssh, ssh_audit_event_t event)
{
char textbuf[BSM_TEXTBUFSZ];
static int logged_in = 0;
const char *user = the_authctxt ? the_authctxt->user : "(unknown user)";
if (cannot_audit(0))
return;
switch(event) {
case SSH_AUTH_SUCCESS:
logged_in = 1;
bsm_audit_session_setup();
snprintf(textbuf, sizeof(textbuf),
gettext("successful login %s"), user);
bsm_audit_record(0, textbuf, AUE_openssh);
break;
case SSH_CONNECTION_CLOSE:
/*
* We can also get a close event if the user attempted auth
* but never succeeded.
*/
if (logged_in) {
snprintf(textbuf, sizeof(textbuf),
gettext("sshd logout %s"), the_authctxt->user);
bsm_audit_record(0, textbuf, AUE_logout);
} else {
debug("%s: connection closed without authentication",
__func__);
}
break;
case SSH_NOLOGIN:
bsm_audit_record(1,
gettext("logins disabled by /etc/nologin"), AUE_openssh);
break;
case SSH_LOGIN_EXCEED_MAXTRIES:
snprintf(textbuf, sizeof(textbuf),
gettext("too many tries for user %s"), the_authctxt->user);
bsm_audit_record(1, textbuf, AUE_openssh);
break;
case SSH_LOGIN_ROOT_DENIED:
bsm_audit_record(2, gettext("not_console"), AUE_openssh);
break;
case SSH_AUTH_FAIL_PASSWD:
bsm_audit_bad_login("password");
break;
case SSH_AUTH_FAIL_KBDINT:
bsm_audit_bad_login("interactive password entry");
break;
default:
debug("%s: unhandled event %d", __func__, event);
}
}
#endif /* BSM */
diff --git a/auth-krb5.c b/auth-krb5.c
index 3096f1c8ea4d..c99e4e430e73 100644
--- a/auth-krb5.c
+++ b/auth-krb5.c
@@ -1,272 +1,273 @@
-/* $OpenBSD: auth-krb5.c,v 1.23 2018/07/09 21:35:50 markus Exp $ */
+/* $OpenBSD: auth-krb5.c,v 1.24 2021/04/03 06:18:40 djm Exp $ */
/*
* Kerberos v5 authentication and ticket-passing routines.
*
* From: FreeBSD: src/crypto/openssh/auth-krb5.c,v 1.6 2001/02/13 16:58:04 assar
*/
/*
* Copyright (c) 2002 Daniel Kouril. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <pwd.h>
#include <stdarg.h>
#include "xmalloc.h"
#include "ssh.h"
#include "packet.h"
#include "log.h"
#include "sshbuf.h"
#include "sshkey.h"
#include "misc.h"
#include "servconf.h"
#include "uidswap.h"
#include "hostfile.h"
#include "auth.h"
#ifdef KRB5
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <krb5.h>
extern ServerOptions options;
static int
krb5_init(void *context)
{
Authctxt *authctxt = (Authctxt *)context;
krb5_error_code problem;
if (authctxt->krb5_ctx == NULL) {
problem = krb5_init_context(&authctxt->krb5_ctx);
if (problem)
return (problem);
}
return (0);
}
int
auth_krb5_password(Authctxt *authctxt, const char *password)
{
#ifndef HEIMDAL
krb5_creds creds;
krb5_principal server;
#endif
krb5_error_code problem;
krb5_ccache ccache = NULL;
int len;
char *client, *platform_client;
const char *errmsg;
/* get platform-specific kerberos client principal name (if it exists) */
platform_client = platform_krb5_get_principal_name(authctxt->pw->pw_name);
client = platform_client ? platform_client : authctxt->pw->pw_name;
temporarily_use_uid(authctxt->pw);
problem = krb5_init(authctxt);
if (problem)
goto out;
problem = krb5_parse_name(authctxt->krb5_ctx, client,
&authctxt->krb5_user);
if (problem)
goto out;
#ifdef HEIMDAL
# ifdef HAVE_KRB5_CC_NEW_UNIQUE
problem = krb5_cc_new_unique(authctxt->krb5_ctx,
- krb5_mcc_ops.prefix, NULL, &ccache);
+ krb5_mcc_ops.prefix, NULL, &ccache);
# else
problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, &ccache);
# endif
if (problem)
goto out;
problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache,
authctxt->krb5_user);
if (problem)
goto out;
restore_uid();
problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user,
ccache, password, 1, NULL);
temporarily_use_uid(authctxt->pw);
if (problem)
goto out;
# ifdef HAVE_KRB5_CC_NEW_UNIQUE
problem = krb5_cc_new_unique(authctxt->krb5_ctx,
- krb5_fcc_ops.prefix, NULL, &authctxt->krb5_fwd_ccache);
+ krb5_fcc_ops.prefix, NULL, &authctxt->krb5_fwd_ccache);
# else
problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops,
&authctxt->krb5_fwd_ccache);
# endif
if (problem)
goto out;
problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache,
authctxt->krb5_fwd_ccache);
krb5_cc_destroy(authctxt->krb5_ctx, ccache);
ccache = NULL;
if (problem)
goto out;
#else
problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds,
authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL);
if (problem)
goto out;
problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL,
KRB5_NT_SRV_HST, &server);
if (problem)
goto out;
restore_uid();
problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server,
NULL, NULL, NULL);
krb5_free_principal(authctxt->krb5_ctx, server);
temporarily_use_uid(authctxt->pw);
if (problem)
goto out;
if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user,
authctxt->pw->pw_name)) {
problem = -1;
goto out;
}
- problem = ssh_krb5_cc_gen(authctxt->krb5_ctx, &authctxt->krb5_fwd_ccache);
+ problem = ssh_krb5_cc_gen(authctxt->krb5_ctx,
+ &authctxt->krb5_fwd_ccache);
if (problem)
goto out;
- problem = krb5_cc_initialize(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache,
- authctxt->krb5_user);
+ problem = krb5_cc_initialize(authctxt->krb5_ctx,
+ authctxt->krb5_fwd_ccache, authctxt->krb5_user);
if (problem)
goto out;
- problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache,
- &creds);
+ problem = krb5_cc_store_cred(authctxt->krb5_ctx,
+ authctxt->krb5_fwd_ccache, &creds);
if (problem)
goto out;
#endif
authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
len = strlen(authctxt->krb5_ticket_file) + 6;
authctxt->krb5_ccname = xmalloc(len);
snprintf(authctxt->krb5_ccname, len, "FILE:%s",
authctxt->krb5_ticket_file);
#ifdef USE_PAM
if (options.use_pam)
do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname);
#endif
out:
restore_uid();
free(platform_client);
if (problem) {
if (ccache)
krb5_cc_destroy(authctxt->krb5_ctx, ccache);
if (authctxt->krb5_ctx != NULL && problem!=-1) {
errmsg = krb5_get_error_message(authctxt->krb5_ctx,
problem);
- debug("Kerberos password authentication failed: %s",
+ debug("Kerberos password authentication failed: %s",
errmsg);
krb5_free_error_message(authctxt->krb5_ctx, errmsg);
} else
debug("Kerberos password authentication failed: %d",
problem);
krb5_cleanup_proc(authctxt);
if (options.kerberos_or_local_passwd)
return (-1);
else
return (0);
}
return (authctxt->valid ? 1 : 0);
}
void
krb5_cleanup_proc(Authctxt *authctxt)
{
debug("krb5_cleanup_proc called");
if (authctxt->krb5_fwd_ccache) {
krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
authctxt->krb5_fwd_ccache = NULL;
}
if (authctxt->krb5_user) {
krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user);
authctxt->krb5_user = NULL;
}
if (authctxt->krb5_ctx) {
krb5_free_context(authctxt->krb5_ctx);
authctxt->krb5_ctx = NULL;
}
}
#ifndef HEIMDAL
krb5_error_code
ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
int tmpfd, ret, oerrno;
char ccname[40];
mode_t old_umask;
ret = snprintf(ccname, sizeof(ccname),
"FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
if (ret < 0 || (size_t)ret >= sizeof(ccname))
return ENOMEM;
old_umask = umask(0177);
tmpfd = mkstemp(ccname + strlen("FILE:"));
oerrno = errno;
umask(old_umask);
if (tmpfd == -1) {
logit("mkstemp(): %.100s", strerror(oerrno));
return oerrno;
}
if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
oerrno = errno;
logit("fchmod(): %.100s", strerror(oerrno));
close(tmpfd);
return oerrno;
}
close(tmpfd);
return (krb5_cc_resolve(ctx, ccname, ccache));
}
#endif /* !HEIMDAL */
#endif /* KRB5 */
diff --git a/auth-options.c b/auth-options.c
index 55b2e9b4cf1c..f68c629dd2c2 100644
--- a/auth-options.c
+++ b/auth-options.c
@@ -1,892 +1,892 @@
-/* $OpenBSD: auth-options.c,v 1.94 2020/10/18 11:32:01 djm Exp $ */
+/* $OpenBSD: auth-options.c,v 1.95 2021/04/03 06:18:40 djm Exp $ */
/*
* Copyright (c) 2018 Damien Miller <djm@mindrot.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include <sys/types.h>
#include <stdlib.h>
#include <netdb.h>
#include <pwd.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#include <limits.h>
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "ssherr.h"
#include "log.h"
#include "sshbuf.h"
#include "misc.h"
#include "sshkey.h"
#include "match.h"
#include "ssh2.h"
#include "auth-options.h"
static int
dup_strings(char ***dstp, size_t *ndstp, char **src, size_t nsrc)
{
char **dst;
size_t i, j;
*dstp = NULL;
*ndstp = 0;
if (nsrc == 0)
return 0;
if ((dst = calloc(nsrc, sizeof(*src))) == NULL)
return -1;
for (i = 0; i < nsrc; i++) {
if ((dst[i] = strdup(src[i])) == NULL) {
for (j = 0; j < i; j++)
free(dst[j]);
free(dst);
return -1;
}
}
/* success */
*dstp = dst;
*ndstp = nsrc;
return 0;
}
#define OPTIONS_CRITICAL 1
#define OPTIONS_EXTENSIONS 2
static int
cert_option_list(struct sshauthopt *opts, struct sshbuf *oblob,
u_int which, int crit)
{
char *command, *allowed;
char *name = NULL;
struct sshbuf *c = NULL, *data = NULL;
int r, ret = -1, found;
if ((c = sshbuf_fromb(oblob)) == NULL) {
error_f("sshbuf_fromb failed");
goto out;
}
while (sshbuf_len(c) > 0) {
sshbuf_free(data);
data = NULL;
if ((r = sshbuf_get_cstring(c, &name, NULL)) != 0 ||
(r = sshbuf_froms(c, &data)) != 0) {
error_r(r, "Unable to parse certificate options");
goto out;
}
debug3("found certificate option \"%.100s\" len %zu",
name, sshbuf_len(data));
found = 0;
if ((which & OPTIONS_EXTENSIONS) != 0) {
if (strcmp(name, "no-touch-required") == 0) {
opts->no_require_user_presence = 1;
found = 1;
} else if (strcmp(name, "permit-X11-forwarding") == 0) {
opts->permit_x11_forwarding_flag = 1;
found = 1;
} else if (strcmp(name,
"permit-agent-forwarding") == 0) {
opts->permit_agent_forwarding_flag = 1;
found = 1;
} else if (strcmp(name,
"permit-port-forwarding") == 0) {
opts->permit_port_forwarding_flag = 1;
found = 1;
} else if (strcmp(name, "permit-pty") == 0) {
opts->permit_pty_flag = 1;
found = 1;
} else if (strcmp(name, "permit-user-rc") == 0) {
opts->permit_user_rc = 1;
found = 1;
}
}
if (!found && (which & OPTIONS_CRITICAL) != 0) {
if (strcmp(name, "verify-required") == 0) {
opts->require_verify = 1;
found = 1;
} else if (strcmp(name, "force-command") == 0) {
if ((r = sshbuf_get_cstring(data, &command,
NULL)) != 0) {
error_r(r, "Unable to parse \"%s\" "
"section", name);
goto out;
}
if (opts->force_command != NULL) {
error("Certificate has multiple "
"force-command options");
free(command);
goto out;
}
opts->force_command = command;
found = 1;
} else if (strcmp(name, "source-address") == 0) {
if ((r = sshbuf_get_cstring(data, &allowed,
NULL)) != 0) {
error_r(r, "Unable to parse \"%s\" "
"section", name);
goto out;
}
if (opts->required_from_host_cert != NULL) {
error("Certificate has multiple "
"source-address options");
free(allowed);
goto out;
}
/* Check syntax */
if (addr_match_cidr_list(NULL, allowed) == -1) {
error("Certificate source-address "
"contents invalid");
goto out;
}
opts->required_from_host_cert = allowed;
found = 1;
}
}
if (!found) {
if (crit) {
error("Certificate critical option \"%s\" "
"is not supported", name);
goto out;
} else {
logit("Certificate extension \"%s\" "
"is not supported", name);
}
} else if (sshbuf_len(data) != 0) {
error("Certificate option \"%s\" corrupt "
"(extra data)", name);
goto out;
}
free(name);
name = NULL;
}
/* successfully parsed all options */
ret = 0;
out:
free(name);
sshbuf_free(data);
sshbuf_free(c);
return ret;
}
struct sshauthopt *
sshauthopt_new(void)
{
struct sshauthopt *ret;
if ((ret = calloc(1, sizeof(*ret))) == NULL)
return NULL;
ret->force_tun_device = -1;
return ret;
}
void
sshauthopt_free(struct sshauthopt *opts)
{
size_t i;
if (opts == NULL)
return;
free(opts->cert_principals);
free(opts->force_command);
free(opts->required_from_host_cert);
free(opts->required_from_host_keys);
for (i = 0; i < opts->nenv; i++)
free(opts->env[i]);
free(opts->env);
for (i = 0; i < opts->npermitopen; i++)
free(opts->permitopen[i]);
free(opts->permitopen);
for (i = 0; i < opts->npermitlisten; i++)
free(opts->permitlisten[i]);
free(opts->permitlisten);
freezero(opts, sizeof(*opts));
}
struct sshauthopt *
sshauthopt_new_with_keys_defaults(void)
{
struct sshauthopt *ret = NULL;
if ((ret = sshauthopt_new()) == NULL)
return NULL;
/* Defaults for authorized_keys flags */
ret->permit_port_forwarding_flag = 1;
ret->permit_agent_forwarding_flag = 1;
ret->permit_x11_forwarding_flag = 1;
ret->permit_pty_flag = 1;
ret->permit_user_rc = 1;
return ret;
}
/*
* Parse and record a permitopen/permitlisten directive.
* Return 0 on success. Return -1 on failure and sets *errstrp to error reason.
*/
static int
handle_permit(const char **optsp, int allow_bare_port,
char ***permitsp, size_t *npermitsp, const char **errstrp)
{
char *opt, *tmp, *cp, *host, **permits = *permitsp;
size_t npermits = *npermitsp;
const char *errstr = "unknown error";
if (npermits > SSH_AUTHOPT_PERMIT_MAX) {
*errstrp = "too many permission directives";
return -1;
}
if ((opt = opt_dequote(optsp, &errstr)) == NULL) {
return -1;
}
if (allow_bare_port && strchr(opt, ':') == NULL) {
/*
* Allow a bare port number in permitlisten to indicate a
* listen_host wildcard.
*/
if (asprintf(&tmp, "*:%s", opt) == -1) {
free(opt);
*errstrp = "memory allocation failed";
return -1;
}
free(opt);
opt = tmp;
}
if ((tmp = strdup(opt)) == NULL) {
free(opt);
*errstrp = "memory allocation failed";
return -1;
}
cp = tmp;
/* validate syntax before recording it. */
host = hpdelim(&cp);
if (host == NULL || strlen(host) >= NI_MAXHOST) {
free(tmp);
free(opt);
*errstrp = "invalid permission hostname";
return -1;
}
/*
* don't want to use permitopen_port to avoid
* dependency on channels.[ch] here.
*/
if (cp == NULL ||
(strcmp(cp, "*") != 0 && a2port(cp) <= 0)) {
free(tmp);
free(opt);
*errstrp = "invalid permission port";
return -1;
}
/* XXX - add streamlocal support */
free(tmp);
/* Record it */
if ((permits = recallocarray(permits, npermits, npermits + 1,
sizeof(*permits))) == NULL) {
free(opt);
/* NB. don't update *permitsp if alloc fails */
*errstrp = "memory allocation failed";
return -1;
}
permits[npermits++] = opt;
*permitsp = permits;
*npermitsp = npermits;
return 0;
}
struct sshauthopt *
sshauthopt_parse(const char *opts, const char **errstrp)
{
char **oarray, *opt, *cp, *tmp;
int r;
struct sshauthopt *ret = NULL;
const char *errstr = "unknown error";
uint64_t valid_before;
if (errstrp != NULL)
*errstrp = NULL;
if ((ret = sshauthopt_new_with_keys_defaults()) == NULL)
goto alloc_fail;
if (opts == NULL)
return ret;
while (*opts && *opts != ' ' && *opts != '\t') {
/* flag options */
if ((r = opt_flag("restrict", 0, &opts)) != -1) {
ret->restricted = 1;
ret->permit_port_forwarding_flag = 0;
ret->permit_agent_forwarding_flag = 0;
ret->permit_x11_forwarding_flag = 0;
ret->permit_pty_flag = 0;
ret->permit_user_rc = 0;
} else if ((r = opt_flag("cert-authority", 0, &opts)) != -1) {
ret->cert_authority = r;
} else if ((r = opt_flag("port-forwarding", 1, &opts)) != -1) {
ret->permit_port_forwarding_flag = r == 1;
} else if ((r = opt_flag("agent-forwarding", 1, &opts)) != -1) {
ret->permit_agent_forwarding_flag = r == 1;
} else if ((r = opt_flag("x11-forwarding", 1, &opts)) != -1) {
ret->permit_x11_forwarding_flag = r == 1;
} else if ((r = opt_flag("touch-required", 1, &opts)) != -1) {
ret->no_require_user_presence = r != 1; /* NB. flip */
} else if ((r = opt_flag("verify-required", 1, &opts)) != -1) {
ret->require_verify = r == 1;
} else if ((r = opt_flag("pty", 1, &opts)) != -1) {
ret->permit_pty_flag = r == 1;
} else if ((r = opt_flag("user-rc", 1, &opts)) != -1) {
ret->permit_user_rc = r == 1;
} else if (opt_match(&opts, "command")) {
if (ret->force_command != NULL) {
errstr = "multiple \"command\" clauses";
goto fail;
}
ret->force_command = opt_dequote(&opts, &errstr);
if (ret->force_command == NULL)
goto fail;
} else if (opt_match(&opts, "principals")) {
if (ret->cert_principals != NULL) {
errstr = "multiple \"principals\" clauses";
goto fail;
}
ret->cert_principals = opt_dequote(&opts, &errstr);
if (ret->cert_principals == NULL)
goto fail;
} else if (opt_match(&opts, "from")) {
if (ret->required_from_host_keys != NULL) {
errstr = "multiple \"from\" clauses";
goto fail;
}
ret->required_from_host_keys = opt_dequote(&opts,
&errstr);
if (ret->required_from_host_keys == NULL)
goto fail;
} else if (opt_match(&opts, "expiry-time")) {
if ((opt = opt_dequote(&opts, &errstr)) == NULL)
goto fail;
if (parse_absolute_time(opt, &valid_before) != 0 ||
valid_before == 0) {
free(opt);
errstr = "invalid expires time";
goto fail;
}
free(opt);
if (ret->valid_before == 0 ||
valid_before < ret->valid_before)
ret->valid_before = valid_before;
} else if (opt_match(&opts, "environment")) {
if (ret->nenv > INT_MAX) {
errstr = "too many environment strings";
goto fail;
}
if ((opt = opt_dequote(&opts, &errstr)) == NULL)
goto fail;
/* env name must be alphanumeric and followed by '=' */
if ((tmp = strchr(opt, '=')) == NULL) {
free(opt);
errstr = "invalid environment string";
goto fail;
}
if ((cp = strdup(opt)) == NULL)
goto alloc_fail;
cp[tmp - opt] = '\0'; /* truncate at '=' */
if (!valid_env_name(cp)) {
free(cp);
free(opt);
errstr = "invalid environment string";
goto fail;
}
free(cp);
/* Append it. */
oarray = ret->env;
if ((ret->env = recallocarray(ret->env, ret->nenv,
ret->nenv + 1, sizeof(*ret->env))) == NULL) {
free(opt);
ret->env = oarray; /* put it back for cleanup */
goto alloc_fail;
}
ret->env[ret->nenv++] = opt;
} else if (opt_match(&opts, "permitopen")) {
if (handle_permit(&opts, 0, &ret->permitopen,
&ret->npermitopen, &errstr) != 0)
goto fail;
} else if (opt_match(&opts, "permitlisten")) {
if (handle_permit(&opts, 1, &ret->permitlisten,
&ret->npermitlisten, &errstr) != 0)
goto fail;
} else if (opt_match(&opts, "tunnel")) {
if ((opt = opt_dequote(&opts, &errstr)) == NULL)
goto fail;
ret->force_tun_device = a2tun(opt, NULL);
free(opt);
if (ret->force_tun_device == SSH_TUNID_ERR) {
errstr = "invalid tun device";
goto fail;
}
}
/*
* Skip the comma, and move to the next option
* (or break out if there are no more).
*/
if (*opts == '\0' || *opts == ' ' || *opts == '\t')
break; /* End of options. */
/* Anything other than a comma is an unknown option */
if (*opts != ',') {
errstr = "unknown key option";
goto fail;
}
opts++;
if (*opts == '\0') {
errstr = "unexpected end-of-options";
goto fail;
}
}
/* success */
if (errstrp != NULL)
*errstrp = NULL;
return ret;
alloc_fail:
errstr = "memory allocation failed";
fail:
sshauthopt_free(ret);
if (errstrp != NULL)
*errstrp = errstr;
return NULL;
}
struct sshauthopt *
sshauthopt_from_cert(struct sshkey *k)
{
struct sshauthopt *ret;
if (k == NULL || !sshkey_type_is_cert(k->type) || k->cert == NULL ||
k->cert->type != SSH2_CERT_TYPE_USER)
return NULL;
if ((ret = sshauthopt_new()) == NULL)
return NULL;
/* Handle options and critical extensions separately */
if (cert_option_list(ret, k->cert->critical,
OPTIONS_CRITICAL, 1) == -1) {
sshauthopt_free(ret);
return NULL;
}
if (cert_option_list(ret, k->cert->extensions,
OPTIONS_EXTENSIONS, 0) == -1) {
sshauthopt_free(ret);
return NULL;
}
/* success */
return ret;
}
/*
* Merges "additional" options to "primary" and returns the result.
* NB. Some options from primary have primacy.
*/
struct sshauthopt *
sshauthopt_merge(const struct sshauthopt *primary,
const struct sshauthopt *additional, const char **errstrp)
{
struct sshauthopt *ret;
const char *errstr = "internal error";
const char *tmp;
if (errstrp != NULL)
*errstrp = NULL;
if ((ret = sshauthopt_new()) == NULL)
goto alloc_fail;
/* cert_authority and cert_principals are cleared in result */
/* Prefer access lists from primary. */
/* XXX err is both set and mismatch? */
tmp = primary->required_from_host_cert;
if (tmp == NULL)
tmp = additional->required_from_host_cert;
if (tmp != NULL && (ret->required_from_host_cert = strdup(tmp)) == NULL)
goto alloc_fail;
tmp = primary->required_from_host_keys;
if (tmp == NULL)
tmp = additional->required_from_host_keys;
if (tmp != NULL && (ret->required_from_host_keys = strdup(tmp)) == NULL)
goto alloc_fail;
/*
* force_tun_device, permitopen/permitlisten and environment all
* prefer the primary.
*/
ret->force_tun_device = primary->force_tun_device;
if (ret->force_tun_device == -1)
ret->force_tun_device = additional->force_tun_device;
if (primary->nenv > 0) {
if (dup_strings(&ret->env, &ret->nenv,
primary->env, primary->nenv) != 0)
goto alloc_fail;
} else if (additional->nenv) {
if (dup_strings(&ret->env, &ret->nenv,
additional->env, additional->nenv) != 0)
goto alloc_fail;
}
if (primary->npermitopen > 0) {
if (dup_strings(&ret->permitopen, &ret->npermitopen,
primary->permitopen, primary->npermitopen) != 0)
goto alloc_fail;
} else if (additional->npermitopen > 0) {
if (dup_strings(&ret->permitopen, &ret->npermitopen,
additional->permitopen, additional->npermitopen) != 0)
goto alloc_fail;
}
if (primary->npermitlisten > 0) {
if (dup_strings(&ret->permitlisten, &ret->npermitlisten,
primary->permitlisten, primary->npermitlisten) != 0)
goto alloc_fail;
} else if (additional->npermitlisten > 0) {
if (dup_strings(&ret->permitlisten, &ret->npermitlisten,
additional->permitlisten, additional->npermitlisten) != 0)
goto alloc_fail;
}
#define OPTFLAG_AND(x) ret->x = (primary->x == 1) && (additional->x == 1)
#define OPTFLAG_OR(x) ret->x = (primary->x == 1) || (additional->x == 1)
/* Permissive flags are logical-AND (i.e. must be set in both) */
OPTFLAG_AND(permit_port_forwarding_flag);
OPTFLAG_AND(permit_agent_forwarding_flag);
OPTFLAG_AND(permit_x11_forwarding_flag);
OPTFLAG_AND(permit_pty_flag);
OPTFLAG_AND(permit_user_rc);
OPTFLAG_AND(no_require_user_presence);
/* Restrictive flags are logical-OR (i.e. must be set in either) */
OPTFLAG_OR(require_verify);
#undef OPTFLAG_AND
/* Earliest expiry time should win */
if (primary->valid_before != 0)
ret->valid_before = primary->valid_before;
if (additional->valid_before != 0 &&
additional->valid_before < ret->valid_before)
ret->valid_before = additional->valid_before;
/*
* When both multiple forced-command are specified, only
* proceed if they are identical, otherwise fail.
*/
if (primary->force_command != NULL &&
additional->force_command != NULL) {
if (strcmp(primary->force_command,
additional->force_command) == 0) {
/* ok */
ret->force_command = strdup(primary->force_command);
if (ret->force_command == NULL)
goto alloc_fail;
} else {
errstr = "forced command options do not match";
goto fail;
}
} else if (primary->force_command != NULL) {
if ((ret->force_command = strdup(
primary->force_command)) == NULL)
goto alloc_fail;
} else if (additional->force_command != NULL) {
if ((ret->force_command = strdup(
additional->force_command)) == NULL)
goto alloc_fail;
}
/* success */
if (errstrp != NULL)
*errstrp = NULL;
return ret;
alloc_fail:
errstr = "memory allocation failed";
fail:
if (errstrp != NULL)
*errstrp = errstr;
sshauthopt_free(ret);
return NULL;
}
/*
* Copy options
*/
struct sshauthopt *
sshauthopt_copy(const struct sshauthopt *orig)
{
struct sshauthopt *ret;
if ((ret = sshauthopt_new()) == NULL)
return NULL;
#define OPTSCALAR(x) ret->x = orig->x
OPTSCALAR(permit_port_forwarding_flag);
OPTSCALAR(permit_agent_forwarding_flag);
OPTSCALAR(permit_x11_forwarding_flag);
OPTSCALAR(permit_pty_flag);
OPTSCALAR(permit_user_rc);
OPTSCALAR(restricted);
OPTSCALAR(cert_authority);
OPTSCALAR(force_tun_device);
OPTSCALAR(valid_before);
OPTSCALAR(no_require_user_presence);
OPTSCALAR(require_verify);
#undef OPTSCALAR
#define OPTSTRING(x) \
do { \
if (orig->x != NULL && (ret->x = strdup(orig->x)) == NULL) { \
sshauthopt_free(ret); \
return NULL; \
} \
} while (0)
OPTSTRING(cert_principals);
OPTSTRING(force_command);
OPTSTRING(required_from_host_cert);
OPTSTRING(required_from_host_keys);
#undef OPTSTRING
if (dup_strings(&ret->env, &ret->nenv, orig->env, orig->nenv) != 0 ||
dup_strings(&ret->permitopen, &ret->npermitopen,
orig->permitopen, orig->npermitopen) != 0 ||
dup_strings(&ret->permitlisten, &ret->npermitlisten,
orig->permitlisten, orig->npermitlisten) != 0) {
sshauthopt_free(ret);
return NULL;
}
return ret;
}
static int
serialise_array(struct sshbuf *m, char **a, size_t n)
{
struct sshbuf *b;
size_t i;
int r;
if (n > INT_MAX)
return SSH_ERR_INTERNAL_ERROR;
if ((b = sshbuf_new()) == NULL) {
return SSH_ERR_ALLOC_FAIL;
}
for (i = 0; i < n; i++) {
if ((r = sshbuf_put_cstring(b, a[i])) != 0) {
sshbuf_free(b);
return r;
}
}
if ((r = sshbuf_put_u32(m, n)) != 0 ||
(r = sshbuf_put_stringb(m, b)) != 0) {
sshbuf_free(b);
return r;
}
/* success */
return 0;
}
static int
deserialise_array(struct sshbuf *m, char ***ap, size_t *np)
{
char **a = NULL;
size_t i, n = 0;
struct sshbuf *b = NULL;
u_int tmp;
int r = SSH_ERR_INTERNAL_ERROR;
if ((r = sshbuf_get_u32(m, &tmp)) != 0 ||
(r = sshbuf_froms(m, &b)) != 0)
goto out;
if (tmp > INT_MAX) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
n = tmp;
if (n > 0 && (a = calloc(n, sizeof(*a))) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
for (i = 0; i < n; i++) {
if ((r = sshbuf_get_cstring(b, &a[i], NULL)) != 0)
goto out;
}
/* success */
r = 0;
*ap = a;
a = NULL;
*np = n;
n = 0;
out:
if (a != NULL) {
for (i = 0; i < n; i++)
free(a[i]);
free(a);
}
sshbuf_free(b);
return r;
}
static int
serialise_nullable_string(struct sshbuf *m, const char *s)
{
int r;
if ((r = sshbuf_put_u8(m, s == NULL)) != 0 ||
(r = sshbuf_put_cstring(m, s)) != 0)
return r;
return 0;
}
static int
deserialise_nullable_string(struct sshbuf *m, char **sp)
{
int r;
u_char flag;
*sp = NULL;
if ((r = sshbuf_get_u8(m, &flag)) != 0 ||
(r = sshbuf_get_cstring(m, flag ? NULL : sp, NULL)) != 0)
return r;
return 0;
}
int
sshauthopt_serialise(const struct sshauthopt *opts, struct sshbuf *m,
int untrusted)
{
int r = SSH_ERR_INTERNAL_ERROR;
/* Flag options */
if ((r = sshbuf_put_u8(m, opts->permit_port_forwarding_flag)) != 0 ||
(r = sshbuf_put_u8(m, opts->permit_agent_forwarding_flag)) != 0 ||
(r = sshbuf_put_u8(m, opts->permit_x11_forwarding_flag)) != 0 ||
(r = sshbuf_put_u8(m, opts->permit_pty_flag)) != 0 ||
(r = sshbuf_put_u8(m, opts->permit_user_rc)) != 0 ||
(r = sshbuf_put_u8(m, opts->restricted)) != 0 ||
(r = sshbuf_put_u8(m, opts->cert_authority)) != 0 ||
(r = sshbuf_put_u8(m, opts->no_require_user_presence)) != 0 ||
(r = sshbuf_put_u8(m, opts->require_verify)) != 0)
return r;
/* Simple integer options */
if ((r = sshbuf_put_u64(m, opts->valid_before)) != 0)
return r;
/* tunnel number can be negative to indicate "unset" */
if ((r = sshbuf_put_u8(m, opts->force_tun_device == -1)) != 0 ||
(r = sshbuf_put_u32(m, (opts->force_tun_device < 0) ?
0 : (u_int)opts->force_tun_device)) != 0)
return r;
/* String options; these may be NULL */
if ((r = serialise_nullable_string(m,
untrusted ? "yes" : opts->cert_principals)) != 0 ||
(r = serialise_nullable_string(m,
untrusted ? "true" : opts->force_command)) != 0 ||
(r = serialise_nullable_string(m,
untrusted ? NULL : opts->required_from_host_cert)) != 0 ||
(r = serialise_nullable_string(m,
- untrusted ? NULL : opts->required_from_host_keys)) != 0)
+ untrusted ? NULL : opts->required_from_host_keys)) != 0)
return r;
/* Array options */
if ((r = serialise_array(m, opts->env,
untrusted ? 0 : opts->nenv)) != 0 ||
(r = serialise_array(m, opts->permitopen,
untrusted ? 0 : opts->npermitopen)) != 0 ||
(r = serialise_array(m, opts->permitlisten,
untrusted ? 0 : opts->npermitlisten)) != 0)
return r;
/* success */
return 0;
}
int
sshauthopt_deserialise(struct sshbuf *m, struct sshauthopt **optsp)
{
struct sshauthopt *opts = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
u_char f;
u_int tmp;
if ((opts = calloc(1, sizeof(*opts))) == NULL)
return SSH_ERR_ALLOC_FAIL;
/* Flag options */
#define OPT_FLAG(x) \
do { \
if ((r = sshbuf_get_u8(m, &f)) != 0) \
goto out; \
opts->x = f; \
} while (0)
OPT_FLAG(permit_port_forwarding_flag);
OPT_FLAG(permit_agent_forwarding_flag);
OPT_FLAG(permit_x11_forwarding_flag);
OPT_FLAG(permit_pty_flag);
OPT_FLAG(permit_user_rc);
OPT_FLAG(restricted);
OPT_FLAG(cert_authority);
OPT_FLAG(no_require_user_presence);
OPT_FLAG(require_verify);
#undef OPT_FLAG
/* Simple integer options */
if ((r = sshbuf_get_u64(m, &opts->valid_before)) != 0)
goto out;
/* tunnel number can be negative to indicate "unset" */
if ((r = sshbuf_get_u8(m, &f)) != 0 ||
(r = sshbuf_get_u32(m, &tmp)) != 0)
goto out;
opts->force_tun_device = f ? -1 : (int)tmp;
/* String options may be NULL */
if ((r = deserialise_nullable_string(m, &opts->cert_principals)) != 0 ||
(r = deserialise_nullable_string(m, &opts->force_command)) != 0 ||
(r = deserialise_nullable_string(m,
&opts->required_from_host_cert)) != 0 ||
(r = deserialise_nullable_string(m,
&opts->required_from_host_keys)) != 0)
goto out;
/* Array options */
if ((r = deserialise_array(m, &opts->env, &opts->nenv)) != 0 ||
(r = deserialise_array(m,
&opts->permitopen, &opts->npermitopen)) != 0 ||
(r = deserialise_array(m,
&opts->permitlisten, &opts->npermitlisten)) != 0)
goto out;
/* success */
r = 0;
*optsp = opts;
opts = NULL;
out:
sshauthopt_free(opts);
return r;
}
diff --git a/auth-pam.c b/auth-pam.c
index d429ef13aaea..0b4a28abc79e 100644
--- a/auth-pam.c
+++ b/auth-pam.c
@@ -1,1397 +1,1397 @@
/*-
* Copyright (c) 2002 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by ThinkSec AS and
* NAI Labs, the Security Research Division of Network Associates, Inc.
* under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
* DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Copyright (c) 2003,2004 Damien Miller <djm@mindrot.org>
* Copyright (c) 2003,2004 Darren Tucker <dtucker@zip.com.au>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* Based on FreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des */
#include "includes.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef USE_PAM
#if defined(HAVE_SECURITY_PAM_APPL_H)
#include <security/pam_appl.h>
#elif defined (HAVE_PAM_PAM_APPL_H)
#include <pam/pam_appl.h>
#endif
#if !defined(SSHD_PAM_SERVICE)
extern char *__progname;
# define SSHD_PAM_SERVICE __progname
#endif
/* OpenGroup RFC86.0 and XSSO specify no "const" on arguments */
#ifdef PAM_SUN_CODEBASE
# define sshpam_const /* Solaris, HP-UX, SunOS */
#else
# define sshpam_const const /* LinuxPAM, OpenPAM, AIX */
#endif
/* Ambiguity in spec: is it an array of pointers or a pointer to an array? */
#ifdef PAM_SUN_CODEBASE
# define PAM_MSG_MEMBER(msg, n, member) ((*(msg))[(n)].member)
#else
# define PAM_MSG_MEMBER(msg, n, member) ((msg)[(n)]->member)
#endif
#include "xmalloc.h"
#include "sshbuf.h"
#include "ssherr.h"
#include "hostfile.h"
#include "auth.h"
#include "auth-pam.h"
#include "canohost.h"
#include "log.h"
#include "msg.h"
#include "packet.h"
#include "misc.h"
#include "servconf.h"
#include "ssh2.h"
#include "auth-options.h"
#include "misc.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
#include "monitor_wrap.h"
extern ServerOptions options;
extern struct sshbuf *loginmsg;
extern u_int utmp_len;
/* so we don't silently change behaviour */
#ifdef USE_POSIX_THREADS
# error "USE_POSIX_THREADS replaced by UNSUPPORTED_POSIX_THREADS_HACK"
#endif
/*
* Formerly known as USE_POSIX_THREADS, using this is completely unsupported
* and generally a bad idea. Use at own risk and do not expect support if
* this breaks.
*/
#ifdef UNSUPPORTED_POSIX_THREADS_HACK
#include <pthread.h>
/*
* Avoid namespace clash when *not* using pthreads for systems *with*
* pthreads, which unconditionally define pthread_t via sys/types.h
* (e.g. Linux)
*/
typedef pthread_t sp_pthread_t;
#else
typedef pid_t sp_pthread_t;
#define pthread_exit fake_pthread_exit
#define pthread_create fake_pthread_create
#define pthread_cancel fake_pthread_cancel
#define pthread_join fake_pthread_join
#endif
struct pam_ctxt {
sp_pthread_t pam_thread;
int pam_psock;
int pam_csock;
int pam_done;
};
static void sshpam_free_ctx(void *);
static struct pam_ctxt *cleanup_ctxt;
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
/*
* Simulate threads with processes.
*/
static int sshpam_thread_status = -1;
static sshsig_t sshpam_oldsig;
static void
sshpam_sigchld_handler(int sig)
{
ssh_signal(SIGCHLD, SIG_DFL);
if (cleanup_ctxt == NULL)
return; /* handler called after PAM cleanup, shouldn't happen */
if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, WNOHANG)
<= 0) {
/* PAM thread has not exitted, privsep slave must have */
kill(cleanup_ctxt->pam_thread, SIGTERM);
while (waitpid(cleanup_ctxt->pam_thread,
&sshpam_thread_status, 0) == -1) {
if (errno == EINTR)
continue;
return;
}
}
if (WIFSIGNALED(sshpam_thread_status) &&
WTERMSIG(sshpam_thread_status) == SIGTERM)
return; /* terminated by pthread_cancel */
if (!WIFEXITED(sshpam_thread_status))
sigdie("PAM: authentication thread exited unexpectedly");
if (WEXITSTATUS(sshpam_thread_status) != 0)
sigdie("PAM: authentication thread exited uncleanly");
}
/* ARGSUSED */
static void
pthread_exit(void *value)
{
_exit(0);
}
/* ARGSUSED */
static int
pthread_create(sp_pthread_t *thread, const void *attr,
void *(*thread_start)(void *), void *arg)
{
pid_t pid;
struct pam_ctxt *ctx = arg;
sshpam_thread_status = -1;
switch ((pid = fork())) {
case -1:
error("fork(): %s", strerror(errno));
return errno;
case 0:
close(ctx->pam_psock);
ctx->pam_psock = -1;
thread_start(arg);
_exit(1);
default:
*thread = pid;
close(ctx->pam_csock);
ctx->pam_csock = -1;
sshpam_oldsig = ssh_signal(SIGCHLD, sshpam_sigchld_handler);
return (0);
}
}
static int
pthread_cancel(sp_pthread_t thread)
{
ssh_signal(SIGCHLD, sshpam_oldsig);
return (kill(thread, SIGTERM));
}
/* ARGSUSED */
static int
pthread_join(sp_pthread_t thread, void **value)
{
int status;
if (sshpam_thread_status != -1)
return (sshpam_thread_status);
ssh_signal(SIGCHLD, sshpam_oldsig);
while (waitpid(thread, &status, 0) == -1) {
if (errno == EINTR)
continue;
fatal("%s: waitpid: %s", __func__, strerror(errno));
}
return (status);
}
#endif
static pam_handle_t *sshpam_handle = NULL;
static int sshpam_err = 0;
static int sshpam_authenticated = 0;
static int sshpam_session_open = 0;
static int sshpam_cred_established = 0;
static int sshpam_account_status = -1;
static int sshpam_maxtries_reached = 0;
static char **sshpam_env = NULL;
static Authctxt *sshpam_authctxt = NULL;
static const char *sshpam_password = NULL;
static char *sshpam_rhost = NULL;
static char *sshpam_laddr = NULL;
static char *sshpam_conninfo = NULL;
/* Some PAM implementations don't implement this */
#ifndef HAVE_PAM_GETENVLIST
static char **
pam_getenvlist(pam_handle_t *pamh)
{
/*
* XXX - If necessary, we can still support environment passing
* for platforms without pam_getenvlist by searching for known
* env vars (e.g. KRB5CCNAME) from the PAM environment.
*/
return NULL;
}
#endif
#ifndef HAVE_PAM_PUTENV
static int
pam_putenv(pam_handle_t *pamh, const char *name_value)
{
return PAM_SUCCESS;
}
#endif /* HAVE_PAM_PUTENV */
/*
* Some platforms, notably Solaris, do not enforce password complexity
* rules during pam_chauthtok() if the real uid of the calling process
* is 0, on the assumption that it's being called by "passwd" run by root.
* This wraps pam_chauthtok and sets/restore the real uid so PAM will do
* the right thing.
*/
#ifdef SSHPAM_CHAUTHTOK_NEEDS_RUID
static int
sshpam_chauthtok_ruid(pam_handle_t *pamh, int flags)
{
int result;
if (sshpam_authctxt == NULL)
fatal("PAM: sshpam_authctxt not initialized");
if (setreuid(sshpam_authctxt->pw->pw_uid, -1) == -1)
fatal("%s: setreuid failed: %s", __func__, strerror(errno));
result = pam_chauthtok(pamh, flags);
if (setreuid(0, -1) == -1)
fatal("%s: setreuid failed: %s", __func__, strerror(errno));
return result;
}
# define pam_chauthtok(a,b) (sshpam_chauthtok_ruid((a), (b)))
#endif
static void
sshpam_password_change_required(int reqd)
{
extern struct sshauthopt *auth_opts;
static int saved_port, saved_agent, saved_x11;
debug3("%s %d", __func__, reqd);
if (sshpam_authctxt == NULL)
fatal("%s: PAM authctxt not initialized", __func__);
sshpam_authctxt->force_pwchange = reqd;
if (reqd) {
saved_port = auth_opts->permit_port_forwarding_flag;
saved_agent = auth_opts->permit_agent_forwarding_flag;
saved_x11 = auth_opts->permit_x11_forwarding_flag;
auth_opts->permit_port_forwarding_flag = 0;
auth_opts->permit_agent_forwarding_flag = 0;
auth_opts->permit_x11_forwarding_flag = 0;
} else {
if (saved_port)
auth_opts->permit_port_forwarding_flag = saved_port;
if (saved_agent)
auth_opts->permit_agent_forwarding_flag = saved_agent;
if (saved_x11)
auth_opts->permit_x11_forwarding_flag = saved_x11;
}
}
/* Import regular and PAM environment from subprocess */
static void
import_environments(struct sshbuf *b)
{
char *env;
u_int n, i, num_env;
int r;
debug3("PAM: %s entering", __func__);
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
/* Import variables set by do_pam_account */
if ((r = sshbuf_get_u32(b, &n)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
if (n > INT_MAX)
fatal("%s: invalid PAM account status %u", __func__, n);
sshpam_account_status = (int)n;
if ((r = sshbuf_get_u32(b, &n)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
sshpam_password_change_required(n != 0);
/* Import environment from subprocess */
if ((r = sshbuf_get_u32(b, &num_env)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
if (num_env > 1024)
fatal("%s: received %u environment variables, expected <= 1024",
__func__, num_env);
sshpam_env = xcalloc(num_env + 1, sizeof(*sshpam_env));
debug3("PAM: num env strings %d", num_env);
for(i = 0; i < num_env; i++) {
if ((r = sshbuf_get_cstring(b, &(sshpam_env[i]), NULL)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
}
sshpam_env[num_env] = NULL;
/* Import PAM environment from subprocess */
if ((r = sshbuf_get_u32(b, &num_env)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
debug("PAM: num PAM env strings %d", num_env);
for (i = 0; i < num_env; i++) {
if ((r = sshbuf_get_cstring(b, &env, NULL)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
/* Errors are not fatal here */
if ((r = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) {
error("PAM: pam_putenv: %s",
pam_strerror(sshpam_handle, r));
}
/*
* XXX this possibly leaks env because it is not documented
* what pam_putenv() does with it. Does it copy it? Does it
* take ownweship? We don't know, so it's safest just to leak.
*/
}
#endif
}
/*
* Conversation function for authentication thread.
*/
static int
sshpam_thread_conv(int n, sshpam_const struct pam_message **msg,
struct pam_response **resp, void *data)
{
struct sshbuf *buffer;
struct pam_ctxt *ctxt;
struct pam_response *reply;
int r, i;
u_char status;
debug3("PAM: %s entering, %d messages", __func__, n);
*resp = NULL;
if (data == NULL) {
error("PAM: conversation function passed a null context");
return (PAM_CONV_ERR);
}
ctxt = data;
if (n <= 0 || n > PAM_MAX_NUM_MSG)
return (PAM_CONV_ERR);
if ((reply = calloc(n, sizeof(*reply))) == NULL)
return PAM_CONV_ERR;
if ((buffer = sshbuf_new()) == NULL) {
free(reply);
return PAM_CONV_ERR;
}
for (i = 0; i < n; ++i) {
switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
case PAM_PROMPT_ECHO_OFF:
case PAM_PROMPT_ECHO_ON:
if ((r = sshbuf_put_cstring(buffer,
PAM_MSG_MEMBER(msg, i, msg))) != 0)
fatal("%s: buffer error: %s",
__func__, ssh_err(r));
if (ssh_msg_send(ctxt->pam_csock,
PAM_MSG_MEMBER(msg, i, msg_style), buffer) == -1)
goto fail;
if (ssh_msg_recv(ctxt->pam_csock, buffer) == -1)
goto fail;
if ((r = sshbuf_get_u8(buffer, &status)) != 0)
fatal("%s: buffer error: %s",
__func__, ssh_err(r));
if (status != PAM_AUTHTOK)
goto fail;
if ((r = sshbuf_get_cstring(buffer,
&reply[i].resp, NULL)) != 0)
fatal("%s: buffer error: %s",
__func__, ssh_err(r));
break;
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
if ((r = sshbuf_put_cstring(buffer,
PAM_MSG_MEMBER(msg, i, msg))) != 0)
fatal("%s: buffer error: %s",
__func__, ssh_err(r));
if (ssh_msg_send(ctxt->pam_csock,
PAM_MSG_MEMBER(msg, i, msg_style), buffer) == -1)
goto fail;
break;
default:
goto fail;
}
sshbuf_reset(buffer);
}
sshbuf_free(buffer);
*resp = reply;
return (PAM_SUCCESS);
fail:
for(i = 0; i < n; i++) {
free(reply[i].resp);
}
free(reply);
sshbuf_free(buffer);
return (PAM_CONV_ERR);
}
/*
* Authentication thread.
*/
static void *
sshpam_thread(void *ctxtp)
{
struct pam_ctxt *ctxt = ctxtp;
struct sshbuf *buffer = NULL;
struct pam_conv sshpam_conv;
int r, flags = (options.permit_empty_passwd == 0 ?
PAM_DISALLOW_NULL_AUTHTOK : 0);
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
extern char **environ;
char **env_from_pam;
u_int i;
const char *pam_user;
const char **ptr_pam_user = &pam_user;
char *tz = getenv("TZ");
sshpam_err = pam_get_item(sshpam_handle, PAM_USER,
(sshpam_const void **)ptr_pam_user);
if (sshpam_err != PAM_SUCCESS)
goto auth_fail;
environ[0] = NULL;
if (tz != NULL)
if (setenv("TZ", tz, 1) == -1)
error("PAM: could not set TZ environment: %s",
strerror(errno));
if (sshpam_authctxt != NULL) {
setproctitle("%s [pam]",
sshpam_authctxt->valid ? pam_user : "unknown");
}
#endif
sshpam_conv.conv = sshpam_thread_conv;
sshpam_conv.appdata_ptr = ctxt;
if (sshpam_authctxt == NULL)
fatal("%s: PAM authctxt not initialized", __func__);
if ((buffer = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
(const void *)&sshpam_conv);
if (sshpam_err != PAM_SUCCESS)
goto auth_fail;
sshpam_err = pam_authenticate(sshpam_handle, flags);
if (sshpam_err == PAM_MAXTRIES)
sshpam_set_maxtries_reached(1);
if (sshpam_err != PAM_SUCCESS)
goto auth_fail;
if (!do_pam_account()) {
sshpam_err = PAM_ACCT_EXPIRED;
goto auth_fail;
}
if (sshpam_authctxt->force_pwchange) {
sshpam_err = pam_chauthtok(sshpam_handle,
PAM_CHANGE_EXPIRED_AUTHTOK);
if (sshpam_err != PAM_SUCCESS)
goto auth_fail;
sshpam_password_change_required(0);
}
if ((r = sshbuf_put_cstring(buffer, "OK")) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
/* Export variables set by do_pam_account */
if ((r = sshbuf_put_u32(buffer, sshpam_account_status)) != 0 ||
(r = sshbuf_put_u32(buffer, sshpam_authctxt->force_pwchange)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
/* Export any environment strings set in child */
for (i = 0; environ[i] != NULL; i++) {
/* Count */
if (i > INT_MAX)
fatal("%s: too many environment strings", __func__);
}
if ((r = sshbuf_put_u32(buffer, i)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
for (i = 0; environ[i] != NULL; i++) {
if ((r = sshbuf_put_cstring(buffer, environ[i])) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
}
/* Export any environment strings set by PAM in child */
env_from_pam = pam_getenvlist(sshpam_handle);
for (i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) {
/* Count */
if (i > INT_MAX)
fatal("%s: too many PAM environment strings", __func__);
}
if ((r = sshbuf_put_u32(buffer, i)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
for (i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) {
if ((r = sshbuf_put_cstring(buffer, env_from_pam[i])) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
}
#endif /* UNSUPPORTED_POSIX_THREADS_HACK */
/* XXX - can't do much about an error here */
ssh_msg_send(ctxt->pam_csock, sshpam_err, buffer);
sshbuf_free(buffer);
pthread_exit(NULL);
auth_fail:
if ((r = sshbuf_put_cstring(buffer,
pam_strerror(sshpam_handle, sshpam_err))) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
/* XXX - can't do much about an error here */
if (sshpam_err == PAM_ACCT_EXPIRED)
ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, buffer);
else if (sshpam_maxtries_reached)
ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, buffer);
else
ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, buffer);
sshbuf_free(buffer);
pthread_exit(NULL);
return (NULL); /* Avoid warning for non-pthread case */
}
void
sshpam_thread_cleanup(void)
{
struct pam_ctxt *ctxt = cleanup_ctxt;
debug3("PAM: %s entering", __func__);
if (ctxt != NULL && ctxt->pam_thread != 0) {
pthread_cancel(ctxt->pam_thread);
pthread_join(ctxt->pam_thread, NULL);
close(ctxt->pam_psock);
close(ctxt->pam_csock);
memset(ctxt, 0, sizeof(*ctxt));
cleanup_ctxt = NULL;
}
}
static int
sshpam_null_conv(int n, sshpam_const struct pam_message **msg,
struct pam_response **resp, void *data)
{
debug3("PAM: %s entering, %d messages", __func__, n);
return (PAM_CONV_ERR);
}
static struct pam_conv null_conv = { sshpam_null_conv, NULL };
static int
sshpam_store_conv(int n, sshpam_const struct pam_message **msg,
struct pam_response **resp, void *data)
{
struct pam_response *reply;
int r, i;
debug3("PAM: %s called with %d messages", __func__, n);
*resp = NULL;
if (n <= 0 || n > PAM_MAX_NUM_MSG)
return (PAM_CONV_ERR);
if ((reply = calloc(n, sizeof(*reply))) == NULL)
return (PAM_CONV_ERR);
for (i = 0; i < n; ++i) {
switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
if ((r = sshbuf_putf(loginmsg, "%s\n",
PAM_MSG_MEMBER(msg, i, msg))) != 0)
fatal("%s: buffer error: %s",
__func__, ssh_err(r));
reply[i].resp_retcode = PAM_SUCCESS;
break;
default:
goto fail;
}
}
*resp = reply;
return (PAM_SUCCESS);
fail:
for(i = 0; i < n; i++) {
free(reply[i].resp);
}
free(reply);
return (PAM_CONV_ERR);
}
static struct pam_conv store_conv = { sshpam_store_conv, NULL };
void
sshpam_cleanup(void)
{
if (sshpam_handle == NULL || (use_privsep && !mm_is_monitor()))
return;
debug("PAM: cleanup");
pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv);
if (sshpam_session_open) {
debug("PAM: closing session");
pam_close_session(sshpam_handle, PAM_SILENT);
sshpam_session_open = 0;
}
if (sshpam_cred_established) {
debug("PAM: deleting credentials");
pam_setcred(sshpam_handle, PAM_DELETE_CRED);
sshpam_cred_established = 0;
}
sshpam_authenticated = 0;
pam_end(sshpam_handle, sshpam_err);
sshpam_handle = NULL;
}
static int
sshpam_init(struct ssh *ssh, Authctxt *authctxt)
{
const char *pam_user, *user = authctxt->user;
const char **ptr_pam_user = &pam_user;
#if defined(PAM_SUN_CODEBASE) && defined(PAM_MAX_RESP_SIZE)
/* Protect buggy PAM implementations from excessively long usernames */
if (strlen(user) >= PAM_MAX_RESP_SIZE)
fatal("Username too long from %s port %d",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
#endif
if (sshpam_handle == NULL) {
if (ssh == NULL) {
fatal("%s: called initially with no "
"packet context", __func__);
}
} if (sshpam_handle != NULL) {
/* We already have a PAM context; check if the user matches */
sshpam_err = pam_get_item(sshpam_handle,
PAM_USER, (sshpam_const void **)ptr_pam_user);
if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0)
return (0);
pam_end(sshpam_handle, sshpam_err);
sshpam_handle = NULL;
}
debug("PAM: initializing for \"%s\"", user);
sshpam_err =
pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle);
sshpam_authctxt = authctxt;
if (sshpam_err != PAM_SUCCESS) {
pam_end(sshpam_handle, sshpam_err);
sshpam_handle = NULL;
return (-1);
}
if (ssh != NULL && sshpam_rhost == NULL) {
/*
* We need to cache these as we don't have packet context
* during the kbdint flow.
*/
sshpam_rhost = xstrdup(auth_get_canonical_hostname(ssh,
options.use_dns));
- sshpam_laddr = get_local_ipaddr(
+ sshpam_laddr = get_local_ipaddr(
ssh_packet_get_connection_in(ssh));
- xasprintf(&sshpam_conninfo, "SSH_CONNECTION=%.50s %d %.50s %d",
+ xasprintf(&sshpam_conninfo, "SSH_CONNECTION=%.50s %d %.50s %d",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
sshpam_laddr, ssh_local_port(ssh));
}
if (sshpam_rhost != NULL) {
debug("PAM: setting PAM_RHOST to \"%s\"", sshpam_rhost);
sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST,
sshpam_rhost);
if (sshpam_err != PAM_SUCCESS) {
pam_end(sshpam_handle, sshpam_err);
sshpam_handle = NULL;
return (-1);
}
/* Put SSH_CONNECTION in the PAM environment too */
pam_putenv(sshpam_handle, sshpam_conninfo);
}
#ifdef PAM_TTY_KLUDGE
/*
* Some silly PAM modules (e.g. pam_time) require a TTY to operate.
* sshd doesn't set the tty until too late in the auth process and
* may not even set one (for tty-less connections)
*/
debug("PAM: setting PAM_TTY to \"ssh\"");
sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, "ssh");
if (sshpam_err != PAM_SUCCESS) {
pam_end(sshpam_handle, sshpam_err);
sshpam_handle = NULL;
return (-1);
}
#endif
return (0);
}
static void
expose_authinfo(const char *caller)
{
char *auth_info;
/*
* Expose authentication information to PAM.
* The environment variable is versioned. Please increment the
* version suffix if the format of session_info changes.
*/
if (sshpam_authctxt->session_info == NULL)
auth_info = xstrdup("");
else if ((auth_info = sshbuf_dup_string(
sshpam_authctxt->session_info)) == NULL)
fatal("%s: sshbuf_dup_string failed", __func__);
debug2("%s: auth information in SSH_AUTH_INFO_0", caller);
do_pam_putenv("SSH_AUTH_INFO_0", auth_info);
free(auth_info);
}
static void *
sshpam_init_ctx(Authctxt *authctxt)
{
struct pam_ctxt *ctxt;
int result, socks[2];
debug3("PAM: %s entering", __func__);
/*
* Refuse to start if we don't have PAM enabled or do_pam_account
* has previously failed.
*/
if (!options.use_pam || sshpam_account_status == 0)
return NULL;
/* Initialize PAM */
if (sshpam_init(NULL, authctxt) == -1) {
error("PAM: initialization failed");
return (NULL);
}
expose_authinfo(__func__);
ctxt = xcalloc(1, sizeof *ctxt);
/* Start the authentication thread */
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
error("PAM: failed create sockets: %s", strerror(errno));
free(ctxt);
return (NULL);
}
ctxt->pam_psock = socks[0];
ctxt->pam_csock = socks[1];
result = pthread_create(&ctxt->pam_thread, NULL, sshpam_thread, ctxt);
if (result != 0) {
error("PAM: failed to start authentication thread: %s",
strerror(result));
close(socks[0]);
close(socks[1]);
free(ctxt);
return (NULL);
}
cleanup_ctxt = ctxt;
return (ctxt);
}
static int
sshpam_query(void *ctx, char **name, char **info,
u_int *num, char ***prompts, u_int **echo_on)
{
struct sshbuf *buffer;
struct pam_ctxt *ctxt = ctx;
size_t plen;
u_char type;
char *msg;
size_t len, mlen;
int r;
debug3("PAM: %s entering", __func__);
if ((buffer = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
*name = xstrdup("");
*info = xstrdup("");
*prompts = xmalloc(sizeof(char *));
**prompts = NULL;
plen = 0;
*echo_on = xmalloc(sizeof(u_int));
while (ssh_msg_recv(ctxt->pam_psock, buffer) == 0) {
if ((r = sshbuf_get_u8(buffer, &type)) != 0 ||
(r = sshbuf_get_cstring(buffer, &msg, &mlen)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
switch (type) {
case PAM_PROMPT_ECHO_ON:
case PAM_PROMPT_ECHO_OFF:
*num = 1;
len = plen + mlen + 1;
**prompts = xreallocarray(**prompts, 1, len);
strlcpy(**prompts + plen, msg, len - plen);
plen += mlen;
**echo_on = (type == PAM_PROMPT_ECHO_ON);
free(msg);
sshbuf_free(buffer);
return (0);
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
/* accumulate messages */
len = plen + mlen + 2;
**prompts = xreallocarray(**prompts, 1, len);
strlcpy(**prompts + plen, msg, len - plen);
plen += mlen;
strlcat(**prompts + plen, "\n", len - plen);
plen++;
free(msg);
break;
case PAM_ACCT_EXPIRED:
case PAM_MAXTRIES:
if (type == PAM_ACCT_EXPIRED)
sshpam_account_status = 0;
if (type == PAM_MAXTRIES)
sshpam_set_maxtries_reached(1);
/* FALLTHROUGH */
case PAM_AUTH_ERR:
debug3("PAM: %s", pam_strerror(sshpam_handle, type));
if (**prompts != NULL && strlen(**prompts) != 0) {
*info = **prompts;
**prompts = NULL;
*num = 0;
**echo_on = 0;
ctxt->pam_done = -1;
free(msg);
sshbuf_free(buffer);
return 0;
}
/* FALLTHROUGH */
case PAM_SUCCESS:
if (**prompts != NULL) {
/* drain any accumulated messages */
debug("PAM: %s", **prompts);
if ((r = sshbuf_put(loginmsg, **prompts,
strlen(**prompts))) != 0)
fatal("%s: buffer error: %s",
__func__, ssh_err(r));
free(**prompts);
**prompts = NULL;
}
if (type == PAM_SUCCESS) {
if (!sshpam_authctxt->valid ||
(sshpam_authctxt->pw->pw_uid == 0 &&
options.permit_root_login != PERMIT_YES))
fatal("Internal error: PAM auth "
"succeeded when it should have "
"failed");
import_environments(buffer);
*num = 0;
**echo_on = 0;
ctxt->pam_done = 1;
free(msg);
sshbuf_free(buffer);
return (0);
}
error("PAM: %s for %s%.100s from %.100s", msg,
sshpam_authctxt->valid ? "" : "illegal user ",
sshpam_authctxt->user, sshpam_rhost);
/* FALLTHROUGH */
default:
*num = 0;
**echo_on = 0;
free(msg);
ctxt->pam_done = -1;
sshbuf_free(buffer);
return (-1);
}
}
sshbuf_free(buffer);
return (-1);
}
/*
* Returns a junk password of identical length to that the user supplied.
* Used to mitigate timing attacks against crypt(3)/PAM stacks that
* vary processing time in proportion to password length.
*/
static char *
fake_password(const char *wire_password)
{
const char junk[] = "\b\n\r\177INCORRECT";
char *ret = NULL;
size_t i, l = wire_password != NULL ? strlen(wire_password) : 0;
if (l >= INT_MAX)
fatal("%s: password length too long: %zu", __func__, l);
ret = malloc(l + 1);
if (ret == NULL)
return NULL;
for (i = 0; i < l; i++)
ret[i] = junk[i % (sizeof(junk) - 1)];
ret[i] = '\0';
return ret;
}
/* XXX - see also comment in auth-chall.c:verify_response */
static int
sshpam_respond(void *ctx, u_int num, char **resp)
{
struct sshbuf *buffer;
struct pam_ctxt *ctxt = ctx;
char *fake;
int r;
debug2("PAM: %s entering, %u responses", __func__, num);
switch (ctxt->pam_done) {
case 1:
sshpam_authenticated = 1;
return (0);
case 0:
break;
default:
return (-1);
}
if (num != 1) {
error("PAM: expected one response, got %u", num);
return (-1);
}
if ((buffer = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
if (sshpam_authctxt->valid &&
(sshpam_authctxt->pw->pw_uid != 0 ||
options.permit_root_login == PERMIT_YES)) {
if ((r = sshbuf_put_cstring(buffer, *resp)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
} else {
fake = fake_password(*resp);
if ((r = sshbuf_put_cstring(buffer, fake)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
free(fake);
}
if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, buffer) == -1) {
sshbuf_free(buffer);
return (-1);
}
sshbuf_free(buffer);
return (1);
}
static void
sshpam_free_ctx(void *ctxtp)
{
struct pam_ctxt *ctxt = ctxtp;
debug3("PAM: %s entering", __func__);
sshpam_thread_cleanup();
free(ctxt);
/*
* We don't call sshpam_cleanup() here because we may need the PAM
* handle at a later stage, e.g. when setting up a session. It's
* still on the cleanup list, so pam_end() *will* be called before
* the server process terminates.
*/
}
KbdintDevice sshpam_device = {
"pam",
sshpam_init_ctx,
sshpam_query,
sshpam_respond,
sshpam_free_ctx
};
KbdintDevice mm_sshpam_device = {
"pam",
mm_sshpam_init_ctx,
mm_sshpam_query,
mm_sshpam_respond,
mm_sshpam_free_ctx
};
/*
* This replaces auth-pam.c
*/
void
start_pam(struct ssh *ssh)
{
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
if (!options.use_pam)
fatal("PAM: initialisation requested when UsePAM=no");
if (sshpam_init(ssh, authctxt) == -1)
fatal("PAM: initialisation failed");
}
void
finish_pam(void)
{
sshpam_cleanup();
}
u_int
do_pam_account(void)
{
debug("%s: called", __func__);
if (sshpam_account_status != -1)
return (sshpam_account_status);
expose_authinfo(__func__);
sshpam_err = pam_acct_mgmt(sshpam_handle, 0);
debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
pam_strerror(sshpam_handle, sshpam_err));
if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) {
sshpam_account_status = 0;
return (sshpam_account_status);
}
if (sshpam_err == PAM_NEW_AUTHTOK_REQD)
sshpam_password_change_required(1);
sshpam_account_status = 1;
return (sshpam_account_status);
}
void
do_pam_setcred(int init)
{
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
(const void *)&store_conv);
if (sshpam_err != PAM_SUCCESS)
fatal("PAM: failed to set PAM_CONV: %s",
pam_strerror(sshpam_handle, sshpam_err));
if (init) {
debug("PAM: establishing credentials");
sshpam_err = pam_setcred(sshpam_handle, PAM_ESTABLISH_CRED);
} else {
debug("PAM: reinitializing credentials");
sshpam_err = pam_setcred(sshpam_handle, PAM_REINITIALIZE_CRED);
}
if (sshpam_err == PAM_SUCCESS) {
sshpam_cred_established = 1;
return;
}
if (sshpam_authenticated)
fatal("PAM: pam_setcred(): %s",
pam_strerror(sshpam_handle, sshpam_err));
else
debug("PAM: pam_setcred(): %s",
pam_strerror(sshpam_handle, sshpam_err));
}
static int
sshpam_tty_conv(int n, sshpam_const struct pam_message **msg,
struct pam_response **resp, void *data)
{
char input[PAM_MAX_MSG_SIZE];
struct pam_response *reply;
int i;
debug3("PAM: %s called with %d messages", __func__, n);
*resp = NULL;
if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO))
return (PAM_CONV_ERR);
if ((reply = calloc(n, sizeof(*reply))) == NULL)
return (PAM_CONV_ERR);
for (i = 0; i < n; ++i) {
switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
case PAM_PROMPT_ECHO_OFF:
reply[i].resp =
read_passphrase(PAM_MSG_MEMBER(msg, i, msg),
RP_ALLOW_STDIN);
reply[i].resp_retcode = PAM_SUCCESS;
break;
case PAM_PROMPT_ECHO_ON:
fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
if (fgets(input, sizeof input, stdin) == NULL)
input[0] = '\0';
if ((reply[i].resp = strdup(input)) == NULL)
goto fail;
reply[i].resp_retcode = PAM_SUCCESS;
break;
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
reply[i].resp_retcode = PAM_SUCCESS;
break;
default:
goto fail;
}
}
*resp = reply;
return (PAM_SUCCESS);
fail:
for(i = 0; i < n; i++) {
free(reply[i].resp);
}
free(reply);
return (PAM_CONV_ERR);
}
static struct pam_conv tty_conv = { sshpam_tty_conv, NULL };
/*
* XXX this should be done in the authentication phase, but ssh1 doesn't
* support that
*/
void
do_pam_chauthtok(void)
{
if (use_privsep)
fatal("Password expired (unable to change with privsep)");
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
(const void *)&tty_conv);
if (sshpam_err != PAM_SUCCESS)
fatal("PAM: failed to set PAM_CONV: %s",
pam_strerror(sshpam_handle, sshpam_err));
debug("PAM: changing password");
sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
if (sshpam_err != PAM_SUCCESS)
fatal("PAM: pam_chauthtok(): %s",
pam_strerror(sshpam_handle, sshpam_err));
}
void
do_pam_session(struct ssh *ssh)
{
debug3("PAM: opening session");
expose_authinfo(__func__);
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
(const void *)&store_conv);
if (sshpam_err != PAM_SUCCESS)
fatal("PAM: failed to set PAM_CONV: %s",
pam_strerror(sshpam_handle, sshpam_err));
sshpam_err = pam_open_session(sshpam_handle, 0);
if (sshpam_err == PAM_SUCCESS)
sshpam_session_open = 1;
else {
sshpam_session_open = 0;
auth_restrict_session(ssh);
error("PAM: pam_open_session(): %s",
pam_strerror(sshpam_handle, sshpam_err));
}
}
int
is_pam_session_open(void)
{
return sshpam_session_open;
}
/*
* Set a PAM environment string. We need to do this so that the session
* modules can handle things like Kerberos/GSI credentials that appear
* during the ssh authentication process.
*/
int
do_pam_putenv(char *name, char *value)
{
int ret = 1;
char *compound;
size_t len;
len = strlen(name) + strlen(value) + 2;
compound = xmalloc(len);
snprintf(compound, len, "%s=%s", name, value);
ret = pam_putenv(sshpam_handle, compound);
free(compound);
return (ret);
}
char **
fetch_pam_child_environment(void)
{
return sshpam_env;
}
char **
fetch_pam_environment(void)
{
return (pam_getenvlist(sshpam_handle));
}
void
free_pam_environment(char **env)
{
char **envp;
if (env == NULL)
return;
for (envp = env; *envp; envp++)
free(*envp);
free(env);
}
/*
* "Blind" conversation function for password authentication. Assumes that
* echo-off prompts are for the password and stores messages for later
* display.
*/
static int
sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
struct pam_response **resp, void *data)
{
struct pam_response *reply;
int r, i;
size_t len;
debug3("PAM: %s called with %d messages", __func__, n);
*resp = NULL;
if (n <= 0 || n > PAM_MAX_NUM_MSG)
return (PAM_CONV_ERR);
if ((reply = calloc(n, sizeof(*reply))) == NULL)
return (PAM_CONV_ERR);
for (i = 0; i < n; ++i) {
switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
case PAM_PROMPT_ECHO_OFF:
if (sshpam_password == NULL)
goto fail;
if ((reply[i].resp = strdup(sshpam_password)) == NULL)
goto fail;
reply[i].resp_retcode = PAM_SUCCESS;
break;
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
len = strlen(PAM_MSG_MEMBER(msg, i, msg));
if (len > 0) {
if ((r = sshbuf_putf(loginmsg, "%s\n",
PAM_MSG_MEMBER(msg, i, msg))) != 0)
fatal("%s: buffer error: %s",
__func__, ssh_err(r));
}
if ((reply[i].resp = strdup("")) == NULL)
goto fail;
reply[i].resp_retcode = PAM_SUCCESS;
break;
default:
goto fail;
}
}
*resp = reply;
return (PAM_SUCCESS);
fail:
for(i = 0; i < n; i++) {
free(reply[i].resp);
}
free(reply);
return (PAM_CONV_ERR);
}
static struct pam_conv passwd_conv = { sshpam_passwd_conv, NULL };
/*
* Attempt password authentication via PAM
*/
int
sshpam_auth_passwd(Authctxt *authctxt, const char *password)
{
int flags = (options.permit_empty_passwd == 0 ?
PAM_DISALLOW_NULL_AUTHTOK : 0);
char *fake = NULL;
if (!options.use_pam || sshpam_handle == NULL)
fatal("PAM: %s called when PAM disabled or failed to "
"initialise.", __func__);
sshpam_password = password;
sshpam_authctxt = authctxt;
/*
* If the user logging in is invalid, or is root but is not permitted
* by PermitRootLogin, use an invalid password to prevent leaking
* information via timing (eg if the PAM config has a delay on fail).
*/
if (!authctxt->valid || (authctxt->pw->pw_uid == 0 &&
options.permit_root_login != PERMIT_YES))
sshpam_password = fake = fake_password(password);
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
(const void *)&passwd_conv);
if (sshpam_err != PAM_SUCCESS)
fatal("PAM: %s: failed to set PAM_CONV: %s", __func__,
pam_strerror(sshpam_handle, sshpam_err));
sshpam_err = pam_authenticate(sshpam_handle, flags);
sshpam_password = NULL;
free(fake);
if (sshpam_err == PAM_MAXTRIES)
sshpam_set_maxtries_reached(1);
if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
debug("PAM: password authentication accepted for %.100s",
authctxt->user);
return 1;
} else {
debug("PAM: password authentication failed for %.100s: %s",
authctxt->valid ? authctxt->user : "an illegal user",
pam_strerror(sshpam_handle, sshpam_err));
return 0;
}
}
int
sshpam_get_maxtries_reached(void)
{
return sshpam_maxtries_reached;
}
void
sshpam_set_maxtries_reached(int reached)
{
if (reached == 0 || sshpam_maxtries_reached)
return;
sshpam_maxtries_reached = 1;
options.password_authentication = 0;
options.kbd_interactive_authentication = 0;
options.challenge_response_authentication = 0;
}
#endif /* USE_PAM */
diff --git a/auth.c b/auth.c
index a0e3cd6fe481..b560eed14b1d 100644
--- a/auth.c
+++ b/auth.c
@@ -1,1041 +1,1041 @@
-/* $OpenBSD: auth.c,v 1.151 2020/12/22 00:12:22 djm Exp $ */
+/* $OpenBSD: auth.c,v 1.152 2021/04/03 06:18:40 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#include <pwd.h>
#ifdef HAVE_LOGIN_H
#include <login.h>
#endif
#ifdef USE_SHADOW
#include <shadow.h>
#endif
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <netdb.h>
#include <time.h>
#include "xmalloc.h"
#include "match.h"
#include "groupaccess.h"
#include "log.h"
#include "sshbuf.h"
#include "misc.h"
#include "servconf.h"
#include "sshkey.h"
#include "hostfile.h"
#include "auth.h"
#include "auth-options.h"
#include "canohost.h"
#include "uidswap.h"
#include "packet.h"
#include "loginrec.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
#include "authfile.h"
#include "monitor_wrap.h"
#include "ssherr.h"
#include "compat.h"
#include "channels.h"
/* import */
extern ServerOptions options;
extern struct include_list includes;
extern int use_privsep;
extern struct sshbuf *loginmsg;
extern struct passwd *privsep_pw;
extern struct sshauthopt *auth_opts;
/* Debugging messages */
static struct sshbuf *auth_debug;
/*
* Check if the user is allowed to log in via ssh. If user is listed
* in DenyUsers or one of user's groups is listed in DenyGroups, false
* will be returned. If AllowUsers isn't empty and user isn't listed
* there, or if AllowGroups isn't empty and one of user's groups isn't
* listed there, false will be returned.
* If the user's shell is not executable, false will be returned.
* Otherwise true is returned.
*/
int
allowed_user(struct ssh *ssh, struct passwd * pw)
{
struct stat st;
const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL;
u_int i;
int r;
#ifdef USE_SHADOW
struct spwd *spw = NULL;
#endif
/* Shouldn't be called if pw is NULL, but better safe than sorry... */
if (!pw || !pw->pw_name)
return 0;
#ifdef USE_SHADOW
if (!options.use_pam)
spw = getspnam(pw->pw_name);
#ifdef HAS_SHADOW_EXPIRE
if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw))
return 0;
#endif /* HAS_SHADOW_EXPIRE */
#endif /* USE_SHADOW */
/* grab passwd field for locked account check */
passwd = pw->pw_passwd;
#ifdef USE_SHADOW
if (spw != NULL)
#ifdef USE_LIBIAF
passwd = get_iaf_password(pw);
#else
passwd = spw->sp_pwdp;
#endif /* USE_LIBIAF */
#endif
/* check for locked account */
if (!options.use_pam && passwd && *passwd) {
int locked = 0;
#ifdef LOCKED_PASSWD_STRING
if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0)
locked = 1;
#endif
#ifdef LOCKED_PASSWD_PREFIX
if (strncmp(passwd, LOCKED_PASSWD_PREFIX,
strlen(LOCKED_PASSWD_PREFIX)) == 0)
locked = 1;
#endif
#ifdef LOCKED_PASSWD_SUBSTR
if (strstr(passwd, LOCKED_PASSWD_SUBSTR))
locked = 1;
#endif
#ifdef USE_LIBIAF
free((void *) passwd);
#endif /* USE_LIBIAF */
if (locked) {
logit("User %.100s not allowed because account is locked",
pw->pw_name);
return 0;
}
}
/*
* Deny if shell does not exist or is not executable unless we
* are chrooting.
*/
if (options.chroot_directory == NULL ||
strcasecmp(options.chroot_directory, "none") == 0) {
char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
_PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
if (stat(shell, &st) == -1) {
logit("User %.100s not allowed because shell %.100s "
"does not exist", pw->pw_name, shell);
free(shell);
return 0;
}
if (S_ISREG(st.st_mode) == 0 ||
(st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
logit("User %.100s not allowed because shell %.100s "
"is not executable", pw->pw_name, shell);
free(shell);
return 0;
}
free(shell);
}
if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
options.num_deny_groups > 0 || options.num_allow_groups > 0) {
hostname = auth_get_canonical_hostname(ssh, options.use_dns);
ipaddr = ssh_remote_ipaddr(ssh);
}
/* Return false if user is listed in DenyUsers */
if (options.num_deny_users > 0) {
for (i = 0; i < options.num_deny_users; i++) {
r = match_user(pw->pw_name, hostname, ipaddr,
options.deny_users[i]);
if (r < 0) {
fatal("Invalid DenyUsers pattern \"%.100s\"",
options.deny_users[i]);
} else if (r != 0) {
logit("User %.100s from %.100s not allowed "
"because listed in DenyUsers",
pw->pw_name, hostname);
return 0;
}
}
}
/* Return false if AllowUsers isn't empty and user isn't listed there */
if (options.num_allow_users > 0) {
for (i = 0; i < options.num_allow_users; i++) {
r = match_user(pw->pw_name, hostname, ipaddr,
options.allow_users[i]);
if (r < 0) {
fatal("Invalid AllowUsers pattern \"%.100s\"",
options.allow_users[i]);
} else if (r == 1)
break;
}
/* i < options.num_allow_users iff we break for loop */
if (i >= options.num_allow_users) {
logit("User %.100s from %.100s not allowed because "
"not listed in AllowUsers", pw->pw_name, hostname);
return 0;
}
}
if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
/* Get the user's group access list (primary and supplementary) */
if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
logit("User %.100s from %.100s not allowed because "
"not in any group", pw->pw_name, hostname);
return 0;
}
/* Return false if one of user's groups is listed in DenyGroups */
if (options.num_deny_groups > 0)
if (ga_match(options.deny_groups,
options.num_deny_groups)) {
ga_free();
logit("User %.100s from %.100s not allowed "
"because a group is listed in DenyGroups",
pw->pw_name, hostname);
return 0;
}
/*
* Return false if AllowGroups isn't empty and one of user's groups
* isn't listed there
*/
if (options.num_allow_groups > 0)
if (!ga_match(options.allow_groups,
options.num_allow_groups)) {
ga_free();
logit("User %.100s from %.100s not allowed "
"because none of user's groups are listed "
"in AllowGroups", pw->pw_name, hostname);
return 0;
}
ga_free();
}
#ifdef CUSTOM_SYS_AUTH_ALLOWED_USER
if (!sys_auth_allowed_user(pw, loginmsg))
return 0;
#endif
/* We found no reason not to let this user try to log on... */
return 1;
}
/*
* Formats any key left in authctxt->auth_method_key for inclusion in
* auth_log()'s message. Also includes authxtct->auth_method_info if present.
*/
static char *
format_method_key(Authctxt *authctxt)
{
const struct sshkey *key = authctxt->auth_method_key;
const char *methinfo = authctxt->auth_method_info;
char *fp, *cafp, *ret = NULL;
if (key == NULL)
return NULL;
if (sshkey_is_cert(key)) {
fp = sshkey_fingerprint(key,
options.fingerprint_hash, SSH_FP_DEFAULT);
cafp = sshkey_fingerprint(key->cert->signature_key,
options.fingerprint_hash, SSH_FP_DEFAULT);
xasprintf(&ret, "%s %s ID %s (serial %llu) CA %s %s%s%s",
sshkey_type(key), fp == NULL ? "(null)" : fp,
key->cert->key_id,
(unsigned long long)key->cert->serial,
sshkey_type(key->cert->signature_key),
cafp == NULL ? "(null)" : cafp,
methinfo == NULL ? "" : ", ",
methinfo == NULL ? "" : methinfo);
free(fp);
free(cafp);
} else {
fp = sshkey_fingerprint(key, options.fingerprint_hash,
SSH_FP_DEFAULT);
xasprintf(&ret, "%s %s%s%s", sshkey_type(key),
fp == NULL ? "(null)" : fp,
methinfo == NULL ? "" : ", ",
methinfo == NULL ? "" : methinfo);
free(fp);
}
return ret;
}
void
auth_log(struct ssh *ssh, int authenticated, int partial,
const char *method, const char *submethod)
{
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
int level = SYSLOG_LEVEL_VERBOSE;
const char *authmsg;
char *extra = NULL;
if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
return;
/* Raise logging level */
if (authenticated == 1 ||
!authctxt->valid ||
authctxt->failures >= options.max_authtries / 2 ||
strcmp(method, "password") == 0)
level = SYSLOG_LEVEL_INFO;
if (authctxt->postponed)
authmsg = "Postponed";
else if (partial)
authmsg = "Partial";
else
authmsg = authenticated ? "Accepted" : "Failed";
if ((extra = format_method_key(authctxt)) == NULL) {
if (authctxt->auth_method_info != NULL)
extra = xstrdup(authctxt->auth_method_info);
}
do_log2(level, "%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
authmsg,
method,
submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
authctxt->valid ? "" : "invalid user ",
authctxt->user,
ssh_remote_ipaddr(ssh),
ssh_remote_port(ssh),
extra != NULL ? ": " : "",
extra != NULL ? extra : "");
free(extra);
#ifdef CUSTOM_FAILED_LOGIN
if (authenticated == 0 && !authctxt->postponed &&
(strcmp(method, "password") == 0 ||
strncmp(method, "keyboard-interactive", 20) == 0 ||
strcmp(method, "challenge-response") == 0))
record_failed_login(ssh, authctxt->user,
auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
# ifdef WITH_AIXAUTHENTICATE
if (authenticated)
sys_auth_record_login(authctxt->user,
auth_get_canonical_hostname(ssh, options.use_dns), "ssh",
loginmsg);
# endif
#endif
#ifdef SSH_AUDIT_EVENTS
if (authenticated == 0 && !authctxt->postponed)
audit_event(ssh, audit_classify_auth(method));
#endif
}
void
auth_maxtries_exceeded(struct ssh *ssh)
{
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
error("maximum authentication attempts exceeded for "
"%s%.100s from %.200s port %d ssh2",
authctxt->valid ? "" : "invalid user ",
authctxt->user,
ssh_remote_ipaddr(ssh),
ssh_remote_port(ssh));
ssh_packet_disconnect(ssh, "Too many authentication failures");
/* NOTREACHED */
}
/*
* Check whether root logins are disallowed.
*/
int
auth_root_allowed(struct ssh *ssh, const char *method)
{
switch (options.permit_root_login) {
case PERMIT_YES:
return 1;
case PERMIT_NO_PASSWD:
if (strcmp(method, "publickey") == 0 ||
strcmp(method, "hostbased") == 0 ||
strcmp(method, "gssapi-with-mic") == 0)
return 1;
break;
case PERMIT_FORCED_ONLY:
if (auth_opts->force_command != NULL) {
logit("Root login accepted for forced command.");
return 1;
}
break;
}
logit("ROOT LOGIN REFUSED FROM %.200s port %d",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
return 0;
}
/*
* Given a template and a passwd structure, build a filename
* by substituting % tokenised options. Currently, %% becomes '%',
* %h becomes the home directory and %u the username.
*
* This returns a buffer allocated by xmalloc.
*/
char *
expand_authorized_keys(const char *filename, struct passwd *pw)
{
char *file, uidstr[32], ret[PATH_MAX];
int i;
snprintf(uidstr, sizeof(uidstr), "%llu",
(unsigned long long)pw->pw_uid);
file = percent_expand(filename, "h", pw->pw_dir,
"u", pw->pw_name, "U", uidstr, (char *)NULL);
/*
* Ensure that filename starts anchored. If not, be backward
* compatible and prepend the '%h/'
*/
if (path_absolute(file))
return (file);
i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
if (i < 0 || (size_t)i >= sizeof(ret))
fatal("expand_authorized_keys: path too long");
free(file);
return (xstrdup(ret));
}
char *
authorized_principals_file(struct passwd *pw)
{
if (options.authorized_principals_file == NULL)
return NULL;
return expand_authorized_keys(options.authorized_principals_file, pw);
}
/* return ok if key exists in sysfile or userfile */
HostStatus
check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host,
const char *sysfile, const char *userfile)
{
char *user_hostfile;
struct stat st;
HostStatus host_status;
struct hostkeys *hostkeys;
const struct hostkey_entry *found;
hostkeys = init_hostkeys();
load_hostkeys(hostkeys, host, sysfile, 0);
if (userfile != NULL) {
user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
if (options.strict_modes &&
(stat(user_hostfile, &st) == 0) &&
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0)) {
logit("Authentication refused for %.100s: "
"bad owner or modes for %.200s",
pw->pw_name, user_hostfile);
auth_debug_add("Ignored %.200s: bad ownership or modes",
user_hostfile);
} else {
temporarily_use_uid(pw);
load_hostkeys(hostkeys, host, user_hostfile, 0);
restore_uid();
}
free(user_hostfile);
}
host_status = check_key_in_hostkeys(hostkeys, key, &found);
if (host_status == HOST_REVOKED)
error("WARNING: revoked key for %s attempted authentication",
host);
else if (host_status == HOST_OK)
debug_f("key for %s found at %s:%ld",
found->host, found->file, found->line);
else
debug_f("key for host %s not found", host);
free_hostkeys(hostkeys);
return host_status;
}
static FILE *
auth_openfile(const char *file, struct passwd *pw, int strict_modes,
int log_missing, char *file_type)
{
char line[1024];
struct stat st;
int fd;
FILE *f;
if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) {
if (log_missing || errno != ENOENT)
debug("Could not open %s '%s': %s", file_type, file,
- strerror(errno));
+ strerror(errno));
return NULL;
}
if (fstat(fd, &st) == -1) {
close(fd);
return NULL;
}
if (!S_ISREG(st.st_mode)) {
logit("User %s %s %s is not a regular file",
pw->pw_name, file_type, file);
close(fd);
return NULL;
}
unset_nonblock(fd);
if ((f = fdopen(fd, "r")) == NULL) {
close(fd);
return NULL;
}
if (strict_modes &&
safe_path_fd(fileno(f), file, pw, line, sizeof(line)) != 0) {
fclose(f);
logit("Authentication refused: %s", line);
auth_debug_add("Ignored %s: %s", file_type, line);
return NULL;
}
return f;
}
FILE *
auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes)
{
return auth_openfile(file, pw, strict_modes, 1, "authorized keys");
}
FILE *
auth_openprincipals(const char *file, struct passwd *pw, int strict_modes)
{
return auth_openfile(file, pw, strict_modes, 0,
"authorized principals");
}
struct passwd *
getpwnamallow(struct ssh *ssh, const char *user)
{
#ifdef HAVE_LOGIN_CAP
extern login_cap_t *lc;
#ifdef BSD_AUTH
auth_session_t *as;
#endif
#endif
struct passwd *pw;
struct connection_info *ci;
u_int i;
ci = get_connection_info(ssh, 1, options.use_dns);
ci->user = user;
parse_server_match_config(&options, &includes, ci);
log_change_level(options.log_level);
log_verbose_reset();
for (i = 0; i < options.num_log_verbose; i++)
log_verbose_add(options.log_verbose[i]);
process_permitopen(ssh, &options);
#if defined(_AIX) && defined(HAVE_SETAUTHDB)
aix_setauthdb(user);
#endif
pw = getpwnam(user);
#if defined(_AIX) && defined(HAVE_SETAUTHDB)
aix_restoreauthdb();
#endif
if (pw == NULL) {
logit("Invalid user %.100s from %.100s port %d",
user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
#ifdef CUSTOM_FAILED_LOGIN
record_failed_login(ssh, user,
auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
#endif
#ifdef SSH_AUDIT_EVENTS
audit_event(ssh, SSH_INVALID_USER);
#endif /* SSH_AUDIT_EVENTS */
return (NULL);
}
if (!allowed_user(ssh, pw))
return (NULL);
#ifdef HAVE_LOGIN_CAP
if ((lc = login_getpwclass(pw)) == NULL) {
debug("unable to get login class: %s", user);
return (NULL);
}
#ifdef BSD_AUTH
if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
debug("Approval failure for %s", user);
pw = NULL;
}
if (as != NULL)
auth_close(as);
#endif
#endif
if (pw != NULL)
return (pwcopy(pw));
return (NULL);
}
/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
int
auth_key_is_revoked(struct sshkey *key)
{
char *fp = NULL;
int r;
if (options.revoked_keys_file == NULL)
return 0;
if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
SSH_FP_DEFAULT)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
error_fr(r, "fingerprint key");
goto out;
}
r = sshkey_check_revoked(key, options.revoked_keys_file);
switch (r) {
case 0:
break; /* not revoked */
case SSH_ERR_KEY_REVOKED:
error("Authentication key %s %s revoked by file %s",
sshkey_type(key), fp, options.revoked_keys_file);
goto out;
default:
error_r(r, "Error checking authentication key %s %s in "
"revoked keys file %s", sshkey_type(key), fp,
options.revoked_keys_file);
goto out;
}
/* Success */
r = 0;
out:
free(fp);
return r == 0 ? 0 : 1;
}
void
auth_debug_add(const char *fmt,...)
{
char buf[1024];
va_list args;
int r;
if (auth_debug == NULL)
return;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
if ((r = sshbuf_put_cstring(auth_debug, buf)) != 0)
fatal_fr(r, "sshbuf_put_cstring");
}
void
auth_debug_send(struct ssh *ssh)
{
char *msg;
int r;
if (auth_debug == NULL)
return;
while (sshbuf_len(auth_debug) != 0) {
if ((r = sshbuf_get_cstring(auth_debug, &msg, NULL)) != 0)
fatal_fr(r, "sshbuf_get_cstring");
ssh_packet_send_debug(ssh, "%s", msg);
free(msg);
}
}
void
auth_debug_reset(void)
{
if (auth_debug != NULL)
sshbuf_reset(auth_debug);
else if ((auth_debug = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
}
struct passwd *
fakepw(void)
{
static struct passwd fake;
memset(&fake, 0, sizeof(fake));
fake.pw_name = "NOUSER";
fake.pw_passwd =
"$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK";
#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
fake.pw_gecos = "NOUSER";
#endif
fake.pw_uid = privsep_pw == NULL ? (uid_t)-1 : privsep_pw->pw_uid;
fake.pw_gid = privsep_pw == NULL ? (gid_t)-1 : privsep_pw->pw_gid;
#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
fake.pw_class = "";
#endif
fake.pw_dir = "/nonexist";
fake.pw_shell = "/nonexist";
return (&fake);
}
/*
* Returns the remote DNS hostname as a string. The returned string must not
* be freed. NB. this will usually trigger a DNS query the first time it is
* called.
* This function does additional checks on the hostname to mitigate some
* attacks on legacy rhosts-style authentication.
* XXX is RhostsRSAAuthentication vulnerable to these?
* XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?)
*/
static char *
remote_hostname(struct ssh *ssh)
{
struct sockaddr_storage from;
socklen_t fromlen;
struct addrinfo hints, *ai, *aitop;
char name[NI_MAXHOST], ntop2[NI_MAXHOST];
const char *ntop = ssh_remote_ipaddr(ssh);
/* Get IP address of client. */
fromlen = sizeof(from);
memset(&from, 0, sizeof(from));
if (getpeername(ssh_packet_get_connection_in(ssh),
(struct sockaddr *)&from, &fromlen) == -1) {
debug("getpeername failed: %.100s", strerror(errno));
return xstrdup(ntop);
}
ipv64_normalise_mapped(&from, &fromlen);
if (from.ss_family == AF_INET6)
fromlen = sizeof(struct sockaddr_in6);
debug3("Trying to reverse map address %.100s.", ntop);
/* Map the IP address to a host name. */
if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
NULL, 0, NI_NAMEREQD) != 0) {
/* Host name not found. Use ip address. */
return xstrdup(ntop);
}
/*
* if reverse lookup result looks like a numeric hostname,
* someone is trying to trick us by PTR record like following:
* 1.1.1.10.in-addr.arpa. IN PTR 2.3.4.5
*/
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
hints.ai_flags = AI_NUMERICHOST;
if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
name, ntop);
freeaddrinfo(ai);
return xstrdup(ntop);
}
/* Names are stored in lowercase. */
lowercase(name);
/*
* Map it back to an IP address and check that the given
* address actually is an address of this host. This is
* necessary because anyone with access to a name server can
* define arbitrary names for an IP address. Mapping from
* name to IP address can be trusted better (but can still be
* fooled if the intruder has access to the name server of
* the domain).
*/
memset(&hints, 0, sizeof(hints));
hints.ai_family = from.ss_family;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
logit("reverse mapping checking getaddrinfo for %.700s "
"[%s] failed.", name, ntop);
return xstrdup(ntop);
}
/* Look for the address from the list of addresses. */
for (ai = aitop; ai; ai = ai->ai_next) {
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
(strcmp(ntop, ntop2) == 0))
break;
}
freeaddrinfo(aitop);
/* If we reached the end of the list, the address was not there. */
if (ai == NULL) {
/* Address not found for the host name. */
logit("Address %.100s maps to %.600s, but this does not "
"map back to the address.", ntop, name);
return xstrdup(ntop);
}
return xstrdup(name);
}
/*
* Return the canonical name of the host in the other side of the current
* connection. The host name is cached, so it is efficient to call this
* several times.
*/
const char *
auth_get_canonical_hostname(struct ssh *ssh, int use_dns)
{
static char *dnsname;
if (!use_dns)
return ssh_remote_ipaddr(ssh);
else if (dnsname != NULL)
return dnsname;
else {
dnsname = remote_hostname(ssh);
return dnsname;
}
}
/* These functions link key/cert options to the auth framework */
/* Log sshauthopt options locally and (optionally) for remote transmission */
void
auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote)
{
int do_env = options.permit_user_env && opts->nenv > 0;
int do_permitopen = opts->npermitopen > 0 &&
(options.allow_tcp_forwarding & FORWARD_LOCAL) != 0;
int do_permitlisten = opts->npermitlisten > 0 &&
(options.allow_tcp_forwarding & FORWARD_REMOTE) != 0;
size_t i;
char msg[1024], buf[64];
snprintf(buf, sizeof(buf), "%d", opts->force_tun_device);
/* Try to keep this alphabetically sorted */
snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
opts->permit_agent_forwarding_flag ? " agent-forwarding" : "",
opts->force_command == NULL ? "" : " command",
do_env ? " environment" : "",
opts->valid_before == 0 ? "" : "expires",
opts->no_require_user_presence ? " no-touch-required" : "",
do_permitopen ? " permitopen" : "",
do_permitlisten ? " permitlisten" : "",
opts->permit_port_forwarding_flag ? " port-forwarding" : "",
opts->cert_principals == NULL ? "" : " principals",
opts->permit_pty_flag ? " pty" : "",
opts->require_verify ? " uv" : "",
opts->force_tun_device == -1 ? "" : " tun=",
opts->force_tun_device == -1 ? "" : buf,
opts->permit_user_rc ? " user-rc" : "",
opts->permit_x11_forwarding_flag ? " x11-forwarding" : "");
debug("%s: %s", loc, msg);
if (do_remote)
auth_debug_add("%s: %s", loc, msg);
if (options.permit_user_env) {
for (i = 0; i < opts->nenv; i++) {
debug("%s: environment: %s", loc, opts->env[i]);
if (do_remote) {
auth_debug_add("%s: environment: %s",
loc, opts->env[i]);
}
}
}
/* Go into a little more details for the local logs. */
if (opts->valid_before != 0) {
format_absolute_time(opts->valid_before, buf, sizeof(buf));
debug("%s: expires at %s", loc, buf);
}
if (opts->cert_principals != NULL) {
debug("%s: authorized principals: \"%s\"",
loc, opts->cert_principals);
}
if (opts->force_command != NULL)
debug("%s: forced command: \"%s\"", loc, opts->force_command);
if (do_permitopen) {
for (i = 0; i < opts->npermitopen; i++) {
debug("%s: permitted open: %s",
loc, opts->permitopen[i]);
}
}
if (do_permitlisten) {
for (i = 0; i < opts->npermitlisten; i++) {
debug("%s: permitted listen: %s",
loc, opts->permitlisten[i]);
}
}
}
/* Activate a new set of key/cert options; merging with what is there. */
int
auth_activate_options(struct ssh *ssh, struct sshauthopt *opts)
{
struct sshauthopt *old = auth_opts;
const char *emsg = NULL;
debug_f("setting new authentication options");
if ((auth_opts = sshauthopt_merge(old, opts, &emsg)) == NULL) {
error("Inconsistent authentication options: %s", emsg);
return -1;
}
return 0;
}
/* Disable forwarding, etc for the session */
void
auth_restrict_session(struct ssh *ssh)
{
struct sshauthopt *restricted;
debug_f("restricting session");
/* A blank sshauthopt defaults to permitting nothing */
restricted = sshauthopt_new();
restricted->permit_pty_flag = 1;
restricted->restricted = 1;
if (auth_activate_options(ssh, restricted) != 0)
fatal_f("failed to restrict session");
sshauthopt_free(restricted);
}
int
auth_authorise_keyopts(struct ssh *ssh, struct passwd *pw,
struct sshauthopt *opts, int allow_cert_authority, const char *loc)
{
const char *remote_ip = ssh_remote_ipaddr(ssh);
const char *remote_host = auth_get_canonical_hostname(ssh,
options.use_dns);
time_t now = time(NULL);
char buf[64];
/*
* Check keys/principals file expiry time.
* NB. validity interval in certificate is handled elsewhere.
*/
if (opts->valid_before && now > 0 &&
opts->valid_before < (uint64_t)now) {
format_absolute_time(opts->valid_before, buf, sizeof(buf));
debug("%s: entry expired at %s", loc, buf);
auth_debug_add("%s: entry expired at %s", loc, buf);
return -1;
}
/* Consistency checks */
if (opts->cert_principals != NULL && !opts->cert_authority) {
debug("%s: principals on non-CA key", loc);
auth_debug_add("%s: principals on non-CA key", loc);
/* deny access */
return -1;
}
/* cert-authority flag isn't valid in authorized_principals files */
if (!allow_cert_authority && opts->cert_authority) {
debug("%s: cert-authority flag invalid here", loc);
auth_debug_add("%s: cert-authority flag invalid here", loc);
/* deny access */
return -1;
}
/* Perform from= checks */
if (opts->required_from_host_keys != NULL) {
switch (match_host_and_ip(remote_host, remote_ip,
opts->required_from_host_keys )) {
case 1:
/* Host name matches. */
break;
case -1:
default:
debug("%s: invalid from criteria", loc);
auth_debug_add("%s: invalid from criteria", loc);
/* FALLTHROUGH */
case 0:
logit("%s: Authentication tried for %.100s with "
"correct key but not from a permitted "
"host (host=%.200s, ip=%.200s, required=%.200s).",
loc, pw->pw_name, remote_host, remote_ip,
opts->required_from_host_keys);
auth_debug_add("%s: Your host '%.200s' is not "
"permitted to use this key for login.",
loc, remote_host);
/* deny access */
return -1;
}
}
/* Check source-address restriction from certificate */
if (opts->required_from_host_cert != NULL) {
switch (addr_match_cidr_list(remote_ip,
opts->required_from_host_cert)) {
case 1:
/* accepted */
break;
case -1:
default:
/* invalid */
error("%s: Certificate source-address invalid", loc);
/* FALLTHROUGH */
case 0:
logit("%s: Authentication tried for %.100s with valid "
"certificate but not from a permitted source "
"address (%.200s).", loc, pw->pw_name, remote_ip);
auth_debug_add("%s: Your address '%.200s' is not "
"permitted to use this certificate for login.",
loc, remote_ip);
return -1;
}
}
/*
*
* XXX this is spammy. We should report remotely only for keys
* that are successful in actual auth attempts, and not PK_OK
* tests.
*/
auth_log_authopts(loc, opts, 1);
return 0;
}
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index 411d2d885144..721c1d9bd750 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -1,1065 +1,1066 @@
-/* $OpenBSD: auth2-pubkey.c,v 1.106 2021/01/27 10:05:28 djm Exp $ */
+/* $OpenBSD: auth2-pubkey.c,v 1.107 2021/04/03 06:18:40 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <limits.h>
#include "xmalloc.h"
#include "ssh.h"
#include "ssh2.h"
#include "packet.h"
#include "kex.h"
#include "sshbuf.h"
#include "log.h"
#include "misc.h"
#include "servconf.h"
#include "compat.h"
#include "sshkey.h"
#include "hostfile.h"
#include "auth.h"
#include "pathnames.h"
#include "uidswap.h"
#include "auth-options.h"
#include "canohost.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
#include "monitor_wrap.h"
#include "authfile.h"
#include "match.h"
#include "ssherr.h"
#include "channels.h" /* XXX for session.h */
#include "session.h" /* XXX for child_set_env(); refactor? */
#include "sk-api.h"
/* import */
extern ServerOptions options;
static char *
format_key(const struct sshkey *key)
{
char *ret, *fp = sshkey_fingerprint(key,
options.fingerprint_hash, SSH_FP_DEFAULT);
xasprintf(&ret, "%s %s", sshkey_type(key), fp);
free(fp);
return ret;
}
static int
userauth_pubkey(struct ssh *ssh)
{
Authctxt *authctxt = ssh->authctxt;
struct passwd *pw = authctxt->pw;
struct sshbuf *b = NULL;
struct sshkey *key = NULL;
char *pkalg = NULL, *userstyle = NULL, *key_s = NULL, *ca_s = NULL;
u_char *pkblob = NULL, *sig = NULL, have_sig;
size_t blen, slen;
int r, pktype;
int req_presence = 0, req_verify = 0, authenticated = 0;
struct sshauthopt *authopts = NULL;
struct sshkey_sig_details *sig_details = NULL;
if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0 ||
(r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
(r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0)
fatal_fr(r, "parse packet");
if (log_level_get() >= SYSLOG_LEVEL_DEBUG2) {
char *keystring;
struct sshbuf *pkbuf;
if ((pkbuf = sshbuf_from(pkblob, blen)) == NULL)
fatal_f("sshbuf_from failed");
if ((keystring = sshbuf_dtob64_string(pkbuf, 0)) == NULL)
fatal_f("sshbuf_dtob64 failed");
debug2_f("%s user %s %s public key %s %s",
authctxt->valid ? "valid" : "invalid", authctxt->user,
have_sig ? "attempting" : "querying", pkalg, keystring);
sshbuf_free(pkbuf);
free(keystring);
}
pktype = sshkey_type_from_name(pkalg);
if (pktype == KEY_UNSPEC) {
/* this is perfectly legal */
verbose_f("unsupported public key algorithm: %s", pkalg);
goto done;
}
if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
error_fr(r, "parse key");
goto done;
}
if (key == NULL) {
error_f("cannot decode key: %s", pkalg);
goto done;
}
if (key->type != pktype) {
error_f("type mismatch for decoded key "
"(received %d, expected %d)", key->type, pktype);
goto done;
}
if (sshkey_type_plain(key->type) == KEY_RSA &&
(ssh->compat & SSH_BUG_RSASIGMD5) != 0) {
logit("Refusing RSA key because client uses unsafe "
"signature scheme");
goto done;
}
if (auth2_key_already_used(authctxt, key)) {
logit("refusing previously-used %s key", sshkey_type(key));
goto done;
}
if (match_pattern_list(pkalg, options.pubkey_accepted_algos, 0) != 1) {
logit_f("key type %s not in PubkeyAcceptedAlgorithms",
sshkey_ssh_name(key));
goto done;
}
if ((r = sshkey_check_cert_sigtype(key,
options.ca_sign_algorithms)) != 0) {
logit_fr(r, "certificate signature algorithm %s",
(key->cert == NULL || key->cert->signature_type == NULL) ?
"(null)" : key->cert->signature_type);
goto done;
}
key_s = format_key(key);
if (sshkey_is_cert(key))
ca_s = format_key(key->cert->signature_key);
if (have_sig) {
debug3_f("have %s signature for %s%s%s", pkalg, key_s,
ca_s == NULL ? "" : " CA ", ca_s == NULL ? "" : ca_s);
if ((r = sshpkt_get_string(ssh, &sig, &slen)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
fatal_fr(r, "parse signature packet");
if ((b = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if (ssh->compat & SSH_OLD_SESSIONID) {
if ((r = sshbuf_putb(b, ssh->kex->session_id)) != 0)
fatal_fr(r, "put old session id");
} else {
if ((r = sshbuf_put_stringb(b,
ssh->kex->session_id)) != 0)
fatal_fr(r, "put session id");
}
if (!authctxt->valid || authctxt->user == NULL) {
debug2_f("disabled because of invalid user");
goto done;
}
/* reconstruct packet */
xasprintf(&userstyle, "%s%s%s", authctxt->user,
authctxt->style ? ":" : "",
authctxt->style ? authctxt->style : "");
if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
(r = sshbuf_put_cstring(b, userstyle)) != 0 ||
(r = sshbuf_put_cstring(b, authctxt->service)) != 0 ||
(r = sshbuf_put_cstring(b, "publickey")) != 0 ||
(r = sshbuf_put_u8(b, have_sig)) != 0 ||
(r = sshbuf_put_cstring(b, pkalg)) != 0 ||
(r = sshbuf_put_string(b, pkblob, blen)) != 0)
fatal_fr(r, "reconstruct packet");
#ifdef DEBUG_PK
sshbuf_dump(b, stderr);
#endif
/* test for correct signature */
authenticated = 0;
if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) &&
PRIVSEP(sshkey_verify(key, sig, slen,
sshbuf_ptr(b), sshbuf_len(b),
(ssh->compat & SSH_BUG_SIGTYPE) == 0 ? pkalg : NULL,
ssh->compat, &sig_details)) == 0) {
authenticated = 1;
}
if (authenticated == 1 && sig_details != NULL) {
auth2_record_info(authctxt, "signature count = %u",
sig_details->sk_counter);
debug_f("sk_counter = %u, sk_flags = 0x%02x",
sig_details->sk_counter, sig_details->sk_flags);
req_presence = (options.pubkey_auth_options &
PUBKEYAUTH_TOUCH_REQUIRED) ||
!authopts->no_require_user_presence;
if (req_presence && (sig_details->sk_flags &
SSH_SK_USER_PRESENCE_REQD) == 0) {
error("public key %s signature for %s%s from "
"%.128s port %d rejected: user presence "
"(authenticator touch) requirement "
"not met ", key_s,
authctxt->valid ? "" : "invalid user ",
authctxt->user, ssh_remote_ipaddr(ssh),
ssh_remote_port(ssh));
authenticated = 0;
goto done;
}
req_verify = (options.pubkey_auth_options &
PUBKEYAUTH_VERIFY_REQUIRED) ||
authopts->require_verify;
if (req_verify && (sig_details->sk_flags &
SSH_SK_USER_VERIFICATION_REQD) == 0) {
error("public key %s signature for %s%s from "
"%.128s port %d rejected: user "
"verification requirement not met ", key_s,
authctxt->valid ? "" : "invalid user ",
authctxt->user, ssh_remote_ipaddr(ssh),
ssh_remote_port(ssh));
authenticated = 0;
goto done;
}
}
auth2_record_key(authctxt, authenticated, key);
} else {
debug_f("test pkalg %s pkblob %s%s%s", pkalg, key_s,
ca_s == NULL ? "" : " CA ", ca_s == NULL ? "" : ca_s);
if ((r = sshpkt_get_end(ssh)) != 0)
fatal_fr(r, "parse packet");
if (!authctxt->valid || authctxt->user == NULL) {
debug2_f("disabled because of invalid user");
goto done;
}
/* XXX fake reply and always send PK_OK ? */
/*
* XXX this allows testing whether a user is allowed
* to login: if you happen to have a valid pubkey this
* message is sent. the message is NEVER sent at all
* if a user is not allowed to login. is this an
* issue? -markus
*/
if (PRIVSEP(user_key_allowed(ssh, pw, key, 0, NULL))) {
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK))
!= 0 ||
(r = sshpkt_put_cstring(ssh, pkalg)) != 0 ||
(r = sshpkt_put_string(ssh, pkblob, blen)) != 0 ||
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
fatal_fr(r, "send packet");
authctxt->postponed = 1;
}
}
done:
if (authenticated == 1 && auth_activate_options(ssh, authopts) != 0) {
debug_f("key options inconsistent with existing");
authenticated = 0;
}
debug2_f("authenticated %d pkalg %s", authenticated, pkalg);
sshbuf_free(b);
sshauthopt_free(authopts);
sshkey_free(key);
free(userstyle);
free(pkalg);
free(pkblob);
free(key_s);
free(ca_s);
free(sig);
sshkey_sig_details_free(sig_details);
return authenticated;
}
static int
match_principals_option(const char *principal_list, struct sshkey_cert *cert)
{
char *result;
u_int i;
/* XXX percent_expand() sequences for authorized_principals? */
for (i = 0; i < cert->nprincipals; i++) {
if ((result = match_list(cert->principals[i],
principal_list, NULL)) != NULL) {
debug3("matched principal from key options \"%.100s\"",
result);
free(result);
return 1;
}
}
return 0;
}
/*
* Process a single authorized_principals format line. Returns 0 and sets
* authoptsp is principal is authorised, -1 otherwise. "loc" is used as a
* log preamble for file/line information.
*/
static int
check_principals_line(struct ssh *ssh, char *cp, const struct sshkey_cert *cert,
const char *loc, struct sshauthopt **authoptsp)
{
u_int i, found = 0;
char *ep, *line_opts;
const char *reason = NULL;
struct sshauthopt *opts = NULL;
if (authoptsp != NULL)
*authoptsp = NULL;
/* Trim trailing whitespace. */
ep = cp + strlen(cp) - 1;
while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t'))
*ep-- = '\0';
/*
* If the line has internal whitespace then assume it has
* key options.
*/
line_opts = NULL;
if ((ep = strrchr(cp, ' ')) != NULL ||
(ep = strrchr(cp, '\t')) != NULL) {
for (; *ep == ' ' || *ep == '\t'; ep++)
;
line_opts = cp;
cp = ep;
}
if ((opts = sshauthopt_parse(line_opts, &reason)) == NULL) {
debug("%s: bad principals options: %s", loc, reason);
auth_debug_add("%s: bad principals options: %s", loc, reason);
return -1;
}
/* Check principals in cert against those on line */
for (i = 0; i < cert->nprincipals; i++) {
if (strcmp(cp, cert->principals[i]) != 0)
continue;
debug3("%s: matched principal \"%.100s\"",
loc, cert->principals[i]);
found = 1;
}
if (found && authoptsp != NULL) {
*authoptsp = opts;
opts = NULL;
}
sshauthopt_free(opts);
return found ? 0 : -1;
}
static int
process_principals(struct ssh *ssh, FILE *f, const char *file,
const struct sshkey_cert *cert, struct sshauthopt **authoptsp)
{
char loc[256], *line = NULL, *cp, *ep;
size_t linesize = 0;
u_long linenum = 0;
u_int found_principal = 0;
if (authoptsp != NULL)
*authoptsp = NULL;
while (getline(&line, &linesize, f) != -1) {
linenum++;
/* Always consume entire input */
if (found_principal)
continue;
/* Skip leading whitespace. */
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
;
/* Skip blank and comment lines. */
if ((ep = strchr(cp, '#')) != NULL)
*ep = '\0';
if (!*cp || *cp == '\n')
continue;
snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum);
if (check_principals_line(ssh, cp, cert, loc, authoptsp) == 0)
found_principal = 1;
}
free(line);
return found_principal;
}
/* XXX remove pw args here and elsewhere once ssh->authctxt is guaranteed */
static int
match_principals_file(struct ssh *ssh, struct passwd *pw, char *file,
struct sshkey_cert *cert, struct sshauthopt **authoptsp)
{
FILE *f;
int success;
if (authoptsp != NULL)
*authoptsp = NULL;
temporarily_use_uid(pw);
debug("trying authorized principals file %s", file);
if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) {
restore_uid();
return 0;
}
success = process_principals(ssh, f, file, cert, authoptsp);
fclose(f);
restore_uid();
return success;
}
/*
* Checks whether principal is allowed in output of command.
* returns 1 if the principal is allowed or 0 otherwise.
*/
static int
match_principals_command(struct ssh *ssh, struct passwd *user_pw,
const struct sshkey *key, struct sshauthopt **authoptsp)
{
struct passwd *runas_pw = NULL;
const struct sshkey_cert *cert = key->cert;
FILE *f = NULL;
int r, ok, found_principal = 0;
int i, ac = 0, uid_swapped = 0;
pid_t pid;
char *tmp, *username = NULL, *command = NULL, **av = NULL;
char *ca_fp = NULL, *key_fp = NULL, *catext = NULL, *keytext = NULL;
char serial_s[32], uidstr[32];
void (*osigchld)(int);
if (authoptsp != NULL)
*authoptsp = NULL;
if (options.authorized_principals_command == NULL)
return 0;
if (options.authorized_principals_command_user == NULL) {
error("No user for AuthorizedPrincipalsCommand specified, "
"skipping");
return 0;
}
/*
* NB. all returns later this function should go via "out" to
* ensure the original SIGCHLD handler is restored properly.
*/
osigchld = ssh_signal(SIGCHLD, SIG_DFL);
/* Prepare and verify the user for the command */
username = percent_expand(options.authorized_principals_command_user,
"u", user_pw->pw_name, (char *)NULL);
runas_pw = getpwnam(username);
if (runas_pw == NULL) {
error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s",
username, strerror(errno));
goto out;
}
/* Turn the command into an argument vector */
if (argv_split(options.authorized_principals_command, &ac, &av) != 0) {
error("AuthorizedPrincipalsCommand \"%s\" contains "
"invalid quotes", options.authorized_principals_command);
goto out;
}
if (ac == 0) {
error("AuthorizedPrincipalsCommand \"%s\" yielded no arguments",
options.authorized_principals_command);
goto out;
}
if ((ca_fp = sshkey_fingerprint(cert->signature_key,
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
error_f("sshkey_fingerprint failed");
goto out;
}
if ((key_fp = sshkey_fingerprint(key,
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
error_f("sshkey_fingerprint failed");
goto out;
}
if ((r = sshkey_to_base64(cert->signature_key, &catext)) != 0) {
error_fr(r, "sshkey_to_base64 failed");
goto out;
}
if ((r = sshkey_to_base64(key, &keytext)) != 0) {
error_fr(r, "sshkey_to_base64 failed");
goto out;
}
snprintf(serial_s, sizeof(serial_s), "%llu",
(unsigned long long)cert->serial);
snprintf(uidstr, sizeof(uidstr), "%llu",
(unsigned long long)user_pw->pw_uid);
for (i = 1; i < ac; i++) {
tmp = percent_expand(av[i],
"U", uidstr,
"u", user_pw->pw_name,
"h", user_pw->pw_dir,
"t", sshkey_ssh_name(key),
"T", sshkey_ssh_name(cert->signature_key),
"f", key_fp,
"F", ca_fp,
"k", keytext,
"K", catext,
"i", cert->key_id,
"s", serial_s,
(char *)NULL);
if (tmp == NULL)
fatal_f("percent_expand failed");
free(av[i]);
av[i] = tmp;
}
/* Prepare a printable command for logs, etc. */
command = argv_assemble(ac, av);
if ((pid = subprocess("AuthorizedPrincipalsCommand", command,
ac, av, &f,
SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD,
runas_pw, temporarily_use_uid, restore_uid)) == 0)
goto out;
uid_swapped = 1;
temporarily_use_uid(runas_pw);
ok = process_principals(ssh, f, "(command)", cert, authoptsp);
fclose(f);
f = NULL;
if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command, 0) != 0)
goto out;
/* Read completed successfully */
found_principal = ok;
out:
if (f != NULL)
fclose(f);
ssh_signal(SIGCHLD, osigchld);
for (i = 0; i < ac; i++)
free(av[i]);
free(av);
if (uid_swapped)
restore_uid();
free(command);
free(username);
free(ca_fp);
free(key_fp);
free(catext);
free(keytext);
return found_principal;
}
/*
* Check a single line of an authorized_keys-format file. Returns 0 if key
* matches, -1 otherwise. Will return key/cert options via *authoptsp
* on success. "loc" is used as file/line location in log messages.
*/
static int
check_authkey_line(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
char *cp, const char *loc, struct sshauthopt **authoptsp)
{
int want_keytype = sshkey_is_cert(key) ? KEY_UNSPEC : key->type;
struct sshkey *found = NULL;
struct sshauthopt *keyopts = NULL, *certopts = NULL, *finalopts = NULL;
char *key_options = NULL, *fp = NULL;
const char *reason = NULL;
int ret = -1;
if (authoptsp != NULL)
*authoptsp = NULL;
if ((found = sshkey_new(want_keytype)) == NULL) {
debug3_f("keytype %d failed", want_keytype);
goto out;
}
/* XXX djm: peek at key type in line and skip if unwanted */
if (sshkey_read(found, &cp) != 0) {
/* no key? check for options */
debug2("%s: check options: '%s'", loc, cp);
key_options = cp;
if (sshkey_advance_past_options(&cp) != 0) {
reason = "invalid key option string";
goto fail_reason;
}
skip_space(&cp);
if (sshkey_read(found, &cp) != 0) {
/* still no key? advance to next line*/
debug2("%s: advance: '%s'", loc, cp);
goto out;
}
}
/* Parse key options now; we need to know if this is a CA key */
if ((keyopts = sshauthopt_parse(key_options, &reason)) == NULL) {
debug("%s: bad key options: %s", loc, reason);
auth_debug_add("%s: bad key options: %s", loc, reason);
goto out;
}
/* Ignore keys that don't match or incorrectly marked as CAs */
if (sshkey_is_cert(key)) {
/* Certificate; check signature key against CA */
if (!sshkey_equal(found, key->cert->signature_key) ||
!keyopts->cert_authority)
goto out;
} else {
/* Plain key: check it against key found in file */
if (!sshkey_equal(found, key) || keyopts->cert_authority)
goto out;
}
/* We have a candidate key, perform authorisation checks */
if ((fp = sshkey_fingerprint(found,
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
fatal_f("fingerprint failed");
debug("%s: matching %s found: %s %s", loc,
sshkey_is_cert(key) ? "CA" : "key", sshkey_type(found), fp);
if (auth_authorise_keyopts(ssh, pw, keyopts,
sshkey_is_cert(key), loc) != 0) {
reason = "Refused by key options";
goto fail_reason;
}
/* That's all we need for plain keys. */
if (!sshkey_is_cert(key)) {
verbose("Accepted key %s %s found at %s",
sshkey_type(found), fp, loc);
finalopts = keyopts;
keyopts = NULL;
goto success;
}
/*
* Additional authorisation for certificates.
*/
/* Parse and check options present in certificate */
if ((certopts = sshauthopt_from_cert(key)) == NULL) {
reason = "Invalid certificate options";
goto fail_reason;
}
if (auth_authorise_keyopts(ssh, pw, certopts, 0, loc) != 0) {
reason = "Refused by certificate options";
goto fail_reason;
}
if ((finalopts = sshauthopt_merge(keyopts, certopts, &reason)) == NULL)
goto fail_reason;
/*
* If the user has specified a list of principals as
* a key option, then prefer that list to matching
* their username in the certificate principals list.
*/
if (keyopts->cert_principals != NULL &&
!match_principals_option(keyopts->cert_principals, key->cert)) {
reason = "Certificate does not contain an authorized principal";
goto fail_reason;
}
if (sshkey_cert_check_authority(key, 0, 0, 0,
- keyopts->cert_principals == NULL ? pw->pw_name : NULL, &reason) != 0)
+ keyopts->cert_principals == NULL ? pw->pw_name : NULL,
+ &reason) != 0)
goto fail_reason;
verbose("Accepted certificate ID \"%s\" (serial %llu) "
"signed by CA %s %s found at %s",
key->cert->key_id,
(unsigned long long)key->cert->serial,
sshkey_type(found), fp, loc);
success:
if (finalopts == NULL)
fatal_f("internal error: missing options");
if (authoptsp != NULL) {
*authoptsp = finalopts;
finalopts = NULL;
}
/* success */
ret = 0;
goto out;
fail_reason:
error("%s", reason);
auth_debug_add("%s", reason);
out:
free(fp);
sshauthopt_free(keyopts);
sshauthopt_free(certopts);
sshauthopt_free(finalopts);
sshkey_free(found);
return ret;
}
/*
* Checks whether key is allowed in authorized_keys-format file,
* returns 1 if the key is allowed or 0 otherwise.
*/
static int
check_authkeys_file(struct ssh *ssh, struct passwd *pw, FILE *f,
char *file, struct sshkey *key, struct sshauthopt **authoptsp)
{
char *cp, *line = NULL, loc[256];
size_t linesize = 0;
int found_key = 0;
u_long linenum = 0;
if (authoptsp != NULL)
*authoptsp = NULL;
while (getline(&line, &linesize, f) != -1) {
linenum++;
/* Always consume entire file */
if (found_key)
continue;
/* Skip leading whitespace, empty and comment lines. */
cp = line;
skip_space(&cp);
if (!*cp || *cp == '\n' || *cp == '#')
continue;
snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum);
if (check_authkey_line(ssh, pw, key, cp, loc, authoptsp) == 0)
found_key = 1;
}
free(line);
return found_key;
}
/* Authenticate a certificate key against TrustedUserCAKeys */
static int
user_cert_trusted_ca(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
struct sshauthopt **authoptsp)
{
char *ca_fp, *principals_file = NULL;
const char *reason;
struct sshauthopt *principals_opts = NULL, *cert_opts = NULL;
struct sshauthopt *final_opts = NULL;
int r, ret = 0, found_principal = 0, use_authorized_principals;
if (authoptsp != NULL)
*authoptsp = NULL;
if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL)
return 0;
if ((ca_fp = sshkey_fingerprint(key->cert->signature_key,
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
return 0;
if ((r = sshkey_in_file(key->cert->signature_key,
options.trusted_user_ca_keys, 1, 0)) != 0) {
debug2_fr(r, "CA %s %s is not listed in %s",
sshkey_type(key->cert->signature_key), ca_fp,
options.trusted_user_ca_keys);
goto out;
}
/*
* If AuthorizedPrincipals is in use, then compare the certificate
* principals against the names in that file rather than matching
* against the username.
*/
if ((principals_file = authorized_principals_file(pw)) != NULL) {
if (match_principals_file(ssh, pw, principals_file,
key->cert, &principals_opts))
found_principal = 1;
}
/* Try querying command if specified */
if (!found_principal && match_principals_command(ssh, pw, key,
&principals_opts))
found_principal = 1;
/* If principals file or command is specified, then require a match */
use_authorized_principals = principals_file != NULL ||
- options.authorized_principals_command != NULL;
+ options.authorized_principals_command != NULL;
if (!found_principal && use_authorized_principals) {
reason = "Certificate does not contain an authorized principal";
goto fail_reason;
}
if (use_authorized_principals && principals_opts == NULL)
fatal_f("internal error: missing principals_opts");
if (sshkey_cert_check_authority(key, 0, 1, 0,
use_authorized_principals ? NULL : pw->pw_name, &reason) != 0)
goto fail_reason;
/* Check authority from options in key and from principals file/cmd */
if ((cert_opts = sshauthopt_from_cert(key)) == NULL) {
reason = "Invalid certificate options";
goto fail_reason;
}
if (auth_authorise_keyopts(ssh, pw, cert_opts, 0, "cert") != 0) {
reason = "Refused by certificate options";
goto fail_reason;
}
if (principals_opts == NULL) {
final_opts = cert_opts;
cert_opts = NULL;
} else {
if (auth_authorise_keyopts(ssh, pw, principals_opts, 0,
"principals") != 0) {
reason = "Refused by certificate principals options";
goto fail_reason;
}
if ((final_opts = sshauthopt_merge(principals_opts,
cert_opts, &reason)) == NULL) {
fail_reason:
error("%s", reason);
auth_debug_add("%s", reason);
goto out;
}
}
/* Success */
verbose("Accepted certificate ID \"%s\" (serial %llu) signed by "
"%s CA %s via %s", key->cert->key_id,
(unsigned long long)key->cert->serial,
sshkey_type(key->cert->signature_key), ca_fp,
options.trusted_user_ca_keys);
if (authoptsp != NULL) {
*authoptsp = final_opts;
final_opts = NULL;
}
ret = 1;
out:
sshauthopt_free(principals_opts);
sshauthopt_free(cert_opts);
sshauthopt_free(final_opts);
free(principals_file);
free(ca_fp);
return ret;
}
/*
* Checks whether key is allowed in file.
* returns 1 if the key is allowed or 0 otherwise.
*/
static int
user_key_allowed2(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
char *file, struct sshauthopt **authoptsp)
{
FILE *f;
int found_key = 0;
if (authoptsp != NULL)
*authoptsp = NULL;
/* Temporarily use the user's uid. */
temporarily_use_uid(pw);
debug("trying public key file %s", file);
if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) {
found_key = check_authkeys_file(ssh, pw, f, file,
key, authoptsp);
fclose(f);
}
restore_uid();
return found_key;
}
/*
* Checks whether key is allowed in output of command.
* returns 1 if the key is allowed or 0 otherwise.
*/
static int
user_key_command_allowed2(struct ssh *ssh, struct passwd *user_pw,
struct sshkey *key, struct sshauthopt **authoptsp)
{
struct passwd *runas_pw = NULL;
FILE *f = NULL;
int r, ok, found_key = 0;
int i, uid_swapped = 0, ac = 0;
pid_t pid;
char *username = NULL, *key_fp = NULL, *keytext = NULL;
char uidstr[32], *tmp, *command = NULL, **av = NULL;
void (*osigchld)(int);
if (authoptsp != NULL)
*authoptsp = NULL;
if (options.authorized_keys_command == NULL)
return 0;
if (options.authorized_keys_command_user == NULL) {
error("No user for AuthorizedKeysCommand specified, skipping");
return 0;
}
/*
* NB. all returns later this function should go via "out" to
* ensure the original SIGCHLD handler is restored properly.
*/
osigchld = ssh_signal(SIGCHLD, SIG_DFL);
/* Prepare and verify the user for the command */
username = percent_expand(options.authorized_keys_command_user,
"u", user_pw->pw_name, (char *)NULL);
runas_pw = getpwnam(username);
if (runas_pw == NULL) {
error("AuthorizedKeysCommandUser \"%s\" not found: %s",
username, strerror(errno));
goto out;
}
/* Prepare AuthorizedKeysCommand */
if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash,
SSH_FP_DEFAULT)) == NULL) {
error_f("sshkey_fingerprint failed");
goto out;
}
if ((r = sshkey_to_base64(key, &keytext)) != 0) {
error_fr(r, "sshkey_to_base64 failed");
goto out;
}
/* Turn the command into an argument vector */
if (argv_split(options.authorized_keys_command, &ac, &av) != 0) {
error("AuthorizedKeysCommand \"%s\" contains invalid quotes",
options.authorized_keys_command);
goto out;
}
if (ac == 0) {
error("AuthorizedKeysCommand \"%s\" yielded no arguments",
options.authorized_keys_command);
goto out;
}
snprintf(uidstr, sizeof(uidstr), "%llu",
(unsigned long long)user_pw->pw_uid);
for (i = 1; i < ac; i++) {
tmp = percent_expand(av[i],
"U", uidstr,
"u", user_pw->pw_name,
"h", user_pw->pw_dir,
"t", sshkey_ssh_name(key),
"f", key_fp,
"k", keytext,
(char *)NULL);
if (tmp == NULL)
fatal_f("percent_expand failed");
free(av[i]);
av[i] = tmp;
}
/* Prepare a printable command for logs, etc. */
command = argv_assemble(ac, av);
/*
* If AuthorizedKeysCommand was run without arguments
* then fall back to the old behaviour of passing the
* target username as a single argument.
*/
if (ac == 1) {
av = xreallocarray(av, ac + 2, sizeof(*av));
av[1] = xstrdup(user_pw->pw_name);
av[2] = NULL;
/* Fix up command too, since it is used in log messages */
free(command);
xasprintf(&command, "%s %s", av[0], av[1]);
}
if ((pid = subprocess("AuthorizedKeysCommand", command,
ac, av, &f,
SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD,
runas_pw, temporarily_use_uid, restore_uid)) == 0)
goto out;
uid_swapped = 1;
temporarily_use_uid(runas_pw);
ok = check_authkeys_file(ssh, user_pw, f,
options.authorized_keys_command, key, authoptsp);
fclose(f);
f = NULL;
if (exited_cleanly(pid, "AuthorizedKeysCommand", command, 0) != 0)
goto out;
/* Read completed successfully */
found_key = ok;
out:
if (f != NULL)
fclose(f);
ssh_signal(SIGCHLD, osigchld);
for (i = 0; i < ac; i++)
free(av[i]);
free(av);
if (uid_swapped)
restore_uid();
free(command);
free(username);
free(key_fp);
free(keytext);
return found_key;
}
/*
* Check whether key authenticates and authorises the user.
*/
int
user_key_allowed(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
int auth_attempt, struct sshauthopt **authoptsp)
{
u_int success = 0, i;
char *file;
struct sshauthopt *opts = NULL;
if (authoptsp != NULL)
*authoptsp = NULL;
if (auth_key_is_revoked(key))
return 0;
if (sshkey_is_cert(key) &&
auth_key_is_revoked(key->cert->signature_key))
return 0;
for (i = 0; !success && i < options.num_authkeys_files; i++) {
if (strcasecmp(options.authorized_keys_files[i], "none") == 0)
continue;
file = expand_authorized_keys(
options.authorized_keys_files[i], pw);
success = user_key_allowed2(ssh, pw, key, file, &opts);
free(file);
if (!success) {
sshauthopt_free(opts);
opts = NULL;
}
}
if (success)
goto out;
if ((success = user_cert_trusted_ca(ssh, pw, key, &opts)) != 0)
goto out;
sshauthopt_free(opts);
opts = NULL;
if ((success = user_key_command_allowed2(ssh, pw, key, &opts)) != 0)
goto out;
sshauthopt_free(opts);
opts = NULL;
out:
if (success && authoptsp != NULL) {
*authoptsp = opts;
opts = NULL;
}
sshauthopt_free(opts);
return success;
}
Authmethod method_pubkey = {
"publickey",
userauth_pubkey,
&options.pubkey_authentication
};
diff --git a/auth2.c b/auth2.c
index 3c8a67bbc595..84d0ed16e7e2 100644
--- a/auth2.c
+++ b/auth2.c
@@ -1,815 +1,815 @@
-/* $OpenBSD: auth2.c,v 1.160 2021/01/27 10:05:28 djm Exp $ */
+/* $OpenBSD: auth2.c,v 1.161 2021/04/03 06:18:40 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <limits.h>
#include <pwd.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include "stdlib.h"
#include "atomicio.h"
#include "xmalloc.h"
#include "ssh2.h"
#include "packet.h"
#include "log.h"
#include "sshbuf.h"
#include "misc.h"
#include "servconf.h"
#include "compat.h"
#include "sshkey.h"
#include "hostfile.h"
#include "auth.h"
#include "dispatch.h"
#include "pathnames.h"
#include "ssherr.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
#include "monitor_wrap.h"
#include "digest.h"
/* import */
extern ServerOptions options;
extern struct sshbuf *loginmsg;
/* methods */
extern Authmethod method_none;
extern Authmethod method_pubkey;
extern Authmethod method_passwd;
extern Authmethod method_kbdint;
extern Authmethod method_hostbased;
#ifdef GSSAPI
extern Authmethod method_gssapi;
#endif
Authmethod *authmethods[] = {
&method_none,
&method_pubkey,
#ifdef GSSAPI
&method_gssapi,
#endif
&method_passwd,
&method_kbdint,
&method_hostbased,
NULL
};
/* protocol */
static int input_service_request(int, u_int32_t, struct ssh *);
static int input_userauth_request(int, u_int32_t, struct ssh *);
/* helper */
static Authmethod *authmethod_lookup(Authctxt *, const char *);
static char *authmethods_get(Authctxt *authctxt);
#define MATCH_NONE 0 /* method or submethod mismatch */
#define MATCH_METHOD 1 /* method matches (no submethod specified) */
#define MATCH_BOTH 2 /* method and submethod match */
#define MATCH_PARTIAL 3 /* method matches, submethod can't be checked */
static int list_starts_with(const char *, const char *, const char *);
char *
auth2_read_banner(void)
{
struct stat st;
char *banner = NULL;
size_t len, n;
int fd;
if ((fd = open(options.banner, O_RDONLY)) == -1)
return (NULL);
if (fstat(fd, &st) == -1) {
close(fd);
return (NULL);
}
if (st.st_size <= 0 || st.st_size > 1*1024*1024) {
close(fd);
return (NULL);
}
len = (size_t)st.st_size; /* truncate */
banner = xmalloc(len + 1);
n = atomicio(read, fd, banner, len);
close(fd);
if (n != len) {
free(banner);
return (NULL);
}
banner[n] = '\0';
return (banner);
}
static void
userauth_send_banner(struct ssh *ssh, const char *msg)
{
int r;
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_BANNER)) != 0 ||
(r = sshpkt_put_cstring(ssh, msg)) != 0 ||
(r = sshpkt_put_cstring(ssh, "")) != 0 || /* language, unused */
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send packet");
debug("%s: sent", __func__);
}
static void
userauth_banner(struct ssh *ssh)
{
char *banner = NULL;
if (options.banner == NULL)
return;
if ((banner = PRIVSEP(auth2_read_banner())) == NULL)
goto done;
userauth_send_banner(ssh, banner);
done:
free(banner);
}
/*
* loop until authctxt->success == TRUE
*/
void
do_authentication2(struct ssh *ssh)
{
Authctxt *authctxt = ssh->authctxt;
ssh_dispatch_init(ssh, &dispatch_protocol_error);
ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_REQUEST, &input_service_request);
ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt->success);
ssh->authctxt = NULL;
}
/*ARGSUSED*/
static int
input_service_request(int type, u_int32_t seq, struct ssh *ssh)
{
Authctxt *authctxt = ssh->authctxt;
char *service = NULL;
int r, acceptit = 0;
if ((r = sshpkt_get_cstring(ssh, &service, NULL)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto out;
if (authctxt == NULL)
fatal("input_service_request: no authctxt");
if (strcmp(service, "ssh-userauth") == 0) {
if (!authctxt->success) {
acceptit = 1;
/* now we can handle user-auth requests */
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST,
&input_userauth_request);
}
}
/* XXX all other service requests are denied */
if (acceptit) {
if ((r = sshpkt_start(ssh, SSH2_MSG_SERVICE_ACCEPT)) != 0 ||
(r = sshpkt_put_cstring(ssh, service)) != 0 ||
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
goto out;
} else {
debug("bad service request %s", service);
ssh_packet_disconnect(ssh, "bad service request %s", service);
}
r = 0;
out:
free(service);
return r;
}
#define MIN_FAIL_DELAY_SECONDS 0.005
static double
user_specific_delay(const char *user)
{
char b[512];
size_t len = ssh_digest_bytes(SSH_DIGEST_SHA512);
u_char *hash = xmalloc(len);
double delay;
(void)snprintf(b, sizeof b, "%llu%s",
- (unsigned long long)options.timing_secret, user);
+ (unsigned long long)options.timing_secret, user);
if (ssh_digest_memory(SSH_DIGEST_SHA512, b, strlen(b), hash, len) != 0)
fatal_f("ssh_digest_memory");
/* 0-4.2 ms of delay */
delay = (double)PEEK_U32(hash) / 1000 / 1000 / 1000 / 1000;
freezero(hash, len);
debug3_f("user specific delay %0.3lfms", delay/1000);
return MIN_FAIL_DELAY_SECONDS + delay;
}
static void
ensure_minimum_time_since(double start, double seconds)
{
struct timespec ts;
double elapsed = monotime_double() - start, req = seconds, remain;
/* if we've already passed the requested time, scale up */
while ((remain = seconds - elapsed) < 0.0)
seconds *= 2;
ts.tv_sec = remain;
ts.tv_nsec = (remain - ts.tv_sec) * 1000000000;
debug3_f("elapsed %0.3lfms, delaying %0.3lfms (requested %0.3lfms)",
elapsed*1000, remain*1000, req*1000);
nanosleep(&ts, NULL);
}
/*ARGSUSED*/
static int
input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
{
Authctxt *authctxt = ssh->authctxt;
Authmethod *m = NULL;
char *user = NULL, *service = NULL, *method = NULL, *style = NULL;
int r, authenticated = 0;
double tstart = monotime_double();
if (authctxt == NULL)
fatal("input_userauth_request: no authctxt");
if ((r = sshpkt_get_cstring(ssh, &user, NULL)) != 0 ||
(r = sshpkt_get_cstring(ssh, &service, NULL)) != 0 ||
(r = sshpkt_get_cstring(ssh, &method, NULL)) != 0)
goto out;
debug("userauth-request for user %s service %s method %s", user, service, method);
debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
if ((style = strchr(user, ':')) != NULL)
*style++ = 0;
if (authctxt->attempt++ == 0) {
/* setup auth context */
authctxt->pw = PRIVSEP(getpwnamallow(ssh, user));
authctxt->user = xstrdup(user);
if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
authctxt->valid = 1;
debug2_f("setting up authctxt for %s", user);
} else {
/* Invalid user, fake password information */
authctxt->pw = fakepw();
#ifdef SSH_AUDIT_EVENTS
PRIVSEP(audit_event(ssh, SSH_INVALID_USER));
#endif
}
#ifdef USE_PAM
if (options.use_pam)
PRIVSEP(start_pam(ssh));
#endif
ssh_packet_set_log_preamble(ssh, "%suser %s",
authctxt->valid ? "authenticating " : "invalid ", user);
setproctitle("%s%s", authctxt->valid ? user : "unknown",
use_privsep ? " [net]" : "");
authctxt->service = xstrdup(service);
authctxt->style = style ? xstrdup(style) : NULL;
if (use_privsep)
mm_inform_authserv(service, style);
userauth_banner(ssh);
if (auth2_setup_methods_lists(authctxt) != 0)
ssh_packet_disconnect(ssh,
"no authentication methods enabled");
} else if (strcmp(user, authctxt->user) != 0 ||
strcmp(service, authctxt->service) != 0) {
ssh_packet_disconnect(ssh, "Change of username or service "
"not allowed: (%s,%s) -> (%s,%s)",
authctxt->user, authctxt->service, user, service);
}
/* reset state */
auth2_challenge_stop(ssh);
#ifdef GSSAPI
/* XXX move to auth2_gssapi_stop() */
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
#endif
auth2_authctxt_reset_info(authctxt);
authctxt->postponed = 0;
authctxt->server_caused_failure = 0;
/* try to authenticate user */
m = authmethod_lookup(authctxt, method);
if (m != NULL && authctxt->failures < options.max_authtries) {
debug2("input_userauth_request: try method %s", method);
authenticated = m->userauth(ssh);
}
if (!authctxt->authenticated)
ensure_minimum_time_since(tstart,
user_specific_delay(authctxt->user));
userauth_finish(ssh, authenticated, method, NULL);
r = 0;
out:
free(service);
free(user);
free(method);
return r;
}
void
userauth_finish(struct ssh *ssh, int authenticated, const char *method,
const char *submethod)
{
Authctxt *authctxt = ssh->authctxt;
char *methods;
int r, partial = 0;
if (!authctxt->valid && authenticated)
fatal("INTERNAL ERROR: authenticated invalid user %s",
authctxt->user);
if (authenticated && authctxt->postponed)
fatal("INTERNAL ERROR: authenticated and postponed");
/* Special handling for root */
if (authenticated && authctxt->pw->pw_uid == 0 &&
!auth_root_allowed(ssh, method)) {
authenticated = 0;
#ifdef SSH_AUDIT_EVENTS
PRIVSEP(audit_event(ssh, SSH_LOGIN_ROOT_DENIED));
#endif
}
if (authenticated && options.num_auth_methods != 0) {
if (!auth2_update_methods_lists(authctxt, method, submethod)) {
authenticated = 0;
partial = 1;
}
}
/* Log before sending the reply */
auth_log(ssh, authenticated, partial, method, submethod);
/* Update information exposed to session */
if (authenticated || partial)
auth2_update_session_info(authctxt, method, submethod);
if (authctxt->postponed)
return;
#ifdef USE_PAM
if (options.use_pam && authenticated) {
int r, success = PRIVSEP(do_pam_account());
/* If PAM returned a message, send it to the user. */
if (sshbuf_len(loginmsg) > 0) {
if ((r = sshbuf_put(loginmsg, "\0", 1)) != 0)
fatal("%s: buffer error: %s",
__func__, ssh_err(r));
userauth_send_banner(ssh, sshbuf_ptr(loginmsg));
if ((r = ssh_packet_write_wait(ssh)) != 0) {
sshpkt_fatal(ssh, r,
"%s: send PAM banner", __func__);
}
}
if (!success) {
fatal("Access denied for user %s by PAM account "
"configuration", authctxt->user);
}
}
#endif
if (authenticated == 1) {
/* turn off userauth */
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST,
&dispatch_protocol_ignore);
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_SUCCESS)) != 0 ||
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
fatal_fr(r, "send success packet");
/* now we can break out */
authctxt->success = 1;
ssh_packet_set_log_preamble(ssh, "user %s", authctxt->user);
} else {
/* Allow initial try of "none" auth without failure penalty */
if (!partial && !authctxt->server_caused_failure &&
(authctxt->attempt > 1 || strcmp(method, "none") != 0))
authctxt->failures++;
if (authctxt->failures >= options.max_authtries) {
#ifdef SSH_AUDIT_EVENTS
PRIVSEP(audit_event(ssh, SSH_LOGIN_EXCEED_MAXTRIES));
#endif
auth_maxtries_exceeded(ssh);
}
methods = authmethods_get(authctxt);
debug3_f("failure partial=%d next methods=\"%s\"",
partial, methods);
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_FAILURE)) != 0 ||
(r = sshpkt_put_cstring(ssh, methods)) != 0 ||
(r = sshpkt_put_u8(ssh, partial)) != 0 ||
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
fatal_fr(r, "send failure packet");
free(methods);
}
}
/*
* Checks whether method is allowed by at least one AuthenticationMethods
* methods list. Returns 1 if allowed, or no methods lists configured.
* 0 otherwise.
*/
int
auth2_method_allowed(Authctxt *authctxt, const char *method,
const char *submethod)
{
u_int i;
/*
* NB. authctxt->num_auth_methods might be zero as a result of
* auth2_setup_methods_lists(), so check the configuration.
*/
if (options.num_auth_methods == 0)
return 1;
for (i = 0; i < authctxt->num_auth_methods; i++) {
if (list_starts_with(authctxt->auth_methods[i], method,
submethod) != MATCH_NONE)
return 1;
}
return 0;
}
static char *
authmethods_get(Authctxt *authctxt)
{
struct sshbuf *b;
char *list;
int i, r;
if ((b = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
for (i = 0; authmethods[i] != NULL; i++) {
if (strcmp(authmethods[i]->name, "none") == 0)
continue;
if (authmethods[i]->enabled == NULL ||
*(authmethods[i]->enabled) == 0)
continue;
if (!auth2_method_allowed(authctxt, authmethods[i]->name,
NULL))
continue;
if ((r = sshbuf_putf(b, "%s%s", sshbuf_len(b) ? "," : "",
authmethods[i]->name)) != 0)
fatal_fr(r, "buffer error");
}
if ((list = sshbuf_dup_string(b)) == NULL)
fatal_f("sshbuf_dup_string failed");
sshbuf_free(b);
return list;
}
static Authmethod *
authmethod_lookup(Authctxt *authctxt, const char *name)
{
int i;
if (name != NULL)
for (i = 0; authmethods[i] != NULL; i++)
if (authmethods[i]->enabled != NULL &&
*(authmethods[i]->enabled) != 0 &&
strcmp(name, authmethods[i]->name) == 0 &&
auth2_method_allowed(authctxt,
authmethods[i]->name, NULL))
return authmethods[i];
debug2("Unrecognized authentication method name: %s",
name ? name : "NULL");
return NULL;
}
/*
* Check a comma-separated list of methods for validity. Is need_enable is
* non-zero, then also require that the methods are enabled.
* Returns 0 on success or -1 if the methods list is invalid.
*/
int
auth2_methods_valid(const char *_methods, int need_enable)
{
char *methods, *omethods, *method, *p;
u_int i, found;
int ret = -1;
if (*_methods == '\0') {
error("empty authentication method list");
return -1;
}
omethods = methods = xstrdup(_methods);
while ((method = strsep(&methods, ",")) != NULL) {
for (found = i = 0; !found && authmethods[i] != NULL; i++) {
if ((p = strchr(method, ':')) != NULL)
*p = '\0';
if (strcmp(method, authmethods[i]->name) != 0)
continue;
if (need_enable) {
if (authmethods[i]->enabled == NULL ||
*(authmethods[i]->enabled) == 0) {
error("Disabled method \"%s\" in "
"AuthenticationMethods list \"%s\"",
method, _methods);
goto out;
}
}
found = 1;
break;
}
if (!found) {
error("Unknown authentication method \"%s\" in list",
method);
goto out;
}
}
ret = 0;
out:
free(omethods);
return ret;
}
/*
* Prune the AuthenticationMethods supplied in the configuration, removing
* any methods lists that include disabled methods. Note that this might
* leave authctxt->num_auth_methods == 0, even when multiple required auth
* has been requested. For this reason, all tests for whether multiple is
* enabled should consult options.num_auth_methods directly.
*/
int
auth2_setup_methods_lists(Authctxt *authctxt)
{
u_int i;
/* First, normalise away the "any" pseudo-method */
if (options.num_auth_methods == 1 &&
strcmp(options.auth_methods[0], "any") == 0) {
free(options.auth_methods[0]);
options.auth_methods[0] = NULL;
options.num_auth_methods = 0;
}
if (options.num_auth_methods == 0)
return 0;
debug3_f("checking methods");
authctxt->auth_methods = xcalloc(options.num_auth_methods,
sizeof(*authctxt->auth_methods));
authctxt->num_auth_methods = 0;
for (i = 0; i < options.num_auth_methods; i++) {
if (auth2_methods_valid(options.auth_methods[i], 1) != 0) {
logit("Authentication methods list \"%s\" contains "
"disabled method, skipping",
options.auth_methods[i]);
continue;
}
debug("authentication methods list %d: %s",
authctxt->num_auth_methods, options.auth_methods[i]);
authctxt->auth_methods[authctxt->num_auth_methods++] =
xstrdup(options.auth_methods[i]);
}
if (authctxt->num_auth_methods == 0) {
error("No AuthenticationMethods left after eliminating "
"disabled methods");
return -1;
}
return 0;
}
static int
list_starts_with(const char *methods, const char *method,
const char *submethod)
{
size_t l = strlen(method);
int match;
const char *p;
if (strncmp(methods, method, l) != 0)
return MATCH_NONE;
p = methods + l;
match = MATCH_METHOD;
if (*p == ':') {
if (!submethod)
return MATCH_PARTIAL;
l = strlen(submethod);
p += 1;
if (strncmp(submethod, p, l))
return MATCH_NONE;
p += l;
match = MATCH_BOTH;
}
if (*p != ',' && *p != '\0')
return MATCH_NONE;
return match;
}
/*
* Remove method from the start of a comma-separated list of methods.
* Returns 0 if the list of methods did not start with that method or 1
* if it did.
*/
static int
remove_method(char **methods, const char *method, const char *submethod)
{
char *omethods = *methods, *p;
size_t l = strlen(method);
int match;
match = list_starts_with(omethods, method, submethod);
if (match != MATCH_METHOD && match != MATCH_BOTH)
return 0;
p = omethods + l;
if (submethod && match == MATCH_BOTH)
p += 1 + strlen(submethod); /* include colon */
if (*p == ',')
p++;
*methods = xstrdup(p);
free(omethods);
return 1;
}
/*
* Called after successful authentication. Will remove the successful method
* from the start of each list in which it occurs. If it was the last method
* in any list, then authentication is deemed successful.
* Returns 1 if the method completed any authentication list or 0 otherwise.
*/
int
auth2_update_methods_lists(Authctxt *authctxt, const char *method,
const char *submethod)
{
u_int i, found = 0;
debug3_f("updating methods list after \"%s\"", method);
for (i = 0; i < authctxt->num_auth_methods; i++) {
if (!remove_method(&(authctxt->auth_methods[i]), method,
submethod))
continue;
found = 1;
if (*authctxt->auth_methods[i] == '\0') {
debug2("authentication methods list %d complete", i);
return 1;
}
debug3("authentication methods list %d remaining: \"%s\"",
i, authctxt->auth_methods[i]);
}
/* This should not happen, but would be bad if it did */
if (!found)
fatal_f("method not in AuthenticationMethods");
return 0;
}
/* Reset method-specific information */
void auth2_authctxt_reset_info(Authctxt *authctxt)
{
sshkey_free(authctxt->auth_method_key);
free(authctxt->auth_method_info);
authctxt->auth_method_key = NULL;
authctxt->auth_method_info = NULL;
}
/* Record auth method-specific information for logs */
void
auth2_record_info(Authctxt *authctxt, const char *fmt, ...)
{
va_list ap;
- int i;
+ int i;
free(authctxt->auth_method_info);
authctxt->auth_method_info = NULL;
va_start(ap, fmt);
i = vasprintf(&authctxt->auth_method_info, fmt, ap);
va_end(ap);
if (i == -1)
fatal_f("vasprintf failed");
}
/*
* Records a public key used in authentication. This is used for logging
* and to ensure that the same key is not subsequently accepted again for
* multiple authentication.
*/
void
auth2_record_key(Authctxt *authctxt, int authenticated,
const struct sshkey *key)
{
struct sshkey **tmp, *dup;
int r;
if ((r = sshkey_from_private(key, &dup)) != 0)
fatal_fr(r, "copy key");
sshkey_free(authctxt->auth_method_key);
authctxt->auth_method_key = dup;
if (!authenticated)
return;
/* If authenticated, make sure we don't accept this key again */
if ((r = sshkey_from_private(key, &dup)) != 0)
fatal_fr(r, "copy key");
if (authctxt->nprev_keys >= INT_MAX ||
(tmp = recallocarray(authctxt->prev_keys, authctxt->nprev_keys,
authctxt->nprev_keys + 1, sizeof(*authctxt->prev_keys))) == NULL)
fatal_f("reallocarray failed");
authctxt->prev_keys = tmp;
authctxt->prev_keys[authctxt->nprev_keys] = dup;
authctxt->nprev_keys++;
}
/* Checks whether a key has already been previously used for authentication */
int
auth2_key_already_used(Authctxt *authctxt, const struct sshkey *key)
{
u_int i;
char *fp;
for (i = 0; i < authctxt->nprev_keys; i++) {
if (sshkey_equal_public(key, authctxt->prev_keys[i])) {
fp = sshkey_fingerprint(authctxt->prev_keys[i],
options.fingerprint_hash, SSH_FP_DEFAULT);
debug3_f("key already used: %s %s",
sshkey_type(authctxt->prev_keys[i]),
fp == NULL ? "UNKNOWN" : fp);
free(fp);
return 1;
}
}
return 0;
}
/*
* Updates authctxt->session_info with details of authentication. Should be
* whenever an authentication method succeeds.
*/
void
auth2_update_session_info(Authctxt *authctxt, const char *method,
const char *submethod)
{
int r;
if (authctxt->session_info == NULL) {
if ((authctxt->session_info = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
}
/* Append method[/submethod] */
if ((r = sshbuf_putf(authctxt->session_info, "%s%s%s",
method, submethod == NULL ? "" : "/",
submethod == NULL ? "" : submethod)) != 0)
fatal_fr(r, "append method");
/* Append key if present */
if (authctxt->auth_method_key != NULL) {
if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 ||
(r = sshkey_format_text(authctxt->auth_method_key,
authctxt->session_info)) != 0)
fatal_fr(r, "append key");
}
if (authctxt->auth_method_info != NULL) {
/* Ensure no ambiguity here */
if (strchr(authctxt->auth_method_info, '\n') != NULL)
fatal_f("auth_method_info contains \\n");
if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 ||
(r = sshbuf_putf(authctxt->session_info, "%s",
authctxt->auth_method_info)) != 0) {
fatal_fr(r, "append method info");
}
}
if ((r = sshbuf_put_u8(authctxt->session_info, '\n')) != 0)
fatal_fr(r, "append");
}
diff --git a/chacha.h b/chacha.h
index 762052565d5c..19a61e294230 100644
--- a/chacha.h
+++ b/chacha.h
@@ -1,36 +1,36 @@
-/* $OpenBSD: chacha.h,v 1.4 2016/08/27 04:04:56 guenther Exp $ */
+/* $OpenBSD: chacha.h,v 1.5 2021/04/03 05:54:14 djm Exp $ */
/*
chacha-merged.c version 20080118
D. J. Bernstein
Public domain.
*/
#ifndef CHACHA_H
#define CHACHA_H
#include <sys/types.h>
#include <stdlib.h>
struct chacha_ctx {
u_int input[16];
};
-#define CHACHA_MINKEYLEN 16
+#define CHACHA_MINKEYLEN 16
#define CHACHA_NONCELEN 8
#define CHACHA_CTRLEN 8
#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN)
#define CHACHA_BLOCKLEN 64
void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits)
__attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN)));
void chacha_ivsetup(struct chacha_ctx *x, const u_char *iv, const u_char *ctr)
__attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN)))
__attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN)));
void chacha_encrypt_bytes(struct chacha_ctx *x, const u_char *m,
u_char *c, u_int bytes)
__attribute__((__bounded__(__buffer__, 2, 4)))
__attribute__((__bounded__(__buffer__, 3, 4)));
#endif /* CHACHA_H */
diff --git a/channels.c b/channels.c
index b60d56c48bb8..32d1f617860e 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4865 +1,4865 @@
-/* $OpenBSD: channels.c,v 1.405 2021/02/15 20:43:15 markus Exp $ */
+/* $OpenBSD: channels.c,v 1.406 2021/04/03 06:18:40 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* This file contains functions for generic socket connection forwarding.
* There is also code for initiating connection forwarding for X11 connections,
* arbitrary tcp/ip connections, and the authentication agent connection.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
* SSH2 support added by Markus Friedl.
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
* Copyright (c) 1999 Dug Song. All rights reserved.
* Copyright (c) 1999 Theo de Raadt. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/un.h>
#include <sys/socket.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <netdb.h>
#include <stdarg.h>
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "ssh.h"
#include "ssh2.h"
#include "ssherr.h"
#include "sshbuf.h"
#include "packet.h"
#include "log.h"
#include "misc.h"
#include "channels.h"
#include "compat.h"
#include "canohost.h"
#include "sshkey.h"
#include "authfd.h"
#include "pathnames.h"
#include "match.h"
/* -- agent forwarding */
#define NUM_SOCKS 10
/* -- tcp forwarding */
/* special-case port number meaning allow any port */
#define FWD_PERMIT_ANY_PORT 0
/* special-case wildcard meaning allow any host */
#define FWD_PERMIT_ANY_HOST "*"
/* -- X11 forwarding */
/* Maximum number of fake X11 displays to try. */
#define MAX_DISPLAYS 1000
/* Per-channel callback for pre/post select() actions */
typedef void chan_fn(struct ssh *, Channel *c,
fd_set *readset, fd_set *writeset);
/*
* Data structure for storing which hosts are permitted for forward requests.
* The local sides of any remote forwards are stored in this array to prevent
* a corrupt remote server from accessing arbitrary TCP/IP ports on our local
* network (which might be behind a firewall).
*/
/* XXX: streamlocal wants a path instead of host:port */
/* Overload host_to_connect; we could just make this match Forward */
/* XXX - can we use listen_host instead of listen_path? */
struct permission {
char *host_to_connect; /* Connect to 'host'. */
int port_to_connect; /* Connect to 'port'. */
char *listen_host; /* Remote side should listen address. */
char *listen_path; /* Remote side should listen path. */
int listen_port; /* Remote side should listen port. */
Channel *downstream; /* Downstream mux*/
};
/*
* Stores the forwarding permission state for a single direction (local or
* remote).
*/
struct permission_set {
/*
* List of all local permitted host/port pairs to allow for the
* user.
*/
u_int num_permitted_user;
struct permission *permitted_user;
/*
* List of all permitted host/port pairs to allow for the admin.
*/
u_int num_permitted_admin;
struct permission *permitted_admin;
/*
* If this is true, all opens/listens are permitted. This is the
* case on the server on which we have to trust the client anyway,
* and the user could do anything after logging in.
*/
int all_permitted;
};
/* Master structure for channels state */
struct ssh_channels {
/*
* Pointer to an array containing all allocated channels. The array
* is dynamically extended as needed.
*/
Channel **channels;
/*
* Size of the channel array. All slots of the array must always be
* initialized (at least the type field); unused slots set to NULL
*/
u_int channels_alloc;
/*
* Maximum file descriptor value used in any of the channels. This is
* updated in channel_new.
*/
int channel_max_fd;
/*
* 'channel_pre*' are called just before select() to add any bits
* relevant to channels in the select bitmasks.
*
* 'channel_post*': perform any appropriate operations for
* channels which have events pending.
*/
chan_fn **channel_pre;
chan_fn **channel_post;
/* -- tcp forwarding */
struct permission_set local_perms;
struct permission_set remote_perms;
/* -- X11 forwarding */
/* Saved X11 local (client) display. */
char *x11_saved_display;
/* Saved X11 authentication protocol name. */
char *x11_saved_proto;
/* Saved X11 authentication data. This is the real data. */
char *x11_saved_data;
u_int x11_saved_data_len;
/* Deadline after which all X11 connections are refused */
u_int x11_refuse_time;
/*
* Fake X11 authentication data. This is what the server will be
* sending us; we should replace any occurrences of this by the
* real data.
*/
u_char *x11_fake_data;
u_int x11_fake_data_len;
/* AF_UNSPEC or AF_INET or AF_INET6 */
int IPv4or6;
};
/* helper */
static void port_open_helper(struct ssh *ssh, Channel *c, char *rtype);
static const char *channel_rfwd_bind_host(const char *listen_host);
/* non-blocking connect helpers */
static int connect_next(struct channel_connect *);
static void channel_connect_ctx_free(struct channel_connect *);
static Channel *rdynamic_connect_prepare(struct ssh *, char *, char *);
static int rdynamic_connect_finish(struct ssh *, Channel *);
/* Setup helper */
static void channel_handler_init(struct ssh_channels *sc);
/* -- channel core */
void
channel_init_channels(struct ssh *ssh)
{
struct ssh_channels *sc;
if ((sc = calloc(1, sizeof(*sc))) == NULL)
fatal_f("allocation failed");
sc->channels_alloc = 10;
sc->channels = xcalloc(sc->channels_alloc, sizeof(*sc->channels));
sc->IPv4or6 = AF_UNSPEC;
channel_handler_init(sc);
ssh->chanctxt = sc;
}
Channel *
channel_by_id(struct ssh *ssh, int id)
{
Channel *c;
if (id < 0 || (u_int)id >= ssh->chanctxt->channels_alloc) {
logit_f("%d: bad id", id);
return NULL;
}
c = ssh->chanctxt->channels[id];
if (c == NULL) {
logit_f("%d: bad id: channel free", id);
return NULL;
}
return c;
}
Channel *
channel_by_remote_id(struct ssh *ssh, u_int remote_id)
{
Channel *c;
u_int i;
for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
c = ssh->chanctxt->channels[i];
if (c != NULL && c->have_remote_id && c->remote_id == remote_id)
return c;
}
return NULL;
}
/*
* Returns the channel if it is allowed to receive protocol messages.
* Private channels, like listening sockets, may not receive messages.
*/
Channel *
channel_lookup(struct ssh *ssh, int id)
{
Channel *c;
if ((c = channel_by_id(ssh, id)) == NULL)
return NULL;
switch (c->type) {
case SSH_CHANNEL_X11_OPEN:
case SSH_CHANNEL_LARVAL:
case SSH_CHANNEL_CONNECTING:
case SSH_CHANNEL_DYNAMIC:
case SSH_CHANNEL_RDYNAMIC_OPEN:
case SSH_CHANNEL_RDYNAMIC_FINISH:
case SSH_CHANNEL_OPENING:
case SSH_CHANNEL_OPEN:
case SSH_CHANNEL_ABANDONED:
case SSH_CHANNEL_MUX_PROXY:
return c;
}
logit("Non-public channel %d, type %d.", id, c->type);
return NULL;
}
/*
* Register filedescriptors for a channel, used when allocating a channel or
* when the channel consumer/producer is ready, e.g. shell exec'd
*/
static void
channel_register_fds(struct ssh *ssh, Channel *c, int rfd, int wfd, int efd,
int extusage, int nonblock, int is_tty)
{
struct ssh_channels *sc = ssh->chanctxt;
/* Update the maximum file descriptor value. */
sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, rfd);
sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, wfd);
sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, efd);
if (rfd != -1)
fcntl(rfd, F_SETFD, FD_CLOEXEC);
if (wfd != -1 && wfd != rfd)
fcntl(wfd, F_SETFD, FD_CLOEXEC);
if (efd != -1 && efd != rfd && efd != wfd)
fcntl(efd, F_SETFD, FD_CLOEXEC);
c->rfd = rfd;
c->wfd = wfd;
c->sock = (rfd == wfd) ? rfd : -1;
c->efd = efd;
c->extended_usage = extusage;
if ((c->isatty = is_tty) != 0)
debug2("channel %d: rfd %d isatty", c->self, c->rfd);
#ifdef _AIX
/* XXX: Later AIX versions can't push as much data to tty */
c->wfd_isatty = is_tty || isatty(c->wfd);
#endif
/* enable nonblocking mode */
if (nonblock) {
if (rfd != -1)
set_nonblock(rfd);
if (wfd != -1)
set_nonblock(wfd);
if (efd != -1)
set_nonblock(efd);
}
}
/*
* Allocate a new channel object and set its type and socket. This will cause
* remote_name to be freed.
*/
Channel *
channel_new(struct ssh *ssh, char *ctype, int type, int rfd, int wfd, int efd,
u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock)
{
struct ssh_channels *sc = ssh->chanctxt;
u_int i, found;
Channel *c;
int r;
/* Try to find a free slot where to put the new channel. */
for (i = 0; i < sc->channels_alloc; i++) {
if (sc->channels[i] == NULL) {
/* Found a free slot. */
found = i;
break;
}
}
if (i >= sc->channels_alloc) {
/*
* There are no free slots. Take last+1 slot and expand
* the array.
*/
found = sc->channels_alloc;
if (sc->channels_alloc > CHANNELS_MAX_CHANNELS)
fatal_f("internal error: channels_alloc %d too big",
sc->channels_alloc);
sc->channels = xrecallocarray(sc->channels, sc->channels_alloc,
sc->channels_alloc + 10, sizeof(*sc->channels));
sc->channels_alloc += 10;
debug2("channel: expanding %d", sc->channels_alloc);
}
/* Initialize and return new channel. */
c = sc->channels[found] = xcalloc(1, sizeof(Channel));
if ((c->input = sshbuf_new()) == NULL ||
(c->output = sshbuf_new()) == NULL ||
(c->extended = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_set_max_size(c->input, CHAN_INPUT_MAX)) != 0)
fatal_fr(r, "sshbuf_set_max_size");
c->ostate = CHAN_OUTPUT_OPEN;
c->istate = CHAN_INPUT_OPEN;
channel_register_fds(ssh, c, rfd, wfd, efd, extusage, nonblock, 0);
c->self = found;
c->type = type;
c->ctype = ctype;
c->local_window = window;
c->local_window_max = window;
c->local_maxpacket = maxpack;
c->remote_name = xstrdup(remote_name);
c->ctl_chan = -1;
c->delayed = 1; /* prevent call to channel_post handler */
TAILQ_INIT(&c->status_confirms);
debug("channel %d: new [%s]", found, remote_name);
return c;
}
static void
channel_find_maxfd(struct ssh_channels *sc)
{
u_int i;
int max = 0;
Channel *c;
for (i = 0; i < sc->channels_alloc; i++) {
c = sc->channels[i];
if (c != NULL) {
max = MAXIMUM(max, c->rfd);
max = MAXIMUM(max, c->wfd);
max = MAXIMUM(max, c->efd);
}
}
sc->channel_max_fd = max;
}
int
channel_close_fd(struct ssh *ssh, int *fdp)
{
struct ssh_channels *sc = ssh->chanctxt;
int ret = 0, fd = *fdp;
if (fd != -1) {
ret = close(fd);
*fdp = -1;
if (fd == sc->channel_max_fd)
channel_find_maxfd(sc);
}
return ret;
}
/* Close all channel fd/socket. */
static void
channel_close_fds(struct ssh *ssh, Channel *c)
{
int sock = c->sock, rfd = c->rfd, wfd = c->wfd, efd = c->efd;
channel_close_fd(ssh, &c->sock);
if (rfd != sock)
channel_close_fd(ssh, &c->rfd);
if (wfd != sock && wfd != rfd)
channel_close_fd(ssh, &c->wfd);
if (efd != sock && efd != rfd && efd != wfd)
channel_close_fd(ssh, &c->efd);
}
static void
fwd_perm_clear(struct permission *perm)
{
free(perm->host_to_connect);
free(perm->listen_host);
free(perm->listen_path);
memset(perm, 0, sizeof(*perm));
}
/* Returns an printable name for the specified forwarding permission list */
static const char *
fwd_ident(int who, int where)
{
if (who == FORWARD_ADM) {
if (where == FORWARD_LOCAL)
return "admin local";
else if (where == FORWARD_REMOTE)
return "admin remote";
} else if (who == FORWARD_USER) {
if (where == FORWARD_LOCAL)
return "user local";
else if (where == FORWARD_REMOTE)
return "user remote";
}
fatal("Unknown forward permission list %d/%d", who, where);
}
/* Returns the forwarding permission list for the specified direction */
static struct permission_set *
permission_set_get(struct ssh *ssh, int where)
{
struct ssh_channels *sc = ssh->chanctxt;
switch (where) {
case FORWARD_LOCAL:
return &sc->local_perms;
break;
case FORWARD_REMOTE:
return &sc->remote_perms;
break;
default:
fatal_f("invalid forwarding direction %d", where);
}
}
/* Returns pointers to the specified forwarding list and its element count */
static void
permission_set_get_array(struct ssh *ssh, int who, int where,
struct permission ***permpp, u_int **npermpp)
{
struct permission_set *pset = permission_set_get(ssh, where);
switch (who) {
case FORWARD_USER:
*permpp = &pset->permitted_user;
*npermpp = &pset->num_permitted_user;
break;
case FORWARD_ADM:
*permpp = &pset->permitted_admin;
*npermpp = &pset->num_permitted_admin;
break;
default:
fatal_f("invalid forwarding client %d", who);
}
}
/* Adds an entry to the spcified forwarding list */
static int
permission_set_add(struct ssh *ssh, int who, int where,
const char *host_to_connect, int port_to_connect,
const char *listen_host, const char *listen_path, int listen_port,
Channel *downstream)
{
struct permission **permp;
u_int n, *npermp;
permission_set_get_array(ssh, who, where, &permp, &npermp);
if (*npermp >= INT_MAX)
fatal_f("%s overflow", fwd_ident(who, where));
*permp = xrecallocarray(*permp, *npermp, *npermp + 1, sizeof(**permp));
n = (*npermp)++;
#define MAYBE_DUP(s) ((s == NULL) ? NULL : xstrdup(s))
(*permp)[n].host_to_connect = MAYBE_DUP(host_to_connect);
(*permp)[n].port_to_connect = port_to_connect;
(*permp)[n].listen_host = MAYBE_DUP(listen_host);
(*permp)[n].listen_path = MAYBE_DUP(listen_path);
(*permp)[n].listen_port = listen_port;
(*permp)[n].downstream = downstream;
#undef MAYBE_DUP
return (int)n;
}
static void
mux_remove_remote_forwardings(struct ssh *ssh, Channel *c)
{
struct ssh_channels *sc = ssh->chanctxt;
struct permission_set *pset = &sc->local_perms;
struct permission *perm;
int r;
u_int i;
for (i = 0; i < pset->num_permitted_user; i++) {
perm = &pset->permitted_user[i];
if (perm->downstream != c)
continue;
/* cancel on the server, since mux client is gone */
debug("channel %d: cleanup remote forward for %s:%u",
c->self, perm->listen_host, perm->listen_port);
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh,
"cancel-tcpip-forward")) != 0 ||
(r = sshpkt_put_u8(ssh, 0)) != 0 ||
(r = sshpkt_put_cstring(ssh,
channel_rfwd_bind_host(perm->listen_host))) != 0 ||
(r = sshpkt_put_u32(ssh, perm->listen_port)) != 0 ||
(r = sshpkt_send(ssh)) != 0) {
fatal_fr(r, "channel %i", c->self);
}
fwd_perm_clear(perm); /* unregister */
}
}
/* Free the channel and close its fd/socket. */
void
channel_free(struct ssh *ssh, Channel *c)
{
struct ssh_channels *sc = ssh->chanctxt;
char *s;
u_int i, n;
Channel *other;
struct channel_confirm *cc;
for (n = 0, i = 0; i < sc->channels_alloc; i++) {
if ((other = sc->channels[i]) == NULL)
continue;
n++;
/* detach from mux client and prepare for closing */
if (c->type == SSH_CHANNEL_MUX_CLIENT &&
other->type == SSH_CHANNEL_MUX_PROXY &&
other->mux_ctx == c) {
other->mux_ctx = NULL;
other->type = SSH_CHANNEL_OPEN;
other->istate = CHAN_INPUT_CLOSED;
other->ostate = CHAN_OUTPUT_CLOSED;
}
}
debug("channel %d: free: %s, nchannels %u", c->self,
c->remote_name ? c->remote_name : "???", n);
if (c->type == SSH_CHANNEL_MUX_CLIENT)
mux_remove_remote_forwardings(ssh, c);
else if (c->type == SSH_CHANNEL_MUX_LISTENER) {
free(c->mux_ctx);
c->mux_ctx = NULL;
}
if (log_level_get() >= SYSLOG_LEVEL_DEBUG3) {
s = channel_open_message(ssh);
debug3("channel %d: status: %s", c->self, s);
free(s);
}
channel_close_fds(ssh, c);
sshbuf_free(c->input);
sshbuf_free(c->output);
sshbuf_free(c->extended);
c->input = c->output = c->extended = NULL;
free(c->remote_name);
c->remote_name = NULL;
free(c->path);
c->path = NULL;
free(c->listening_addr);
c->listening_addr = NULL;
while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) {
if (cc->abandon_cb != NULL)
cc->abandon_cb(ssh, c, cc->ctx);
TAILQ_REMOVE(&c->status_confirms, cc, entry);
freezero(cc, sizeof(*cc));
}
if (c->filter_cleanup != NULL && c->filter_ctx != NULL)
c->filter_cleanup(ssh, c->self, c->filter_ctx);
sc->channels[c->self] = NULL;
freezero(c, sizeof(*c));
}
void
channel_free_all(struct ssh *ssh)
{
u_int i;
struct ssh_channels *sc = ssh->chanctxt;
for (i = 0; i < sc->channels_alloc; i++)
if (sc->channels[i] != NULL)
channel_free(ssh, sc->channels[i]);
free(sc->channels);
sc->channels = NULL;
sc->channels_alloc = 0;
sc->channel_max_fd = 0;
free(sc->x11_saved_display);
sc->x11_saved_display = NULL;
free(sc->x11_saved_proto);
sc->x11_saved_proto = NULL;
free(sc->x11_saved_data);
sc->x11_saved_data = NULL;
sc->x11_saved_data_len = 0;
free(sc->x11_fake_data);
sc->x11_fake_data = NULL;
sc->x11_fake_data_len = 0;
}
/*
* Closes the sockets/fds of all channels. This is used to close extra file
* descriptors after a fork.
*/
void
channel_close_all(struct ssh *ssh)
{
u_int i;
for (i = 0; i < ssh->chanctxt->channels_alloc; i++)
if (ssh->chanctxt->channels[i] != NULL)
channel_close_fds(ssh, ssh->chanctxt->channels[i]);
}
/*
* Stop listening to channels.
*/
void
channel_stop_listening(struct ssh *ssh)
{
u_int i;
Channel *c;
for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
c = ssh->chanctxt->channels[i];
if (c != NULL) {
switch (c->type) {
case SSH_CHANNEL_AUTH_SOCKET:
case SSH_CHANNEL_PORT_LISTENER:
case SSH_CHANNEL_RPORT_LISTENER:
case SSH_CHANNEL_X11_LISTENER:
case SSH_CHANNEL_UNIX_LISTENER:
case SSH_CHANNEL_RUNIX_LISTENER:
channel_close_fd(ssh, &c->sock);
channel_free(ssh, c);
break;
}
}
}
}
/*
* Returns true if no channel has too much buffered data, and false if one or
* more channel is overfull.
*/
int
channel_not_very_much_buffered_data(struct ssh *ssh)
{
u_int i;
u_int maxsize = ssh_packet_get_maxsize(ssh);
Channel *c;
for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
c = ssh->chanctxt->channels[i];
if (c == NULL || c->type != SSH_CHANNEL_OPEN)
continue;
if (sshbuf_len(c->output) > maxsize) {
debug2("channel %d: big output buffer %zu > %u",
c->self, sshbuf_len(c->output), maxsize);
return 0;
}
}
return 1;
}
/* Returns true if any channel is still open. */
int
channel_still_open(struct ssh *ssh)
{
u_int i;
Channel *c;
for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
c = ssh->chanctxt->channels[i];
if (c == NULL)
continue;
switch (c->type) {
case SSH_CHANNEL_X11_LISTENER:
case SSH_CHANNEL_PORT_LISTENER:
case SSH_CHANNEL_RPORT_LISTENER:
case SSH_CHANNEL_MUX_LISTENER:
case SSH_CHANNEL_CLOSED:
case SSH_CHANNEL_AUTH_SOCKET:
case SSH_CHANNEL_DYNAMIC:
case SSH_CHANNEL_RDYNAMIC_OPEN:
case SSH_CHANNEL_CONNECTING:
case SSH_CHANNEL_ZOMBIE:
case SSH_CHANNEL_ABANDONED:
case SSH_CHANNEL_UNIX_LISTENER:
case SSH_CHANNEL_RUNIX_LISTENER:
continue;
case SSH_CHANNEL_LARVAL:
continue;
case SSH_CHANNEL_OPENING:
case SSH_CHANNEL_OPEN:
case SSH_CHANNEL_RDYNAMIC_FINISH:
case SSH_CHANNEL_X11_OPEN:
case SSH_CHANNEL_MUX_CLIENT:
case SSH_CHANNEL_MUX_PROXY:
return 1;
default:
fatal_f("bad channel type %d", c->type);
/* NOTREACHED */
}
}
return 0;
}
/* Returns the id of an open channel suitable for keepaliving */
int
channel_find_open(struct ssh *ssh)
{
u_int i;
Channel *c;
for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
c = ssh->chanctxt->channels[i];
if (c == NULL || !c->have_remote_id)
continue;
switch (c->type) {
case SSH_CHANNEL_CLOSED:
case SSH_CHANNEL_DYNAMIC:
case SSH_CHANNEL_RDYNAMIC_OPEN:
case SSH_CHANNEL_RDYNAMIC_FINISH:
case SSH_CHANNEL_X11_LISTENER:
case SSH_CHANNEL_PORT_LISTENER:
case SSH_CHANNEL_RPORT_LISTENER:
case SSH_CHANNEL_MUX_LISTENER:
case SSH_CHANNEL_MUX_CLIENT:
case SSH_CHANNEL_MUX_PROXY:
case SSH_CHANNEL_OPENING:
case SSH_CHANNEL_CONNECTING:
case SSH_CHANNEL_ZOMBIE:
case SSH_CHANNEL_ABANDONED:
case SSH_CHANNEL_UNIX_LISTENER:
case SSH_CHANNEL_RUNIX_LISTENER:
continue;
case SSH_CHANNEL_LARVAL:
case SSH_CHANNEL_AUTH_SOCKET:
case SSH_CHANNEL_OPEN:
case SSH_CHANNEL_X11_OPEN:
return i;
default:
fatal_f("bad channel type %d", c->type);
/* NOTREACHED */
}
}
return -1;
}
/* Returns the state of the channel's extended usage flag */
const char *
channel_format_extended_usage(const Channel *c)
{
if (c->efd == -1)
return "closed";
switch (c->extended_usage) {
case CHAN_EXTENDED_WRITE:
return "write";
case CHAN_EXTENDED_READ:
return "read";
case CHAN_EXTENDED_IGNORE:
return "ignore";
default:
return "UNKNOWN";
}
}
static char *
channel_format_status(const Channel *c)
{
char *ret = NULL;
xasprintf(&ret, "t%d %s%u i%u/%zu o%u/%zu e[%s]/%zu "
"fd %d/%d/%d sock %d cc %d",
c->type,
c->have_remote_id ? "r" : "nr", c->remote_id,
c->istate, sshbuf_len(c->input),
c->ostate, sshbuf_len(c->output),
channel_format_extended_usage(c), sshbuf_len(c->extended),
c->rfd, c->wfd, c->efd, c->sock, c->ctl_chan);
return ret;
}
/*
* Returns a message describing the currently open forwarded connections,
* suitable for sending to the client. The message contains crlf pairs for
* newlines.
*/
char *
channel_open_message(struct ssh *ssh)
{
struct sshbuf *buf;
Channel *c;
u_int i;
int r;
char *cp, *ret;
if ((buf = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_putf(buf,
"The following connections are open:\r\n")) != 0)
fatal_fr(r, "sshbuf_putf");
for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
c = ssh->chanctxt->channels[i];
if (c == NULL)
continue;
switch (c->type) {
case SSH_CHANNEL_X11_LISTENER:
case SSH_CHANNEL_PORT_LISTENER:
case SSH_CHANNEL_RPORT_LISTENER:
case SSH_CHANNEL_CLOSED:
case SSH_CHANNEL_AUTH_SOCKET:
case SSH_CHANNEL_ZOMBIE:
case SSH_CHANNEL_ABANDONED:
case SSH_CHANNEL_MUX_LISTENER:
case SSH_CHANNEL_UNIX_LISTENER:
case SSH_CHANNEL_RUNIX_LISTENER:
continue;
case SSH_CHANNEL_LARVAL:
case SSH_CHANNEL_OPENING:
case SSH_CHANNEL_CONNECTING:
case SSH_CHANNEL_DYNAMIC:
case SSH_CHANNEL_RDYNAMIC_OPEN:
case SSH_CHANNEL_RDYNAMIC_FINISH:
case SSH_CHANNEL_OPEN:
case SSH_CHANNEL_X11_OPEN:
case SSH_CHANNEL_MUX_PROXY:
case SSH_CHANNEL_MUX_CLIENT:
cp = channel_format_status(c);
if ((r = sshbuf_putf(buf, " #%d %.300s (%s)\r\n",
c->self, c->remote_name, cp)) != 0) {
free(cp);
fatal_fr(r, "sshbuf_putf");
}
free(cp);
continue;
default:
fatal_f("bad channel type %d", c->type);
/* NOTREACHED */
}
}
if ((ret = sshbuf_dup_string(buf)) == NULL)
fatal_f("sshbuf_dup_string");
sshbuf_free(buf);
return ret;
}
static void
open_preamble(struct ssh *ssh, const char *where, Channel *c, const char *type)
{
int r;
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN)) != 0 ||
(r = sshpkt_put_cstring(ssh, type)) != 0 ||
(r = sshpkt_put_u32(ssh, c->self)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) {
fatal_r(r, "%s: channel %i: open", where, c->self);
}
}
void
channel_send_open(struct ssh *ssh, int id)
{
Channel *c = channel_lookup(ssh, id);
int r;
if (c == NULL) {
logit("channel_send_open: %d: bad id", id);
return;
}
debug2("channel %d: send open", id);
open_preamble(ssh, __func__, c, c->ctype);
if ((r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "channel %i", c->self);
}
void
channel_request_start(struct ssh *ssh, int id, char *service, int wantconfirm)
{
Channel *c = channel_lookup(ssh, id);
int r;
if (c == NULL) {
logit_f("%d: unknown channel id", id);
return;
}
if (!c->have_remote_id)
fatal_f("channel %d: no remote id", c->self);
debug2("channel %d: request %s confirm %d", id, service, wantconfirm);
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_REQUEST)) != 0 ||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
(r = sshpkt_put_cstring(ssh, service)) != 0 ||
(r = sshpkt_put_u8(ssh, wantconfirm)) != 0) {
fatal_fr(r, "channel %i", c->self);
}
}
void
channel_register_status_confirm(struct ssh *ssh, int id,
channel_confirm_cb *cb, channel_confirm_abandon_cb *abandon_cb, void *ctx)
{
struct channel_confirm *cc;
Channel *c;
if ((c = channel_lookup(ssh, id)) == NULL)
fatal_f("%d: bad id", id);
cc = xcalloc(1, sizeof(*cc));
cc->cb = cb;
cc->abandon_cb = abandon_cb;
cc->ctx = ctx;
TAILQ_INSERT_TAIL(&c->status_confirms, cc, entry);
}
void
channel_register_open_confirm(struct ssh *ssh, int id,
channel_open_fn *fn, void *ctx)
{
Channel *c = channel_lookup(ssh, id);
if (c == NULL) {
logit_f("%d: bad id", id);
return;
}
c->open_confirm = fn;
c->open_confirm_ctx = ctx;
}
void
channel_register_cleanup(struct ssh *ssh, int id,
channel_callback_fn *fn, int do_close)
{
Channel *c = channel_by_id(ssh, id);
if (c == NULL) {
logit_f("%d: bad id", id);
return;
}
c->detach_user = fn;
c->detach_close = do_close;
}
void
channel_cancel_cleanup(struct ssh *ssh, int id)
{
Channel *c = channel_by_id(ssh, id);
if (c == NULL) {
logit_f("%d: bad id", id);
return;
}
c->detach_user = NULL;
c->detach_close = 0;
}
void
channel_register_filter(struct ssh *ssh, int id, channel_infilter_fn *ifn,
channel_outfilter_fn *ofn, channel_filter_cleanup_fn *cfn, void *ctx)
{
Channel *c = channel_lookup(ssh, id);
if (c == NULL) {
logit_f("%d: bad id", id);
return;
}
c->input_filter = ifn;
c->output_filter = ofn;
c->filter_ctx = ctx;
c->filter_cleanup = cfn;
}
void
channel_set_fds(struct ssh *ssh, int id, int rfd, int wfd, int efd,
int extusage, int nonblock, int is_tty, u_int window_max)
{
Channel *c = channel_lookup(ssh, id);
int r;
if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
fatal("channel_activate for non-larval channel %d.", id);
if (!c->have_remote_id)
fatal_f("channel %d: no remote id", c->self);
channel_register_fds(ssh, c, rfd, wfd, efd, extusage, nonblock, is_tty);
c->type = SSH_CHANNEL_OPEN;
c->local_window = c->local_window_max = window_max;
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_WINDOW_ADJUST)) != 0 ||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "channel %i", c->self);
}
static void
channel_pre_listener(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
FD_SET(c->sock, readset);
}
static void
channel_pre_connecting(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
debug3("channel %d: waiting for connection", c->self);
FD_SET(c->sock, writeset);
}
static void
channel_pre_open(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
if (c->istate == CHAN_INPUT_OPEN &&
c->remote_window > 0 &&
sshbuf_len(c->input) < c->remote_window &&
sshbuf_check_reserve(c->input, CHAN_RBUF) == 0)
FD_SET(c->rfd, readset);
if (c->ostate == CHAN_OUTPUT_OPEN ||
c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
if (sshbuf_len(c->output) > 0) {
FD_SET(c->wfd, writeset);
} else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
if (CHANNEL_EFD_OUTPUT_ACTIVE(c))
debug2("channel %d: "
"obuf_empty delayed efd %d/(%zu)", c->self,
c->efd, sshbuf_len(c->extended));
else
chan_obuf_empty(ssh, c);
}
}
/** XXX check close conditions, too */
if (c->efd != -1 && !(c->istate == CHAN_INPUT_CLOSED &&
c->ostate == CHAN_OUTPUT_CLOSED)) {
if (c->extended_usage == CHAN_EXTENDED_WRITE &&
sshbuf_len(c->extended) > 0)
FD_SET(c->efd, writeset);
else if (c->efd != -1 && !(c->flags & CHAN_EOF_SENT) &&
(c->extended_usage == CHAN_EXTENDED_READ ||
c->extended_usage == CHAN_EXTENDED_IGNORE) &&
sshbuf_len(c->extended) < c->remote_window)
FD_SET(c->efd, readset);
}
/* XXX: What about efd? races? */
}
/*
* This is a special state for X11 authentication spoofing. An opened X11
* connection (when authentication spoofing is being done) remains in this
* state until the first packet has been completely read. The authentication
* data in that packet is then substituted by the real data if it matches the
* fake data, and the channel is put into normal mode.
* XXX All this happens at the client side.
* Returns: 0 = need more data, -1 = wrong cookie, 1 = ok
*/
static int
x11_open_helper(struct ssh *ssh, struct sshbuf *b)
{
struct ssh_channels *sc = ssh->chanctxt;
u_char *ucp;
u_int proto_len, data_len;
/* Is this being called after the refusal deadline? */
if (sc->x11_refuse_time != 0 &&
(u_int)monotime() >= sc->x11_refuse_time) {
verbose("Rejected X11 connection after ForwardX11Timeout "
"expired");
return -1;
}
/* Check if the fixed size part of the packet is in buffer. */
if (sshbuf_len(b) < 12)
return 0;
/* Parse the lengths of variable-length fields. */
ucp = sshbuf_mutable_ptr(b);
if (ucp[0] == 0x42) { /* Byte order MSB first. */
proto_len = 256 * ucp[6] + ucp[7];
data_len = 256 * ucp[8] + ucp[9];
} else if (ucp[0] == 0x6c) { /* Byte order LSB first. */
proto_len = ucp[6] + 256 * ucp[7];
data_len = ucp[8] + 256 * ucp[9];
} else {
debug2("Initial X11 packet contains bad byte order byte: 0x%x",
ucp[0]);
return -1;
}
/* Check if the whole packet is in buffer. */
if (sshbuf_len(b) <
12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))
return 0;
/* Check if authentication protocol matches. */
if (proto_len != strlen(sc->x11_saved_proto) ||
memcmp(ucp + 12, sc->x11_saved_proto, proto_len) != 0) {
debug2("X11 connection uses different authentication protocol.");
return -1;
}
/* Check if authentication data matches our fake data. */
if (data_len != sc->x11_fake_data_len ||
timingsafe_bcmp(ucp + 12 + ((proto_len + 3) & ~3),
sc->x11_fake_data, sc->x11_fake_data_len) != 0) {
debug2("X11 auth data does not match fake data.");
return -1;
}
/* Check fake data length */
if (sc->x11_fake_data_len != sc->x11_saved_data_len) {
error("X11 fake_data_len %d != saved_data_len %d",
sc->x11_fake_data_len, sc->x11_saved_data_len);
return -1;
}
/*
* Received authentication protocol and data match
* our fake data. Substitute the fake data with real
* data.
*/
memcpy(ucp + 12 + ((proto_len + 3) & ~3),
sc->x11_saved_data, sc->x11_saved_data_len);
return 1;
}
static void
channel_pre_x11_open(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
int ret = x11_open_helper(ssh, c->output);
/* c->force_drain = 1; */
if (ret == 1) {
c->type = SSH_CHANNEL_OPEN;
channel_pre_open(ssh, c, readset, writeset);
} else if (ret == -1) {
logit("X11 connection rejected because of wrong authentication.");
debug2("X11 rejected %d i%d/o%d",
c->self, c->istate, c->ostate);
chan_read_failed(ssh, c);
sshbuf_reset(c->input);
chan_ibuf_empty(ssh, c);
sshbuf_reset(c->output);
chan_write_failed(ssh, c);
debug2("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate);
}
}
static void
channel_pre_mux_client(struct ssh *ssh,
Channel *c, fd_set *readset, fd_set *writeset)
{
if (c->istate == CHAN_INPUT_OPEN && !c->mux_pause &&
sshbuf_check_reserve(c->input, CHAN_RBUF) == 0)
FD_SET(c->rfd, readset);
if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
/* clear buffer immediately (discard any partial packet) */
sshbuf_reset(c->input);
chan_ibuf_empty(ssh, c);
/* Start output drain. XXX just kill chan? */
chan_rcvd_oclose(ssh, c);
}
if (c->ostate == CHAN_OUTPUT_OPEN ||
c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
if (sshbuf_len(c->output) > 0)
FD_SET(c->wfd, writeset);
else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN)
chan_obuf_empty(ssh, c);
}
}
/* try to decode a socks4 header */
static int
channel_decode_socks4(Channel *c, struct sshbuf *input, struct sshbuf *output)
{
const u_char *p;
char *host;
u_int len, have, i, found, need;
char username[256];
struct {
u_int8_t version;
u_int8_t command;
u_int16_t dest_port;
struct in_addr dest_addr;
} s4_req, s4_rsp;
int r;
debug2("channel %d: decode socks4", c->self);
have = sshbuf_len(input);
len = sizeof(s4_req);
if (have < len)
return 0;
p = sshbuf_ptr(input);
need = 1;
/* SOCKS4A uses an invalid IP address 0.0.0.x */
if (p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] != 0) {
debug2("channel %d: socks4a request", c->self);
/* ... and needs an extra string (the hostname) */
need = 2;
}
/* Check for terminating NUL on the string(s) */
for (found = 0, i = len; i < have; i++) {
if (p[i] == '\0') {
found++;
if (found == need)
break;
}
if (i > 1024) {
/* the peer is probably sending garbage */
debug("channel %d: decode socks4: too long",
c->self);
return -1;
}
}
if (found < need)
return 0;
if ((r = sshbuf_get(input, &s4_req.version, 1)) != 0 ||
(r = sshbuf_get(input, &s4_req.command, 1)) != 0 ||
(r = sshbuf_get(input, &s4_req.dest_port, 2)) != 0 ||
(r = sshbuf_get(input, &s4_req.dest_addr, 4)) != 0) {
debug_r(r, "channels %d: decode socks4", c->self);
return -1;
}
have = sshbuf_len(input);
p = sshbuf_ptr(input);
if (memchr(p, '\0', have) == NULL) {
error("channel %d: decode socks4: unterminated user", c->self);
return -1;
}
len = strlen(p);
debug2("channel %d: decode socks4: user %s/%d", c->self, p, len);
len++; /* trailing '\0' */
strlcpy(username, p, sizeof(username));
if ((r = sshbuf_consume(input, len)) != 0)
fatal_fr(r, "channel %d: consume", c->self);
free(c->path);
c->path = NULL;
if (need == 1) { /* SOCKS4: one string */
host = inet_ntoa(s4_req.dest_addr);
c->path = xstrdup(host);
} else { /* SOCKS4A: two strings */
have = sshbuf_len(input);
p = sshbuf_ptr(input);
if (memchr(p, '\0', have) == NULL) {
error("channel %d: decode socks4a: host not nul "
"terminated", c->self);
return -1;
}
len = strlen(p);
debug2("channel %d: decode socks4a: host %s/%d",
c->self, p, len);
len++; /* trailing '\0' */
if (len > NI_MAXHOST) {
error("channel %d: hostname \"%.100s\" too long",
c->self, p);
return -1;
}
c->path = xstrdup(p);
if ((r = sshbuf_consume(input, len)) != 0)
fatal_fr(r, "channel %d: consume", c->self);
}
c->host_port = ntohs(s4_req.dest_port);
debug2("channel %d: dynamic request: socks4 host %s port %u command %u",
c->self, c->path, c->host_port, s4_req.command);
if (s4_req.command != 1) {
debug("channel %d: cannot handle: %s cn %d",
c->self, need == 1 ? "SOCKS4" : "SOCKS4A", s4_req.command);
return -1;
}
s4_rsp.version = 0; /* vn: 0 for reply */
s4_rsp.command = 90; /* cd: req granted */
s4_rsp.dest_port = 0; /* ignored */
s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */
if ((r = sshbuf_put(output, &s4_rsp, sizeof(s4_rsp))) != 0)
fatal_fr(r, "channel %d: append reply", c->self);
return 1;
}
/* try to decode a socks5 header */
#define SSH_SOCKS5_AUTHDONE 0x1000
#define SSH_SOCKS5_NOAUTH 0x00
#define SSH_SOCKS5_IPV4 0x01
#define SSH_SOCKS5_DOMAIN 0x03
#define SSH_SOCKS5_IPV6 0x04
#define SSH_SOCKS5_CONNECT 0x01
#define SSH_SOCKS5_SUCCESS 0x00
static int
channel_decode_socks5(Channel *c, struct sshbuf *input, struct sshbuf *output)
{
/* XXX use get/put_u8 instead of trusting struct padding */
struct {
u_int8_t version;
u_int8_t command;
u_int8_t reserved;
u_int8_t atyp;
} s5_req, s5_rsp;
u_int16_t dest_port;
char dest_addr[255+1], ntop[INET6_ADDRSTRLEN];
const u_char *p;
u_int have, need, i, found, nmethods, addrlen, af;
int r;
debug2("channel %d: decode socks5", c->self);
p = sshbuf_ptr(input);
if (p[0] != 0x05)
return -1;
have = sshbuf_len(input);
if (!(c->flags & SSH_SOCKS5_AUTHDONE)) {
/* format: ver | nmethods | methods */
if (have < 2)
return 0;
nmethods = p[1];
if (have < nmethods + 2)
return 0;
/* look for method: "NO AUTHENTICATION REQUIRED" */
for (found = 0, i = 2; i < nmethods + 2; i++) {
if (p[i] == SSH_SOCKS5_NOAUTH) {
found = 1;
break;
}
}
if (!found) {
debug("channel %d: method SSH_SOCKS5_NOAUTH not found",
c->self);
return -1;
}
if ((r = sshbuf_consume(input, nmethods + 2)) != 0)
fatal_fr(r, "channel %d: consume", c->self);
/* version, method */
if ((r = sshbuf_put_u8(output, 0x05)) != 0 ||
(r = sshbuf_put_u8(output, SSH_SOCKS5_NOAUTH)) != 0)
fatal_fr(r, "channel %d: append reply", c->self);
c->flags |= SSH_SOCKS5_AUTHDONE;
debug2("channel %d: socks5 auth done", c->self);
return 0; /* need more */
}
debug2("channel %d: socks5 post auth", c->self);
if (have < sizeof(s5_req)+1)
return 0; /* need more */
memcpy(&s5_req, p, sizeof(s5_req));
if (s5_req.version != 0x05 ||
s5_req.command != SSH_SOCKS5_CONNECT ||
s5_req.reserved != 0x00) {
debug2("channel %d: only socks5 connect supported", c->self);
return -1;
}
switch (s5_req.atyp){
case SSH_SOCKS5_IPV4:
addrlen = 4;
af = AF_INET;
break;
case SSH_SOCKS5_DOMAIN:
addrlen = p[sizeof(s5_req)];
af = -1;
break;
case SSH_SOCKS5_IPV6:
addrlen = 16;
af = AF_INET6;
break;
default:
debug2("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp);
return -1;
}
need = sizeof(s5_req) + addrlen + 2;
if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
need++;
if (have < need)
return 0;
if ((r = sshbuf_consume(input, sizeof(s5_req))) != 0)
fatal_fr(r, "channel %d: consume", c->self);
if (s5_req.atyp == SSH_SOCKS5_DOMAIN) {
/* host string length */
if ((r = sshbuf_consume(input, 1)) != 0)
fatal_fr(r, "channel %d: consume", c->self);
}
if ((r = sshbuf_get(input, &dest_addr, addrlen)) != 0 ||
(r = sshbuf_get(input, &dest_port, 2)) != 0) {
debug_r(r, "channel %d: parse addr/port", c->self);
return -1;
}
dest_addr[addrlen] = '\0';
free(c->path);
c->path = NULL;
if (s5_req.atyp == SSH_SOCKS5_DOMAIN) {
if (addrlen >= NI_MAXHOST) {
error("channel %d: dynamic request: socks5 hostname "
"\"%.100s\" too long", c->self, dest_addr);
return -1;
}
c->path = xstrdup(dest_addr);
} else {
if (inet_ntop(af, dest_addr, ntop, sizeof(ntop)) == NULL)
return -1;
c->path = xstrdup(ntop);
}
c->host_port = ntohs(dest_port);
debug2("channel %d: dynamic request: socks5 host %s port %u command %u",
c->self, c->path, c->host_port, s5_req.command);
s5_rsp.version = 0x05;
s5_rsp.command = SSH_SOCKS5_SUCCESS;
s5_rsp.reserved = 0; /* ignored */
s5_rsp.atyp = SSH_SOCKS5_IPV4;
dest_port = 0; /* ignored */
if ((r = sshbuf_put(output, &s5_rsp, sizeof(s5_rsp))) != 0 ||
(r = sshbuf_put_u32(output, ntohl(INADDR_ANY))) != 0 ||
(r = sshbuf_put(output, &dest_port, sizeof(dest_port))) != 0)
fatal_fr(r, "channel %d: append reply", c->self);
return 1;
}
Channel *
channel_connect_stdio_fwd(struct ssh *ssh,
const char *host_to_connect, u_short port_to_connect, int in, int out)
{
Channel *c;
debug_f("%s:%d", host_to_connect, port_to_connect);
c = channel_new(ssh, "stdio-forward", SSH_CHANNEL_OPENING, in, out,
-1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
0, "stdio-forward", /*nonblock*/0);
c->path = xstrdup(host_to_connect);
c->host_port = port_to_connect;
c->listening_port = 0;
c->force_drain = 1;
channel_register_fds(ssh, c, in, out, -1, 0, 1, 0);
port_open_helper(ssh, c, "direct-tcpip");
return c;
}
/* dynamic port forwarding */
static void
channel_pre_dynamic(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
const u_char *p;
u_int have;
int ret;
have = sshbuf_len(c->input);
debug2("channel %d: pre_dynamic: have %d", c->self, have);
/* sshbuf_dump(c->input, stderr); */
/* check if the fixed size part of the packet is in buffer. */
if (have < 3) {
/* need more */
FD_SET(c->sock, readset);
return;
}
/* try to guess the protocol */
p = sshbuf_ptr(c->input);
/* XXX sshbuf_peek_u8? */
switch (p[0]) {
case 0x04:
ret = channel_decode_socks4(c, c->input, c->output);
break;
case 0x05:
ret = channel_decode_socks5(c, c->input, c->output);
break;
default:
ret = -1;
break;
}
if (ret < 0) {
chan_mark_dead(ssh, c);
} else if (ret == 0) {
debug2("channel %d: pre_dynamic: need more", c->self);
/* need more */
FD_SET(c->sock, readset);
if (sshbuf_len(c->output))
FD_SET(c->sock, writeset);
} else {
/* switch to the next state */
c->type = SSH_CHANNEL_OPENING;
port_open_helper(ssh, c, "direct-tcpip");
}
}
/* simulate read-error */
static void
rdynamic_close(struct ssh *ssh, Channel *c)
{
c->type = SSH_CHANNEL_OPEN;
chan_read_failed(ssh, c);
sshbuf_reset(c->input);
chan_ibuf_empty(ssh, c);
sshbuf_reset(c->output);
chan_write_failed(ssh, c);
}
/* reverse dynamic port forwarding */
static void
channel_before_prepare_select_rdynamic(struct ssh *ssh, Channel *c)
{
const u_char *p;
u_int have, len;
int r, ret;
have = sshbuf_len(c->output);
debug2("channel %d: pre_rdynamic: have %d", c->self, have);
/* sshbuf_dump(c->output, stderr); */
/* EOF received */
if (c->flags & CHAN_EOF_RCVD) {
if ((r = sshbuf_consume(c->output, have)) != 0)
fatal_fr(r, "channel %d: consume", c->self);
rdynamic_close(ssh, c);
return;
}
/* check if the fixed size part of the packet is in buffer. */
if (have < 3)
return;
/* try to guess the protocol */
p = sshbuf_ptr(c->output);
switch (p[0]) {
case 0x04:
/* switch input/output for reverse forwarding */
ret = channel_decode_socks4(c, c->output, c->input);
break;
case 0x05:
ret = channel_decode_socks5(c, c->output, c->input);
break;
default:
ret = -1;
break;
}
if (ret < 0) {
rdynamic_close(ssh, c);
} else if (ret == 0) {
debug2("channel %d: pre_rdynamic: need more", c->self);
/* send socks request to peer */
len = sshbuf_len(c->input);
if (len > 0 && len < c->remote_window) {
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 ||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
(r = sshpkt_put_stringb(ssh, c->input)) != 0 ||
(r = sshpkt_send(ssh)) != 0) {
fatal_fr(r, "channel %i: rdynamic", c->self);
}
if ((r = sshbuf_consume(c->input, len)) != 0)
fatal_fr(r, "channel %d: consume", c->self);
c->remote_window -= len;
}
} else if (rdynamic_connect_finish(ssh, c) < 0) {
/* the connect failed */
rdynamic_close(ssh, c);
}
}
/* This is our fake X11 server socket. */
static void
channel_post_x11_listener(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
Channel *nc;
struct sockaddr_storage addr;
int r, newsock, oerrno, remote_port;
socklen_t addrlen;
char buf[16384], *remote_ipaddr;
if (!FD_ISSET(c->sock, readset))
return;
debug("X11 connection requested.");
addrlen = sizeof(addr);
newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
if (c->single_connection) {
oerrno = errno;
debug2("single_connection: closing X11 listener.");
channel_close_fd(ssh, &c->sock);
chan_mark_dead(ssh, c);
errno = oerrno;
}
if (newsock == -1) {
if (errno != EINTR && errno != EWOULDBLOCK &&
errno != ECONNABORTED)
error("accept: %.100s", strerror(errno));
if (errno == EMFILE || errno == ENFILE)
c->notbefore = monotime() + 1;
return;
}
set_nodelay(newsock);
remote_ipaddr = get_peer_ipaddr(newsock);
remote_port = get_peer_port(newsock);
snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",
remote_ipaddr, remote_port);
nc = channel_new(ssh, "accepted x11 socket",
SSH_CHANNEL_OPENING, newsock, newsock, -1,
c->local_window_max, c->local_maxpacket, 0, buf, 1);
open_preamble(ssh, __func__, nc, "x11");
if ((r = sshpkt_put_cstring(ssh, remote_ipaddr)) != 0 ||
(r = sshpkt_put_u32(ssh, remote_port)) != 0) {
fatal_fr(r, "channel %i: reply", c->self);
}
if ((r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "channel %i: send", c->self);
free(remote_ipaddr);
}
static void
port_open_helper(struct ssh *ssh, Channel *c, char *rtype)
{
char *local_ipaddr = get_local_ipaddr(c->sock);
int local_port = c->sock == -1 ? 65536 : get_local_port(c->sock);
char *remote_ipaddr = get_peer_ipaddr(c->sock);
int remote_port = get_peer_port(c->sock);
int r;
if (remote_port == -1) {
/* Fake addr/port to appease peers that validate it (Tectia) */
free(remote_ipaddr);
remote_ipaddr = xstrdup("127.0.0.1");
remote_port = 65535;
}
free(c->remote_name);
xasprintf(&c->remote_name,
"%s: listening port %d for %.100s port %d, "
"connect from %.200s port %d to %.100s port %d",
rtype, c->listening_port, c->path, c->host_port,
remote_ipaddr, remote_port, local_ipaddr, local_port);
open_preamble(ssh, __func__, c, rtype);
if (strcmp(rtype, "direct-tcpip") == 0) {
/* target host, port */
if ((r = sshpkt_put_cstring(ssh, c->path)) != 0 ||
(r = sshpkt_put_u32(ssh, c->host_port)) != 0)
fatal_fr(r, "channel %i: reply", c->self);
} else if (strcmp(rtype, "direct-streamlocal@openssh.com") == 0) {
/* target path */
if ((r = sshpkt_put_cstring(ssh, c->path)) != 0)
fatal_fr(r, "channel %i: reply", c->self);
} else if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
/* listen path */
if ((r = sshpkt_put_cstring(ssh, c->path)) != 0)
fatal_fr(r, "channel %i: reply", c->self);
} else {
/* listen address, port */
if ((r = sshpkt_put_cstring(ssh, c->path)) != 0 ||
(r = sshpkt_put_u32(ssh, local_port)) != 0)
fatal_fr(r, "channel %i: reply", c->self);
}
if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
/* reserved for future owner/mode info */
if ((r = sshpkt_put_cstring(ssh, "")) != 0)
fatal_fr(r, "channel %i: reply", c->self);
} else {
/* originator host and port */
if ((r = sshpkt_put_cstring(ssh, remote_ipaddr)) != 0 ||
(r = sshpkt_put_u32(ssh, (u_int)remote_port)) != 0)
fatal_fr(r, "channel %i: reply", c->self);
}
if ((r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "channel %i: send", c->self);
free(remote_ipaddr);
free(local_ipaddr);
}
void
channel_set_x11_refuse_time(struct ssh *ssh, u_int refuse_time)
{
ssh->chanctxt->x11_refuse_time = refuse_time;
}
/*
* This socket is listening for connections to a forwarded TCP/IP port.
*/
static void
channel_post_port_listener(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
Channel *nc;
struct sockaddr_storage addr;
int newsock, nextstate;
socklen_t addrlen;
char *rtype;
if (!FD_ISSET(c->sock, readset))
return;
debug("Connection to port %d forwarding to %.100s port %d requested.",
c->listening_port, c->path, c->host_port);
if (c->type == SSH_CHANNEL_RPORT_LISTENER) {
nextstate = SSH_CHANNEL_OPENING;
rtype = "forwarded-tcpip";
} else if (c->type == SSH_CHANNEL_RUNIX_LISTENER) {
nextstate = SSH_CHANNEL_OPENING;
rtype = "forwarded-streamlocal@openssh.com";
} else if (c->host_port == PORT_STREAMLOCAL) {
nextstate = SSH_CHANNEL_OPENING;
rtype = "direct-streamlocal@openssh.com";
} else if (c->host_port == 0) {
nextstate = SSH_CHANNEL_DYNAMIC;
rtype = "dynamic-tcpip";
} else {
nextstate = SSH_CHANNEL_OPENING;
rtype = "direct-tcpip";
}
addrlen = sizeof(addr);
newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
if (newsock == -1) {
if (errno != EINTR && errno != EWOULDBLOCK &&
errno != ECONNABORTED)
error("accept: %.100s", strerror(errno));
if (errno == EMFILE || errno == ENFILE)
c->notbefore = monotime() + 1;
return;
}
if (c->host_port != PORT_STREAMLOCAL)
set_nodelay(newsock);
nc = channel_new(ssh, rtype, nextstate, newsock, newsock, -1,
c->local_window_max, c->local_maxpacket, 0, rtype, 1);
nc->listening_port = c->listening_port;
nc->host_port = c->host_port;
if (c->path != NULL)
nc->path = xstrdup(c->path);
if (nextstate != SSH_CHANNEL_DYNAMIC)
port_open_helper(ssh, nc, rtype);
}
/*
* This is the authentication agent socket listening for connections from
* clients.
*/
static void
channel_post_auth_listener(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
Channel *nc;
int r, newsock;
struct sockaddr_storage addr;
socklen_t addrlen;
if (!FD_ISSET(c->sock, readset))
return;
addrlen = sizeof(addr);
newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
if (newsock == -1) {
error("accept from auth socket: %.100s", strerror(errno));
if (errno == EMFILE || errno == ENFILE)
c->notbefore = monotime() + 1;
return;
}
nc = channel_new(ssh, "accepted auth socket",
SSH_CHANNEL_OPENING, newsock, newsock, -1,
c->local_window_max, c->local_maxpacket,
0, "accepted auth socket", 1);
open_preamble(ssh, __func__, nc, "auth-agent@openssh.com");
if ((r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "channel %i", c->self);
}
static void
channel_post_connecting(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
int err = 0, sock, isopen, r;
socklen_t sz = sizeof(err);
if (!FD_ISSET(c->sock, writeset))
return;
if (!c->have_remote_id)
fatal_f("channel %d: no remote id", c->self);
/* for rdynamic the OPEN_CONFIRMATION has been sent already */
isopen = (c->type == SSH_CHANNEL_RDYNAMIC_FINISH);
if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) == -1) {
err = errno;
error("getsockopt SO_ERROR failed");
}
if (err == 0) {
debug("channel %d: connected to %s port %d",
c->self, c->connect_ctx.host, c->connect_ctx.port);
channel_connect_ctx_free(&c->connect_ctx);
c->type = SSH_CHANNEL_OPEN;
if (isopen) {
/* no message necessary */
} else {
if ((r = sshpkt_start(ssh,
SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 ||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
(r = sshpkt_put_u32(ssh, c->self)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "channel %i open confirm", c->self);
}
} else {
debug("channel %d: connection failed: %s",
c->self, strerror(err));
/* Try next address, if any */
if ((sock = connect_next(&c->connect_ctx)) > 0) {
close(c->sock);
c->sock = c->rfd = c->wfd = sock;
channel_find_maxfd(ssh->chanctxt);
return;
}
/* Exhausted all addresses */
error("connect_to %.100s port %d: failed.",
c->connect_ctx.host, c->connect_ctx.port);
channel_connect_ctx_free(&c->connect_ctx);
if (isopen) {
rdynamic_close(ssh, c);
} else {
if ((r = sshpkt_start(ssh,
SSH2_MSG_CHANNEL_OPEN_FAILURE)) != 0 ||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
(r = sshpkt_put_u32(ssh,
SSH2_OPEN_CONNECT_FAILED)) != 0 ||
(r = sshpkt_put_cstring(ssh, strerror(err))) != 0 ||
(r = sshpkt_put_cstring(ssh, "")) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "channel %i: failure", c->self);
chan_mark_dead(ssh, c);
}
}
}
static int
channel_handle_rfd(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
char buf[CHAN_RBUF];
ssize_t len;
int r, force;
force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED;
if (c->rfd == -1 || (!force && !FD_ISSET(c->rfd, readset)))
return 1;
errno = 0;
len = read(c->rfd, buf, sizeof(buf));
if (len == -1 && (errno == EINTR ||
((errno == EAGAIN || errno == EWOULDBLOCK) && !force)))
return 1;
#ifndef PTY_ZEROREAD
- if (len <= 0) {
+ if (len <= 0) {
#else
if ((!c->isatty && len <= 0) ||
(c->isatty && (len < 0 || (len == 0 && errno != 0)))) {
#endif
debug2("channel %d: read<=0 rfd %d len %zd",
c->self, c->rfd, len);
if (c->type != SSH_CHANNEL_OPEN) {
debug2("channel %d: not open", c->self);
chan_mark_dead(ssh, c);
return -1;
} else {
chan_read_failed(ssh, c);
}
return -1;
}
if (c->input_filter != NULL) {
if (c->input_filter(ssh, c, buf, len) == -1) {
debug2("channel %d: filter stops", c->self);
chan_read_failed(ssh, c);
}
} else if (c->datagram) {
if ((r = sshbuf_put_string(c->input, buf, len)) != 0)
fatal_fr(r, "channel %i: put datagram", c->self);
} else if ((r = sshbuf_put(c->input, buf, len)) != 0)
fatal_fr(r, "channel %i: put data", c->self);
return 1;
}
static int
channel_handle_wfd(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
struct termios tio;
u_char *data = NULL, *buf; /* XXX const; need filter API change */
size_t dlen, olen = 0;
int r, len;
if (c->wfd == -1 || !FD_ISSET(c->wfd, writeset) ||
sshbuf_len(c->output) == 0)
return 1;
/* Send buffered output data to the socket. */
olen = sshbuf_len(c->output);
if (c->output_filter != NULL) {
if ((buf = c->output_filter(ssh, c, &data, &dlen)) == NULL) {
debug2("channel %d: filter stops", c->self);
if (c->type != SSH_CHANNEL_OPEN)
chan_mark_dead(ssh, c);
else
chan_write_failed(ssh, c);
return -1;
}
} else if (c->datagram) {
if ((r = sshbuf_get_string(c->output, &data, &dlen)) != 0)
fatal_fr(r, "channel %i: get datagram", c->self);
buf = data;
} else {
buf = data = sshbuf_mutable_ptr(c->output);
dlen = sshbuf_len(c->output);
}
if (c->datagram) {
/* ignore truncated writes, datagrams might get lost */
len = write(c->wfd, buf, dlen);
free(data);
if (len == -1 && (errno == EINTR || errno == EAGAIN ||
errno == EWOULDBLOCK))
return 1;
if (len <= 0)
goto write_fail;
goto out;
}
#ifdef _AIX
/* XXX: Later AIX versions can't push as much data to tty */
if (c->wfd_isatty)
dlen = MIN(dlen, 8*1024);
#endif
len = write(c->wfd, buf, dlen);
if (len == -1 &&
(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
return 1;
if (len <= 0) {
write_fail:
if (c->type != SSH_CHANNEL_OPEN) {
debug2("channel %d: not open", c->self);
chan_mark_dead(ssh, c);
return -1;
} else {
chan_write_failed(ssh, c);
}
return -1;
}
#ifndef BROKEN_TCGETATTR_ICANON
if (c->isatty && dlen >= 1 && buf[0] != '\r') {
if (tcgetattr(c->wfd, &tio) == 0 &&
!(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
/*
* Simulate echo to reduce the impact of
* traffic analysis. We need to match the
* size of a SSH2_MSG_CHANNEL_DATA message
* (4 byte channel id + buf)
*/
if ((r = sshpkt_msg_ignore(ssh, 4+len)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "channel %i: ignore", c->self);
}
}
#endif /* BROKEN_TCGETATTR_ICANON */
if ((r = sshbuf_consume(c->output, len)) != 0)
fatal_fr(r, "channel %i: consume", c->self);
out:
c->local_consumed += olen - sshbuf_len(c->output);
return 1;
}
static int
channel_handle_efd_write(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
int r;
ssize_t len;
if (!FD_ISSET(c->efd, writeset) || sshbuf_len(c->extended) == 0)
return 1;
len = write(c->efd, sshbuf_ptr(c->extended),
sshbuf_len(c->extended));
debug2("channel %d: written %zd to efd %d", c->self, len, c->efd);
if (len == -1 && (errno == EINTR || errno == EAGAIN ||
errno == EWOULDBLOCK))
return 1;
if (len <= 0) {
debug2("channel %d: closing write-efd %d", c->self, c->efd);
channel_close_fd(ssh, &c->efd);
} else {
if ((r = sshbuf_consume(c->extended, len)) != 0)
fatal_fr(r, "channel %i: consume", c->self);
c->local_consumed += len;
}
return 1;
}
static int
channel_handle_efd_read(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
char buf[CHAN_RBUF];
ssize_t len;
int r, force;
force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED;
if (c->efd == -1 || (!force && !FD_ISSET(c->efd, readset)))
return 1;
len = read(c->efd, buf, sizeof(buf));
debug2("channel %d: read %zd from efd %d", c->self, len, c->efd);
if (len == -1 && (errno == EINTR || ((errno == EAGAIN ||
errno == EWOULDBLOCK) && !force)))
return 1;
if (len <= 0) {
debug2("channel %d: closing read-efd %d", c->self, c->efd);
channel_close_fd(ssh, &c->efd);
} else if (c->extended_usage == CHAN_EXTENDED_IGNORE)
debug3("channel %d: discard efd", c->self);
else if ((r = sshbuf_put(c->extended, buf, len)) != 0)
fatal_fr(r, "channel %i: append", c->self);
return 1;
}
static int
channel_handle_efd(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
if (c->efd == -1)
return 1;
/** XXX handle drain efd, too */
if (c->extended_usage == CHAN_EXTENDED_WRITE)
return channel_handle_efd_write(ssh, c, readset, writeset);
else if (c->extended_usage == CHAN_EXTENDED_READ ||
c->extended_usage == CHAN_EXTENDED_IGNORE)
return channel_handle_efd_read(ssh, c, readset, writeset);
return 1;
}
static int
channel_check_window(struct ssh *ssh, Channel *c)
{
int r;
if (c->type == SSH_CHANNEL_OPEN &&
!(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) &&
((c->local_window_max - c->local_window >
c->local_maxpacket*3) ||
c->local_window < c->local_window_max/2) &&
c->local_consumed > 0) {
if (!c->have_remote_id)
fatal_f("channel %d: no remote id", c->self);
if ((r = sshpkt_start(ssh,
SSH2_MSG_CHANNEL_WINDOW_ADJUST)) != 0 ||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_consumed)) != 0 ||
(r = sshpkt_send(ssh)) != 0) {
fatal_fr(r, "channel %i", c->self);
}
debug2("channel %d: window %d sent adjust %d", c->self,
c->local_window, c->local_consumed);
c->local_window += c->local_consumed;
c->local_consumed = 0;
}
return 1;
}
static void
channel_post_open(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
channel_handle_rfd(ssh, c, readset, writeset);
channel_handle_wfd(ssh, c, readset, writeset);
channel_handle_efd(ssh, c, readset, writeset);
channel_check_window(ssh, c);
}
static u_int
read_mux(struct ssh *ssh, Channel *c, u_int need)
{
char buf[CHAN_RBUF];
ssize_t len;
u_int rlen;
int r;
if (sshbuf_len(c->input) < need) {
rlen = need - sshbuf_len(c->input);
len = read(c->rfd, buf, MINIMUM(rlen, CHAN_RBUF));
if (len == -1 && (errno == EINTR || errno == EAGAIN))
return sshbuf_len(c->input);
if (len <= 0) {
debug2("channel %d: ctl read<=0 rfd %d len %zd",
c->self, c->rfd, len);
chan_read_failed(ssh, c);
return 0;
} else if ((r = sshbuf_put(c->input, buf, len)) != 0)
fatal_fr(r, "channel %i: append", c->self);
}
return sshbuf_len(c->input);
}
static void
channel_post_mux_client_read(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
u_int need;
if (c->rfd == -1 || !FD_ISSET(c->rfd, readset))
return;
if (c->istate != CHAN_INPUT_OPEN && c->istate != CHAN_INPUT_WAIT_DRAIN)
return;
if (c->mux_pause)
return;
/*
* Don't not read past the precise end of packets to
* avoid disrupting fd passing.
*/
if (read_mux(ssh, c, 4) < 4) /* read header */
return;
/* XXX sshbuf_peek_u32 */
need = PEEK_U32(sshbuf_ptr(c->input));
#define CHANNEL_MUX_MAX_PACKET (256 * 1024)
if (need > CHANNEL_MUX_MAX_PACKET) {
debug2("channel %d: packet too big %u > %u",
c->self, CHANNEL_MUX_MAX_PACKET, need);
chan_rcvd_oclose(ssh, c);
return;
}
if (read_mux(ssh, c, need + 4) < need + 4) /* read body */
return;
if (c->mux_rcb(ssh, c) != 0) {
debug("channel %d: mux_rcb failed", c->self);
chan_mark_dead(ssh, c);
return;
}
}
static void
channel_post_mux_client_write(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
ssize_t len;
int r;
if (c->wfd == -1 || !FD_ISSET(c->wfd, writeset) ||
sshbuf_len(c->output) == 0)
return;
len = write(c->wfd, sshbuf_ptr(c->output), sshbuf_len(c->output));
if (len == -1 && (errno == EINTR || errno == EAGAIN))
return;
if (len <= 0) {
chan_mark_dead(ssh, c);
return;
}
if ((r = sshbuf_consume(c->output, len)) != 0)
fatal_fr(r, "channel %i: consume", c->self);
}
static void
channel_post_mux_client(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
channel_post_mux_client_read(ssh, c, readset, writeset);
channel_post_mux_client_write(ssh, c, readset, writeset);
}
static void
channel_post_mux_listener(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
Channel *nc;
struct sockaddr_storage addr;
socklen_t addrlen;
int newsock;
uid_t euid;
gid_t egid;
if (!FD_ISSET(c->sock, readset))
return;
debug("multiplexing control connection");
/*
* Accept connection on control socket
*/
memset(&addr, 0, sizeof(addr));
addrlen = sizeof(addr);
if ((newsock = accept(c->sock, (struct sockaddr*)&addr,
&addrlen)) == -1) {
error_f("accept: %s", strerror(errno));
if (errno == EMFILE || errno == ENFILE)
c->notbefore = monotime() + 1;
return;
}
if (getpeereid(newsock, &euid, &egid) == -1) {
error_f("getpeereid failed: %s", strerror(errno));
close(newsock);
return;
}
if ((euid != 0) && (getuid() != euid)) {
error("multiplex uid mismatch: peer euid %u != uid %u",
(u_int)euid, (u_int)getuid());
close(newsock);
return;
}
nc = channel_new(ssh, "multiplex client", SSH_CHANNEL_MUX_CLIENT,
newsock, newsock, -1, c->local_window_max,
c->local_maxpacket, 0, "mux-control", 1);
nc->mux_rcb = c->mux_rcb;
debug3_f("new mux channel %d fd %d", nc->self, nc->sock);
/* establish state */
nc->mux_rcb(ssh, nc);
/* mux state transitions must not elicit protocol messages */
nc->flags |= CHAN_LOCAL;
}
static void
channel_handler_init(struct ssh_channels *sc)
{
chan_fn **pre, **post;
if ((pre = calloc(SSH_CHANNEL_MAX_TYPE, sizeof(*pre))) == NULL ||
- (post = calloc(SSH_CHANNEL_MAX_TYPE, sizeof(*post))) == NULL)
+ (post = calloc(SSH_CHANNEL_MAX_TYPE, sizeof(*post))) == NULL)
fatal_f("allocation failed");
pre[SSH_CHANNEL_OPEN] = &channel_pre_open;
pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open;
pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener;
pre[SSH_CHANNEL_UNIX_LISTENER] = &channel_pre_listener;
pre[SSH_CHANNEL_RUNIX_LISTENER] = &channel_pre_listener;
pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener;
pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener;
pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting;
pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic;
pre[SSH_CHANNEL_RDYNAMIC_FINISH] = &channel_pre_connecting;
pre[SSH_CHANNEL_MUX_LISTENER] = &channel_pre_listener;
pre[SSH_CHANNEL_MUX_CLIENT] = &channel_pre_mux_client;
post[SSH_CHANNEL_OPEN] = &channel_post_open;
post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener;
post[SSH_CHANNEL_UNIX_LISTENER] = &channel_post_port_listener;
post[SSH_CHANNEL_RUNIX_LISTENER] = &channel_post_port_listener;
post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener;
post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
post[SSH_CHANNEL_DYNAMIC] = &channel_post_open;
post[SSH_CHANNEL_RDYNAMIC_FINISH] = &channel_post_connecting;
post[SSH_CHANNEL_MUX_LISTENER] = &channel_post_mux_listener;
post[SSH_CHANNEL_MUX_CLIENT] = &channel_post_mux_client;
sc->channel_pre = pre;
sc->channel_post = post;
}
/* gc dead channels */
static void
channel_garbage_collect(struct ssh *ssh, Channel *c)
{
if (c == NULL)
return;
if (c->detach_user != NULL) {
if (!chan_is_dead(ssh, c, c->detach_close))
return;
debug2("channel %d: gc: notify user", c->self);
c->detach_user(ssh, c->self, NULL);
/* if we still have a callback */
if (c->detach_user != NULL)
return;
debug2("channel %d: gc: user detached", c->self);
}
if (!chan_is_dead(ssh, c, 1))
return;
debug2("channel %d: garbage collecting", c->self);
channel_free(ssh, c);
}
enum channel_table { CHAN_PRE, CHAN_POST };
static void
channel_handler(struct ssh *ssh, int table,
fd_set *readset, fd_set *writeset, time_t *unpause_secs)
{
struct ssh_channels *sc = ssh->chanctxt;
chan_fn **ftab = table == CHAN_PRE ? sc->channel_pre : sc->channel_post;
u_int i, oalloc;
Channel *c;
time_t now;
now = monotime();
if (unpause_secs != NULL)
*unpause_secs = 0;
for (i = 0, oalloc = sc->channels_alloc; i < oalloc; i++) {
c = sc->channels[i];
if (c == NULL)
continue;
if (c->delayed) {
if (table == CHAN_PRE)
c->delayed = 0;
else
continue;
}
if (ftab[c->type] != NULL) {
/*
* Run handlers that are not paused.
*/
if (c->notbefore <= now)
(*ftab[c->type])(ssh, c, readset, writeset);
else if (unpause_secs != NULL) {
/*
* Collect the time that the earliest
* channel comes off pause.
*/
debug3_f("chan %d: skip for %d more "
"seconds", c->self,
(int)(c->notbefore - now));
if (*unpause_secs == 0 ||
(c->notbefore - now) < *unpause_secs)
*unpause_secs = c->notbefore - now;
}
}
channel_garbage_collect(ssh, c);
}
if (unpause_secs != NULL && *unpause_secs != 0)
debug3_f("first channel unpauses in %d seconds",
(int)*unpause_secs);
}
/*
* Create sockets before allocating the select bitmasks.
* This is necessary for things that need to happen after reading
* the network-input but before channel_prepare_select().
*/
static void
channel_before_prepare_select(struct ssh *ssh)
{
struct ssh_channels *sc = ssh->chanctxt;
Channel *c;
u_int i, oalloc;
for (i = 0, oalloc = sc->channels_alloc; i < oalloc; i++) {
c = sc->channels[i];
if (c == NULL)
continue;
if (c->type == SSH_CHANNEL_RDYNAMIC_OPEN)
channel_before_prepare_select_rdynamic(ssh, c);
}
}
/*
* Allocate/update select bitmasks and add any bits relevant to channels in
* select bitmasks.
*/
void
channel_prepare_select(struct ssh *ssh, fd_set **readsetp, fd_set **writesetp,
int *maxfdp, u_int *nallocp, time_t *minwait_secs)
{
u_int n, sz, nfdset;
channel_before_prepare_select(ssh); /* might update channel_max_fd */
n = MAXIMUM(*maxfdp, ssh->chanctxt->channel_max_fd);
nfdset = howmany(n+1, NFDBITS);
/* Explicitly test here, because xrealloc isn't always called */
if (nfdset && SIZE_MAX / nfdset < sizeof(fd_mask))
fatal("channel_prepare_select: max_fd (%d) is too large", n);
sz = nfdset * sizeof(fd_mask);
/* perhaps check sz < nalloc/2 and shrink? */
if (*readsetp == NULL || sz > *nallocp) {
*readsetp = xreallocarray(*readsetp, nfdset, sizeof(fd_mask));
*writesetp = xreallocarray(*writesetp, nfdset, sizeof(fd_mask));
*nallocp = sz;
}
*maxfdp = n;
memset(*readsetp, 0, sz);
memset(*writesetp, 0, sz);
if (!ssh_packet_is_rekeying(ssh))
channel_handler(ssh, CHAN_PRE, *readsetp, *writesetp,
minwait_secs);
}
/*
* After select, perform any appropriate operations for channels which have
* events pending.
*/
void
channel_after_select(struct ssh *ssh, fd_set *readset, fd_set *writeset)
{
channel_handler(ssh, CHAN_POST, readset, writeset, NULL);
}
/*
* Enqueue data for channels with open or draining c->input.
*/
static void
channel_output_poll_input_open(struct ssh *ssh, Channel *c)
{
size_t len, plen;
const u_char *pkt;
int r;
if ((len = sshbuf_len(c->input)) == 0) {
if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
/*
* input-buffer is empty and read-socket shutdown:
* tell peer, that we will not send more data:
* send IEOF.
* hack for extended data: delay EOF if EFD still
* in use.
*/
if (CHANNEL_EFD_INPUT_ACTIVE(c))
debug2("channel %d: "
"ibuf_empty delayed efd %d/(%zu)",
c->self, c->efd, sshbuf_len(c->extended));
else
chan_ibuf_empty(ssh, c);
}
return;
}
if (!c->have_remote_id)
fatal_f("channel %d: no remote id", c->self);
if (c->datagram) {
/* Check datagram will fit; drop if not */
if ((r = sshbuf_get_string_direct(c->input, &pkt, &plen)) != 0)
fatal_fr(r, "channel %i: get datagram", c->self);
/*
* XXX this does tail-drop on the datagram queue which is
* usually suboptimal compared to head-drop. Better to have
* backpressure at read time? (i.e. read + discard)
*/
if (plen > c->remote_window || plen > c->remote_maxpacket) {
debug("channel %d: datagram too big", c->self);
return;
}
/* Enqueue it */
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 ||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
(r = sshpkt_put_string(ssh, pkt, plen)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "channel %i: send datagram", c->self);
c->remote_window -= plen;
return;
}
/* Enqueue packet for buffered data. */
if (len > c->remote_window)
len = c->remote_window;
if (len > c->remote_maxpacket)
len = c->remote_maxpacket;
if (len == 0)
return;
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 ||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
(r = sshpkt_put_string(ssh, sshbuf_ptr(c->input), len)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "channel %i: send data", c->self);
if ((r = sshbuf_consume(c->input, len)) != 0)
fatal_fr(r, "channel %i: consume", c->self);
c->remote_window -= len;
}
/*
* Enqueue data for channels with open c->extended in read mode.
*/
static void
channel_output_poll_extended_read(struct ssh *ssh, Channel *c)
{
size_t len;
int r;
if ((len = sshbuf_len(c->extended)) == 0)
return;
debug2("channel %d: rwin %u elen %zu euse %d", c->self,
c->remote_window, sshbuf_len(c->extended), c->extended_usage);
if (len > c->remote_window)
len = c->remote_window;
if (len > c->remote_maxpacket)
len = c->remote_maxpacket;
if (len == 0)
return;
if (!c->have_remote_id)
fatal_f("channel %d: no remote id", c->self);
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_EXTENDED_DATA)) != 0 ||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
(r = sshpkt_put_u32(ssh, SSH2_EXTENDED_DATA_STDERR)) != 0 ||
(r = sshpkt_put_string(ssh, sshbuf_ptr(c->extended), len)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "channel %i: data", c->self);
if ((r = sshbuf_consume(c->extended, len)) != 0)
fatal_fr(r, "channel %i: consume", c->self);
c->remote_window -= len;
debug2("channel %d: sent ext data %zu", c->self, len);
}
/* If there is data to send to the connection, enqueue some of it now. */
void
channel_output_poll(struct ssh *ssh)
{
struct ssh_channels *sc = ssh->chanctxt;
Channel *c;
u_int i;
for (i = 0; i < sc->channels_alloc; i++) {
c = sc->channels[i];
if (c == NULL)
continue;
/*
* We are only interested in channels that can have buffered
* incoming data.
*/
if (c->type != SSH_CHANNEL_OPEN)
continue;
if ((c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) {
/* XXX is this true? */
debug3("channel %d: will not send data after close",
c->self);
continue;
}
/* Get the amount of buffered data for this channel. */
if (c->istate == CHAN_INPUT_OPEN ||
c->istate == CHAN_INPUT_WAIT_DRAIN)
channel_output_poll_input_open(ssh, c);
/* Send extended data, i.e. stderr */
if (!(c->flags & CHAN_EOF_SENT) &&
c->extended_usage == CHAN_EXTENDED_READ)
channel_output_poll_extended_read(ssh, c);
}
}
/* -- mux proxy support */
/*
* When multiplexing channel messages for mux clients we have to deal
* with downstream messages from the mux client and upstream messages
* from the ssh server:
* 1) Handling downstream messages is straightforward and happens
* in channel_proxy_downstream():
* - We forward all messages (mostly) unmodified to the server.
* - However, in order to route messages from upstream to the correct
* downstream client, we have to replace the channel IDs used by the
* mux clients with a unique channel ID because the mux clients might
* use conflicting channel IDs.
* - so we inspect and change both SSH2_MSG_CHANNEL_OPEN and
* SSH2_MSG_CHANNEL_OPEN_CONFIRMATION messages, create a local
* SSH_CHANNEL_MUX_PROXY channel and replace the mux clients ID
* with the newly allocated channel ID.
* 2) Upstream messages are received by matching SSH_CHANNEL_MUX_PROXY
* channels and processed by channel_proxy_upstream(). The local channel ID
* is then translated back to the original mux client ID.
* 3) In both cases we need to keep track of matching SSH2_MSG_CHANNEL_CLOSE
* messages so we can clean up SSH_CHANNEL_MUX_PROXY channels.
* 4) The SSH_CHANNEL_MUX_PROXY channels also need to closed when the
* downstream mux client are removed.
* 5) Handling SSH2_MSG_CHANNEL_OPEN messages from the upstream server
* requires more work, because they are not addressed to a specific
* channel. E.g. client_request_forwarded_tcpip() needs to figure
* out whether the request is addressed to the local client or a
* specific downstream client based on the listen-address/port.
* 6) Agent and X11-Forwarding have a similar problem and are currently
* not supported as the matching session/channel cannot be identified
* easily.
*/
/*
* receive packets from downstream mux clients:
* channel callback fired on read from mux client, creates
* SSH_CHANNEL_MUX_PROXY channels and translates channel IDs
* on channel creation.
*/
int
channel_proxy_downstream(struct ssh *ssh, Channel *downstream)
{
Channel *c = NULL;
struct sshbuf *original = NULL, *modified = NULL;
const u_char *cp;
char *ctype = NULL, *listen_host = NULL;
u_char type;
size_t have;
int ret = -1, r;
u_int id, remote_id, listen_port;
/* sshbuf_dump(downstream->input, stderr); */
if ((r = sshbuf_get_string_direct(downstream->input, &cp, &have))
!= 0) {
error_fr(r, "parse");
return -1;
}
if (have < 2) {
error_f("short message");
return -1;
}
type = cp[1];
/* skip padlen + type */
cp += 2;
have -= 2;
if (ssh_packet_log_type(type))
debug3_f("channel %u: down->up: type %u",
downstream->self, type);
switch (type) {
case SSH2_MSG_CHANNEL_OPEN:
if ((original = sshbuf_from(cp, have)) == NULL ||
(modified = sshbuf_new()) == NULL) {
error_f("alloc");
goto out;
}
if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0 ||
(r = sshbuf_get_u32(original, &id)) != 0) {
error_fr(r, "parse");
goto out;
}
c = channel_new(ssh, "mux proxy", SSH_CHANNEL_MUX_PROXY,
- -1, -1, -1, 0, 0, 0, ctype, 1);
+ -1, -1, -1, 0, 0, 0, ctype, 1);
c->mux_ctx = downstream; /* point to mux client */
c->mux_downstream_id = id; /* original downstream id */
if ((r = sshbuf_put_cstring(modified, ctype)) != 0 ||
(r = sshbuf_put_u32(modified, c->self)) != 0 ||
(r = sshbuf_putb(modified, original)) != 0) {
error_fr(r, "compose");
channel_free(ssh, c);
goto out;
}
break;
case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
/*
* Almost the same as SSH2_MSG_CHANNEL_OPEN, except then we
* need to parse 'remote_id' instead of 'ctype'.
*/
if ((original = sshbuf_from(cp, have)) == NULL ||
(modified = sshbuf_new()) == NULL) {
error_f("alloc");
goto out;
}
if ((r = sshbuf_get_u32(original, &remote_id)) != 0 ||
(r = sshbuf_get_u32(original, &id)) != 0) {
error_fr(r, "parse");
goto out;
}
c = channel_new(ssh, "mux proxy", SSH_CHANNEL_MUX_PROXY,
- -1, -1, -1, 0, 0, 0, "mux-down-connect", 1);
+ -1, -1, -1, 0, 0, 0, "mux-down-connect", 1);
c->mux_ctx = downstream; /* point to mux client */
c->mux_downstream_id = id;
c->remote_id = remote_id;
c->have_remote_id = 1;
if ((r = sshbuf_put_u32(modified, remote_id)) != 0 ||
(r = sshbuf_put_u32(modified, c->self)) != 0 ||
(r = sshbuf_putb(modified, original)) != 0) {
error_fr(r, "compose");
channel_free(ssh, c);
goto out;
}
break;
case SSH2_MSG_GLOBAL_REQUEST:
if ((original = sshbuf_from(cp, have)) == NULL) {
error_f("alloc");
goto out;
}
if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0) {
error_fr(r, "parse");
goto out;
}
if (strcmp(ctype, "tcpip-forward") != 0) {
error_f("unsupported request %s", ctype);
goto out;
}
if ((r = sshbuf_get_u8(original, NULL)) != 0 ||
(r = sshbuf_get_cstring(original, &listen_host, NULL)) != 0 ||
(r = sshbuf_get_u32(original, &listen_port)) != 0) {
error_fr(r, "parse");
goto out;
}
if (listen_port > 65535) {
error_f("tcpip-forward for %s: bad port %u",
listen_host, listen_port);
goto out;
}
/* Record that connection to this host/port is permitted. */
permission_set_add(ssh, FORWARD_USER, FORWARD_LOCAL, "<mux>", -1,
listen_host, NULL, (int)listen_port, downstream);
listen_host = NULL;
break;
case SSH2_MSG_CHANNEL_CLOSE:
if (have < 4)
break;
remote_id = PEEK_U32(cp);
if ((c = channel_by_remote_id(ssh, remote_id)) != NULL) {
if (c->flags & CHAN_CLOSE_RCVD)
channel_free(ssh, c);
else
c->flags |= CHAN_CLOSE_SENT;
}
break;
}
if (modified) {
if ((r = sshpkt_start(ssh, type)) != 0 ||
(r = sshpkt_putb(ssh, modified)) != 0 ||
(r = sshpkt_send(ssh)) != 0) {
error_fr(r, "send");
goto out;
}
} else {
if ((r = sshpkt_start(ssh, type)) != 0 ||
(r = sshpkt_put(ssh, cp, have)) != 0 ||
(r = sshpkt_send(ssh)) != 0) {
error_fr(r, "send");
goto out;
}
}
ret = 0;
out:
free(ctype);
free(listen_host);
sshbuf_free(original);
sshbuf_free(modified);
return ret;
}
/*
* receive packets from upstream server and de-multiplex packets
* to correct downstream:
* implemented as a helper for channel input handlers,
* replaces local (proxy) channel ID with downstream channel ID.
*/
int
channel_proxy_upstream(Channel *c, int type, u_int32_t seq, struct ssh *ssh)
{
struct sshbuf *b = NULL;
Channel *downstream;
const u_char *cp = NULL;
size_t len;
int r;
/*
* When receiving packets from the peer we need to check whether we
* need to forward the packets to the mux client. In this case we
* restore the original channel id and keep track of CLOSE messages,
* so we can cleanup the channel.
*/
if (c == NULL || c->type != SSH_CHANNEL_MUX_PROXY)
return 0;
if ((downstream = c->mux_ctx) == NULL)
return 0;
switch (type) {
case SSH2_MSG_CHANNEL_CLOSE:
case SSH2_MSG_CHANNEL_DATA:
case SSH2_MSG_CHANNEL_EOF:
case SSH2_MSG_CHANNEL_EXTENDED_DATA:
case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
case SSH2_MSG_CHANNEL_OPEN_FAILURE:
case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
case SSH2_MSG_CHANNEL_SUCCESS:
case SSH2_MSG_CHANNEL_FAILURE:
case SSH2_MSG_CHANNEL_REQUEST:
break;
default:
debug2_f("channel %u: unsupported type %u", c->self, type);
return 0;
}
if ((b = sshbuf_new()) == NULL) {
error_f("alloc reply");
goto out;
}
/* get remaining payload (after id) */
cp = sshpkt_ptr(ssh, &len);
if (cp == NULL) {
error_f("no packet");
goto out;
}
/* translate id and send to muxclient */
if ((r = sshbuf_put_u8(b, 0)) != 0 || /* padlen */
(r = sshbuf_put_u8(b, type)) != 0 ||
(r = sshbuf_put_u32(b, c->mux_downstream_id)) != 0 ||
(r = sshbuf_put(b, cp, len)) != 0 ||
(r = sshbuf_put_stringb(downstream->output, b)) != 0) {
error_fr(r, "compose muxclient");
goto out;
}
/* sshbuf_dump(b, stderr); */
if (ssh_packet_log_type(type))
debug3_f("channel %u: up->down: type %u", c->self, type);
out:
/* update state */
switch (type) {
case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
/* record remote_id for SSH2_MSG_CHANNEL_CLOSE */
if (cp && len > 4) {
c->remote_id = PEEK_U32(cp);
c->have_remote_id = 1;
}
break;
case SSH2_MSG_CHANNEL_CLOSE:
if (c->flags & CHAN_CLOSE_SENT)
channel_free(ssh, c);
else
c->flags |= CHAN_CLOSE_RCVD;
break;
}
sshbuf_free(b);
return 1;
}
/* -- protocol input */
/* Parse a channel ID from the current packet */
static int
channel_parse_id(struct ssh *ssh, const char *where, const char *what)
{
u_int32_t id;
int r;
if ((r = sshpkt_get_u32(ssh, &id)) != 0) {
error_r(r, "%s: parse id", where);
ssh_packet_disconnect(ssh, "Invalid %s message", what);
}
if (id > INT_MAX) {
error_r(r, "%s: bad channel id %u", where, id);
ssh_packet_disconnect(ssh, "Invalid %s channel id", what);
}
return (int)id;
}
/* Lookup a channel from an ID in the current packet */
static Channel *
channel_from_packet_id(struct ssh *ssh, const char *where, const char *what)
{
int id = channel_parse_id(ssh, where, what);
Channel *c;
if ((c = channel_lookup(ssh, id)) == NULL) {
ssh_packet_disconnect(ssh,
"%s packet referred to nonexistent channel %d", what, id);
}
return c;
}
int
channel_input_data(int type, u_int32_t seq, struct ssh *ssh)
{
const u_char *data;
size_t data_len, win_len;
Channel *c = channel_from_packet_id(ssh, __func__, "data");
int r;
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
/* Ignore any data for non-open channels (might happen on close) */
if (c->type != SSH_CHANNEL_OPEN &&
c->type != SSH_CHANNEL_RDYNAMIC_OPEN &&
c->type != SSH_CHANNEL_RDYNAMIC_FINISH &&
c->type != SSH_CHANNEL_X11_OPEN)
return 0;
/* Get the data. */
if ((r = sshpkt_get_string_direct(ssh, &data, &data_len)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
fatal_fr(r, "channel %i: get data", c->self);
win_len = data_len;
if (c->datagram)
win_len += 4; /* string length header */
/*
* The sending side reduces its window as it sends data, so we
* must 'fake' consumption of the data in order to ensure that window
* updates are sent back. Otherwise the connection might deadlock.
*/
if (c->ostate != CHAN_OUTPUT_OPEN) {
c->local_window -= win_len;
c->local_consumed += win_len;
return 0;
}
if (win_len > c->local_maxpacket) {
logit("channel %d: rcvd big packet %zu, maxpack %u",
c->self, win_len, c->local_maxpacket);
return 0;
}
if (win_len > c->local_window) {
logit("channel %d: rcvd too much data %zu, win %u",
c->self, win_len, c->local_window);
return 0;
}
c->local_window -= win_len;
if (c->datagram) {
if ((r = sshbuf_put_string(c->output, data, data_len)) != 0)
fatal_fr(r, "channel %i: append datagram", c->self);
} else if ((r = sshbuf_put(c->output, data, data_len)) != 0)
fatal_fr(r, "channel %i: append data", c->self);
return 0;
}
int
channel_input_extended_data(int type, u_int32_t seq, struct ssh *ssh)
{
const u_char *data;
size_t data_len;
u_int32_t tcode;
Channel *c = channel_from_packet_id(ssh, __func__, "extended data");
int r;
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
if (c->type != SSH_CHANNEL_OPEN) {
logit("channel %d: ext data for non open", c->self);
return 0;
}
if (c->flags & CHAN_EOF_RCVD) {
if (ssh->compat & SSH_BUG_EXTEOF)
debug("channel %d: accepting ext data after eof",
c->self);
else
ssh_packet_disconnect(ssh, "Received extended_data "
"after EOF on channel %d.", c->self);
}
if ((r = sshpkt_get_u32(ssh, &tcode)) != 0) {
error_fr(r, "parse tcode");
ssh_packet_disconnect(ssh, "Invalid extended_data message");
}
if (c->efd == -1 ||
c->extended_usage != CHAN_EXTENDED_WRITE ||
tcode != SSH2_EXTENDED_DATA_STDERR) {
logit("channel %d: bad ext data", c->self);
return 0;
}
if ((r = sshpkt_get_string_direct(ssh, &data, &data_len)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0) {
error_fr(r, "parse data");
ssh_packet_disconnect(ssh, "Invalid extended_data message");
}
if (data_len > c->local_window) {
logit("channel %d: rcvd too much extended_data %zu, win %u",
c->self, data_len, c->local_window);
return 0;
}
debug2("channel %d: rcvd ext data %zu", c->self, data_len);
/* XXX sshpkt_getb? */
if ((r = sshbuf_put(c->extended, data, data_len)) != 0)
error_fr(r, "append");
c->local_window -= data_len;
return 0;
}
int
channel_input_ieof(int type, u_int32_t seq, struct ssh *ssh)
{
Channel *c = channel_from_packet_id(ssh, __func__, "ieof");
int r;
if ((r = sshpkt_get_end(ssh)) != 0) {
error_fr(r, "parse data");
ssh_packet_disconnect(ssh, "Invalid ieof message");
}
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
chan_rcvd_ieof(ssh, c);
/* XXX force input close */
if (c->force_drain && c->istate == CHAN_INPUT_OPEN) {
debug("channel %d: FORCE input drain", c->self);
c->istate = CHAN_INPUT_WAIT_DRAIN;
if (sshbuf_len(c->input) == 0)
chan_ibuf_empty(ssh, c);
}
return 0;
}
int
channel_input_oclose(int type, u_int32_t seq, struct ssh *ssh)
{
Channel *c = channel_from_packet_id(ssh, __func__, "oclose");
int r;
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
if ((r = sshpkt_get_end(ssh)) != 0) {
error_fr(r, "parse data");
ssh_packet_disconnect(ssh, "Invalid oclose message");
}
chan_rcvd_oclose(ssh, c);
return 0;
}
int
channel_input_open_confirmation(int type, u_int32_t seq, struct ssh *ssh)
{
Channel *c = channel_from_packet_id(ssh, __func__, "open confirmation");
u_int32_t remote_window, remote_maxpacket;
int r;
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
if (c->type != SSH_CHANNEL_OPENING)
ssh_packet_disconnect(ssh, "Received open confirmation for "
"non-opening channel %d.", c->self);
/*
* Record the remote channel number and mark that the channel
* is now open.
*/
if ((r = sshpkt_get_u32(ssh, &c->remote_id)) != 0 ||
(r = sshpkt_get_u32(ssh, &remote_window)) != 0 ||
(r = sshpkt_get_u32(ssh, &remote_maxpacket)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0) {
error_fr(r, "window/maxpacket");
ssh_packet_disconnect(ssh, "Invalid open confirmation message");
}
c->have_remote_id = 1;
c->remote_window = remote_window;
c->remote_maxpacket = remote_maxpacket;
c->type = SSH_CHANNEL_OPEN;
if (c->open_confirm) {
debug2_f("channel %d: callback start", c->self);
c->open_confirm(ssh, c->self, 1, c->open_confirm_ctx);
debug2_f("channel %d: callback done", c->self);
}
debug2("channel %d: open confirm rwindow %u rmax %u", c->self,
c->remote_window, c->remote_maxpacket);
return 0;
}
static char *
reason2txt(int reason)
{
switch (reason) {
case SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED:
return "administratively prohibited";
case SSH2_OPEN_CONNECT_FAILED:
return "connect failed";
case SSH2_OPEN_UNKNOWN_CHANNEL_TYPE:
return "unknown channel type";
case SSH2_OPEN_RESOURCE_SHORTAGE:
return "resource shortage";
}
return "unknown reason";
}
int
channel_input_open_failure(int type, u_int32_t seq, struct ssh *ssh)
{
Channel *c = channel_from_packet_id(ssh, __func__, "open failure");
u_int32_t reason;
char *msg = NULL;
int r;
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
if (c->type != SSH_CHANNEL_OPENING)
ssh_packet_disconnect(ssh, "Received open failure for "
"non-opening channel %d.", c->self);
if ((r = sshpkt_get_u32(ssh, &reason)) != 0) {
error_fr(r, "parse reason");
ssh_packet_disconnect(ssh, "Invalid open failure message");
}
/* skip language */
if ((r = sshpkt_get_cstring(ssh, &msg, NULL)) != 0 ||
(r = sshpkt_get_string_direct(ssh, NULL, NULL)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0) {
error_fr(r, "parse msg/lang");
ssh_packet_disconnect(ssh, "Invalid open failure message");
}
logit("channel %d: open failed: %s%s%s", c->self,
reason2txt(reason), msg ? ": ": "", msg ? msg : "");
free(msg);
if (c->open_confirm) {
debug2_f("channel %d: callback start", c->self);
c->open_confirm(ssh, c->self, 0, c->open_confirm_ctx);
debug2_f("channel %d: callback done", c->self);
}
/* Schedule the channel for cleanup/deletion. */
chan_mark_dead(ssh, c);
return 0;
}
int
channel_input_window_adjust(int type, u_int32_t seq, struct ssh *ssh)
{
int id = channel_parse_id(ssh, __func__, "window adjust");
Channel *c;
u_int32_t adjust;
u_int new_rwin;
int r;
if ((c = channel_lookup(ssh, id)) == NULL) {
logit("Received window adjust for non-open channel %d.", id);
return 0;
}
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
if ((r = sshpkt_get_u32(ssh, &adjust)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0) {
error_fr(r, "parse adjust");
ssh_packet_disconnect(ssh, "Invalid window adjust message");
}
debug2("channel %d: rcvd adjust %u", c->self, adjust);
if ((new_rwin = c->remote_window + adjust) < c->remote_window) {
fatal("channel %d: adjust %u overflows remote window %u",
c->self, adjust, c->remote_window);
}
c->remote_window = new_rwin;
return 0;
}
int
channel_input_status_confirm(int type, u_int32_t seq, struct ssh *ssh)
{
int id = channel_parse_id(ssh, __func__, "status confirm");
Channel *c;
struct channel_confirm *cc;
/* Reset keepalive timeout */
ssh_packet_set_alive_timeouts(ssh, 0);
debug2_f("type %d id %d", type, id);
if ((c = channel_lookup(ssh, id)) == NULL) {
logit_f("%d: unknown", id);
return 0;
}
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
if (sshpkt_get_end(ssh) != 0)
ssh_packet_disconnect(ssh, "Invalid status confirm message");
if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL)
return 0;
cc->cb(ssh, type, c, cc->ctx);
TAILQ_REMOVE(&c->status_confirms, cc, entry);
freezero(cc, sizeof(*cc));
return 0;
}
/* -- tcp forwarding */
void
channel_set_af(struct ssh *ssh, int af)
{
ssh->chanctxt->IPv4or6 = af;
}
/*
* Determine whether or not a port forward listens to loopback, the
* specified address or wildcard. On the client, a specified bind
* address will always override gateway_ports. On the server, a
* gateway_ports of 1 (``yes'') will override the client's specification
* and force a wildcard bind, whereas a value of 2 (``clientspecified'')
* will bind to whatever address the client asked for.
*
* Special-case listen_addrs are:
*
* "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR
* "" (empty string), "*" -> wildcard v4/v6
* "localhost" -> loopback v4/v6
* "127.0.0.1" / "::1" -> accepted even if gateway_ports isn't set
*/
static const char *
channel_fwd_bind_addr(struct ssh *ssh, const char *listen_addr, int *wildcardp,
int is_client, struct ForwardOptions *fwd_opts)
{
const char *addr = NULL;
int wildcard = 0;
if (listen_addr == NULL) {
/* No address specified: default to gateway_ports setting */
if (fwd_opts->gateway_ports)
wildcard = 1;
} else if (fwd_opts->gateway_ports || is_client) {
if (((ssh->compat & SSH_OLD_FORWARD_ADDR) &&
strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
*listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
(!is_client && fwd_opts->gateway_ports == 1)) {
wildcard = 1;
/*
* Notify client if they requested a specific listen
* address and it was overridden.
*/
if (*listen_addr != '\0' &&
strcmp(listen_addr, "0.0.0.0") != 0 &&
strcmp(listen_addr, "*") != 0) {
ssh_packet_send_debug(ssh,
"Forwarding listen address "
"\"%s\" overridden by server "
"GatewayPorts", listen_addr);
}
} else if (strcmp(listen_addr, "localhost") != 0 ||
strcmp(listen_addr, "127.0.0.1") == 0 ||
strcmp(listen_addr, "::1") == 0) {
/*
* Accept explicit localhost address when
* GatewayPorts=yes. The "localhost" hostname is
* deliberately skipped here so it will listen on all
* available local address families.
*/
addr = listen_addr;
}
} else if (strcmp(listen_addr, "127.0.0.1") == 0 ||
strcmp(listen_addr, "::1") == 0) {
/*
* If a specific IPv4/IPv6 localhost address has been
* requested then accept it even if gateway_ports is in
* effect. This allows the client to prefer IPv4 or IPv6.
*/
addr = listen_addr;
}
if (wildcardp != NULL)
*wildcardp = wildcard;
return addr;
}
static int
channel_setup_fwd_listener_tcpip(struct ssh *ssh, int type,
struct Forward *fwd, int *allocated_listen_port,
struct ForwardOptions *fwd_opts)
{
Channel *c;
int sock, r, success = 0, wildcard = 0, is_client;
struct addrinfo hints, *ai, *aitop;
const char *host, *addr;
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
in_port_t *lport_p;
is_client = (type == SSH_CHANNEL_PORT_LISTENER);
if (is_client && fwd->connect_path != NULL) {
host = fwd->connect_path;
} else {
host = (type == SSH_CHANNEL_RPORT_LISTENER) ?
fwd->listen_host : fwd->connect_host;
if (host == NULL) {
error("No forward host name.");
return 0;
}
if (strlen(host) >= NI_MAXHOST) {
error("Forward host name too long.");
return 0;
}
}
/* Determine the bind address, cf. channel_fwd_bind_addr() comment */
addr = channel_fwd_bind_addr(ssh, fwd->listen_host, &wildcard,
is_client, fwd_opts);
debug3_f("type %d wildcard %d addr %s", type, wildcard,
(addr == NULL) ? "NULL" : addr);
/*
* getaddrinfo returns a loopback address if the hostname is
* set to NULL and hints.ai_flags is not AI_PASSIVE
*/
memset(&hints, 0, sizeof(hints));
hints.ai_family = ssh->chanctxt->IPv4or6;
hints.ai_flags = wildcard ? AI_PASSIVE : 0;
hints.ai_socktype = SOCK_STREAM;
snprintf(strport, sizeof strport, "%d", fwd->listen_port);
if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) {
if (addr == NULL) {
/* This really shouldn't happen */
ssh_packet_disconnect(ssh, "getaddrinfo: fatal error: %s",
ssh_gai_strerror(r));
} else {
error_f("getaddrinfo(%.64s): %s", addr,
ssh_gai_strerror(r));
}
return 0;
}
if (allocated_listen_port != NULL)
*allocated_listen_port = 0;
for (ai = aitop; ai; ai = ai->ai_next) {
switch (ai->ai_family) {
case AF_INET:
lport_p = &((struct sockaddr_in *)ai->ai_addr)->
sin_port;
break;
case AF_INET6:
lport_p = &((struct sockaddr_in6 *)ai->ai_addr)->
sin6_port;
break;
default:
continue;
}
/*
* If allocating a port for -R forwards, then use the
* same port for all address families.
*/
if (type == SSH_CHANNEL_RPORT_LISTENER &&
fwd->listen_port == 0 && allocated_listen_port != NULL &&
*allocated_listen_port > 0)
*lport_p = htons(*allocated_listen_port);
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
strport, sizeof(strport),
NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
error_f("getnameinfo failed");
continue;
}
/* Create a port to listen for the host. */
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sock == -1) {
/* this is no error since kernel may not support ipv6 */
verbose("socket [%s]:%s: %.100s", ntop, strport,
strerror(errno));
continue;
}
set_reuseaddr(sock);
if (ai->ai_family == AF_INET6)
sock_set_v6only(sock);
debug("Local forwarding listening on %s port %s.",
ntop, strport);
/* Bind the socket to the address. */
if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
/*
* address can be in if use ipv6 address is
* already bound
*/
if (!ai->ai_next)
error("bind [%s]:%s: %.100s",
ntop, strport, strerror(errno));
else
verbose("bind [%s]:%s: %.100s",
ntop, strport, strerror(errno));
close(sock);
continue;
}
/* Start listening for connections on the socket. */
if (listen(sock, SSH_LISTEN_BACKLOG) == -1) {
error("listen: %.100s", strerror(errno));
error("listen [%s]:%s: %.100s", ntop, strport,
strerror(errno));
close(sock);
continue;
}
/*
* fwd->listen_port == 0 requests a dynamically allocated port -
* record what we got.
*/
if (type == SSH_CHANNEL_RPORT_LISTENER &&
fwd->listen_port == 0 &&
allocated_listen_port != NULL &&
*allocated_listen_port == 0) {
*allocated_listen_port = get_local_port(sock);
debug("Allocated listen port %d",
*allocated_listen_port);
}
/* Allocate a channel number for the socket. */
c = channel_new(ssh, "port listener", type, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
0, "port listener", 1);
c->path = xstrdup(host);
c->host_port = fwd->connect_port;
c->listening_addr = addr == NULL ? NULL : xstrdup(addr);
if (fwd->listen_port == 0 && allocated_listen_port != NULL &&
!(ssh->compat & SSH_BUG_DYNAMIC_RPORT))
c->listening_port = *allocated_listen_port;
else
c->listening_port = fwd->listen_port;
success = 1;
}
if (success == 0)
error_f("cannot listen to port: %d", fwd->listen_port);
freeaddrinfo(aitop);
return success;
}
static int
channel_setup_fwd_listener_streamlocal(struct ssh *ssh, int type,
struct Forward *fwd, struct ForwardOptions *fwd_opts)
{
struct sockaddr_un sunaddr;
const char *path;
Channel *c;
int port, sock;
mode_t omask;
switch (type) {
case SSH_CHANNEL_UNIX_LISTENER:
if (fwd->connect_path != NULL) {
if (strlen(fwd->connect_path) > sizeof(sunaddr.sun_path)) {
error("Local connecting path too long: %s",
fwd->connect_path);
return 0;
}
path = fwd->connect_path;
port = PORT_STREAMLOCAL;
} else {
if (fwd->connect_host == NULL) {
error("No forward host name.");
return 0;
}
if (strlen(fwd->connect_host) >= NI_MAXHOST) {
error("Forward host name too long.");
return 0;
}
path = fwd->connect_host;
port = fwd->connect_port;
}
break;
case SSH_CHANNEL_RUNIX_LISTENER:
path = fwd->listen_path;
port = PORT_STREAMLOCAL;
break;
default:
error_f("unexpected channel type %d", type);
return 0;
}
if (fwd->listen_path == NULL) {
error("No forward path name.");
return 0;
}
if (strlen(fwd->listen_path) > sizeof(sunaddr.sun_path)) {
error("Local listening path too long: %s", fwd->listen_path);
return 0;
}
debug3_f("type %d path %s", type, fwd->listen_path);
/* Start a Unix domain listener. */
omask = umask(fwd_opts->streamlocal_bind_mask);
sock = unix_listener(fwd->listen_path, SSH_LISTEN_BACKLOG,
fwd_opts->streamlocal_bind_unlink);
umask(omask);
if (sock < 0)
return 0;
debug("Local forwarding listening on path %s.", fwd->listen_path);
/* Allocate a channel number for the socket. */
c = channel_new(ssh, "unix listener", type, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
0, "unix listener", 1);
c->path = xstrdup(path);
c->host_port = port;
c->listening_port = PORT_STREAMLOCAL;
c->listening_addr = xstrdup(fwd->listen_path);
return 1;
}
static int
channel_cancel_rport_listener_tcpip(struct ssh *ssh,
const char *host, u_short port)
{
u_int i;
int found = 0;
for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
Channel *c = ssh->chanctxt->channels[i];
if (c == NULL || c->type != SSH_CHANNEL_RPORT_LISTENER)
continue;
if (strcmp(c->path, host) == 0 && c->listening_port == port) {
debug2_f("close channel %d", i);
channel_free(ssh, c);
found = 1;
}
}
return found;
}
static int
channel_cancel_rport_listener_streamlocal(struct ssh *ssh, const char *path)
{
u_int i;
int found = 0;
for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
Channel *c = ssh->chanctxt->channels[i];
if (c == NULL || c->type != SSH_CHANNEL_RUNIX_LISTENER)
continue;
if (c->path == NULL)
continue;
if (strcmp(c->path, path) == 0) {
debug2_f("close channel %d", i);
channel_free(ssh, c);
found = 1;
}
}
return found;
}
int
channel_cancel_rport_listener(struct ssh *ssh, struct Forward *fwd)
{
if (fwd->listen_path != NULL) {
return channel_cancel_rport_listener_streamlocal(ssh,
fwd->listen_path);
} else {
return channel_cancel_rport_listener_tcpip(ssh,
fwd->listen_host, fwd->listen_port);
}
}
static int
channel_cancel_lport_listener_tcpip(struct ssh *ssh,
const char *lhost, u_short lport, int cport,
struct ForwardOptions *fwd_opts)
{
u_int i;
int found = 0;
const char *addr = channel_fwd_bind_addr(ssh, lhost, NULL, 1, fwd_opts);
for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
Channel *c = ssh->chanctxt->channels[i];
if (c == NULL || c->type != SSH_CHANNEL_PORT_LISTENER)
continue;
if (c->listening_port != lport)
continue;
if (cport == CHANNEL_CANCEL_PORT_STATIC) {
/* skip dynamic forwardings */
if (c->host_port == 0)
continue;
} else {
if (c->host_port != cport)
continue;
}
if ((c->listening_addr == NULL && addr != NULL) ||
(c->listening_addr != NULL && addr == NULL))
continue;
if (addr == NULL || strcmp(c->listening_addr, addr) == 0) {
debug2_f("close channel %d", i);
channel_free(ssh, c);
found = 1;
}
}
return found;
}
static int
channel_cancel_lport_listener_streamlocal(struct ssh *ssh, const char *path)
{
u_int i;
int found = 0;
if (path == NULL) {
error_f("no path specified.");
return 0;
}
for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
Channel *c = ssh->chanctxt->channels[i];
if (c == NULL || c->type != SSH_CHANNEL_UNIX_LISTENER)
continue;
if (c->listening_addr == NULL)
continue;
if (strcmp(c->listening_addr, path) == 0) {
debug2_f("close channel %d", i);
channel_free(ssh, c);
found = 1;
}
}
return found;
}
int
channel_cancel_lport_listener(struct ssh *ssh,
struct Forward *fwd, int cport, struct ForwardOptions *fwd_opts)
{
if (fwd->listen_path != NULL) {
return channel_cancel_lport_listener_streamlocal(ssh,
fwd->listen_path);
} else {
return channel_cancel_lport_listener_tcpip(ssh,
fwd->listen_host, fwd->listen_port, cport, fwd_opts);
}
}
/* protocol local port fwd, used by ssh */
int
channel_setup_local_fwd_listener(struct ssh *ssh,
struct Forward *fwd, struct ForwardOptions *fwd_opts)
{
if (fwd->listen_path != NULL) {
return channel_setup_fwd_listener_streamlocal(ssh,
SSH_CHANNEL_UNIX_LISTENER, fwd, fwd_opts);
} else {
return channel_setup_fwd_listener_tcpip(ssh,
SSH_CHANNEL_PORT_LISTENER, fwd, NULL, fwd_opts);
}
}
/* Matches a remote forwarding permission against a requested forwarding */
static int
remote_open_match(struct permission *allowed_open, struct Forward *fwd)
{
int ret;
char *lhost;
/* XXX add ACLs for streamlocal */
if (fwd->listen_path != NULL)
return 1;
if (fwd->listen_host == NULL || allowed_open->listen_host == NULL)
return 0;
if (allowed_open->listen_port != FWD_PERMIT_ANY_PORT &&
allowed_open->listen_port != fwd->listen_port)
return 0;
/* Match hostnames case-insensitively */
lhost = xstrdup(fwd->listen_host);
lowercase(lhost);
ret = match_pattern(lhost, allowed_open->listen_host);
free(lhost);
return ret;
}
/* Checks whether a requested remote forwarding is permitted */
static int
check_rfwd_permission(struct ssh *ssh, struct Forward *fwd)
{
struct ssh_channels *sc = ssh->chanctxt;
struct permission_set *pset = &sc->remote_perms;
u_int i, permit, permit_adm = 1;
struct permission *perm;
/* XXX apply GatewayPorts override before checking? */
permit = pset->all_permitted;
if (!permit) {
for (i = 0; i < pset->num_permitted_user; i++) {
perm = &pset->permitted_user[i];
if (remote_open_match(perm, fwd)) {
permit = 1;
break;
}
}
}
if (pset->num_permitted_admin > 0) {
permit_adm = 0;
for (i = 0; i < pset->num_permitted_admin; i++) {
perm = &pset->permitted_admin[i];
if (remote_open_match(perm, fwd)) {
permit_adm = 1;
break;
}
}
}
return permit && permit_adm;
}
/* protocol v2 remote port fwd, used by sshd */
int
channel_setup_remote_fwd_listener(struct ssh *ssh, struct Forward *fwd,
int *allocated_listen_port, struct ForwardOptions *fwd_opts)
{
if (!check_rfwd_permission(ssh, fwd)) {
ssh_packet_send_debug(ssh, "port forwarding refused");
if (fwd->listen_path != NULL)
/* XXX always allowed, see remote_open_match() */
logit("Received request from %.100s port %d to "
"remote forward to path \"%.100s\", "
"but the request was denied.",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
fwd->listen_path);
else if(fwd->listen_host != NULL)
logit("Received request from %.100s port %d to "
"remote forward to host %.100s port %d, "
"but the request was denied.",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
fwd->listen_host, fwd->listen_port );
else
logit("Received request from %.100s port %d to remote "
"forward, but the request was denied.",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
return 0;
}
if (fwd->listen_path != NULL) {
return channel_setup_fwd_listener_streamlocal(ssh,
SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts);
} else {
return channel_setup_fwd_listener_tcpip(ssh,
SSH_CHANNEL_RPORT_LISTENER, fwd, allocated_listen_port,
fwd_opts);
}
}
/*
* Translate the requested rfwd listen host to something usable for
* this server.
*/
static const char *
channel_rfwd_bind_host(const char *listen_host)
{
if (listen_host == NULL) {
return "localhost";
} else if (*listen_host == '\0' || strcmp(listen_host, "*") == 0) {
return "";
} else
return listen_host;
}
/*
* Initiate forwarding of connections to port "port" on remote host through
* the secure channel to host:port from local side.
* Returns handle (index) for updating the dynamic listen port with
* channel_update_permission().
*/
int
channel_request_remote_forwarding(struct ssh *ssh, struct Forward *fwd)
{
int r, success = 0, idx = -1;
char *host_to_connect, *listen_host, *listen_path;
int port_to_connect, listen_port;
/* Send the forward request to the remote side. */
if (fwd->listen_path != NULL) {
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh,
"streamlocal-forward@openssh.com")) != 0 ||
(r = sshpkt_put_u8(ssh, 1)) != 0 || /* want reply */
(r = sshpkt_put_cstring(ssh, fwd->listen_path)) != 0 ||
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
fatal_fr(r, "request streamlocal");
} else {
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, "tcpip-forward")) != 0 ||
(r = sshpkt_put_u8(ssh, 1)) != 0 || /* want reply */
(r = sshpkt_put_cstring(ssh,
channel_rfwd_bind_host(fwd->listen_host))) != 0 ||
(r = sshpkt_put_u32(ssh, fwd->listen_port)) != 0 ||
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
fatal_fr(r, "request tcpip-forward");
}
/* Assume that server accepts the request */
success = 1;
if (success) {
/* Record that connection to this host/port is permitted. */
host_to_connect = listen_host = listen_path = NULL;
port_to_connect = listen_port = 0;
if (fwd->connect_path != NULL) {
host_to_connect = xstrdup(fwd->connect_path);
port_to_connect = PORT_STREAMLOCAL;
} else {
host_to_connect = xstrdup(fwd->connect_host);
port_to_connect = fwd->connect_port;
}
if (fwd->listen_path != NULL) {
listen_path = xstrdup(fwd->listen_path);
listen_port = PORT_STREAMLOCAL;
} else {
if (fwd->listen_host != NULL)
listen_host = xstrdup(fwd->listen_host);
listen_port = fwd->listen_port;
}
idx = permission_set_add(ssh, FORWARD_USER, FORWARD_LOCAL,
host_to_connect, port_to_connect,
listen_host, listen_path, listen_port, NULL);
}
return idx;
}
static int
open_match(struct permission *allowed_open, const char *requestedhost,
int requestedport)
{
if (allowed_open->host_to_connect == NULL)
return 0;
if (allowed_open->port_to_connect != FWD_PERMIT_ANY_PORT &&
allowed_open->port_to_connect != requestedport)
return 0;
if (strcmp(allowed_open->host_to_connect, FWD_PERMIT_ANY_HOST) != 0 &&
strcmp(allowed_open->host_to_connect, requestedhost) != 0)
return 0;
return 1;
}
/*
* Note that in the listen host/port case
* we don't support FWD_PERMIT_ANY_PORT and
* need to translate between the configured-host (listen_host)
* and what we've sent to the remote server (channel_rfwd_bind_host)
*/
static int
open_listen_match_tcpip(struct permission *allowed_open,
const char *requestedhost, u_short requestedport, int translate)
{
const char *allowed_host;
if (allowed_open->host_to_connect == NULL)
return 0;
if (allowed_open->listen_port != requestedport)
return 0;
if (!translate && allowed_open->listen_host == NULL &&
requestedhost == NULL)
return 1;
allowed_host = translate ?
channel_rfwd_bind_host(allowed_open->listen_host) :
allowed_open->listen_host;
if (allowed_host == NULL || requestedhost == NULL ||
strcmp(allowed_host, requestedhost) != 0)
return 0;
return 1;
}
static int
open_listen_match_streamlocal(struct permission *allowed_open,
const char *requestedpath)
{
if (allowed_open->host_to_connect == NULL)
return 0;
if (allowed_open->listen_port != PORT_STREAMLOCAL)
return 0;
if (allowed_open->listen_path == NULL ||
strcmp(allowed_open->listen_path, requestedpath) != 0)
return 0;
return 1;
}
/*
* Request cancellation of remote forwarding of connection host:port from
* local side.
*/
static int
channel_request_rforward_cancel_tcpip(struct ssh *ssh,
const char *host, u_short port)
{
struct ssh_channels *sc = ssh->chanctxt;
struct permission_set *pset = &sc->local_perms;
int r;
u_int i;
struct permission *perm = NULL;
for (i = 0; i < pset->num_permitted_user; i++) {
perm = &pset->permitted_user[i];
if (open_listen_match_tcpip(perm, host, port, 0))
break;
perm = NULL;
}
if (perm == NULL) {
debug_f("requested forward not found");
return -1;
}
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, "cancel-tcpip-forward")) != 0 ||
(r = sshpkt_put_u8(ssh, 0)) != 0 || /* want reply */
(r = sshpkt_put_cstring(ssh, channel_rfwd_bind_host(host))) != 0 ||
(r = sshpkt_put_u32(ssh, port)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send cancel");
fwd_perm_clear(perm); /* unregister */
return 0;
}
/*
* Request cancellation of remote forwarding of Unix domain socket
* path from local side.
*/
static int
channel_request_rforward_cancel_streamlocal(struct ssh *ssh, const char *path)
{
struct ssh_channels *sc = ssh->chanctxt;
struct permission_set *pset = &sc->local_perms;
int r;
u_int i;
struct permission *perm = NULL;
for (i = 0; i < pset->num_permitted_user; i++) {
perm = &pset->permitted_user[i];
if (open_listen_match_streamlocal(perm, path))
break;
perm = NULL;
}
if (perm == NULL) {
debug_f("requested forward not found");
return -1;
}
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh,
"cancel-streamlocal-forward@openssh.com")) != 0 ||
(r = sshpkt_put_u8(ssh, 0)) != 0 || /* want reply */
(r = sshpkt_put_cstring(ssh, path)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send cancel");
fwd_perm_clear(perm); /* unregister */
return 0;
}
/*
* Request cancellation of remote forwarding of a connection from local side.
*/
int
channel_request_rforward_cancel(struct ssh *ssh, struct Forward *fwd)
{
if (fwd->listen_path != NULL) {
return channel_request_rforward_cancel_streamlocal(ssh,
fwd->listen_path);
} else {
return channel_request_rforward_cancel_tcpip(ssh,
fwd->listen_host,
fwd->listen_port ? fwd->listen_port : fwd->allocated_port);
}
}
/*
* Permits opening to any host/port if permitted_user[] is empty. This is
* usually called by the server, because the user could connect to any port
* anyway, and the server has no way to know but to trust the client anyway.
*/
void
channel_permit_all(struct ssh *ssh, int where)
{
struct permission_set *pset = permission_set_get(ssh, where);
if (pset->num_permitted_user == 0)
pset->all_permitted = 1;
}
/*
* Permit the specified host/port for forwarding.
*/
void
channel_add_permission(struct ssh *ssh, int who, int where,
char *host, int port)
{
int local = where == FORWARD_LOCAL;
struct permission_set *pset = permission_set_get(ssh, where);
debug("allow %s forwarding to host %s port %d",
fwd_ident(who, where), host, port);
/*
* Remote forwards set listen_host/port, local forwards set
* host/port_to_connect.
*/
permission_set_add(ssh, who, where,
local ? host : 0, local ? port : 0,
local ? NULL : host, NULL, local ? 0 : port, NULL);
pset->all_permitted = 0;
}
/*
* Administratively disable forwarding.
*/
void
channel_disable_admin(struct ssh *ssh, int where)
{
channel_clear_permission(ssh, FORWARD_ADM, where);
permission_set_add(ssh, FORWARD_ADM, where,
NULL, 0, NULL, NULL, 0, NULL);
}
/*
* Clear a list of permitted opens.
*/
void
channel_clear_permission(struct ssh *ssh, int who, int where)
{
struct permission **permp;
u_int *npermp;
permission_set_get_array(ssh, who, where, &permp, &npermp);
*permp = xrecallocarray(*permp, *npermp, 0, sizeof(**permp));
*npermp = 0;
}
/*
* Update the listen port for a dynamic remote forward, after
* the actual 'newport' has been allocated. If 'newport' < 0 is
* passed then they entry will be invalidated.
*/
void
channel_update_permission(struct ssh *ssh, int idx, int newport)
{
struct permission_set *pset = &ssh->chanctxt->local_perms;
if (idx < 0 || (u_int)idx >= pset->num_permitted_user) {
debug_f("index out of range: %d num_permitted_user %d",
idx, pset->num_permitted_user);
return;
}
debug("%s allowed port %d for forwarding to host %s port %d",
newport > 0 ? "Updating" : "Removing",
newport,
pset->permitted_user[idx].host_to_connect,
pset->permitted_user[idx].port_to_connect);
if (newport <= 0)
fwd_perm_clear(&pset->permitted_user[idx]);
else {
pset->permitted_user[idx].listen_port =
(ssh->compat & SSH_BUG_DYNAMIC_RPORT) ? 0 : newport;
}
}
/* returns port number, FWD_PERMIT_ANY_PORT or -1 on error */
int
permitopen_port(const char *p)
{
int port;
if (strcmp(p, "*") == 0)
return FWD_PERMIT_ANY_PORT;
if ((port = a2port(p)) > 0)
return port;
return -1;
}
/* Try to start non-blocking connect to next host in cctx list */
static int
connect_next(struct channel_connect *cctx)
{
int sock, saved_errno;
struct sockaddr_un *sunaddr;
char ntop[NI_MAXHOST];
char strport[MAXIMUM(NI_MAXSERV, sizeof(sunaddr->sun_path))];
for (; cctx->ai; cctx->ai = cctx->ai->ai_next) {
switch (cctx->ai->ai_family) {
case AF_UNIX:
/* unix:pathname instead of host:port */
sunaddr = (struct sockaddr_un *)cctx->ai->ai_addr;
strlcpy(ntop, "unix", sizeof(ntop));
strlcpy(strport, sunaddr->sun_path, sizeof(strport));
break;
case AF_INET:
case AF_INET6:
if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen,
ntop, sizeof(ntop), strport, sizeof(strport),
NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
error("connect_next: getnameinfo failed");
continue;
}
break;
default:
continue;
}
if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype,
cctx->ai->ai_protocol)) == -1) {
if (cctx->ai->ai_next == NULL)
error("socket: %.100s", strerror(errno));
else
verbose("socket: %.100s", strerror(errno));
continue;
}
if (set_nonblock(sock) == -1)
fatal_f("set_nonblock(%d)", sock);
if (connect(sock, cctx->ai->ai_addr,
cctx->ai->ai_addrlen) == -1 && errno != EINPROGRESS) {
debug("connect_next: host %.100s ([%.100s]:%s): "
"%.100s", cctx->host, ntop, strport,
strerror(errno));
saved_errno = errno;
close(sock);
errno = saved_errno;
continue; /* fail -- try next */
}
if (cctx->ai->ai_family != AF_UNIX)
set_nodelay(sock);
debug("connect_next: host %.100s ([%.100s]:%s) "
"in progress, fd=%d", cctx->host, ntop, strport, sock);
cctx->ai = cctx->ai->ai_next;
return sock;
}
return -1;
}
static void
channel_connect_ctx_free(struct channel_connect *cctx)
{
free(cctx->host);
if (cctx->aitop) {
if (cctx->aitop->ai_family == AF_UNIX)
free(cctx->aitop);
else
freeaddrinfo(cctx->aitop);
}
memset(cctx, 0, sizeof(*cctx));
}
/*
* Return connecting socket to remote host:port or local socket path,
* passing back the failure reason if appropriate.
*/
static int
connect_to_helper(struct ssh *ssh, const char *name, int port, int socktype,
char *ctype, char *rname, struct channel_connect *cctx,
int *reason, const char **errmsg)
{
struct addrinfo hints;
int gaierr;
int sock = -1;
char strport[NI_MAXSERV];
if (port == PORT_STREAMLOCAL) {
struct sockaddr_un *sunaddr;
struct addrinfo *ai;
if (strlen(name) > sizeof(sunaddr->sun_path)) {
error("%.100s: %.100s", name, strerror(ENAMETOOLONG));
return -1;
}
/*
* Fake up a struct addrinfo for AF_UNIX connections.
* channel_connect_ctx_free() must check ai_family
* and use free() not freeaddirinfo() for AF_UNIX.
*/
ai = xmalloc(sizeof(*ai) + sizeof(*sunaddr));
memset(ai, 0, sizeof(*ai) + sizeof(*sunaddr));
ai->ai_addr = (struct sockaddr *)(ai + 1);
ai->ai_addrlen = sizeof(*sunaddr);
ai->ai_family = AF_UNIX;
ai->ai_socktype = socktype;
ai->ai_protocol = PF_UNSPEC;
sunaddr = (struct sockaddr_un *)ai->ai_addr;
sunaddr->sun_family = AF_UNIX;
strlcpy(sunaddr->sun_path, name, sizeof(sunaddr->sun_path));
cctx->aitop = ai;
} else {
memset(&hints, 0, sizeof(hints));
hints.ai_family = ssh->chanctxt->IPv4or6;
hints.ai_socktype = socktype;
snprintf(strport, sizeof strport, "%d", port);
if ((gaierr = getaddrinfo(name, strport, &hints, &cctx->aitop))
!= 0) {
if (errmsg != NULL)
*errmsg = ssh_gai_strerror(gaierr);
if (reason != NULL)
*reason = SSH2_OPEN_CONNECT_FAILED;
error("connect_to %.100s: unknown host (%s)", name,
ssh_gai_strerror(gaierr));
return -1;
}
}
cctx->host = xstrdup(name);
cctx->port = port;
cctx->ai = cctx->aitop;
if ((sock = connect_next(cctx)) == -1) {
error("connect to %.100s port %d failed: %s",
name, port, strerror(errno));
return -1;
}
return sock;
}
/* Return CONNECTING channel to remote host:port or local socket path */
static Channel *
connect_to(struct ssh *ssh, const char *host, int port,
char *ctype, char *rname)
{
struct channel_connect cctx;
Channel *c;
int sock;
memset(&cctx, 0, sizeof(cctx));
sock = connect_to_helper(ssh, host, port, SOCK_STREAM, ctype, rname,
&cctx, NULL, NULL);
if (sock == -1) {
channel_connect_ctx_free(&cctx);
return NULL;
}
c = channel_new(ssh, ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1);
c->host_port = port;
c->path = xstrdup(host);
c->connect_ctx = cctx;
return c;
}
/*
* returns either the newly connected channel or the downstream channel
* that needs to deal with this connection.
*/
Channel *
channel_connect_by_listen_address(struct ssh *ssh, const char *listen_host,
u_short listen_port, char *ctype, char *rname)
{
struct ssh_channels *sc = ssh->chanctxt;
struct permission_set *pset = &sc->local_perms;
u_int i;
struct permission *perm;
for (i = 0; i < pset->num_permitted_user; i++) {
perm = &pset->permitted_user[i];
if (open_listen_match_tcpip(perm,
listen_host, listen_port, 1)) {
if (perm->downstream)
return perm->downstream;
if (perm->port_to_connect == 0)
return rdynamic_connect_prepare(ssh,
ctype, rname);
return connect_to(ssh,
perm->host_to_connect, perm->port_to_connect,
ctype, rname);
}
}
error("WARNING: Server requests forwarding for unknown listen_port %d",
listen_port);
return NULL;
}
Channel *
channel_connect_by_listen_path(struct ssh *ssh, const char *path,
char *ctype, char *rname)
{
struct ssh_channels *sc = ssh->chanctxt;
struct permission_set *pset = &sc->local_perms;
u_int i;
struct permission *perm;
for (i = 0; i < pset->num_permitted_user; i++) {
perm = &pset->permitted_user[i];
if (open_listen_match_streamlocal(perm, path)) {
return connect_to(ssh,
perm->host_to_connect, perm->port_to_connect,
ctype, rname);
}
}
error("WARNING: Server requests forwarding for unknown path %.100s",
path);
return NULL;
}
/* Check if connecting to that port is permitted and connect. */
Channel *
channel_connect_to_port(struct ssh *ssh, const char *host, u_short port,
char *ctype, char *rname, int *reason, const char **errmsg)
{
struct ssh_channels *sc = ssh->chanctxt;
struct permission_set *pset = &sc->local_perms;
struct channel_connect cctx;
Channel *c;
u_int i, permit, permit_adm = 1;
int sock;
struct permission *perm;
permit = pset->all_permitted;
if (!permit) {
for (i = 0; i < pset->num_permitted_user; i++) {
perm = &pset->permitted_user[i];
if (open_match(perm, host, port)) {
permit = 1;
break;
}
}
}
if (pset->num_permitted_admin > 0) {
permit_adm = 0;
for (i = 0; i < pset->num_permitted_admin; i++) {
perm = &pset->permitted_admin[i];
if (open_match(perm, host, port)) {
permit_adm = 1;
break;
}
}
}
if (!permit || !permit_adm) {
logit("Received request from %.100s port %d to connect to "
"host %.100s port %d, but the request was denied.",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), host, port);
if (reason != NULL)
*reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED;
return NULL;
}
memset(&cctx, 0, sizeof(cctx));
sock = connect_to_helper(ssh, host, port, SOCK_STREAM, ctype, rname,
&cctx, reason, errmsg);
if (sock == -1) {
channel_connect_ctx_free(&cctx);
return NULL;
}
c = channel_new(ssh, ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1);
c->host_port = port;
c->path = xstrdup(host);
c->connect_ctx = cctx;
return c;
}
/* Check if connecting to that path is permitted and connect. */
Channel *
channel_connect_to_path(struct ssh *ssh, const char *path,
char *ctype, char *rname)
{
struct ssh_channels *sc = ssh->chanctxt;
struct permission_set *pset = &sc->local_perms;
u_int i, permit, permit_adm = 1;
struct permission *perm;
permit = pset->all_permitted;
if (!permit) {
for (i = 0; i < pset->num_permitted_user; i++) {
perm = &pset->permitted_user[i];
if (open_match(perm, path, PORT_STREAMLOCAL)) {
permit = 1;
break;
}
}
}
if (pset->num_permitted_admin > 0) {
permit_adm = 0;
for (i = 0; i < pset->num_permitted_admin; i++) {
perm = &pset->permitted_admin[i];
if (open_match(perm, path, PORT_STREAMLOCAL)) {
permit_adm = 1;
break;
}
}
}
if (!permit || !permit_adm) {
logit("Received request to connect to path %.100s, "
"but the request was denied.", path);
return NULL;
}
return connect_to(ssh, path, PORT_STREAMLOCAL, ctype, rname);
}
void
channel_send_window_changes(struct ssh *ssh)
{
struct ssh_channels *sc = ssh->chanctxt;
struct winsize ws;
int r;
u_int i;
for (i = 0; i < sc->channels_alloc; i++) {
if (sc->channels[i] == NULL || !sc->channels[i]->client_tty ||
sc->channels[i]->type != SSH_CHANNEL_OPEN)
continue;
if (ioctl(sc->channels[i]->rfd, TIOCGWINSZ, &ws) == -1)
continue;
channel_request_start(ssh, i, "window-change", 0);
if ((r = sshpkt_put_u32(ssh, (u_int)ws.ws_col)) != 0 ||
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_row)) != 0 ||
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_xpixel)) != 0 ||
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_ypixel)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "channel %u; send window-change", i);
}
}
/* Return RDYNAMIC_OPEN channel: channel allows SOCKS, but is not connected */
static Channel *
rdynamic_connect_prepare(struct ssh *ssh, char *ctype, char *rname)
{
Channel *c;
int r;
c = channel_new(ssh, ctype, SSH_CHANNEL_RDYNAMIC_OPEN, -1, -1, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1);
c->host_port = 0;
c->path = NULL;
/*
* We need to open the channel before we have a FD,
* so that we can get SOCKS header from peer.
*/
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 ||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
(r = sshpkt_put_u32(ssh, c->self)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0)
fatal_fr(r, "channel %i; confirm", c->self);
return c;
}
/* Return CONNECTING socket to remote host:port or local socket path */
static int
rdynamic_connect_finish(struct ssh *ssh, Channel *c)
{
struct ssh_channels *sc = ssh->chanctxt;
struct permission_set *pset = &sc->local_perms;
struct permission *perm;
struct channel_connect cctx;
u_int i, permit_adm = 1;
int sock;
if (pset->num_permitted_admin > 0) {
permit_adm = 0;
for (i = 0; i < pset->num_permitted_admin; i++) {
perm = &pset->permitted_admin[i];
if (open_match(perm, c->path, c->host_port)) {
permit_adm = 1;
break;
}
}
}
if (!permit_adm) {
debug_f("requested forward not permitted");
return -1;
}
memset(&cctx, 0, sizeof(cctx));
sock = connect_to_helper(ssh, c->path, c->host_port, SOCK_STREAM, NULL,
NULL, &cctx, NULL, NULL);
if (sock == -1)
channel_connect_ctx_free(&cctx);
else {
/* similar to SSH_CHANNEL_CONNECTING but we've already sent the open */
c->type = SSH_CHANNEL_RDYNAMIC_FINISH;
c->connect_ctx = cctx;
channel_register_fds(ssh, c, sock, sock, -1, 0, 1, 0);
}
return sock;
}
/* -- X11 forwarding */
/*
* Creates an internet domain socket for listening for X11 connections.
* Returns 0 and a suitable display number for the DISPLAY variable
* stored in display_numberp , or -1 if an error occurs.
*/
int
x11_create_display_inet(struct ssh *ssh, int x11_display_offset,
int x11_use_localhost, int single_connection,
u_int *display_numberp, int **chanids)
{
Channel *nc = NULL;
int display_number, sock;
u_short port;
struct addrinfo hints, *ai, *aitop;
char strport[NI_MAXSERV];
int gaierr, n, num_socks = 0, socks[NUM_SOCKS];
if (chanids == NULL)
return -1;
for (display_number = x11_display_offset;
display_number < MAX_DISPLAYS;
display_number++) {
port = 6000 + display_number;
memset(&hints, 0, sizeof(hints));
hints.ai_family = ssh->chanctxt->IPv4or6;
hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE;
hints.ai_socktype = SOCK_STREAM;
snprintf(strport, sizeof strport, "%d", port);
if ((gaierr = getaddrinfo(NULL, strport,
&hints, &aitop)) != 0) {
error("getaddrinfo: %.100s", ssh_gai_strerror(gaierr));
return -1;
}
for (ai = aitop; ai; ai = ai->ai_next) {
if (ai->ai_family != AF_INET &&
ai->ai_family != AF_INET6)
continue;
sock = socket(ai->ai_family, ai->ai_socktype,
ai->ai_protocol);
if (sock == -1) {
if ((errno != EINVAL) && (errno != EAFNOSUPPORT)
#ifdef EPFNOSUPPORT
&& (errno != EPFNOSUPPORT)
#endif
) {
error("socket: %.100s", strerror(errno));
freeaddrinfo(aitop);
return -1;
} else {
debug("x11_create_display_inet: Socket family %d not supported",
ai->ai_family);
continue;
}
}
if (ai->ai_family == AF_INET6)
sock_set_v6only(sock);
if (x11_use_localhost)
set_reuseaddr(sock);
if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
debug2_f("bind port %d: %.100s", port,
strerror(errno));
close(sock);
for (n = 0; n < num_socks; n++)
close(socks[n]);
num_socks = 0;
break;
}
socks[num_socks++] = sock;
if (num_socks == NUM_SOCKS)
break;
}
freeaddrinfo(aitop);
if (num_socks > 0)
break;
}
if (display_number >= MAX_DISPLAYS) {
error("Failed to allocate internet-domain X11 display socket.");
return -1;
}
/* Start listening for connections on the socket. */
for (n = 0; n < num_socks; n++) {
sock = socks[n];
if (listen(sock, SSH_LISTEN_BACKLOG) == -1) {
error("listen: %.100s", strerror(errno));
close(sock);
return -1;
}
}
/* Allocate a channel for each socket. */
*chanids = xcalloc(num_socks + 1, sizeof(**chanids));
for (n = 0; n < num_socks; n++) {
sock = socks[n];
nc = channel_new(ssh, "x11 listener",
SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
0, "X11 inet listener", 1);
nc->single_connection = single_connection;
(*chanids)[n] = nc->self;
}
(*chanids)[n] = -1;
/* Return the display number for the DISPLAY environment variable. */
*display_numberp = display_number;
return 0;
}
static int
connect_local_xsocket_path(const char *pathname)
{
int sock;
struct sockaddr_un addr;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock == -1)
error("socket: %.100s", strerror(errno));
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strlcpy(addr.sun_path, pathname, sizeof addr.sun_path);
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0)
return sock;
close(sock);
error("connect %.100s: %.100s", addr.sun_path, strerror(errno));
return -1;
}
static int
connect_local_xsocket(u_int dnr)
{
char buf[1024];
snprintf(buf, sizeof buf, _PATH_UNIX_X, dnr);
return connect_local_xsocket_path(buf);
}
#ifdef __APPLE__
static int
is_path_to_xsocket(const char *display, char *path, size_t pathlen)
{
struct stat sbuf;
if (strlcpy(path, display, pathlen) >= pathlen) {
error("%s: display path too long", __func__);
return 0;
}
if (display[0] != '/')
return 0;
if (stat(path, &sbuf) == 0) {
return 1;
} else {
char *dot = strrchr(path, '.');
if (dot != NULL) {
*dot = '\0';
if (stat(path, &sbuf) == 0) {
return 1;
}
}
}
return 0;
}
#endif
int
x11_connect_display(struct ssh *ssh)
{
u_int display_number;
const char *display;
char buf[1024], *cp;
struct addrinfo hints, *ai, *aitop;
char strport[NI_MAXSERV];
int gaierr, sock = 0;
/* Try to open a socket for the local X server. */
display = getenv("DISPLAY");
if (!display) {
error("DISPLAY not set.");
return -1;
}
/*
* Now we decode the value of the DISPLAY variable and make a
* connection to the real X server.
*/
#ifdef __APPLE__
/* Check if display is a path to a socket (as set by launchd). */
{
char path[PATH_MAX];
if (is_path_to_xsocket(display, path, sizeof(path))) {
debug("x11_connect_display: $DISPLAY is launchd");
/* Create a socket. */
sock = connect_local_xsocket_path(path);
if (sock < 0)
return -1;
/* OK, we now have a connection to the display. */
return sock;
}
}
#endif
/*
* Check if it is a unix domain socket. Unix domain displays are in
* one of the following formats: unix:d[.s], :d[.s], ::d[.s]
*/
if (strncmp(display, "unix:", 5) == 0 ||
display[0] == ':') {
/* Connect to the unix domain socket. */
if (sscanf(strrchr(display, ':') + 1, "%u",
&display_number) != 1) {
error("Could not parse display number from DISPLAY: "
"%.100s", display);
return -1;
}
/* Create a socket. */
sock = connect_local_xsocket(display_number);
if (sock < 0)
return -1;
/* OK, we now have a connection to the display. */
return sock;
}
/*
* Connect to an inet socket. The DISPLAY value is supposedly
* hostname:d[.s], where hostname may also be numeric IP address.
*/
strlcpy(buf, display, sizeof(buf));
cp = strchr(buf, ':');
if (!cp) {
error("Could not find ':' in DISPLAY: %.100s", display);
return -1;
}
*cp = 0;
/*
* buf now contains the host name. But first we parse the
* display number.
*/
if (sscanf(cp + 1, "%u", &display_number) != 1) {
error("Could not parse display number from DISPLAY: %.100s",
display);
return -1;
}
/* Look up the host address */
memset(&hints, 0, sizeof(hints));
hints.ai_family = ssh->chanctxt->IPv4or6;
hints.ai_socktype = SOCK_STREAM;
snprintf(strport, sizeof strport, "%u", 6000 + display_number);
if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
error("%.100s: unknown host. (%s)", buf,
ssh_gai_strerror(gaierr));
return -1;
}
for (ai = aitop; ai; ai = ai->ai_next) {
/* Create a socket. */
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sock == -1) {
debug2("socket: %.100s", strerror(errno));
continue;
}
/* Connect it to the display. */
if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
debug2("connect %.100s port %u: %.100s", buf,
6000 + display_number, strerror(errno));
close(sock);
continue;
}
/* Success */
break;
}
freeaddrinfo(aitop);
if (!ai) {
error("connect %.100s port %u: %.100s", buf,
6000 + display_number, strerror(errno));
return -1;
}
set_nodelay(sock);
return sock;
}
/*
* Requests forwarding of X11 connections, generates fake authentication
* data, and enables authentication spoofing.
* This should be called in the client only.
*/
void
x11_request_forwarding_with_spoofing(struct ssh *ssh, int client_session_id,
const char *disp, const char *proto, const char *data, int want_reply)
{
struct ssh_channels *sc = ssh->chanctxt;
u_int data_len = (u_int) strlen(data) / 2;
u_int i, value;
const char *cp;
char *new_data;
int r, screen_number;
if (sc->x11_saved_display == NULL)
sc->x11_saved_display = xstrdup(disp);
else if (strcmp(disp, sc->x11_saved_display) != 0) {
error("x11_request_forwarding_with_spoofing: different "
"$DISPLAY already forwarded");
return;
}
cp = strchr(disp, ':');
if (cp)
cp = strchr(cp, '.');
if (cp)
screen_number = (u_int)strtonum(cp + 1, 0, 400, NULL);
else
screen_number = 0;
if (sc->x11_saved_proto == NULL) {
/* Save protocol name. */
sc->x11_saved_proto = xstrdup(proto);
/* Extract real authentication data. */
sc->x11_saved_data = xmalloc(data_len);
for (i = 0; i < data_len; i++) {
if (sscanf(data + 2 * i, "%2x", &value) != 1) {
fatal("x11_request_forwarding: bad "
"authentication data: %.100s", data);
}
sc->x11_saved_data[i] = value;
}
sc->x11_saved_data_len = data_len;
/* Generate fake data of the same length. */
sc->x11_fake_data = xmalloc(data_len);
arc4random_buf(sc->x11_fake_data, data_len);
sc->x11_fake_data_len = data_len;
}
/* Convert the fake data into hex. */
new_data = tohex(sc->x11_fake_data, data_len);
/* Send the request packet. */
channel_request_start(ssh, client_session_id, "x11-req", want_reply);
if ((r = sshpkt_put_u8(ssh, 0)) != 0 || /* bool: single connection */
(r = sshpkt_put_cstring(ssh, proto)) != 0 ||
(r = sshpkt_put_cstring(ssh, new_data)) != 0 ||
(r = sshpkt_put_u32(ssh, screen_number)) != 0 ||
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
fatal_fr(r, "send x11-req");
free(new_data);
}
diff --git a/channels.h b/channels.h
index 74e9b3f87110..378d987c6c04 100644
--- a/channels.h
+++ b/channels.h
@@ -1,355 +1,355 @@
-/* $OpenBSD: channels.h,v 1.135 2020/09/20 05:47:25 djm Exp $ */
+/* $OpenBSD: channels.h,v 1.137 2021/04/03 06:18:40 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CHANNEL_H
#define CHANNEL_H
/* Definitions for channel types. */
#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11 conn. */
#define SSH_CHANNEL_PORT_LISTENER 2 /* Listening on a port. */
#define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */
#define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */
#define SSH_CHANNEL_CLOSED 5 /* waiting for close confirmation */
#define SSH_CHANNEL_AUTH_SOCKET 6 /* authentication socket */
#define SSH_CHANNEL_X11_OPEN 7 /* reading first X11 packet */
#define SSH_CHANNEL_LARVAL 10 /* larval session */
#define SSH_CHANNEL_RPORT_LISTENER 11 /* Listening to a R-style port */
#define SSH_CHANNEL_CONNECTING 12
#define SSH_CHANNEL_DYNAMIC 13
#define SSH_CHANNEL_ZOMBIE 14 /* Almost dead. */
#define SSH_CHANNEL_MUX_LISTENER 15 /* Listener for mux conn. */
#define SSH_CHANNEL_MUX_CLIENT 16 /* Conn. to mux client */
#define SSH_CHANNEL_ABANDONED 17 /* Abandoned session, eg mux */
#define SSH_CHANNEL_UNIX_LISTENER 18 /* Listening on a domain socket. */
#define SSH_CHANNEL_RUNIX_LISTENER 19 /* Listening to a R-style domain socket. */
#define SSH_CHANNEL_MUX_PROXY 20 /* proxy channel for mux-client */
#define SSH_CHANNEL_RDYNAMIC_OPEN 21 /* reverse SOCKS, parsing request */
#define SSH_CHANNEL_RDYNAMIC_FINISH 22 /* reverse SOCKS, finishing connect */
#define SSH_CHANNEL_MAX_TYPE 23
#define CHANNEL_CANCEL_PORT_STATIC -1
/* TCP forwarding */
#define FORWARD_DENY 0
#define FORWARD_REMOTE (1)
#define FORWARD_LOCAL (1<<1)
#define FORWARD_ALLOW (FORWARD_REMOTE|FORWARD_LOCAL)
#define FORWARD_ADM 0x100
#define FORWARD_USER 0x101
struct ssh;
struct Channel;
typedef struct Channel Channel;
struct fwd_perm_list;
typedef void channel_open_fn(struct ssh *, int, int, void *);
typedef void channel_callback_fn(struct ssh *, int, void *);
typedef int channel_infilter_fn(struct ssh *, struct Channel *, char *, int);
typedef void channel_filter_cleanup_fn(struct ssh *, int, void *);
typedef u_char *channel_outfilter_fn(struct ssh *, struct Channel *,
u_char **, size_t *);
/* Channel success/failure callbacks */
typedef void channel_confirm_cb(struct ssh *, int, struct Channel *, void *);
typedef void channel_confirm_abandon_cb(struct ssh *, struct Channel *, void *);
struct channel_confirm {
TAILQ_ENTRY(channel_confirm) entry;
channel_confirm_cb *cb;
channel_confirm_abandon_cb *abandon_cb;
void *ctx;
};
TAILQ_HEAD(channel_confirms, channel_confirm);
/* Context for non-blocking connects */
struct channel_connect {
char *host;
int port;
struct addrinfo *ai, *aitop;
};
/* Callbacks for mux channels back into client-specific code */
typedef int mux_callback_fn(struct ssh *, struct Channel *);
/*
* NB. channel IDs on the wire and in c->remote_id are uint32, but local
* channel IDs (e.g. c->self) only ever use the int32 subset of this range,
* because we use local channel ID -1 for housekeeping. Remote channels have
* a dedicated "have_remote_id" flag to indicate their validity.
*/
struct Channel {
int type; /* channel type/state */
int self; /* my own channel identifier */
uint32_t remote_id; /* channel identifier for remote peer */
int have_remote_id; /* non-zero if remote_id is valid */
u_int istate; /* input from channel (state of receive half) */
u_int ostate; /* output to channel (state of transmit half) */
int flags; /* close sent/rcvd */
int rfd; /* read fd */
int wfd; /* write fd */
int efd; /* extended fd */
int sock; /* sock fd */
int ctl_chan; /* control channel (multiplexed connections) */
int isatty; /* rfd is a tty */
#ifdef _AIX
int wfd_isatty; /* wfd is a tty */
#endif
int client_tty; /* (client) TTY has been requested */
int force_drain; /* force close on iEOF */
time_t notbefore; /* Pause IO until deadline (time_t) */
int delayed; /* post-select handlers for newly created
* channels are delayed until the first call
* to a matching pre-select handler.
* this way post-select handlers are not
* accidentally called if a FD gets reused */
struct sshbuf *input; /* data read from socket, to be sent over
* encrypted connection */
struct sshbuf *output; /* data received over encrypted connection for
* send on socket */
struct sshbuf *extended;
char *path;
/* path for unix domain sockets, or host name for forwards */
int listening_port; /* port being listened for forwards */
char *listening_addr; /* addr being listened for forwards */
int host_port; /* remote port to connect for forwards */
char *remote_name; /* remote hostname */
u_int remote_window;
u_int remote_maxpacket;
u_int local_window;
u_int local_window_max;
u_int local_consumed;
u_int local_maxpacket;
int extended_usage;
int single_connection;
char *ctype; /* type */
/* callback */
channel_open_fn *open_confirm;
void *open_confirm_ctx;
channel_callback_fn *detach_user;
int detach_close;
struct channel_confirms status_confirms;
/* filter */
channel_infilter_fn *input_filter;
channel_outfilter_fn *output_filter;
void *filter_ctx;
channel_filter_cleanup_fn *filter_cleanup;
/* keep boundaries */
- int datagram;
+ int datagram;
/* non-blocking connect */
/* XXX make this a pointer so the structure can be opaque */
struct channel_connect connect_ctx;
/* multiplexing protocol hook, called for each packet received */
mux_callback_fn *mux_rcb;
void *mux_ctx;
int mux_pause;
- int mux_downstream_id;
+ int mux_downstream_id;
};
#define CHAN_EXTENDED_IGNORE 0
#define CHAN_EXTENDED_READ 1
#define CHAN_EXTENDED_WRITE 2
/* default window/packet sizes for tcp/x11-fwd-channel */
#define CHAN_SES_PACKET_DEFAULT (32*1024)
#define CHAN_SES_WINDOW_DEFAULT (64*CHAN_SES_PACKET_DEFAULT)
#define CHAN_TCP_PACKET_DEFAULT (32*1024)
#define CHAN_TCP_WINDOW_DEFAULT (64*CHAN_TCP_PACKET_DEFAULT)
#define CHAN_X11_PACKET_DEFAULT (16*1024)
#define CHAN_X11_WINDOW_DEFAULT (4*CHAN_X11_PACKET_DEFAULT)
/* possible input states */
#define CHAN_INPUT_OPEN 0
#define CHAN_INPUT_WAIT_DRAIN 1
#define CHAN_INPUT_WAIT_OCLOSE 2
#define CHAN_INPUT_CLOSED 3
/* possible output states */
#define CHAN_OUTPUT_OPEN 0
#define CHAN_OUTPUT_WAIT_DRAIN 1
#define CHAN_OUTPUT_WAIT_IEOF 2
#define CHAN_OUTPUT_CLOSED 3
#define CHAN_CLOSE_SENT 0x01
#define CHAN_CLOSE_RCVD 0x02
#define CHAN_EOF_SENT 0x04
#define CHAN_EOF_RCVD 0x08
#define CHAN_LOCAL 0x10
/* Read buffer size */
#define CHAN_RBUF (16*1024)
/* Maximum channel input buffer size */
#define CHAN_INPUT_MAX (16*1024*1024)
/* Hard limit on number of channels */
#define CHANNELS_MAX_CHANNELS (16*1024)
/* check whether 'efd' is still in use */
#define CHANNEL_EFD_INPUT_ACTIVE(c) \
(c->extended_usage == CHAN_EXTENDED_READ && \
(c->efd != -1 || \
sshbuf_len(c->extended) > 0))
#define CHANNEL_EFD_OUTPUT_ACTIVE(c) \
(c->extended_usage == CHAN_EXTENDED_WRITE && \
c->efd != -1 && (!(c->flags & (CHAN_EOF_RCVD|CHAN_CLOSE_RCVD)) || \
sshbuf_len(c->extended) > 0))
/* Add channel management structures to SSH transport instance */
void channel_init_channels(struct ssh *ssh);
/* channel management */
Channel *channel_by_id(struct ssh *, int);
Channel *channel_by_remote_id(struct ssh *, u_int);
Channel *channel_lookup(struct ssh *, int);
Channel *channel_new(struct ssh *, char *, int, int, int, int,
u_int, u_int, int, char *, int);
void channel_set_fds(struct ssh *, int, int, int, int, int,
int, int, u_int);
void channel_free(struct ssh *, Channel *);
void channel_free_all(struct ssh *);
void channel_stop_listening(struct ssh *);
void channel_send_open(struct ssh *, int);
void channel_request_start(struct ssh *, int, char *, int);
void channel_register_cleanup(struct ssh *, int,
channel_callback_fn *, int);
void channel_register_open_confirm(struct ssh *, int,
channel_open_fn *, void *);
void channel_register_filter(struct ssh *, int, channel_infilter_fn *,
channel_outfilter_fn *, channel_filter_cleanup_fn *, void *);
void channel_register_status_confirm(struct ssh *, int,
channel_confirm_cb *, channel_confirm_abandon_cb *, void *);
void channel_cancel_cleanup(struct ssh *, int);
int channel_close_fd(struct ssh *, int *);
void channel_send_window_changes(struct ssh *);
/* mux proxy support */
int channel_proxy_downstream(struct ssh *, Channel *mc);
int channel_proxy_upstream(Channel *, int, u_int32_t, struct ssh *);
/* protocol handler */
int channel_input_data(int, u_int32_t, struct ssh *);
int channel_input_extended_data(int, u_int32_t, struct ssh *);
int channel_input_ieof(int, u_int32_t, struct ssh *);
int channel_input_oclose(int, u_int32_t, struct ssh *);
int channel_input_open_confirmation(int, u_int32_t, struct ssh *);
int channel_input_open_failure(int, u_int32_t, struct ssh *);
int channel_input_port_open(int, u_int32_t, struct ssh *);
int channel_input_window_adjust(int, u_int32_t, struct ssh *);
int channel_input_status_confirm(int, u_int32_t, struct ssh *);
/* file descriptor handling (read/write) */
void channel_prepare_select(struct ssh *, fd_set **, fd_set **, int *,
- u_int*, time_t*);
+ u_int*, time_t*);
void channel_after_select(struct ssh *, fd_set *, fd_set *);
void channel_output_poll(struct ssh *);
int channel_not_very_much_buffered_data(struct ssh *);
void channel_close_all(struct ssh *);
int channel_still_open(struct ssh *);
const char *channel_format_extended_usage(const Channel *);
char *channel_open_message(struct ssh *);
int channel_find_open(struct ssh *);
/* tcp forwarding */
struct Forward;
struct ForwardOptions;
void channel_set_af(struct ssh *, int af);
void channel_permit_all(struct ssh *, int);
void channel_add_permission(struct ssh *, int, int, char *, int);
void channel_clear_permission(struct ssh *, int, int);
void channel_disable_admin(struct ssh *, int);
void channel_update_permission(struct ssh *, int, int);
Channel *channel_connect_to_port(struct ssh *, const char *, u_short,
char *, char *, int *, const char **);
Channel *channel_connect_to_path(struct ssh *, const char *, char *, char *);
Channel *channel_connect_stdio_fwd(struct ssh *, const char*,
u_short, int, int);
Channel *channel_connect_by_listen_address(struct ssh *, const char *,
u_short, char *, char *);
Channel *channel_connect_by_listen_path(struct ssh *, const char *,
char *, char *);
int channel_request_remote_forwarding(struct ssh *, struct Forward *);
int channel_setup_local_fwd_listener(struct ssh *, struct Forward *,
struct ForwardOptions *);
int channel_request_rforward_cancel(struct ssh *, struct Forward *);
int channel_setup_remote_fwd_listener(struct ssh *, struct Forward *,
int *, struct ForwardOptions *);
int channel_cancel_rport_listener(struct ssh *, struct Forward *);
int channel_cancel_lport_listener(struct ssh *, struct Forward *,
int, struct ForwardOptions *);
int permitopen_port(const char *);
/* x11 forwarding */
void channel_set_x11_refuse_time(struct ssh *, u_int);
int x11_connect_display(struct ssh *);
int x11_create_display_inet(struct ssh *, int, int, int, u_int *, int **);
void x11_request_forwarding_with_spoofing(struct ssh *, int,
const char *, const char *, const char *, int);
/* channel close */
int chan_is_dead(struct ssh *, Channel *, int);
void chan_mark_dead(struct ssh *, Channel *);
/* channel events */
void chan_rcvd_oclose(struct ssh *, Channel *);
void chan_rcvd_eow(struct ssh *, Channel *);
void chan_read_failed(struct ssh *, Channel *);
void chan_ibuf_empty(struct ssh *, Channel *);
void chan_rcvd_ieof(struct ssh *, Channel *);
void chan_write_failed(struct ssh *, Channel *);
void chan_obuf_empty(struct ssh *, Channel *);
#endif
diff --git a/cipher.c b/cipher.c
index 639511cfdb1e..5b3a86d69219 100644
--- a/cipher.c
+++ b/cipher.c
@@ -1,539 +1,539 @@
-/* $OpenBSD: cipher.c,v 1.118 2020/12/21 11:09:32 dtucker Exp $ */
+/* $OpenBSD: cipher.c,v 1.119 2021/04/03 06:18:40 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
*
* Copyright (c) 1999 Niels Provos. All rights reserved.
* Copyright (c) 1999, 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include "cipher.h"
#include "misc.h"
#include "sshbuf.h"
#include "ssherr.h"
#include "digest.h"
#include "openbsd-compat/openssl-compat.h"
#ifndef WITH_OPENSSL
#define EVP_CIPHER_CTX void
#endif
struct sshcipher_ctx {
int plaintext;
int encrypt;
EVP_CIPHER_CTX *evp;
struct chachapoly_ctx *cp_ctx;
struct aesctr_ctx ac_ctx; /* XXX union with evp? */
const struct sshcipher *cipher;
};
struct sshcipher {
char *name;
u_int block_size;
u_int key_len;
u_int iv_len; /* defaults to block_size */
u_int auth_len;
u_int flags;
#define CFLAG_CBC (1<<0)
#define CFLAG_CHACHAPOLY (1<<1)
#define CFLAG_AESCTR (1<<2)
#define CFLAG_NONE (1<<3)
#define CFLAG_INTERNAL CFLAG_NONE /* Don't use "none" for packets */
#ifdef WITH_OPENSSL
const EVP_CIPHER *(*evptype)(void);
#else
void *ignored;
#endif
};
static const struct sshcipher ciphers[] = {
#ifdef WITH_OPENSSL
#ifndef OPENSSL_NO_DES
{ "3des-cbc", 8, 24, 0, 0, CFLAG_CBC, EVP_des_ede3_cbc },
#endif
{ "aes128-cbc", 16, 16, 0, 0, CFLAG_CBC, EVP_aes_128_cbc },
{ "aes192-cbc", 16, 24, 0, 0, CFLAG_CBC, EVP_aes_192_cbc },
{ "aes256-cbc", 16, 32, 0, 0, CFLAG_CBC, EVP_aes_256_cbc },
{ "aes128-ctr", 16, 16, 0, 0, 0, EVP_aes_128_ctr },
{ "aes192-ctr", 16, 24, 0, 0, 0, EVP_aes_192_ctr },
{ "aes256-ctr", 16, 32, 0, 0, 0, EVP_aes_256_ctr },
# ifdef OPENSSL_HAVE_EVPGCM
{ "aes128-gcm@openssh.com",
16, 16, 12, 16, 0, EVP_aes_128_gcm },
{ "aes256-gcm@openssh.com",
16, 32, 12, 16, 0, EVP_aes_256_gcm },
# endif /* OPENSSL_HAVE_EVPGCM */
#else
{ "aes128-ctr", 16, 16, 0, 0, CFLAG_AESCTR, NULL },
{ "aes192-ctr", 16, 24, 0, 0, CFLAG_AESCTR, NULL },
{ "aes256-ctr", 16, 32, 0, 0, CFLAG_AESCTR, NULL },
#endif
{ "chacha20-poly1305@openssh.com",
8, 64, 0, 16, CFLAG_CHACHAPOLY, NULL },
{ "none", 8, 0, 0, 0, CFLAG_NONE, NULL },
{ NULL, 0, 0, 0, 0, 0, NULL }
};
/*--*/
/* Returns a comma-separated list of supported ciphers. */
char *
cipher_alg_list(char sep, int auth_only)
{
char *tmp, *ret = NULL;
size_t nlen, rlen = 0;
const struct sshcipher *c;
for (c = ciphers; c->name != NULL; c++) {
if ((c->flags & CFLAG_INTERNAL) != 0)
continue;
if (auth_only && c->auth_len == 0)
continue;
if (ret != NULL)
ret[rlen++] = sep;
nlen = strlen(c->name);
if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
free(ret);
return NULL;
}
ret = tmp;
memcpy(ret + rlen, c->name, nlen + 1);
rlen += nlen;
}
return ret;
}
const char *
compression_alg_list(int compression)
{
#ifdef WITH_ZLIB
return compression ? "zlib@openssh.com,zlib,none" :
"none,zlib@openssh.com,zlib";
#else
return "none";
#endif
}
u_int
cipher_blocksize(const struct sshcipher *c)
{
return (c->block_size);
}
u_int
cipher_keylen(const struct sshcipher *c)
{
return (c->key_len);
}
u_int
cipher_seclen(const struct sshcipher *c)
{
if (strcmp("3des-cbc", c->name) == 0)
return 14;
return cipher_keylen(c);
}
u_int
cipher_authlen(const struct sshcipher *c)
{
return (c->auth_len);
}
u_int
cipher_ivlen(const struct sshcipher *c)
{
/*
* Default is cipher block size, except for chacha20+poly1305 that
* needs no IV. XXX make iv_len == -1 default?
*/
return (c->iv_len != 0 || (c->flags & CFLAG_CHACHAPOLY) != 0) ?
c->iv_len : c->block_size;
}
u_int
cipher_is_cbc(const struct sshcipher *c)
{
return (c->flags & CFLAG_CBC) != 0;
}
u_int
cipher_ctx_is_plaintext(struct sshcipher_ctx *cc)
{
return cc->plaintext;
}
const struct sshcipher *
cipher_by_name(const char *name)
{
const struct sshcipher *c;
for (c = ciphers; c->name != NULL; c++)
if (strcmp(c->name, name) == 0)
return c;
return NULL;
}
#define CIPHER_SEP ","
int
ciphers_valid(const char *names)
{
const struct sshcipher *c;
char *cipher_list, *cp;
char *p;
if (names == NULL || strcmp(names, "") == 0)
return 0;
if ((cipher_list = cp = strdup(names)) == NULL)
return 0;
for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
(p = strsep(&cp, CIPHER_SEP))) {
c = cipher_by_name(p);
if (c == NULL || (c->flags & CFLAG_INTERNAL) != 0) {
free(cipher_list);
return 0;
}
}
free(cipher_list);
return 1;
}
const char *
cipher_warning_message(const struct sshcipher_ctx *cc)
{
if (cc == NULL || cc->cipher == NULL)
return NULL;
/* XXX repurpose for CBC warning */
return NULL;
}
int
cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher,
const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
int do_encrypt)
{
struct sshcipher_ctx *cc = NULL;
int ret = SSH_ERR_INTERNAL_ERROR;
#ifdef WITH_OPENSSL
const EVP_CIPHER *type;
int klen;
#endif
*ccp = NULL;
if ((cc = calloc(sizeof(*cc), 1)) == NULL)
return SSH_ERR_ALLOC_FAIL;
cc->plaintext = (cipher->flags & CFLAG_NONE) != 0;
cc->encrypt = do_encrypt;
if (keylen < cipher->key_len ||
(iv != NULL && ivlen < cipher_ivlen(cipher))) {
ret = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
cc->cipher = cipher;
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
cc->cp_ctx = chachapoly_new(key, keylen);
ret = cc->cp_ctx != NULL ? 0 : SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((cc->cipher->flags & CFLAG_NONE) != 0) {
ret = 0;
goto out;
}
#ifndef WITH_OPENSSL
if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen);
aesctr_ivsetup(&cc->ac_ctx, iv);
ret = 0;
goto out;
}
ret = SSH_ERR_INVALID_ARGUMENT;
goto out;
#else /* WITH_OPENSSL */
type = (*cipher->evptype)();
if ((cc->evp = EVP_CIPHER_CTX_new()) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (EVP_CipherInit(cc->evp, type, NULL, (u_char *)iv,
(do_encrypt == CIPHER_ENCRYPT)) == 0) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if (cipher_authlen(cipher) &&
!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_SET_IV_FIXED,
-1, (u_char *)iv)) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
klen = EVP_CIPHER_CTX_key_length(cc->evp);
if (klen > 0 && keylen != (u_int)klen) {
if (EVP_CIPHER_CTX_set_key_length(cc->evp, keylen) == 0) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
}
if (EVP_CipherInit(cc->evp, NULL, (u_char *)key, NULL, -1) == 0) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
ret = 0;
#endif /* WITH_OPENSSL */
out:
if (ret == 0) {
/* success */
*ccp = cc;
} else {
if (cc != NULL) {
#ifdef WITH_OPENSSL
EVP_CIPHER_CTX_free(cc->evp);
#endif /* WITH_OPENSSL */
freezero(cc, sizeof(*cc));
}
}
return ret;
}
/*
* cipher_crypt() operates as following:
* Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'.
* These bytes are treated as additional authenticated data for
* authenticated encryption modes.
* En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'.
* Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag.
* This tag is written on encryption and verified on decryption.
* Both 'aadlen' and 'authlen' can be set to 0.
*/
int
cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest,
const u_char *src, u_int len, u_int aadlen, u_int authlen)
{
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
return chachapoly_crypt(cc->cp_ctx, seqnr, dest, src,
len, aadlen, authlen, cc->encrypt);
}
if ((cc->cipher->flags & CFLAG_NONE) != 0) {
memcpy(dest, src, aadlen + len);
return 0;
}
#ifndef WITH_OPENSSL
if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
if (aadlen)
memcpy(dest, src, aadlen);
aesctr_encrypt_bytes(&cc->ac_ctx, src + aadlen,
dest + aadlen, len);
return 0;
}
return SSH_ERR_INVALID_ARGUMENT;
#else
if (authlen) {
u_char lastiv[1];
if (authlen != cipher_authlen(cc->cipher))
return SSH_ERR_INVALID_ARGUMENT;
/* increment IV */
if (!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN,
1, lastiv))
return SSH_ERR_LIBCRYPTO_ERROR;
/* set tag on decyption */
if (!cc->encrypt &&
!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_SET_TAG,
authlen, (u_char *)src + aadlen + len))
return SSH_ERR_LIBCRYPTO_ERROR;
}
if (aadlen) {
if (authlen &&
EVP_Cipher(cc->evp, NULL, (u_char *)src, aadlen) < 0)
return SSH_ERR_LIBCRYPTO_ERROR;
memcpy(dest, src, aadlen);
}
if (len % cc->cipher->block_size)
return SSH_ERR_INVALID_ARGUMENT;
if (EVP_Cipher(cc->evp, dest + aadlen, (u_char *)src + aadlen,
len) < 0)
return SSH_ERR_LIBCRYPTO_ERROR;
if (authlen) {
/* compute tag (on encrypt) or verify tag (on decrypt) */
if (EVP_Cipher(cc->evp, NULL, NULL, 0) < 0)
return cc->encrypt ?
SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID;
if (cc->encrypt &&
!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_GET_TAG,
authlen, dest + aadlen + len))
return SSH_ERR_LIBCRYPTO_ERROR;
}
return 0;
#endif
}
/* Extract the packet length, including any decryption necessary beforehand */
int
cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr,
const u_char *cp, u_int len)
{
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
return chachapoly_get_length(cc->cp_ctx, plenp, seqnr,
cp, len);
if (len < 4)
return SSH_ERR_MESSAGE_INCOMPLETE;
*plenp = PEEK_U32(cp);
return 0;
}
void
cipher_free(struct sshcipher_ctx *cc)
{
if (cc == NULL)
return;
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
chachapoly_free(cc->cp_ctx);
cc->cp_ctx = NULL;
} else if ((cc->cipher->flags & CFLAG_AESCTR) != 0)
explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx));
#ifdef WITH_OPENSSL
EVP_CIPHER_CTX_free(cc->evp);
cc->evp = NULL;
#endif
freezero(cc, sizeof(*cc));
}
/*
* Exports an IV from the sshcipher_ctx required to export the key
* state back from the unprivileged child to the privileged parent
* process.
*/
int
cipher_get_keyiv_len(const struct sshcipher_ctx *cc)
{
const struct sshcipher *c = cc->cipher;
if ((c->flags & CFLAG_CHACHAPOLY) != 0)
return 0;
else if ((c->flags & CFLAG_AESCTR) != 0)
return sizeof(cc->ac_ctx.ctr);
#ifdef WITH_OPENSSL
return EVP_CIPHER_CTX_iv_length(cc->evp);
#else
return 0;
#endif
}
int
cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, size_t len)
{
#ifdef WITH_OPENSSL
const struct sshcipher *c = cc->cipher;
int evplen;
#endif
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
if (len != 0)
return SSH_ERR_INVALID_ARGUMENT;
return 0;
}
if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
if (len != sizeof(cc->ac_ctx.ctr))
return SSH_ERR_INVALID_ARGUMENT;
memcpy(iv, cc->ac_ctx.ctr, len);
return 0;
}
if ((cc->cipher->flags & CFLAG_NONE) != 0)
return 0;
#ifdef WITH_OPENSSL
evplen = EVP_CIPHER_CTX_iv_length(cc->evp);
if (evplen == 0)
return 0;
else if (evplen < 0)
return SSH_ERR_LIBCRYPTO_ERROR;
if ((size_t)evplen != len)
return SSH_ERR_INVALID_ARGUMENT;
#ifndef OPENSSL_HAVE_EVPCTR
if (c->evptype == evp_aes_128_ctr)
ssh_aes_ctr_iv(cc->evp, 0, iv, len);
else
#endif
if (cipher_authlen(c)) {
if (!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN,
- len, iv))
- return SSH_ERR_LIBCRYPTO_ERROR;
+ len, iv))
+ return SSH_ERR_LIBCRYPTO_ERROR;
} else if (!EVP_CIPHER_CTX_get_iv(cc->evp, iv, len))
- return SSH_ERR_LIBCRYPTO_ERROR;
+ return SSH_ERR_LIBCRYPTO_ERROR;
#endif
return 0;
}
int
cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv, size_t len)
{
#ifdef WITH_OPENSSL
const struct sshcipher *c = cc->cipher;
int evplen = 0;
#endif
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
return 0;
if ((cc->cipher->flags & CFLAG_NONE) != 0)
return 0;
#ifdef WITH_OPENSSL
evplen = EVP_CIPHER_CTX_iv_length(cc->evp);
if (evplen <= 0)
return SSH_ERR_LIBCRYPTO_ERROR;
if ((size_t)evplen != len)
return SSH_ERR_INVALID_ARGUMENT;
#ifndef OPENSSL_HAVE_EVPCTR
/* XXX iv arg is const, but ssh_aes_ctr_iv isn't */
if (c->evptype == evp_aes_128_ctr)
ssh_aes_ctr_iv(cc->evp, 1, (u_char *)iv, evplen);
else
#endif
if (cipher_authlen(c)) {
/* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */
if (!EVP_CIPHER_CTX_ctrl(cc->evp,
EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv))
return SSH_ERR_LIBCRYPTO_ERROR;
} else if (!EVP_CIPHER_CTX_set_iv(cc->evp, iv, evplen))
return SSH_ERR_LIBCRYPTO_ERROR;
#endif
return 0;
}
diff --git a/clientloop.c b/clientloop.c
index 70f492f89371..cb3ff8645274 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,2606 +1,2606 @@
-/* $OpenBSD: clientloop.c,v 1.358 2021/01/27 10:05:28 djm Exp $ */
+/* $OpenBSD: clientloop.c,v 1.359 2021/03/19 02:22:34 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* The main loop for the interactive session (client side).
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
*
* Copyright (c) 1999 Theo de Raadt. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* SSH2 support added by Markus Friedl.
* Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/ioctl.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/socket.h>
#include <ctype.h>
#include <errno.h>
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <termios.h>
#include <pwd.h>
#include <unistd.h>
#include <limits.h>
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "ssh.h"
#include "ssh2.h"
#include "packet.h"
#include "sshbuf.h"
#include "compat.h"
#include "channels.h"
#include "dispatch.h"
#include "sshkey.h"
#include "cipher.h"
#include "kex.h"
#include "myproposal.h"
#include "log.h"
#include "misc.h"
#include "readconf.h"
#include "clientloop.h"
#include "sshconnect.h"
#include "authfd.h"
#include "atomicio.h"
#include "sshpty.h"
#include "match.h"
#include "msg.h"
#include "ssherr.h"
#include "hostfile.h"
/* import options */
extern Options options;
/* Flag indicating that stdin should be redirected from /dev/null. */
extern int stdin_null_flag;
/* Flag indicating that no shell has been requested */
extern int no_shell_flag;
/* Flag indicating that ssh should daemonise after authentication is complete */
extern int fork_after_authentication_flag;
/* Control socket */
extern int muxserver_sock; /* XXX use mux_client_cleanup() instead */
/*
* Name of the host we are connecting to. This is the name given on the
* command line, or the Hostname specified for the user-supplied name in a
* configuration file.
*/
extern char *host;
/*
* If this field is not NULL, the ForwardAgent socket is this path and different
* instead of SSH_AUTH_SOCK.
*/
extern char *forward_agent_sock_path;
/*
* Flag to indicate that we have received a window change signal which has
* not yet been processed. This will cause a message indicating the new
* window size to be sent to the server a little later. This is volatile
* because this is updated in a signal handler.
*/
static volatile sig_atomic_t received_window_change_signal = 0;
static volatile sig_atomic_t received_signal = 0;
/* Time when backgrounded control master using ControlPersist should exit */
static time_t control_persist_exit_time = 0;
/* Common data for the client loop code. */
volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
static int last_was_cr; /* Last character was a newline. */
static int exit_status; /* Used to store the command exit status. */
static struct sshbuf *stderr_buffer; /* Used for final exit message. */
static int connection_in; /* Connection to server (input). */
static int connection_out; /* Connection to server (output). */
static int need_rekeying; /* Set to non-zero if rekeying is requested. */
static int session_closed; /* In SSH2: login session closed. */
static u_int x11_refuse_time; /* If >0, refuse x11 opens after this time. */
static time_t server_alive_time; /* Time to do server_alive_check */
static void client_init_dispatch(struct ssh *ssh);
int session_ident = -1;
/* Track escape per proto2 channel */
struct escape_filter_ctx {
int escape_pending;
int escape_char;
};
/* Context for channel confirmation replies */
struct channel_reply_ctx {
const char *request_type;
int id;
enum confirm_action action;
};
/* Global request success/failure callbacks */
/* XXX move to struct ssh? */
struct global_confirm {
TAILQ_ENTRY(global_confirm) entry;
global_confirm_cb *cb;
void *ctx;
int ref_count;
};
TAILQ_HEAD(global_confirms, global_confirm);
static struct global_confirms global_confirms =
TAILQ_HEAD_INITIALIZER(global_confirms);
void ssh_process_session2_setup(int, int, int, struct sshbuf *);
/*
* Signal handler for the window change signal (SIGWINCH). This just sets a
* flag indicating that the window has changed.
*/
/*ARGSUSED */
static void
window_change_handler(int sig)
{
received_window_change_signal = 1;
}
/*
* Signal handler for signals that cause the program to terminate. These
* signals must be trapped to restore terminal modes.
*/
/*ARGSUSED */
static void
signal_handler(int sig)
{
received_signal = sig;
quit_pending = 1;
}
/*
* Sets control_persist_exit_time to the absolute time when the
* backgrounded control master should exit due to expiry of the
* ControlPersist timeout. Sets it to 0 if we are not a backgrounded
* control master process, or if there is no ControlPersist timeout.
*/
static void
set_control_persist_exit_time(struct ssh *ssh)
{
if (muxserver_sock == -1 || !options.control_persist
|| options.control_persist_timeout == 0) {
/* not using a ControlPersist timeout */
control_persist_exit_time = 0;
} else if (channel_still_open(ssh)) {
/* some client connections are still open */
if (control_persist_exit_time > 0)
debug2_f("cancel scheduled exit");
control_persist_exit_time = 0;
} else if (control_persist_exit_time <= 0) {
/* a client connection has recently closed */
control_persist_exit_time = monotime() +
(time_t)options.control_persist_timeout;
debug2_f("schedule exit in %d seconds",
options.control_persist_timeout);
}
/* else we are already counting down to the timeout */
}
#define SSH_X11_VALID_DISPLAY_CHARS ":/.-_"
static int
client_x11_display_valid(const char *display)
{
size_t i, dlen;
if (display == NULL)
return 0;
dlen = strlen(display);
for (i = 0; i < dlen; i++) {
if (!isalnum((u_char)display[i]) &&
strchr(SSH_X11_VALID_DISPLAY_CHARS, display[i]) == NULL) {
debug("Invalid character '%c' in DISPLAY", display[i]);
return 0;
}
}
return 1;
}
#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1"
#define X11_TIMEOUT_SLACK 60
int
client_x11_get_proto(struct ssh *ssh, const char *display,
const char *xauth_path, u_int trusted, u_int timeout,
char **_proto, char **_data)
{
char *cmd, line[512], xdisplay[512];
char xauthfile[PATH_MAX], xauthdir[PATH_MAX];
static char proto[512], data[512];
FILE *f;
int got_data = 0, generated = 0, do_unlink = 0, r;
struct stat st;
u_int now, x11_timeout_real;
*_proto = proto;
*_data = data;
proto[0] = data[0] = xauthfile[0] = xauthdir[0] = '\0';
if (!client_x11_display_valid(display)) {
if (display != NULL)
logit("DISPLAY \"%s\" invalid; disabling X11 forwarding",
display);
return -1;
}
if (xauth_path != NULL && stat(xauth_path, &st) == -1) {
debug("No xauth program.");
xauth_path = NULL;
}
if (xauth_path != NULL) {
/*
* Handle FamilyLocal case where $DISPLAY does
* not match an authorization entry. For this we
* just try "xauth list unix:displaynum.screennum".
* XXX: "localhost" match to determine FamilyLocal
* is not perfect.
*/
if (strncmp(display, "localhost:", 10) == 0) {
if ((r = snprintf(xdisplay, sizeof(xdisplay), "unix:%s",
display + 10)) < 0 ||
(size_t)r >= sizeof(xdisplay)) {
error_f("display name too long");
return -1;
}
display = xdisplay;
}
if (trusted == 0) {
/*
* Generate an untrusted X11 auth cookie.
*
* The authentication cookie should briefly outlive
* ssh's willingness to forward X11 connections to
* avoid nasty fail-open behaviour in the X server.
*/
mktemp_proto(xauthdir, sizeof(xauthdir));
if (mkdtemp(xauthdir) == NULL) {
error_f("mkdtemp: %s", strerror(errno));
return -1;
}
do_unlink = 1;
if ((r = snprintf(xauthfile, sizeof(xauthfile),
"%s/xauthfile", xauthdir)) < 0 ||
(size_t)r >= sizeof(xauthfile)) {
error_f("xauthfile path too long");
rmdir(xauthdir);
return -1;
}
if (timeout == 0) {
/* auth doesn't time out */
xasprintf(&cmd, "%s -f %s generate %s %s "
"untrusted 2>%s",
xauth_path, xauthfile, display,
SSH_X11_PROTO, _PATH_DEVNULL);
} else {
/* Add some slack to requested expiry */
if (timeout < UINT_MAX - X11_TIMEOUT_SLACK)
x11_timeout_real = timeout +
X11_TIMEOUT_SLACK;
else {
/* Don't overflow on long timeouts */
x11_timeout_real = UINT_MAX;
}
xasprintf(&cmd, "%s -f %s generate %s %s "
"untrusted timeout %u 2>%s",
xauth_path, xauthfile, display,
SSH_X11_PROTO, x11_timeout_real,
_PATH_DEVNULL);
}
debug2_f("xauth command: %s", cmd);
if (timeout != 0 && x11_refuse_time == 0) {
now = monotime() + 1;
if (UINT_MAX - timeout < now)
x11_refuse_time = UINT_MAX;
else
x11_refuse_time = now + timeout;
channel_set_x11_refuse_time(ssh,
x11_refuse_time);
}
if (system(cmd) == 0)
generated = 1;
free(cmd);
}
/*
* When in untrusted mode, we read the cookie only if it was
* successfully generated as an untrusted one in the step
* above.
*/
if (trusted || generated) {
xasprintf(&cmd,
"%s %s%s list %s 2>" _PATH_DEVNULL,
xauth_path,
generated ? "-f " : "" ,
generated ? xauthfile : "",
display);
debug2("x11_get_proto: %s", cmd);
f = popen(cmd, "r");
if (f && fgets(line, sizeof(line), f) &&
sscanf(line, "%*s %511s %511s", proto, data) == 2)
got_data = 1;
if (f)
pclose(f);
free(cmd);
}
}
if (do_unlink) {
unlink(xauthfile);
rmdir(xauthdir);
}
/* Don't fall back to fake X11 data for untrusted forwarding */
if (!trusted && !got_data) {
error("Warning: untrusted X11 forwarding setup failed: "
"xauth key data not generated");
return -1;
}
/*
* If we didn't get authentication data, just make up some
* data. The forwarding code will check the validity of the
* response anyway, and substitute this data. The X11
* server, however, will ignore this fake data and use
* whatever authentication mechanisms it was using otherwise
* for the local connection.
*/
if (!got_data) {
u_int8_t rnd[16];
u_int i;
logit("Warning: No xauth data; "
"using fake authentication data for X11 forwarding.");
strlcpy(proto, SSH_X11_PROTO, sizeof proto);
arc4random_buf(rnd, sizeof(rnd));
for (i = 0; i < sizeof(rnd); i++) {
snprintf(data + 2 * i, sizeof data - 2 * i, "%02x",
rnd[i]);
}
}
return 0;
}
/*
* Checks if the client window has changed, and sends a packet about it to
* the server if so. The actual change is detected elsewhere (by a software
* interrupt on Unix); this just checks the flag and sends a message if
* appropriate.
*/
static void
client_check_window_change(struct ssh *ssh)
{
if (!received_window_change_signal)
return;
received_window_change_signal = 0;
debug2_f("changed");
channel_send_window_changes(ssh);
}
static int
client_global_request_reply(int type, u_int32_t seq, struct ssh *ssh)
{
struct global_confirm *gc;
if ((gc = TAILQ_FIRST(&global_confirms)) == NULL)
return 0;
if (gc->cb != NULL)
gc->cb(ssh, type, seq, gc->ctx);
if (--gc->ref_count <= 0) {
TAILQ_REMOVE(&global_confirms, gc, entry);
freezero(gc, sizeof(*gc));
}
ssh_packet_set_alive_timeouts(ssh, 0);
return 0;
}
static void
schedule_server_alive_check(void)
{
if (options.server_alive_interval > 0)
server_alive_time = monotime() + options.server_alive_interval;
}
static void
server_alive_check(struct ssh *ssh)
{
int r;
if (ssh_packet_inc_alive_timeouts(ssh) > options.server_alive_count_max) {
logit("Timeout, server %s not responding.", host);
cleanup_exit(255);
}
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, "keepalive@openssh.com")) != 0 ||
(r = sshpkt_put_u8(ssh, 1)) != 0 || /* boolean: want reply */
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send packet");
/* Insert an empty placeholder to maintain ordering */
client_register_global_confirm(NULL, NULL);
schedule_server_alive_check();
}
/*
* Waits until the client can do something (some data becomes available on
* one of the file descriptors).
*/
static void
client_wait_until_can_do_something(struct ssh *ssh,
fd_set **readsetp, fd_set **writesetp,
int *maxfdp, u_int *nallocp, int rekeying)
{
struct timeval tv, *tvp;
int timeout_secs;
time_t minwait_secs = 0, now = monotime();
int r, ret;
/* Add any selections by the channel mechanism. */
channel_prepare_select(ssh, readsetp, writesetp, maxfdp,
nallocp, &minwait_secs);
/* channel_prepare_select could have closed the last channel */
if (session_closed && !channel_still_open(ssh) &&
!ssh_packet_have_data_to_write(ssh)) {
/* clear mask since we did not call select() */
memset(*readsetp, 0, *nallocp);
memset(*writesetp, 0, *nallocp);
return;
}
FD_SET(connection_in, *readsetp);
/* Select server connection if have data to write to the server. */
if (ssh_packet_have_data_to_write(ssh))
FD_SET(connection_out, *writesetp);
/*
* Wait for something to happen. This will suspend the process until
* some selected descriptor can be read, written, or has some other
* event pending, or a timeout expires.
*/
timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */
if (options.server_alive_interval > 0)
timeout_secs = MAXIMUM(server_alive_time - now, 0);
if (options.rekey_interval > 0 && !rekeying)
timeout_secs = MINIMUM(timeout_secs,
ssh_packet_get_rekey_timeout(ssh));
set_control_persist_exit_time(ssh);
if (control_persist_exit_time > 0) {
timeout_secs = MINIMUM(timeout_secs,
control_persist_exit_time - now);
if (timeout_secs < 0)
timeout_secs = 0;
}
if (minwait_secs != 0)
timeout_secs = MINIMUM(timeout_secs, (int)minwait_secs);
if (timeout_secs == INT_MAX)
tvp = NULL;
else {
tv.tv_sec = timeout_secs;
tv.tv_usec = 0;
tvp = &tv;
}
ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
if (ret == -1) {
/*
* We have to clear the select masks, because we return.
* We have to return, because the mainloop checks for the flags
* set by the signal handlers.
*/
memset(*readsetp, 0, *nallocp);
memset(*writesetp, 0, *nallocp);
if (errno == EINTR)
return;
/* Note: we might still have data in the buffers. */
if ((r = sshbuf_putf(stderr_buffer,
"select: %s\r\n", strerror(errno))) != 0)
fatal_fr(r, "sshbuf_putf");
quit_pending = 1;
} else if (options.server_alive_interval > 0 && !FD_ISSET(connection_in,
- *readsetp) && monotime() >= server_alive_time)
+ *readsetp) && monotime() >= server_alive_time)
/*
* ServerAlive check is needed. We can't rely on the select
* timing out since traffic on the client side such as port
* forwards can keep waking it up.
*/
server_alive_check(ssh);
}
static void
client_suspend_self(struct sshbuf *bin, struct sshbuf *bout, struct sshbuf *berr)
{
/* Flush stdout and stderr buffers. */
if (sshbuf_len(bout) > 0)
atomicio(vwrite, fileno(stdout), sshbuf_mutable_ptr(bout),
sshbuf_len(bout));
if (sshbuf_len(berr) > 0)
atomicio(vwrite, fileno(stderr), sshbuf_mutable_ptr(berr),
sshbuf_len(berr));
leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
sshbuf_reset(bin);
sshbuf_reset(bout);
sshbuf_reset(berr);
/* Send the suspend signal to the program itself. */
kill(getpid(), SIGTSTP);
/* Reset window sizes in case they have changed */
received_window_change_signal = 1;
enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
}
static void
client_process_net_input(struct ssh *ssh, fd_set *readset)
{
char buf[SSH_IOBUFSZ];
int r, len;
/*
* Read input from the server, and add any such data to the buffer of
* the packet subsystem.
*/
if (FD_ISSET(connection_in, readset)) {
schedule_server_alive_check();
/* Read as much as possible. */
len = read(connection_in, buf, sizeof(buf));
if (len == 0) {
/*
* Received EOF. The remote host has closed the
* connection.
*/
if ((r = sshbuf_putf(stderr_buffer,
"Connection to %.300s closed by remote host.\r\n",
host)) != 0)
fatal_fr(r, "sshbuf_putf");
quit_pending = 1;
return;
}
/*
* There is a kernel bug on Solaris that causes select to
* sometimes wake up even though there is no data available.
*/
if (len == -1 &&
(errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK))
len = 0;
if (len == -1) {
/*
* An error has encountered. Perhaps there is a
* network problem.
*/
if ((r = sshbuf_putf(stderr_buffer,
"Read from remote host %.300s: %.100s\r\n",
host, strerror(errno))) != 0)
fatal_fr(r, "sshbuf_putf");
quit_pending = 1;
return;
}
ssh_packet_process_incoming(ssh, buf, len);
}
}
static void
client_status_confirm(struct ssh *ssh, int type, Channel *c, void *ctx)
{
struct channel_reply_ctx *cr = (struct channel_reply_ctx *)ctx;
char errmsg[256];
int r, tochan;
/*
* If a TTY was explicitly requested, then a failure to allocate
* one is fatal.
*/
if (cr->action == CONFIRM_TTY &&
(options.request_tty == REQUEST_TTY_FORCE ||
options.request_tty == REQUEST_TTY_YES))
cr->action = CONFIRM_CLOSE;
/* XXX suppress on mux _client_ quietmode */
tochan = options.log_level >= SYSLOG_LEVEL_ERROR &&
c->ctl_chan != -1 && c->extended_usage == CHAN_EXTENDED_WRITE;
if (type == SSH2_MSG_CHANNEL_SUCCESS) {
debug2("%s request accepted on channel %d",
cr->request_type, c->self);
} else if (type == SSH2_MSG_CHANNEL_FAILURE) {
if (tochan) {
snprintf(errmsg, sizeof(errmsg),
"%s request failed\r\n", cr->request_type);
} else {
snprintf(errmsg, sizeof(errmsg),
"%s request failed on channel %d",
cr->request_type, c->self);
}
/* If error occurred on primary session channel, then exit */
if (cr->action == CONFIRM_CLOSE && c->self == session_ident)
fatal("%s", errmsg);
/*
* If error occurred on mux client, append to
* their stderr.
*/
if (tochan) {
if ((r = sshbuf_put(c->extended, errmsg,
strlen(errmsg))) != 0)
fatal_fr(r, "sshbuf_put");
} else
error("%s", errmsg);
if (cr->action == CONFIRM_TTY) {
/*
* If a TTY allocation error occurred, then arrange
* for the correct TTY to leave raw mode.
*/
if (c->self == session_ident)
leave_raw_mode(0);
else
mux_tty_alloc_failed(ssh, c);
} else if (cr->action == CONFIRM_CLOSE) {
chan_read_failed(ssh, c);
chan_write_failed(ssh, c);
}
}
free(cr);
}
static void
client_abandon_status_confirm(struct ssh *ssh, Channel *c, void *ctx)
{
free(ctx);
}
void
client_expect_confirm(struct ssh *ssh, int id, const char *request,
enum confirm_action action)
{
struct channel_reply_ctx *cr = xcalloc(1, sizeof(*cr));
cr->request_type = request;
cr->action = action;
channel_register_status_confirm(ssh, id, client_status_confirm,
client_abandon_status_confirm, cr);
}
void
client_register_global_confirm(global_confirm_cb *cb, void *ctx)
{
struct global_confirm *gc, *last_gc;
/* Coalesce identical callbacks */
last_gc = TAILQ_LAST(&global_confirms, global_confirms);
if (last_gc && last_gc->cb == cb && last_gc->ctx == ctx) {
if (++last_gc->ref_count >= INT_MAX)
fatal_f("last_gc->ref_count = %d",
last_gc->ref_count);
return;
}
gc = xcalloc(1, sizeof(*gc));
gc->cb = cb;
gc->ctx = ctx;
gc->ref_count = 1;
TAILQ_INSERT_TAIL(&global_confirms, gc, entry);
}
static void
process_cmdline(struct ssh *ssh)
{
void (*handler)(int);
char *s, *cmd;
int ok, delete = 0, local = 0, remote = 0, dynamic = 0;
struct Forward fwd;
memset(&fwd, 0, sizeof(fwd));
leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
handler = ssh_signal(SIGINT, SIG_IGN);
cmd = s = read_passphrase("\r\nssh> ", RP_ECHO);
if (s == NULL)
goto out;
while (isspace((u_char)*s))
s++;
if (*s == '-')
s++; /* Skip cmdline '-', if any */
if (*s == '\0')
goto out;
if (*s == 'h' || *s == 'H' || *s == '?') {
logit("Commands:");
logit(" -L[bind_address:]port:host:hostport "
"Request local forward");
logit(" -R[bind_address:]port:host:hostport "
"Request remote forward");
logit(" -D[bind_address:]port "
"Request dynamic forward");
logit(" -KL[bind_address:]port "
"Cancel local forward");
logit(" -KR[bind_address:]port "
"Cancel remote forward");
logit(" -KD[bind_address:]port "
"Cancel dynamic forward");
if (!options.permit_local_command)
goto out;
logit(" !args "
"Execute local command");
goto out;
}
if (*s == '!' && options.permit_local_command) {
s++;
ssh_local_cmd(s);
goto out;
}
if (*s == 'K') {
delete = 1;
s++;
}
if (*s == 'L')
local = 1;
else if (*s == 'R')
remote = 1;
else if (*s == 'D')
dynamic = 1;
else {
logit("Invalid command.");
goto out;
}
while (isspace((u_char)*++s))
;
/* XXX update list of forwards in options */
if (delete) {
/* We pass 1 for dynamicfwd to restrict to 1 or 2 fields. */
if (!parse_forward(&fwd, s, 1, 0)) {
logit("Bad forwarding close specification.");
goto out;
}
if (remote)
ok = channel_request_rforward_cancel(ssh, &fwd) == 0;
else if (dynamic)
ok = channel_cancel_lport_listener(ssh, &fwd,
0, &options.fwd_opts) > 0;
else
ok = channel_cancel_lport_listener(ssh, &fwd,
CHANNEL_CANCEL_PORT_STATIC,
&options.fwd_opts) > 0;
if (!ok) {
logit("Unknown port forwarding.");
goto out;
}
logit("Canceled forwarding.");
} else {
if (!parse_forward(&fwd, s, dynamic, remote)) {
logit("Bad forwarding specification.");
goto out;
}
if (local || dynamic) {
if (!channel_setup_local_fwd_listener(ssh, &fwd,
&options.fwd_opts)) {
logit("Port forwarding failed.");
goto out;
}
} else {
if (channel_request_remote_forwarding(ssh, &fwd) < 0) {
logit("Port forwarding failed.");
goto out;
}
}
logit("Forwarding port.");
}
out:
ssh_signal(SIGINT, handler);
enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
free(cmd);
free(fwd.listen_host);
free(fwd.listen_path);
free(fwd.connect_host);
free(fwd.connect_path);
}
/* reasons to suppress output of an escape command in help output */
#define SUPPRESS_NEVER 0 /* never suppress, always show */
#define SUPPRESS_MUXCLIENT 1 /* don't show in mux client sessions */
#define SUPPRESS_MUXMASTER 2 /* don't show in mux master sessions */
#define SUPPRESS_SYSLOG 4 /* don't show when logging to syslog */
struct escape_help_text {
const char *cmd;
const char *text;
unsigned int flags;
};
static struct escape_help_text esc_txt[] = {
{".", "terminate session", SUPPRESS_MUXMASTER},
{".", "terminate connection (and any multiplexed sessions)",
SUPPRESS_MUXCLIENT},
{"B", "send a BREAK to the remote system", SUPPRESS_NEVER},
{"C", "open a command line", SUPPRESS_MUXCLIENT},
{"R", "request rekey", SUPPRESS_NEVER},
{"V/v", "decrease/increase verbosity (LogLevel)", SUPPRESS_MUXCLIENT},
{"^Z", "suspend ssh", SUPPRESS_MUXCLIENT},
{"#", "list forwarded connections", SUPPRESS_NEVER},
{"&", "background ssh (when waiting for connections to terminate)",
SUPPRESS_MUXCLIENT},
{"?", "this message", SUPPRESS_NEVER},
};
static void
print_escape_help(struct sshbuf *b, int escape_char, int mux_client,
int using_stderr)
{
unsigned int i, suppress_flags;
int r;
if ((r = sshbuf_putf(b,
"%c?\r\nSupported escape sequences:\r\n", escape_char)) != 0)
fatal_fr(r, "sshbuf_putf");
suppress_flags =
(mux_client ? SUPPRESS_MUXCLIENT : 0) |
(mux_client ? 0 : SUPPRESS_MUXMASTER) |
(using_stderr ? 0 : SUPPRESS_SYSLOG);
for (i = 0; i < sizeof(esc_txt)/sizeof(esc_txt[0]); i++) {
if (esc_txt[i].flags & suppress_flags)
continue;
if ((r = sshbuf_putf(b, " %c%-3s - %s\r\n",
escape_char, esc_txt[i].cmd, esc_txt[i].text)) != 0)
fatal_fr(r, "sshbuf_putf");
}
if ((r = sshbuf_putf(b,
" %c%c - send the escape character by typing it twice\r\n"
"(Note that escapes are only recognized immediately after "
"newline.)\r\n", escape_char, escape_char)) != 0)
fatal_fr(r, "sshbuf_putf");
}
/*
* Process the characters one by one.
*/
static int
process_escapes(struct ssh *ssh, Channel *c,
struct sshbuf *bin, struct sshbuf *bout, struct sshbuf *berr,
char *buf, int len)
{
pid_t pid;
int r, bytes = 0;
u_int i;
u_char ch;
char *s;
struct escape_filter_ctx *efc = c->filter_ctx == NULL ?
NULL : (struct escape_filter_ctx *)c->filter_ctx;
if (c->filter_ctx == NULL)
return 0;
if (len <= 0)
return (0);
for (i = 0; i < (u_int)len; i++) {
/* Get one character at a time. */
ch = buf[i];
if (efc->escape_pending) {
/* We have previously seen an escape character. */
/* Clear the flag now. */
efc->escape_pending = 0;
/* Process the escaped character. */
switch (ch) {
case '.':
/* Terminate the connection. */
if ((r = sshbuf_putf(berr, "%c.\r\n",
efc->escape_char)) != 0)
fatal_fr(r, "sshbuf_putf");
if (c && c->ctl_chan != -1) {
chan_read_failed(ssh, c);
chan_write_failed(ssh, c);
if (c->detach_user) {
c->detach_user(ssh,
c->self, NULL);
}
c->type = SSH_CHANNEL_ABANDONED;
sshbuf_reset(c->input);
chan_ibuf_empty(ssh, c);
return 0;
} else
quit_pending = 1;
return -1;
case 'Z' - 64:
/* XXX support this for mux clients */
if (c && c->ctl_chan != -1) {
char b[16];
noescape:
if (ch == 'Z' - 64)
snprintf(b, sizeof b, "^Z");
else
snprintf(b, sizeof b, "%c", ch);
if ((r = sshbuf_putf(berr,
"%c%s escape not available to "
"multiplexed sessions\r\n",
efc->escape_char, b)) != 0)
fatal_fr(r, "sshbuf_putf");
continue;
}
/* Suspend the program. Inform the user */
if ((r = sshbuf_putf(berr,
"%c^Z [suspend ssh]\r\n",
efc->escape_char)) != 0)
fatal_fr(r, "sshbuf_putf");
/* Restore terminal modes and suspend. */
client_suspend_self(bin, bout, berr);
/* We have been continued. */
continue;
case 'B':
if ((r = sshbuf_putf(berr,
"%cB\r\n", efc->escape_char)) != 0)
fatal_fr(r, "sshbuf_putf");
channel_request_start(ssh, c->self, "break", 0);
if ((r = sshpkt_put_u32(ssh, 1000)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send packet");
continue;
case 'R':
if (ssh->compat & SSH_BUG_NOREKEY)
logit("Server does not "
"support re-keying");
else
need_rekeying = 1;
continue;
case 'V':
/* FALLTHROUGH */
case 'v':
if (c && c->ctl_chan != -1)
goto noescape;
if (!log_is_on_stderr()) {
if ((r = sshbuf_putf(berr,
"%c%c [Logging to syslog]\r\n",
efc->escape_char, ch)) != 0)
fatal_fr(r, "sshbuf_putf");
continue;
}
if (ch == 'V' && options.log_level >
SYSLOG_LEVEL_QUIET)
log_change_level(--options.log_level);
if (ch == 'v' && options.log_level <
SYSLOG_LEVEL_DEBUG3)
log_change_level(++options.log_level);
if ((r = sshbuf_putf(berr,
"%c%c [LogLevel %s]\r\n",
efc->escape_char, ch,
log_level_name(options.log_level))) != 0)
fatal_fr(r, "sshbuf_putf");
continue;
case '&':
if (c && c->ctl_chan != -1)
goto noescape;
/*
* Detach the program (continue to serve
* connections, but put in background and no
* more new connections).
*/
/* Restore tty modes. */
leave_raw_mode(
options.request_tty == REQUEST_TTY_FORCE);
/* Stop listening for new connections. */
channel_stop_listening(ssh);
if ((r = sshbuf_putf(berr, "%c& "
"[backgrounded]\n", efc->escape_char)) != 0)
fatal_fr(r, "sshbuf_putf");
/* Fork into background. */
pid = fork();
if (pid == -1) {
error("fork: %.100s", strerror(errno));
continue;
}
if (pid != 0) { /* This is the parent. */
/* The parent just exits. */
exit(0);
}
/* The child continues serving connections. */
/* fake EOF on stdin */
if ((r = sshbuf_put_u8(bin, 4)) != 0)
fatal_fr(r, "sshbuf_put_u8");
return -1;
case '?':
print_escape_help(berr, efc->escape_char,
(c && c->ctl_chan != -1),
log_is_on_stderr());
continue;
case '#':
if ((r = sshbuf_putf(berr, "%c#\r\n",
efc->escape_char)) != 0)
fatal_fr(r, "sshbuf_putf");
s = channel_open_message(ssh);
if ((r = sshbuf_put(berr, s, strlen(s))) != 0)
fatal_fr(r, "sshbuf_put");
free(s);
continue;
case 'C':
if (c && c->ctl_chan != -1)
goto noescape;
process_cmdline(ssh);
continue;
default:
if (ch != efc->escape_char) {
if ((r = sshbuf_put_u8(bin,
efc->escape_char)) != 0)
fatal_fr(r, "sshbuf_put_u8");
bytes++;
}
/* Escaped characters fall through here */
break;
}
} else {
/*
* The previous character was not an escape char.
* Check if this is an escape.
*/
if (last_was_cr && ch == efc->escape_char) {
/*
* It is. Set the flag and continue to
* next character.
*/
efc->escape_pending = 1;
continue;
}
}
/*
* Normal character. Record whether it was a newline,
* and append it to the buffer.
*/
last_was_cr = (ch == '\r' || ch == '\n');
if ((r = sshbuf_put_u8(bin, ch)) != 0)
fatal_fr(r, "sshbuf_put_u8");
bytes++;
}
return bytes;
}
/*
* Get packets from the connection input buffer, and process them as long as
* there are packets available.
*
* Any unknown packets received during the actual
* session cause the session to terminate. This is
* intended to make debugging easier since no
* confirmations are sent. Any compatible protocol
* extensions must be negotiated during the
* preparatory phase.
*/
static void
client_process_buffered_input_packets(struct ssh *ssh)
{
ssh_dispatch_run_fatal(ssh, DISPATCH_NONBLOCK, &quit_pending);
}
/* scan buf[] for '~' before sending data to the peer */
/* Helper: allocate a new escape_filter_ctx and fill in its escape char */
void *
client_new_escape_filter_ctx(int escape_char)
{
struct escape_filter_ctx *ret;
ret = xcalloc(1, sizeof(*ret));
ret->escape_pending = 0;
ret->escape_char = escape_char;
return (void *)ret;
}
/* Free the escape filter context on channel free */
void
client_filter_cleanup(struct ssh *ssh, int cid, void *ctx)
{
free(ctx);
}
int
client_simple_escape_filter(struct ssh *ssh, Channel *c, char *buf, int len)
{
if (c->extended_usage != CHAN_EXTENDED_WRITE)
return 0;
return process_escapes(ssh, c, c->input, c->output, c->extended,
buf, len);
}
static void
client_channel_closed(struct ssh *ssh, int id, void *arg)
{
channel_cancel_cleanup(ssh, id);
session_closed = 1;
leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
}
/*
* Implements the interactive session with the server. This is called after
* the user has been authenticated, and a command has been started on the
* remote host. If escape_char != SSH_ESCAPECHAR_NONE, it is the character
* used as an escape character for terminating or suspending the session.
*/
int
client_loop(struct ssh *ssh, int have_pty, int escape_char_arg,
int ssh2_chan_id)
{
fd_set *readset = NULL, *writeset = NULL;
double start_time, total_time;
int r, max_fd = 0, max_fd2 = 0, len;
u_int64_t ibytes, obytes;
u_int nalloc = 0;
debug("Entering interactive session.");
if (options.control_master &&
!option_clear_or_none(options.control_path)) {
debug("pledge: id");
if (pledge("stdio rpath wpath cpath unix inet dns recvfd sendfd proc exec id tty",
NULL) == -1)
fatal_f("pledge(): %s", strerror(errno));
} else if (options.forward_x11 || options.permit_local_command) {
debug("pledge: exec");
if (pledge("stdio rpath wpath cpath unix inet dns proc exec tty",
NULL) == -1)
fatal_f("pledge(): %s", strerror(errno));
} else if (options.update_hostkeys) {
debug("pledge: filesystem full");
if (pledge("stdio rpath wpath cpath unix inet dns proc tty",
NULL) == -1)
fatal_f("pledge(): %s", strerror(errno));
} else if (!option_clear_or_none(options.proxy_command) ||
fork_after_authentication_flag) {
debug("pledge: proc");
if (pledge("stdio cpath unix inet dns proc tty", NULL) == -1)
fatal_f("pledge(): %s", strerror(errno));
} else {
debug("pledge: network");
if (pledge("stdio unix inet dns proc tty", NULL) == -1)
fatal_f("pledge(): %s", strerror(errno));
}
start_time = monotime_double();
/* Initialize variables. */
last_was_cr = 1;
exit_status = -1;
connection_in = ssh_packet_get_connection_in(ssh);
connection_out = ssh_packet_get_connection_out(ssh);
max_fd = MAXIMUM(connection_in, connection_out);
quit_pending = 0;
/* Initialize buffer. */
if ((stderr_buffer = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
client_init_dispatch(ssh);
/*
* Set signal handlers, (e.g. to restore non-blocking mode)
* but don't overwrite SIG_IGN, matches behaviour from rsh(1)
*/
if (ssh_signal(SIGHUP, SIG_IGN) != SIG_IGN)
ssh_signal(SIGHUP, signal_handler);
if (ssh_signal(SIGINT, SIG_IGN) != SIG_IGN)
ssh_signal(SIGINT, signal_handler);
if (ssh_signal(SIGQUIT, SIG_IGN) != SIG_IGN)
ssh_signal(SIGQUIT, signal_handler);
if (ssh_signal(SIGTERM, SIG_IGN) != SIG_IGN)
ssh_signal(SIGTERM, signal_handler);
ssh_signal(SIGWINCH, window_change_handler);
if (have_pty)
enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
session_ident = ssh2_chan_id;
if (session_ident != -1) {
if (escape_char_arg != SSH_ESCAPECHAR_NONE) {
channel_register_filter(ssh, session_ident,
client_simple_escape_filter, NULL,
client_filter_cleanup,
client_new_escape_filter_ctx(
escape_char_arg));
}
channel_register_cleanup(ssh, session_ident,
client_channel_closed, 0);
}
schedule_server_alive_check();
/* Main loop of the client for the interactive session mode. */
while (!quit_pending) {
/* Process buffered packets sent by the server. */
client_process_buffered_input_packets(ssh);
if (session_closed && !channel_still_open(ssh))
break;
if (ssh_packet_is_rekeying(ssh)) {
debug("rekeying in progress");
} else if (need_rekeying) {
/* manual rekey request */
debug("need rekeying");
if ((r = kex_start_rekex(ssh)) != 0)
fatal_fr(r, "kex_start_rekex");
need_rekeying = 0;
} else {
/*
* Make packets from buffered channel data, and
* enqueue them for sending to the server.
*/
if (ssh_packet_not_very_much_data_to_write(ssh))
channel_output_poll(ssh);
/*
* Check if the window size has changed, and buffer a
* message about it to the server if so.
*/
client_check_window_change(ssh);
if (quit_pending)
break;
}
/*
* Wait until we have something to do (something becomes
* available on one of the descriptors).
*/
max_fd2 = max_fd;
client_wait_until_can_do_something(ssh, &readset, &writeset,
&max_fd2, &nalloc, ssh_packet_is_rekeying(ssh));
if (quit_pending)
break;
/* Do channel operations unless rekeying in progress. */
if (!ssh_packet_is_rekeying(ssh))
channel_after_select(ssh, readset, writeset);
/* Buffer input from the connection. */
client_process_net_input(ssh, readset);
if (quit_pending)
break;
/*
* Send as much buffered packet data as possible to the
* sender.
*/
if (FD_ISSET(connection_out, writeset)) {
if ((r = ssh_packet_write_poll(ssh)) != 0) {
sshpkt_fatal(ssh, r,
"%s: ssh_packet_write_poll", __func__);
}
}
/*
* If we are a backgrounded control master, and the
* timeout has expired without any active client
* connections, then quit.
*/
if (control_persist_exit_time > 0) {
if (monotime() >= control_persist_exit_time) {
debug("ControlPersist timeout expired");
break;
}
}
}
free(readset);
free(writeset);
/* Terminate the session. */
/* Stop watching for window change. */
ssh_signal(SIGWINCH, SIG_DFL);
if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 ||
(r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_BY_APPLICATION)) != 0 ||
(r = sshpkt_put_cstring(ssh, "disconnected by user")) != 0 ||
(r = sshpkt_put_cstring(ssh, "")) != 0 || /* language tag */
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
fatal_fr(r, "send disconnect");
channel_free_all(ssh);
if (have_pty)
leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
/* restore blocking io */
if (!isatty(fileno(stdin)))
unset_nonblock(fileno(stdin));
if (!isatty(fileno(stdout)))
unset_nonblock(fileno(stdout));
if (!isatty(fileno(stderr)))
unset_nonblock(fileno(stderr));
/*
* If there was no shell or command requested, there will be no remote
* exit status to be returned. In that case, clear error code if the
* connection was deliberately terminated at this end.
*/
if (no_shell_flag && received_signal == SIGTERM) {
received_signal = 0;
exit_status = 0;
}
if (received_signal) {
verbose("Killed by signal %d.", (int) received_signal);
- cleanup_exit(0);
+ cleanup_exit(255);
}
/*
* In interactive mode (with pseudo tty) display a message indicating
* that the connection has been closed.
*/
if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) {
if ((r = sshbuf_putf(stderr_buffer,
"Connection to %.64s closed.\r\n", host)) != 0)
fatal_fr(r, "sshbuf_putf");
}
/* Output any buffered data for stderr. */
if (sshbuf_len(stderr_buffer) > 0) {
len = atomicio(vwrite, fileno(stderr),
(u_char *)sshbuf_ptr(stderr_buffer),
sshbuf_len(stderr_buffer));
if (len < 0 || (u_int)len != sshbuf_len(stderr_buffer))
error("Write failed flushing stderr buffer.");
else if ((r = sshbuf_consume(stderr_buffer, len)) != 0)
fatal_fr(r, "sshbuf_consume");
}
/* Clear and free any buffers. */
sshbuf_free(stderr_buffer);
/* Report bytes transferred, and transfer rates. */
total_time = monotime_double() - start_time;
ssh_packet_get_bytes(ssh, &ibytes, &obytes);
verbose("Transferred: sent %llu, received %llu bytes, in %.1f seconds",
(unsigned long long)obytes, (unsigned long long)ibytes, total_time);
if (total_time > 0)
verbose("Bytes per second: sent %.1f, received %.1f",
obytes / total_time, ibytes / total_time);
/* Return the exit status of the program. */
debug("Exit status %d", exit_status);
return exit_status;
}
/*********/
static Channel *
client_request_forwarded_tcpip(struct ssh *ssh, const char *request_type,
int rchan, u_int rwindow, u_int rmaxpack)
{
Channel *c = NULL;
struct sshbuf *b = NULL;
char *listen_address, *originator_address;
u_int listen_port, originator_port;
int r;
/* Get rest of the packet */
if ((r = sshpkt_get_cstring(ssh, &listen_address, NULL)) != 0 ||
(r = sshpkt_get_u32(ssh, &listen_port)) != 0 ||
(r = sshpkt_get_cstring(ssh, &originator_address, NULL)) != 0 ||
(r = sshpkt_get_u32(ssh, &originator_port)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
fatal_fr(r, "parse packet");
debug_f("listen %s port %d, originator %s port %d",
listen_address, listen_port, originator_address, originator_port);
if (listen_port > 0xffff)
error_f("invalid listen port");
else if (originator_port > 0xffff)
error_f("invalid originator port");
else {
c = channel_connect_by_listen_address(ssh,
listen_address, listen_port, "forwarded-tcpip",
originator_address);
}
if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) {
if ((b = sshbuf_new()) == NULL) {
error_f("alloc reply");
goto out;
}
/* reconstruct and send to muxclient */
if ((r = sshbuf_put_u8(b, 0)) != 0 || /* padlen */
(r = sshbuf_put_u8(b, SSH2_MSG_CHANNEL_OPEN)) != 0 ||
(r = sshbuf_put_cstring(b, request_type)) != 0 ||
(r = sshbuf_put_u32(b, rchan)) != 0 ||
(r = sshbuf_put_u32(b, rwindow)) != 0 ||
(r = sshbuf_put_u32(b, rmaxpack)) != 0 ||
(r = sshbuf_put_cstring(b, listen_address)) != 0 ||
(r = sshbuf_put_u32(b, listen_port)) != 0 ||
(r = sshbuf_put_cstring(b, originator_address)) != 0 ||
(r = sshbuf_put_u32(b, originator_port)) != 0 ||
(r = sshbuf_put_stringb(c->output, b)) != 0) {
error_fr(r, "compose for muxclient");
goto out;
}
}
out:
sshbuf_free(b);
free(originator_address);
free(listen_address);
return c;
}
static Channel *
client_request_forwarded_streamlocal(struct ssh *ssh,
const char *request_type, int rchan)
{
Channel *c = NULL;
char *listen_path;
int r;
/* Get the remote path. */
if ((r = sshpkt_get_cstring(ssh, &listen_path, NULL)) != 0 ||
(r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* reserved */
(r = sshpkt_get_end(ssh)) != 0)
fatal_fr(r, "parse packet");
debug_f("request: %s", listen_path);
c = channel_connect_by_listen_path(ssh, listen_path,
"forwarded-streamlocal@openssh.com", "forwarded-streamlocal");
free(listen_path);
return c;
}
static Channel *
client_request_x11(struct ssh *ssh, const char *request_type, int rchan)
{
Channel *c = NULL;
char *originator;
u_int originator_port;
int r, sock;
if (!options.forward_x11) {
error("Warning: ssh server tried X11 forwarding.");
error("Warning: this is probably a break-in attempt by a "
"malicious server.");
return NULL;
}
if (x11_refuse_time != 0 && (u_int)monotime() >= x11_refuse_time) {
verbose("Rejected X11 connection after ForwardX11Timeout "
"expired");
return NULL;
}
if ((r = sshpkt_get_cstring(ssh, &originator, NULL)) != 0 ||
(r = sshpkt_get_u32(ssh, &originator_port)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
fatal_fr(r, "parse packet");
/* XXX check permission */
/* XXX range check originator port? */
debug("client_request_x11: request from %s %u", originator,
originator_port);
free(originator);
sock = x11_connect_display(ssh);
if (sock < 0)
return NULL;
c = channel_new(ssh, "x11",
SSH_CHANNEL_X11_OPEN, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1);
c->force_drain = 1;
return c;
}
static Channel *
client_request_agent(struct ssh *ssh, const char *request_type, int rchan)
{
Channel *c = NULL;
int r, sock;
if (!options.forward_agent) {
error("Warning: ssh server tried agent forwarding.");
error("Warning: this is probably a break-in attempt by a "
"malicious server.");
return NULL;
}
if (forward_agent_sock_path == NULL) {
r = ssh_get_authentication_socket(&sock);
} else {
r = ssh_get_authentication_socket_path(forward_agent_sock_path, &sock);
}
if (r != 0) {
if (r != SSH_ERR_AGENT_NOT_PRESENT)
debug_fr(r, "ssh_get_authentication_socket");
return NULL;
}
c = channel_new(ssh, "authentication agent connection",
SSH_CHANNEL_OPEN, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0,
"authentication agent connection", 1);
c->force_drain = 1;
return c;
}
char *
client_request_tun_fwd(struct ssh *ssh, int tun_mode,
int local_tun, int remote_tun, channel_open_fn *cb, void *cbctx)
{
Channel *c;
int r, fd;
char *ifname = NULL;
if (tun_mode == SSH_TUNMODE_NO)
return 0;
debug("Requesting tun unit %d in mode %d", local_tun, tun_mode);
/* Open local tunnel device */
if ((fd = tun_open(local_tun, tun_mode, &ifname)) == -1) {
error("Tunnel device open failed.");
return NULL;
}
debug("Tunnel forwarding using interface %s", ifname);
c = channel_new(ssh, "tun", SSH_CHANNEL_OPENING, fd, fd, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
c->datagram = 1;
#if defined(SSH_TUN_FILTER)
if (options.tun_open == SSH_TUNMODE_POINTOPOINT)
channel_register_filter(ssh, c->self, sys_tun_infilter,
sys_tun_outfilter, NULL, NULL);
#endif
if (cb != NULL)
channel_register_open_confirm(ssh, c->self, cb, cbctx);
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN)) != 0 ||
(r = sshpkt_put_cstring(ssh, "tun@openssh.com")) != 0 ||
(r = sshpkt_put_u32(ssh, c->self)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_window_max)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0 ||
(r = sshpkt_put_u32(ssh, tun_mode)) != 0 ||
(r = sshpkt_put_u32(ssh, remote_tun)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: send reply", __func__);
return ifname;
}
/* XXXX move to generic input handler */
static int
client_input_channel_open(int type, u_int32_t seq, struct ssh *ssh)
{
Channel *c = NULL;
char *ctype = NULL;
int r;
u_int rchan;
size_t len;
u_int rmaxpack, rwindow;
if ((r = sshpkt_get_cstring(ssh, &ctype, &len)) != 0 ||
(r = sshpkt_get_u32(ssh, &rchan)) != 0 ||
(r = sshpkt_get_u32(ssh, &rwindow)) != 0 ||
(r = sshpkt_get_u32(ssh, &rmaxpack)) != 0)
goto out;
debug("client_input_channel_open: ctype %s rchan %d win %d max %d",
ctype, rchan, rwindow, rmaxpack);
if (strcmp(ctype, "forwarded-tcpip") == 0) {
c = client_request_forwarded_tcpip(ssh, ctype, rchan, rwindow,
rmaxpack);
} else if (strcmp(ctype, "forwarded-streamlocal@openssh.com") == 0) {
c = client_request_forwarded_streamlocal(ssh, ctype, rchan);
} else if (strcmp(ctype, "x11") == 0) {
c = client_request_x11(ssh, ctype, rchan);
} else if (strcmp(ctype, "auth-agent@openssh.com") == 0) {
c = client_request_agent(ssh, ctype, rchan);
}
if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) {
debug3("proxied to downstream: %s", ctype);
} else if (c != NULL) {
debug("confirm %s", ctype);
c->remote_id = rchan;
c->have_remote_id = 1;
c->remote_window = rwindow;
c->remote_maxpacket = rmaxpack;
if (c->type != SSH_CHANNEL_CONNECTING) {
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 ||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
(r = sshpkt_put_u32(ssh, c->self)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: send reply", __func__);
}
} else {
debug("failure %s", ctype);
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN_FAILURE)) != 0 ||
(r = sshpkt_put_u32(ssh, rchan)) != 0 ||
(r = sshpkt_put_u32(ssh, SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED)) != 0 ||
(r = sshpkt_put_cstring(ssh, "open failed")) != 0 ||
(r = sshpkt_put_cstring(ssh, "")) != 0 ||
(r = sshpkt_send(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: send failure", __func__);
}
r = 0;
out:
free(ctype);
return r;
}
static int
client_input_channel_req(int type, u_int32_t seq, struct ssh *ssh)
{
Channel *c = NULL;
char *rtype = NULL;
u_char reply;
u_int id, exitval;
int r, success = 0;
if ((r = sshpkt_get_u32(ssh, &id)) != 0)
return r;
if (id <= INT_MAX)
c = channel_lookup(ssh, id);
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
if ((r = sshpkt_get_cstring(ssh, &rtype, NULL)) != 0 ||
(r = sshpkt_get_u8(ssh, &reply)) != 0)
goto out;
debug("client_input_channel_req: channel %u rtype %s reply %d",
id, rtype, reply);
if (c == NULL) {
error("client_input_channel_req: channel %d: "
"unknown channel", id);
} else if (strcmp(rtype, "eow@openssh.com") == 0) {
if ((r = sshpkt_get_end(ssh)) != 0)
goto out;
chan_rcvd_eow(ssh, c);
} else if (strcmp(rtype, "exit-status") == 0) {
if ((r = sshpkt_get_u32(ssh, &exitval)) != 0)
goto out;
if (c->ctl_chan != -1) {
mux_exit_message(ssh, c, exitval);
success = 1;
} else if ((int)id == session_ident) {
/* Record exit value of local session */
success = 1;
exit_status = exitval;
} else {
/* Probably for a mux channel that has already closed */
debug_f("no sink for exit-status on channel %d",
id);
}
if ((r = sshpkt_get_end(ssh)) != 0)
goto out;
}
if (reply && c != NULL && !(c->flags & CHAN_CLOSE_SENT)) {
if (!c->have_remote_id)
fatal_f("channel %d: no remote_id", c->self);
if ((r = sshpkt_start(ssh, success ?
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE)) != 0 ||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: send failure", __func__);
}
r = 0;
out:
free(rtype);
return r;
}
struct hostkeys_update_ctx {
/* The hostname and (optionally) IP address string for the server */
char *host_str, *ip_str;
/*
* Keys received from the server and a flag for each indicating
* whether they already exist in known_hosts.
* keys_match is filled in by hostkeys_find() and later (for new
* keys) by client_global_hostkeys_private_confirm().
*/
struct sshkey **keys;
u_int *keys_match; /* mask of HKF_MATCH_* from hostfile.h */
int *keys_verified; /* flag for new keys verified by server */
size_t nkeys, nnew, nincomplete; /* total, new keys, incomplete match */
/*
* Keys that are in known_hosts, but were not present in the update
* from the server (i.e. scheduled to be deleted).
* Filled in by hostkeys_find().
*/
struct sshkey **old_keys;
size_t nold;
/* Various special cases. */
int complex_hostspec; /* wildcard or manual pattern-list host name */
int ca_available; /* saw CA key for this host */
int old_key_seen; /* saw old key with other name/addr */
int other_name_seen; /* saw key with other name/addr */
};
static void
hostkeys_update_ctx_free(struct hostkeys_update_ctx *ctx)
{
size_t i;
if (ctx == NULL)
return;
for (i = 0; i < ctx->nkeys; i++)
sshkey_free(ctx->keys[i]);
free(ctx->keys);
free(ctx->keys_match);
free(ctx->keys_verified);
for (i = 0; i < ctx->nold; i++)
sshkey_free(ctx->old_keys[i]);
free(ctx->old_keys);
free(ctx->host_str);
free(ctx->ip_str);
free(ctx);
}
/*
* Returns non-zero if a known_hosts hostname list is not of a form that
* can be handled by UpdateHostkeys. These include wildcard hostnames and
* hostnames lists that do not follow the form host[,ip].
*/
static int
hostspec_is_complex(const char *hosts)
{
char *cp;
/* wildcard */
if (strchr(hosts, '*') != NULL || strchr(hosts, '?') != NULL)
return 1;
/* single host/ip = ok */
if ((cp = strchr(hosts, ',')) == NULL)
return 0;
/* more than two entries on the line */
if (strchr(cp + 1, ',') != NULL)
return 1;
/* XXX maybe parse cp+1 and ensure it is an IP? */
return 0;
}
/* callback to search for ctx->keys in known_hosts */
static int
hostkeys_find(struct hostkey_foreach_line *l, void *_ctx)
{
struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx;
size_t i;
struct sshkey **tmp;
if (l->key == NULL)
return 0;
if (l->status != HKF_STATUS_MATCHED) {
/* Record if one of the keys appears on a non-matching line */
for (i = 0; i < ctx->nkeys; i++) {
if (sshkey_equal(l->key, ctx->keys[i])) {
ctx->other_name_seen = 1;
debug3_f("found %s key under different "
"name/addr at %s:%ld",
sshkey_ssh_name(ctx->keys[i]),
l->path, l->linenum);
return 0;
}
}
return 0;
}
/* Don't proceed if revocation or CA markers are present */
/* XXX relax this */
if (l->marker != MRK_NONE) {
debug3_f("hostkeys file %s:%ld has CA/revocation marker",
l->path, l->linenum);
ctx->complex_hostspec = 1;
return 0;
}
/* If CheckHostIP is enabled, then check for mismatched hostname/addr */
if (ctx->ip_str != NULL && strchr(l->hosts, ',') != NULL) {
if ((l->match & HKF_MATCH_HOST) == 0) {
/* Record if address matched a different hostname. */
ctx->other_name_seen = 1;
debug3_f("found address %s against different hostname "
"at %s:%ld", ctx->ip_str, l->path, l->linenum);
return 0;
} else if ((l->match & HKF_MATCH_IP) == 0) {
/* Record if hostname matched a different address. */
ctx->other_name_seen = 1;
debug3_f("found hostname %s against different address "
"at %s:%ld", ctx->host_str, l->path, l->linenum);
}
}
/*
* UpdateHostkeys is skipped for wildcard host names and hostnames
* that contain more than two entries (ssh never writes these).
*/
if (hostspec_is_complex(l->hosts)) {
debug3_f("hostkeys file %s:%ld complex host specification",
l->path, l->linenum);
ctx->complex_hostspec = 1;
return 0;
}
/* Mark off keys we've already seen for this host */
for (i = 0; i < ctx->nkeys; i++) {
if (!sshkey_equal(l->key, ctx->keys[i]))
continue;
debug3_f("found %s key at %s:%ld",
sshkey_ssh_name(ctx->keys[i]), l->path, l->linenum);
ctx->keys_match[i] |= l->match;
return 0;
}
/* This line contained a key that not offered by the server */
debug3_f("deprecated %s key at %s:%ld", sshkey_ssh_name(l->key),
l->path, l->linenum);
if ((tmp = recallocarray(ctx->old_keys, ctx->nold, ctx->nold + 1,
sizeof(*ctx->old_keys))) == NULL)
fatal_f("recallocarray failed nold = %zu", ctx->nold);
ctx->old_keys = tmp;
ctx->old_keys[ctx->nold++] = l->key;
l->key = NULL;
return 0;
}
/* callback to search for ctx->old_keys in known_hosts under other names */
static int
hostkeys_check_old(struct hostkey_foreach_line *l, void *_ctx)
{
struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx;
size_t i;
int hashed;
/* only care about lines that *don't* match the active host spec */
if (l->status == HKF_STATUS_MATCHED || l->key == NULL)
return 0;
hashed = l->match & (HKF_MATCH_HOST_HASHED|HKF_MATCH_IP_HASHED);
for (i = 0; i < ctx->nold; i++) {
if (!sshkey_equal(l->key, ctx->old_keys[i]))
continue;
debug3_f("found deprecated %s key at %s:%ld as %s",
sshkey_ssh_name(ctx->keys[i]), l->path, l->linenum,
hashed ? "[HASHED]" : l->hosts);
ctx->old_key_seen = 1;
break;
}
return 0;
}
/*
* Check known_hosts files for deprecated keys under other names. Returns 0
* on success or -1 on failure. Updates ctx->old_key_seen if deprecated keys
* exist under names other than the active hostname/IP.
*/
static int
check_old_keys_othernames(struct hostkeys_update_ctx *ctx)
{
size_t i;
int r;
debug2_f("checking for %zu deprecated keys", ctx->nold);
for (i = 0; i < options.num_user_hostfiles; i++) {
debug3_f("searching %s for %s / %s",
options.user_hostfiles[i], ctx->host_str,
ctx->ip_str ? ctx->ip_str : "(none)");
if ((r = hostkeys_foreach(options.user_hostfiles[i],
hostkeys_check_old, ctx, ctx->host_str, ctx->ip_str,
HKF_WANT_PARSE_KEY, 0)) != 0) {
if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) {
debug_f("hostkeys file %s does not exist",
options.user_hostfiles[i]);
continue;
}
error_fr(r, "hostkeys_foreach failed for %s",
options.user_hostfiles[i]);
return -1;
}
}
return 0;
}
static void
hostkey_change_preamble(LogLevel loglevel)
{
do_log2(loglevel, "The server has updated its host keys.");
do_log2(loglevel, "These changes were verified by the server's "
"existing trusted key.");
}
static void
update_known_hosts(struct hostkeys_update_ctx *ctx)
{
int r, was_raw = 0, first = 1;
int asking = options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK;
LogLevel loglevel = asking ? SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_VERBOSE;
char *fp, *response;
size_t i;
struct stat sb;
for (i = 0; i < ctx->nkeys; i++) {
if (!ctx->keys_verified[i])
continue;
if ((fp = sshkey_fingerprint(ctx->keys[i],
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
fatal_f("sshkey_fingerprint failed");
if (first && asking)
hostkey_change_preamble(loglevel);
do_log2(loglevel, "Learned new hostkey: %s %s",
sshkey_type(ctx->keys[i]), fp);
first = 0;
free(fp);
}
for (i = 0; i < ctx->nold; i++) {
if ((fp = sshkey_fingerprint(ctx->old_keys[i],
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
fatal_f("sshkey_fingerprint failed");
if (first && asking)
hostkey_change_preamble(loglevel);
do_log2(loglevel, "Deprecating obsolete hostkey: %s %s",
sshkey_type(ctx->old_keys[i]), fp);
first = 0;
free(fp);
}
if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK) {
if (get_saved_tio() != NULL) {
leave_raw_mode(1);
was_raw = 1;
}
response = NULL;
for (i = 0; !quit_pending && i < 3; i++) {
free(response);
response = read_passphrase("Accept updated hostkeys? "
"(yes/no): ", RP_ECHO);
if (strcasecmp(response, "yes") == 0)
break;
else if (quit_pending || response == NULL ||
strcasecmp(response, "no") == 0) {
options.update_hostkeys = 0;
break;
} else {
do_log2(loglevel, "Please enter "
"\"yes\" or \"no\"");
}
}
if (quit_pending || i >= 3 || response == NULL)
options.update_hostkeys = 0;
free(response);
if (was_raw)
enter_raw_mode(1);
}
if (options.update_hostkeys == 0)
return;
/*
* Now that all the keys are verified, we can go ahead and replace
* them in known_hosts (assuming SSH_UPDATE_HOSTKEYS_ASK didn't
* cancel the operation).
*/
for (i = 0; i < options.num_user_hostfiles; i++) {
/*
* NB. keys are only added to hostfiles[0], for the rest we
* just delete the hostname entries.
*/
if (stat(options.user_hostfiles[i], &sb) != 0) {
if (errno == ENOENT) {
debug_f("known hosts file %s does not "
"exist", options.user_hostfiles[i]);
} else {
error_f("known hosts file %s "
"inaccessible: %s",
options.user_hostfiles[i], strerror(errno));
}
continue;
}
if ((r = hostfile_replace_entries(options.user_hostfiles[i],
ctx->host_str, ctx->ip_str,
i == 0 ? ctx->keys : NULL, i == 0 ? ctx->nkeys : 0,
options.hash_known_hosts, 0,
options.fingerprint_hash)) != 0) {
error_fr(r, "hostfile_replace_entries failed for %s",
options.user_hostfiles[i]);
}
}
}
static void
client_global_hostkeys_private_confirm(struct ssh *ssh, int type,
u_int32_t seq, void *_ctx)
{
struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx;
size_t i, ndone;
struct sshbuf *signdata;
int r, kexsigtype, use_kexsigtype;
const u_char *sig;
size_t siglen;
if (ctx->nnew == 0)
fatal_f("ctx->nnew == 0"); /* sanity */
if (type != SSH2_MSG_REQUEST_SUCCESS) {
error("Server failed to confirm ownership of "
"private host keys");
hostkeys_update_ctx_free(ctx);
return;
}
kexsigtype = sshkey_type_plain(
sshkey_type_from_name(ssh->kex->hostkey_alg));
if ((signdata = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
/*
* Expect a signature for each of the ctx->nnew private keys we
* haven't seen before. They will be in the same order as the
* ctx->keys where the corresponding ctx->keys_match[i] == 0.
*/
for (ndone = i = 0; i < ctx->nkeys; i++) {
if (ctx->keys_match[i])
continue;
/* Prepare data to be signed: session ID, unique string, key */
sshbuf_reset(signdata);
if ( (r = sshbuf_put_cstring(signdata,
"hostkeys-prove-00@openssh.com")) != 0 ||
(r = sshbuf_put_stringb(signdata,
ssh->kex->session_id)) != 0 ||
(r = sshkey_puts(ctx->keys[i], signdata)) != 0)
fatal_fr(r, "compose signdata");
/* Extract and verify signature */
if ((r = sshpkt_get_string_direct(ssh, &sig, &siglen)) != 0) {
error_fr(r, "parse sig");
goto out;
}
/*
* For RSA keys, prefer to use the signature type negotiated
* during KEX to the default (SHA1).
*/
use_kexsigtype = kexsigtype == KEY_RSA &&
sshkey_type_plain(ctx->keys[i]->type) == KEY_RSA;
if ((r = sshkey_verify(ctx->keys[i], sig, siglen,
sshbuf_ptr(signdata), sshbuf_len(signdata),
use_kexsigtype ? ssh->kex->hostkey_alg : NULL, 0,
NULL)) != 0) {
error_f("server gave bad signature for %s key %zu",
sshkey_type(ctx->keys[i]), i);
goto out;
}
/* Key is good. Mark it as 'seen' */
ctx->keys_verified[i] = 1;
ndone++;
}
/* Shouldn't happen */
if (ndone != ctx->nnew)
fatal_f("ndone != ctx->nnew (%zu / %zu)", ndone, ctx->nnew);
if ((r = sshpkt_get_end(ssh)) != 0) {
error_f("protocol error");
goto out;
}
/* Make the edits to known_hosts */
update_known_hosts(ctx);
out:
hostkeys_update_ctx_free(ctx);
}
/*
* Returns non-zero if the key is accepted by HostkeyAlgorithms.
* Made slightly less trivial by the multiple RSA signature algorithm names.
*/
static int
key_accepted_by_hostkeyalgs(const struct sshkey *key)
{
const char *ktype = sshkey_ssh_name(key);
const char *hostkeyalgs = options.hostkeyalgorithms;
if (key == NULL || key->type == KEY_UNSPEC)
return 0;
if (key->type == KEY_RSA &&
(match_pattern_list("rsa-sha2-256", hostkeyalgs, 0) == 1 ||
match_pattern_list("rsa-sha2-512", hostkeyalgs, 0) == 1))
return 1;
return match_pattern_list(ktype, hostkeyalgs, 0) == 1;
}
/*
* Handle hostkeys-00@openssh.com global request to inform the client of all
* the server's hostkeys. The keys are checked against the user's
* HostkeyAlgorithms preference before they are accepted.
*/
static int
client_input_hostkeys(struct ssh *ssh)
{
const u_char *blob = NULL;
size_t i, len = 0;
struct sshbuf *buf = NULL;
struct sshkey *key = NULL, **tmp;
int r;
char *fp;
static int hostkeys_seen = 0; /* XXX use struct ssh */
extern struct sockaddr_storage hostaddr; /* XXX from ssh.c */
struct hostkeys_update_ctx *ctx = NULL;
u_int want;
if (hostkeys_seen)
fatal_f("server already sent hostkeys");
if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK &&
options.batch_mode)
return 1; /* won't ask in batchmode, so don't even try */
if (!options.update_hostkeys || options.num_user_hostfiles <= 0)
return 1;
ctx = xcalloc(1, sizeof(*ctx));
while (ssh_packet_remaining(ssh) > 0) {
sshkey_free(key);
key = NULL;
if ((r = sshpkt_get_string_direct(ssh, &blob, &len)) != 0) {
error_fr(r, "parse key");
goto out;
}
if ((r = sshkey_from_blob(blob, len, &key)) != 0) {
do_log2_fr(r, r == SSH_ERR_KEY_TYPE_UNKNOWN ?
SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_ERROR,
"convert key");
continue;
}
fp = sshkey_fingerprint(key, options.fingerprint_hash,
SSH_FP_DEFAULT);
debug3_f("received %s key %s", sshkey_type(key), fp);
free(fp);
if (!key_accepted_by_hostkeyalgs(key)) {
debug3_f("%s key not permitted by "
"HostkeyAlgorithms", sshkey_ssh_name(key));
continue;
}
/* Skip certs */
if (sshkey_is_cert(key)) {
debug3_f("%s key is a certificate; skipping",
sshkey_ssh_name(key));
continue;
}
/* Ensure keys are unique */
for (i = 0; i < ctx->nkeys; i++) {
if (sshkey_equal(key, ctx->keys[i])) {
error_f("received duplicated %s host key",
sshkey_ssh_name(key));
goto out;
}
}
/* Key is good, record it */
if ((tmp = recallocarray(ctx->keys, ctx->nkeys, ctx->nkeys + 1,
sizeof(*ctx->keys))) == NULL)
fatal_f("recallocarray failed nkeys = %zu",
ctx->nkeys);
ctx->keys = tmp;
ctx->keys[ctx->nkeys++] = key;
key = NULL;
}
if (ctx->nkeys == 0) {
debug_f("server sent no hostkeys");
goto out;
}
if ((ctx->keys_match = calloc(ctx->nkeys,
sizeof(*ctx->keys_match))) == NULL ||
(ctx->keys_verified = calloc(ctx->nkeys,
sizeof(*ctx->keys_verified))) == NULL)
fatal_f("calloc failed");
get_hostfile_hostname_ipaddr(host,
options.check_host_ip ? (struct sockaddr *)&hostaddr : NULL,
options.port, &ctx->host_str,
options.check_host_ip ? &ctx->ip_str : NULL);
/* Find which keys we already know about. */
for (i = 0; i < options.num_user_hostfiles; i++) {
debug_f("searching %s for %s / %s",
options.user_hostfiles[i], ctx->host_str,
ctx->ip_str ? ctx->ip_str : "(none)");
if ((r = hostkeys_foreach(options.user_hostfiles[i],
hostkeys_find, ctx, ctx->host_str, ctx->ip_str,
HKF_WANT_PARSE_KEY, 0)) != 0) {
if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) {
debug_f("hostkeys file %s does not exist",
options.user_hostfiles[i]);
continue;
}
error_fr(r, "hostkeys_foreach failed for %s",
options.user_hostfiles[i]);
goto out;
}
}
/* Figure out if we have any new keys to add */
ctx->nnew = ctx->nincomplete = 0;
want = HKF_MATCH_HOST | ( options.check_host_ip ? HKF_MATCH_IP : 0);
for (i = 0; i < ctx->nkeys; i++) {
if (ctx->keys_match[i] == 0)
ctx->nnew++;
if ((ctx->keys_match[i] & want) != want)
ctx->nincomplete++;
}
debug3_f("%zu server keys: %zu new, %zu retained, "
"%zu incomplete match. %zu to remove", ctx->nkeys, ctx->nnew,
ctx->nkeys - ctx->nnew - ctx->nincomplete,
ctx->nincomplete, ctx->nold);
if (ctx->nnew == 0 && ctx->nold == 0) {
debug_f("no new or deprecated keys from server");
goto out;
}
/* Various reasons why we cannot proceed with the update */
if (ctx->complex_hostspec) {
debug_f("CA/revocation marker, manual host list or wildcard "
"host pattern found, skipping UserKnownHostsFile update");
goto out;
}
if (ctx->other_name_seen) {
debug_f("host key found matching a different name/address, "
"skipping UserKnownHostsFile update");
goto out;
}
/*
* If removing keys, check whether they appear under different
* names/addresses and refuse to proceed if they do. This avoids
* cases such as hosts with multiple names becoming inconsistent
* with regards to CheckHostIP entries.
* XXX UpdateHostkeys=force to override this (and other) checks?
*/
if (ctx->nold != 0) {
if (check_old_keys_othernames(ctx) != 0)
goto out; /* error already logged */
if (ctx->old_key_seen) {
debug_f("key(s) for %s%s%s exist under other names; "
"skipping UserKnownHostsFile update",
ctx->host_str, ctx->ip_str == NULL ? "" : ",",
ctx->ip_str == NULL ? "" : ctx->ip_str);
goto out;
}
}
if (ctx->nnew == 0) {
/*
* We have some keys to remove or fix matching for.
* We can proceed to do this without requiring a fresh proof
* from the server.
*/
update_known_hosts(ctx);
goto out;
}
/*
* We have received previously-unseen keys from the server.
* Ask the server to confirm ownership of the private halves.
*/
debug3_f("asking server to prove ownership for %zu keys", ctx->nnew);
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh,
"hostkeys-prove-00@openssh.com")) != 0 ||
(r = sshpkt_put_u8(ssh, 1)) != 0) /* bool: want reply */
fatal_fr(r, "prepare hostkeys-prove");
if ((buf = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
for (i = 0; i < ctx->nkeys; i++) {
if (ctx->keys_match[i])
continue;
sshbuf_reset(buf);
if ((r = sshkey_putb(ctx->keys[i], buf)) != 0 ||
(r = sshpkt_put_stringb(ssh, buf)) != 0)
fatal_fr(r, "assemble hostkeys-prove");
}
if ((r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send hostkeys-prove");
client_register_global_confirm(
client_global_hostkeys_private_confirm, ctx);
ctx = NULL; /* will be freed in callback */
/* Success */
out:
hostkeys_update_ctx_free(ctx);
sshkey_free(key);
sshbuf_free(buf);
/*
* NB. Return success for all cases. The server doesn't need to know
* what the client does with its hosts file.
*/
return 1;
}
static int
client_input_global_request(int type, u_int32_t seq, struct ssh *ssh)
{
char *rtype;
u_char want_reply;
int r, success = 0;
if ((r = sshpkt_get_cstring(ssh, &rtype, NULL)) != 0 ||
(r = sshpkt_get_u8(ssh, &want_reply)) != 0)
goto out;
debug("client_input_global_request: rtype %s want_reply %d",
rtype, want_reply);
if (strcmp(rtype, "hostkeys-00@openssh.com") == 0)
success = client_input_hostkeys(ssh);
if (want_reply) {
if ((r = sshpkt_start(ssh, success ? SSH2_MSG_REQUEST_SUCCESS :
SSH2_MSG_REQUEST_FAILURE)) != 0 ||
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
goto out;
}
r = 0;
out:
free(rtype);
return r;
}
static void
client_send_env(struct ssh *ssh, int id, const char *name, const char *val)
{
int r;
debug("channel %d: setting env %s = \"%s\"", id, name, val);
channel_request_start(ssh, id, "env", 0);
if ((r = sshpkt_put_cstring(ssh, name)) != 0 ||
(r = sshpkt_put_cstring(ssh, val)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send setenv");
}
void
client_session2_setup(struct ssh *ssh, int id, int want_tty, int want_subsystem,
const char *term, struct termios *tiop, int in_fd, struct sshbuf *cmd,
char **env)
{
int i, j, matched, len, r;
char *name, *val;
Channel *c = NULL;
debug2_f("id %d", id);
if ((c = channel_lookup(ssh, id)) == NULL)
fatal_f("channel %d: unknown channel", id);
ssh_packet_set_interactive(ssh, want_tty,
options.ip_qos_interactive, options.ip_qos_bulk);
if (want_tty) {
struct winsize ws;
/* Store window size in the packet. */
if (ioctl(in_fd, TIOCGWINSZ, &ws) == -1)
memset(&ws, 0, sizeof(ws));
channel_request_start(ssh, id, "pty-req", 1);
client_expect_confirm(ssh, id, "PTY allocation", CONFIRM_TTY);
if ((r = sshpkt_put_cstring(ssh, term != NULL ? term : ""))
!= 0 ||
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_col)) != 0 ||
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_row)) != 0 ||
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_xpixel)) != 0 ||
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_ypixel)) != 0)
fatal_fr(r, "build pty-req");
if (tiop == NULL)
tiop = get_saved_tio();
ssh_tty_make_modes(ssh, -1, tiop);
if ((r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send pty-req");
/* XXX wait for reply */
c->client_tty = 1;
}
/* Transfer any environment variables from client to server */
if (options.num_send_env != 0 && env != NULL) {
debug("Sending environment.");
for (i = 0; env[i] != NULL; i++) {
/* Split */
name = xstrdup(env[i]);
if ((val = strchr(name, '=')) == NULL) {
free(name);
continue;
}
*val++ = '\0';
matched = 0;
for (j = 0; j < options.num_send_env; j++) {
if (match_pattern(name, options.send_env[j])) {
matched = 1;
break;
}
}
if (!matched) {
debug3("Ignored env %s", name);
free(name);
continue;
}
client_send_env(ssh, id, name, val);
free(name);
}
}
for (i = 0; i < options.num_setenv; i++) {
/* Split */
name = xstrdup(options.setenv[i]);
if ((val = strchr(name, '=')) == NULL) {
free(name);
continue;
}
*val++ = '\0';
client_send_env(ssh, id, name, val);
free(name);
}
len = sshbuf_len(cmd);
if (len > 0) {
if (len > 900)
len = 900;
if (want_subsystem) {
debug("Sending subsystem: %.*s",
len, (const u_char*)sshbuf_ptr(cmd));
channel_request_start(ssh, id, "subsystem", 1);
client_expect_confirm(ssh, id, "subsystem",
CONFIRM_CLOSE);
} else {
debug("Sending command: %.*s",
len, (const u_char*)sshbuf_ptr(cmd));
channel_request_start(ssh, id, "exec", 1);
client_expect_confirm(ssh, id, "exec", CONFIRM_CLOSE);
}
if ((r = sshpkt_put_stringb(ssh, cmd)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send command");
} else {
channel_request_start(ssh, id, "shell", 1);
client_expect_confirm(ssh, id, "shell", CONFIRM_CLOSE);
if ((r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send shell");
}
}
static void
client_init_dispatch(struct ssh *ssh)
{
ssh_dispatch_init(ssh, &dispatch_protocol_error);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_DATA, &channel_input_data);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_OPEN, &client_input_channel_open);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_SUCCESS, &channel_input_status_confirm);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_FAILURE, &channel_input_status_confirm);
ssh_dispatch_set(ssh, SSH2_MSG_GLOBAL_REQUEST, &client_input_global_request);
/* rekeying */
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
/* global request reply messages */
ssh_dispatch_set(ssh, SSH2_MSG_REQUEST_FAILURE, &client_global_request_reply);
ssh_dispatch_set(ssh, SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply);
}
void
client_stop_mux(void)
{
if (options.control_path != NULL && muxserver_sock != -1)
unlink(options.control_path);
/*
* If we are in persist mode, or don't have a shell, signal that we
* should close when all active channels are closed.
*/
if (options.control_persist || no_shell_flag) {
session_closed = 1;
setproctitle("[stopped mux]");
}
}
/* client specific fatal cleanup */
void
cleanup_exit(int i)
{
leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
if (options.control_path != NULL && muxserver_sock != -1)
unlink(options.control_path);
ssh_kill_proxy_command();
_exit(i);
}
diff --git a/contrib/Makefile b/contrib/Makefile
index 3a36387b3222..45d878bdcf22 100644
--- a/contrib/Makefile
+++ b/contrib/Makefile
@@ -1,22 +1,22 @@
PKG_CONFIG = pkg-config
all:
- @echo "Valid targets: gnome-ssh-askpass1 gnome-ssh-askpass2"
+ @echo "Valid targets: gnome-ssh-askpass1 gnome-ssh-askpass2 gnome-ssk-askpass3"
gnome-ssh-askpass1: gnome-ssh-askpass1.c
$(CC) $(CFLAGS) `gnome-config --cflags gnome gnomeui` \
gnome-ssh-askpass1.c -o gnome-ssh-askpass1 \
`gnome-config --libs gnome gnomeui`
gnome-ssh-askpass2: gnome-ssh-askpass2.c
$(CC) $(CFLAGS) `$(PKG_CONFIG) --cflags gtk+-2.0` \
gnome-ssh-askpass2.c -o gnome-ssh-askpass2 \
`$(PKG_CONFIG) --libs gtk+-2.0 x11`
-gnome-ssh-askpass3: gnome-ssh-askpass2.c
+gnome-ssh-askpass3: gnome-ssh-askpass3.c
$(CC) $(CFLAGS) `$(PKG_CONFIG) --cflags gtk+-3.0` \
- gnome-ssh-askpass2.c -o gnome-ssh-askpass3 \
+ gnome-ssh-askpass3.c -o gnome-ssh-askpass3 \
`$(PKG_CONFIG) --libs gtk+-3.0 x11`
clean:
rm -f *.o gnome-ssh-askpass gnome-ssh-askpass[123]
diff --git a/contrib/gnome-ssh-askpass1.c b/contrib/gnome-ssh-askpass1.c
index 4d51032d1d36..4c92c177b5d2 100644
--- a/contrib/gnome-ssh-askpass1.c
+++ b/contrib/gnome-ssh-askpass1.c
@@ -1,171 +1,172 @@
/*
* Copyright (c) 2000-2002 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This is a simple GNOME SSH passphrase grabber. To use it, set the
* environment variable SSH_ASKPASS to point to the location of
* gnome-ssh-askpass before calling "ssh-add < /dev/null".
*
* There is only two run-time options: if you set the environment variable
* "GNOME_SSH_ASKPASS_GRAB_SERVER=true" then gnome-ssh-askpass will grab
* the X server. If you set "GNOME_SSH_ASKPASS_GRAB_POINTER=true", then the
* pointer will be grabbed too. These may have some benefit to security if
* you don't trust your X server. We grab the keyboard always.
*/
/*
* Compile with:
*
* cc `gnome-config --cflags gnome gnomeui` \
* gnome-ssh-askpass1.c -o gnome-ssh-askpass \
* `gnome-config --libs gnome gnomeui`
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gnome.h>
#include <X11/Xlib.h>
#include <gdk/gdkx.h>
void
report_failed_grab (void)
{
GtkWidget *err;
err = gnome_message_box_new("Could not grab keyboard or mouse.\n"
"A malicious client may be eavesdropping on your session.",
GNOME_MESSAGE_BOX_ERROR, "EXIT", NULL);
gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER);
gtk_object_set(GTK_OBJECT(err), "type", GTK_WINDOW_POPUP, NULL);
gnome_dialog_run_and_close(GNOME_DIALOG(err));
}
int
passphrase_dialog(char *message)
{
char *passphrase;
char **messages;
int result, i, grab_server, grab_pointer;
GtkWidget *dialog, *entry, *label;
grab_server = (getenv("GNOME_SSH_ASKPASS_GRAB_SERVER") != NULL);
grab_pointer = (getenv("GNOME_SSH_ASKPASS_GRAB_POINTER") != NULL);
dialog = gnome_dialog_new("OpenSSH", GNOME_STOCK_BUTTON_OK,
GNOME_STOCK_BUTTON_CANCEL, NULL);
messages = g_strsplit(message, "\\n", 0);
if (messages)
for(i = 0; messages[i]; i++) {
label = gtk_label_new(messages[i]);
gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox),
label, FALSE, FALSE, 0);
}
entry = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), entry, FALSE,
FALSE, 0);
gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
gtk_widget_grab_focus(entry);
/* Center window and prepare for grab */
gtk_object_set(GTK_OBJECT(dialog), "type", GTK_WINDOW_POPUP, NULL);
gnome_dialog_set_default(GNOME_DIALOG(dialog), 0);
gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, TRUE);
gnome_dialog_close_hides(GNOME_DIALOG(dialog), TRUE);
gtk_container_set_border_width(GTK_CONTAINER(GNOME_DIALOG(dialog)->vbox),
GNOME_PAD);
gtk_widget_show_all(dialog);
/* Grab focus */
if (grab_server)
XGrabServer(GDK_DISPLAY());
if (grab_pointer && gdk_pointer_grab(dialog->window, TRUE, 0,
NULL, NULL, GDK_CURRENT_TIME))
goto nograb;
if (gdk_keyboard_grab(dialog->window, FALSE, GDK_CURRENT_TIME))
goto nograbkb;
/* Make <enter> close dialog */
gnome_dialog_editable_enters(GNOME_DIALOG(dialog), GTK_EDITABLE(entry));
/* Run dialog */
result = gnome_dialog_run(GNOME_DIALOG(dialog));
/* Ungrab */
if (grab_server)
XUngrabServer(GDK_DISPLAY());
if (grab_pointer)
gdk_pointer_ungrab(GDK_CURRENT_TIME);
gdk_keyboard_ungrab(GDK_CURRENT_TIME);
gdk_flush();
/* Report passphrase if user selected OK */
passphrase = gtk_entry_get_text(GTK_ENTRY(entry));
if (result == 0)
puts(passphrase);
/* Zero passphrase in memory */
memset(passphrase, '\0', strlen(passphrase));
gtk_entry_set_text(GTK_ENTRY(entry), passphrase);
gnome_dialog_close(GNOME_DIALOG(dialog));
return (result == 0 ? 0 : -1);
- /* At least one grab failed - ungrab what we got, and report
- the failure to the user. Note that XGrabServer() cannot
- fail. */
+ /*
+ * At least one grab failed - ungrab what we got, and report the
+ * failure to the user. Note that XGrabServer() cannot fail.
+ */
nograbkb:
gdk_pointer_ungrab(GDK_CURRENT_TIME);
nograb:
if (grab_server)
XUngrabServer(GDK_DISPLAY());
gnome_dialog_close(GNOME_DIALOG(dialog));
report_failed_grab();
return (-1);
}
int
main(int argc, char **argv)
{
char *message;
int result;
gnome_init("GNOME ssh-askpass", "0.1", argc, argv);
if (argc == 2)
message = argv[1];
else
message = "Enter your OpenSSH passphrase:";
setvbuf(stdout, 0, _IONBF, 0);
result = passphrase_dialog(message);
return (result);
}
diff --git a/contrib/gnome-ssh-askpass2.c b/contrib/gnome-ssh-askpass2.c
index f7912727c3b3..a62f98152950 100644
--- a/contrib/gnome-ssh-askpass2.c
+++ b/contrib/gnome-ssh-askpass2.c
@@ -1,343 +1,341 @@
/*
* Copyright (c) 2000-2002 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* GTK2 support by Nalin Dahyabhai <nalin@redhat.com> */
/*
* This is a simple GNOME SSH passphrase grabber. To use it, set the
* environment variable SSH_ASKPASS to point to the location of
* gnome-ssh-askpass before calling "ssh-add < /dev/null".
*
* There is only two run-time options: if you set the environment variable
* "GNOME_SSH_ASKPASS_GRAB_SERVER=true" then gnome-ssh-askpass will grab
* the X server. If you set "GNOME_SSH_ASKPASS_GRAB_POINTER=true", then the
* pointer will be grabbed too. These may have some benefit to security if
* you don't trust your X server. We grab the keyboard always.
*/
#define GRAB_TRIES 16
#define GRAB_WAIT 250 /* milliseconds */
#define PROMPT_ENTRY 0
#define PROMPT_CONFIRM 1
#define PROMPT_NONE 2
/*
* Compile with:
*
* cc -Wall `pkg-config --cflags gtk+-2.0` \
* gnome-ssh-askpass2.c -o gnome-ssh-askpass \
* `pkg-config --libs gtk+-2.0`
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <gdk/gdkkeysyms.h>
static void
report_failed_grab (GtkWidget *parent_window, const char *what)
{
GtkWidget *err;
err = gtk_message_dialog_new(GTK_WINDOW(parent_window), 0,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE,
- "Could not grab %s. "
- "A malicious client may be eavesdropping "
- "on your session.", what);
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ "Could not grab %s. A malicious client may be eavesdropping "
+ "on your session.", what);
gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER);
gtk_dialog_run(GTK_DIALOG(err));
gtk_widget_destroy(err);
}
static void
ok_dialog(GtkWidget *entry, gpointer dialog)
{
g_return_if_fail(GTK_IS_DIALOG(dialog));
gtk_dialog_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
}
static gboolean
check_none(GtkWidget *widget, GdkEventKey *event, gpointer dialog)
{
switch (event->keyval) {
case GDK_KEY_Escape:
/* esc -> close dialog */
gtk_dialog_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE);
return TRUE;
case GDK_KEY_Tab:
/* tab -> focus close button */
gtk_widget_grab_focus(gtk_dialog_get_widget_for_response(
dialog, GTK_RESPONSE_CLOSE));
return TRUE;
default:
/* eat all other key events */
return TRUE;
}
}
static int
parse_env_hex_color(const char *env, GdkColor *c)
{
const char *s;
unsigned long ul;
char *ep;
size_t n;
if ((s = getenv(env)) == NULL)
return 0;
memset(c, 0, sizeof(*c));
/* Permit hex rgb or rrggbb optionally prefixed by '#' or '0x' */
if (*s == '#')
s++;
else if (strncmp(s, "0x", 2) == 0)
s += 2;
n = strlen(s);
if (n != 3 && n != 6)
goto bad;
ul = strtoul(s, &ep, 16);
if (*ep != '\0' || ul > 0xffffff) {
bad:
fprintf(stderr, "Invalid $%s - invalid hex color code\n", env);
return 0;
}
/* Valid hex sequence; expand into a GdkColor */
if (n == 3) {
/* 4-bit RGB */
c->red = ((ul >> 8) & 0xf) << 12;
c->green = ((ul >> 4) & 0xf) << 12;
c->blue = (ul & 0xf) << 12;
} else {
/* 8-bit RGB */
c->red = ((ul >> 16) & 0xff) << 8;
c->green = ((ul >> 8) & 0xff) << 8;
c->blue = (ul & 0xff) << 8;
}
return 1;
}
static int
passphrase_dialog(char *message, int prompt_type)
{
const char *failed;
char *passphrase, *local;
int result, grab_tries, grab_server, grab_pointer;
int buttons, default_response;
GtkWidget *parent_window, *dialog, *entry;
GdkGrabStatus status;
GdkColor fg, bg;
int fg_set = 0, bg_set = 0;
grab_server = (getenv("GNOME_SSH_ASKPASS_GRAB_SERVER") != NULL);
grab_pointer = (getenv("GNOME_SSH_ASKPASS_GRAB_POINTER") != NULL);
grab_tries = 0;
fg_set = parse_env_hex_color("GNOME_SSH_ASKPASS_FG_COLOR", &fg);
bg_set = parse_env_hex_color("GNOME_SSH_ASKPASS_BG_COLOR", &bg);
/* Create an invisible parent window so that GtkDialog doesn't
* complain. */
parent_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
switch (prompt_type) {
case PROMPT_CONFIRM:
buttons = GTK_BUTTONS_YES_NO;
default_response = GTK_RESPONSE_YES;
break;
case PROMPT_NONE:
buttons = GTK_BUTTONS_CLOSE;
default_response = GTK_RESPONSE_CLOSE;
break;
default:
buttons = GTK_BUTTONS_OK_CANCEL;
default_response = GTK_RESPONSE_OK;
break;
}
dialog = gtk_message_dialog_new(GTK_WINDOW(parent_window), 0,
GTK_MESSAGE_QUESTION, buttons, "%s", message);
gtk_window_set_title(GTK_WINDOW(dialog), "OpenSSH");
gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
gtk_dialog_set_default_response(GTK_DIALOG(dialog), default_response);
gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
if (fg_set)
gtk_widget_modify_fg(dialog, GTK_STATE_NORMAL, &fg);
if (bg_set)
gtk_widget_modify_bg(dialog, GTK_STATE_NORMAL, &bg);
if (prompt_type == PROMPT_ENTRY || prompt_type == PROMPT_NONE) {
entry = gtk_entry_new();
if (fg_set)
gtk_widget_modify_fg(entry, GTK_STATE_NORMAL, &fg);
if (bg_set)
gtk_widget_modify_bg(entry, GTK_STATE_NORMAL, &bg);
gtk_box_pack_start(
GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
entry, FALSE, FALSE, 0);
gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
gtk_widget_grab_focus(entry);
if (prompt_type == PROMPT_ENTRY) {
gtk_widget_show(entry);
/* Make <enter> close dialog */
g_signal_connect(G_OBJECT(entry), "activate",
G_CALLBACK(ok_dialog), dialog);
} else {
/*
* Ensure the 'close' button is not focused by default
* but is still reachable via tab. This is a bit of a
* hack - it uses a hidden entry that responds to a
* couple of keypress events (escape and tab only).
*/
gtk_widget_realize(entry);
g_signal_connect(G_OBJECT(entry), "key_press_event",
- G_CALLBACK(check_none), dialog);
+ G_CALLBACK(check_none), dialog);
}
}
/* Grab focus */
gtk_widget_show_now(dialog);
if (grab_pointer) {
for(;;) {
status = gdk_pointer_grab(
(gtk_widget_get_window(GTK_WIDGET(dialog))), TRUE,
0, NULL, NULL, GDK_CURRENT_TIME);
if (status == GDK_GRAB_SUCCESS)
break;
usleep(GRAB_WAIT * 1000);
if (++grab_tries > GRAB_TRIES) {
failed = "mouse";
goto nograb;
}
}
}
for(;;) {
status = gdk_keyboard_grab(
gtk_widget_get_window(GTK_WIDGET(dialog)), FALSE,
GDK_CURRENT_TIME);
if (status == GDK_GRAB_SUCCESS)
break;
usleep(GRAB_WAIT * 1000);
if (++grab_tries > GRAB_TRIES) {
failed = "keyboard";
goto nograbkb;
}
}
if (grab_server) {
gdk_x11_grab_server();
}
result = gtk_dialog_run(GTK_DIALOG(dialog));
/* Ungrab */
if (grab_server)
XUngrabServer(gdk_x11_get_default_xdisplay());
if (grab_pointer)
gdk_pointer_ungrab(GDK_CURRENT_TIME);
gdk_keyboard_ungrab(GDK_CURRENT_TIME);
gdk_flush();
/* Report passphrase if user selected OK */
if (prompt_type == PROMPT_ENTRY) {
passphrase = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
if (result == GTK_RESPONSE_OK) {
local = g_locale_from_utf8(passphrase,
strlen(passphrase), NULL, NULL, NULL);
if (local != NULL) {
puts(local);
memset(local, '\0', strlen(local));
g_free(local);
} else {
puts(passphrase);
}
}
/* Zero passphrase in memory */
memset(passphrase, '\b', strlen(passphrase));
gtk_entry_set_text(GTK_ENTRY(entry), passphrase);
memset(passphrase, '\0', strlen(passphrase));
g_free(passphrase);
}
gtk_widget_destroy(dialog);
if (result != GTK_RESPONSE_OK && result != GTK_RESPONSE_YES)
return -1;
return 0;
nograbkb:
/*
* At least one grab failed - ungrab what we got, and report
* the failure to the user. Note that XGrabServer() cannot
* fail.
*/
gdk_pointer_ungrab(GDK_CURRENT_TIME);
nograb:
if (grab_server)
XUngrabServer(gdk_x11_get_default_xdisplay());
gtk_widget_destroy(dialog);
report_failed_grab(parent_window, failed);
return (-1);
}
int
main(int argc, char **argv)
{
char *message, *prompt_mode;
int result, prompt_type = PROMPT_ENTRY;
gtk_init(&argc, &argv);
if (argc > 1) {
message = g_strjoinv(" ", argv + 1);
} else {
message = g_strdup("Enter your OpenSSH passphrase:");
}
if ((prompt_mode = getenv("SSH_ASKPASS_PROMPT")) != NULL) {
if (strcasecmp(prompt_mode, "confirm") == 0)
prompt_type = PROMPT_CONFIRM;
else if (strcasecmp(prompt_mode, "none") == 0)
prompt_type = PROMPT_NONE;
}
setvbuf(stdout, 0, _IONBF, 0);
result = passphrase_dialog(message, prompt_type);
g_free(message);
return (result);
}
diff --git a/contrib/gnome-ssh-askpass2.c b/contrib/gnome-ssh-askpass3.c
similarity index 85%
copy from contrib/gnome-ssh-askpass2.c
copy to contrib/gnome-ssh-askpass3.c
index f7912727c3b3..e1a0533ef624 100644
--- a/contrib/gnome-ssh-askpass2.c
+++ b/contrib/gnome-ssh-askpass3.c
@@ -1,343 +1,305 @@
/*
* Copyright (c) 2000-2002 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* GTK2 support by Nalin Dahyabhai <nalin@redhat.com> */
/*
* This is a simple GNOME SSH passphrase grabber. To use it, set the
* environment variable SSH_ASKPASS to point to the location of
* gnome-ssh-askpass before calling "ssh-add < /dev/null".
*
* There is only two run-time options: if you set the environment variable
* "GNOME_SSH_ASKPASS_GRAB_SERVER=true" then gnome-ssh-askpass will grab
* the X server. If you set "GNOME_SSH_ASKPASS_GRAB_POINTER=true", then the
* pointer will be grabbed too. These may have some benefit to security if
* you don't trust your X server. We grab the keyboard always.
*/
#define GRAB_TRIES 16
#define GRAB_WAIT 250 /* milliseconds */
#define PROMPT_ENTRY 0
#define PROMPT_CONFIRM 1
#define PROMPT_NONE 2
/*
* Compile with:
*
* cc -Wall `pkg-config --cflags gtk+-2.0` \
* gnome-ssh-askpass2.c -o gnome-ssh-askpass \
* `pkg-config --libs gtk+-2.0`
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <gdk/gdkkeysyms.h>
-static void
-report_failed_grab (GtkWidget *parent_window, const char *what)
-{
- GtkWidget *err;
-
- err = gtk_message_dialog_new(GTK_WINDOW(parent_window), 0,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE,
- "Could not grab %s. "
- "A malicious client may be eavesdropping "
- "on your session.", what);
- gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER);
-
- gtk_dialog_run(GTK_DIALOG(err));
-
- gtk_widget_destroy(err);
-}
-
static void
ok_dialog(GtkWidget *entry, gpointer dialog)
{
g_return_if_fail(GTK_IS_DIALOG(dialog));
gtk_dialog_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
}
static gboolean
check_none(GtkWidget *widget, GdkEventKey *event, gpointer dialog)
{
switch (event->keyval) {
case GDK_KEY_Escape:
/* esc -> close dialog */
gtk_dialog_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE);
return TRUE;
case GDK_KEY_Tab:
/* tab -> focus close button */
gtk_widget_grab_focus(gtk_dialog_get_widget_for_response(
dialog, GTK_RESPONSE_CLOSE));
return TRUE;
default:
/* eat all other key events */
return TRUE;
}
}
static int
parse_env_hex_color(const char *env, GdkColor *c)
{
const char *s;
unsigned long ul;
char *ep;
size_t n;
if ((s = getenv(env)) == NULL)
return 0;
memset(c, 0, sizeof(*c));
/* Permit hex rgb or rrggbb optionally prefixed by '#' or '0x' */
if (*s == '#')
s++;
else if (strncmp(s, "0x", 2) == 0)
s += 2;
n = strlen(s);
if (n != 3 && n != 6)
goto bad;
ul = strtoul(s, &ep, 16);
if (*ep != '\0' || ul > 0xffffff) {
bad:
fprintf(stderr, "Invalid $%s - invalid hex color code\n", env);
return 0;
}
/* Valid hex sequence; expand into a GdkColor */
if (n == 3) {
/* 4-bit RGB */
c->red = ((ul >> 8) & 0xf) << 12;
c->green = ((ul >> 4) & 0xf) << 12;
c->blue = (ul & 0xf) << 12;
} else {
/* 8-bit RGB */
c->red = ((ul >> 16) & 0xff) << 8;
c->green = ((ul >> 8) & 0xff) << 8;
c->blue = (ul & 0xff) << 8;
}
return 1;
}
static int
passphrase_dialog(char *message, int prompt_type)
{
const char *failed;
char *passphrase, *local;
int result, grab_tries, grab_server, grab_pointer;
int buttons, default_response;
- GtkWidget *parent_window, *dialog, *entry;
+ GtkWidget *parent_window, *dialog, *entry, *err;
GdkGrabStatus status;
GdkColor fg, bg;
+ GdkSeat *seat;
+ GdkDisplay *display;
+ GdkSeatCapabilities caps;
int fg_set = 0, bg_set = 0;
grab_server = (getenv("GNOME_SSH_ASKPASS_GRAB_SERVER") != NULL);
grab_pointer = (getenv("GNOME_SSH_ASKPASS_GRAB_POINTER") != NULL);
grab_tries = 0;
fg_set = parse_env_hex_color("GNOME_SSH_ASKPASS_FG_COLOR", &fg);
bg_set = parse_env_hex_color("GNOME_SSH_ASKPASS_BG_COLOR", &bg);
/* Create an invisible parent window so that GtkDialog doesn't
* complain. */
parent_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
switch (prompt_type) {
case PROMPT_CONFIRM:
buttons = GTK_BUTTONS_YES_NO;
default_response = GTK_RESPONSE_YES;
break;
case PROMPT_NONE:
buttons = GTK_BUTTONS_CLOSE;
default_response = GTK_RESPONSE_CLOSE;
break;
default:
buttons = GTK_BUTTONS_OK_CANCEL;
default_response = GTK_RESPONSE_OK;
break;
}
dialog = gtk_message_dialog_new(GTK_WINDOW(parent_window), 0,
GTK_MESSAGE_QUESTION, buttons, "%s", message);
gtk_window_set_title(GTK_WINDOW(dialog), "OpenSSH");
gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
gtk_dialog_set_default_response(GTK_DIALOG(dialog), default_response);
gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
if (fg_set)
gtk_widget_modify_fg(dialog, GTK_STATE_NORMAL, &fg);
if (bg_set)
gtk_widget_modify_bg(dialog, GTK_STATE_NORMAL, &bg);
if (prompt_type == PROMPT_ENTRY || prompt_type == PROMPT_NONE) {
entry = gtk_entry_new();
if (fg_set)
gtk_widget_modify_fg(entry, GTK_STATE_NORMAL, &fg);
if (bg_set)
gtk_widget_modify_bg(entry, GTK_STATE_NORMAL, &bg);
gtk_box_pack_start(
GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
entry, FALSE, FALSE, 0);
gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
gtk_widget_grab_focus(entry);
if (prompt_type == PROMPT_ENTRY) {
gtk_widget_show(entry);
/* Make <enter> close dialog */
g_signal_connect(G_OBJECT(entry), "activate",
G_CALLBACK(ok_dialog), dialog);
} else {
/*
* Ensure the 'close' button is not focused by default
* but is still reachable via tab. This is a bit of a
* hack - it uses a hidden entry that responds to a
* couple of keypress events (escape and tab only).
*/
gtk_widget_realize(entry);
g_signal_connect(G_OBJECT(entry), "key_press_event",
- G_CALLBACK(check_none), dialog);
+ G_CALLBACK(check_none), dialog);
}
}
-
/* Grab focus */
gtk_widget_show_now(dialog);
- if (grab_pointer) {
- for(;;) {
- status = gdk_pointer_grab(
- (gtk_widget_get_window(GTK_WIDGET(dialog))), TRUE,
- 0, NULL, NULL, GDK_CURRENT_TIME);
- if (status == GDK_GRAB_SUCCESS)
- break;
- usleep(GRAB_WAIT * 1000);
- if (++grab_tries > GRAB_TRIES) {
- failed = "mouse";
- goto nograb;
- }
- }
- }
- for(;;) {
- status = gdk_keyboard_grab(
- gtk_widget_get_window(GTK_WIDGET(dialog)), FALSE,
- GDK_CURRENT_TIME);
+ display = gtk_widget_get_display(GTK_WIDGET(dialog));
+ seat = gdk_display_get_default_seat(display);
+ caps = GDK_SEAT_CAPABILITY_KEYBOARD;
+ if (grab_pointer)
+ caps |= GDK_SEAT_CAPABILITY_ALL_POINTING;
+ if (grab_server)
+ caps = GDK_SEAT_CAPABILITY_ALL;
+ for (;;) {
+ status = gdk_seat_grab(seat, gtk_widget_get_window(dialog),
+ caps, TRUE, NULL, NULL, NULL, NULL);
if (status == GDK_GRAB_SUCCESS)
break;
usleep(GRAB_WAIT * 1000);
- if (++grab_tries > GRAB_TRIES) {
- failed = "keyboard";
- goto nograbkb;
- }
- }
- if (grab_server) {
- gdk_x11_grab_server();
+ if (++grab_tries > GRAB_TRIES)
+ goto nograb;
}
result = gtk_dialog_run(GTK_DIALOG(dialog));
/* Ungrab */
- if (grab_server)
- XUngrabServer(gdk_x11_get_default_xdisplay());
- if (grab_pointer)
- gdk_pointer_ungrab(GDK_CURRENT_TIME);
- gdk_keyboard_ungrab(GDK_CURRENT_TIME);
- gdk_flush();
+ gdk_seat_ungrab(seat);
+ gdk_display_flush(display);
/* Report passphrase if user selected OK */
if (prompt_type == PROMPT_ENTRY) {
passphrase = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
if (result == GTK_RESPONSE_OK) {
local = g_locale_from_utf8(passphrase,
strlen(passphrase), NULL, NULL, NULL);
if (local != NULL) {
puts(local);
memset(local, '\0', strlen(local));
g_free(local);
} else {
puts(passphrase);
}
}
/* Zero passphrase in memory */
memset(passphrase, '\b', strlen(passphrase));
gtk_entry_set_text(GTK_ENTRY(entry), passphrase);
memset(passphrase, '\0', strlen(passphrase));
g_free(passphrase);
}
gtk_widget_destroy(dialog);
if (result != GTK_RESPONSE_OK && result != GTK_RESPONSE_YES)
return -1;
return 0;
- nograbkb:
- /*
- * At least one grab failed - ungrab what we got, and report
- * the failure to the user. Note that XGrabServer() cannot
- * fail.
- */
- gdk_pointer_ungrab(GDK_CURRENT_TIME);
nograb:
- if (grab_server)
- XUngrabServer(gdk_x11_get_default_xdisplay());
gtk_widget_destroy(dialog);
-
- report_failed_grab(parent_window, failed);
-
- return (-1);
+ err = gtk_message_dialog_new(GTK_WINDOW(parent_window), 0,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ "Could not grab input. A malicious client may be eavesdropping "
+ "on your session.");
+ gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER);
+ gtk_dialog_run(GTK_DIALOG(err));
+ gtk_widget_destroy(err);
+ return -1;
}
int
main(int argc, char **argv)
{
char *message, *prompt_mode;
int result, prompt_type = PROMPT_ENTRY;
gtk_init(&argc, &argv);
if (argc > 1) {
message = g_strjoinv(" ", argv + 1);
} else {
message = g_strdup("Enter your OpenSSH passphrase:");
}
if ((prompt_mode = getenv("SSH_ASKPASS_PROMPT")) != NULL) {
if (strcasecmp(prompt_mode, "confirm") == 0)
prompt_type = PROMPT_CONFIRM;
else if (strcasecmp(prompt_mode, "none") == 0)
prompt_type = PROMPT_NONE;
}
setvbuf(stdout, 0, _IONBF, 0);
result = passphrase_dialog(message, prompt_type);
g_free(message);
return (result);
}
diff --git a/contrib/redhat/openssh.spec b/contrib/redhat/openssh.spec
index 908cafdacd1b..96972ec48804 100644
--- a/contrib/redhat/openssh.spec
+++ b/contrib/redhat/openssh.spec
@@ -1,848 +1,848 @@
-%global ver 8.5p1
+%global ver 8.6p1
%global rel 1%{?dist}
# OpenSSH privilege separation requires a user & group ID
%global sshd_uid 74
%global sshd_gid 74
# Version of ssh-askpass
%global aversion 1.2.4.1
# Do we want to disable building of x11-askpass? (1=yes 0=no)
%global no_x11_askpass 0
# Do we want to disable building of gnome-askpass? (1=yes 0=no)
%global no_gnome_askpass 0
# Do we want to link against a static libcrypto? (1=yes 0=no)
%global static_libcrypto 0
# Do we want smartcard support (1=yes 0=no)
%global scard 0
# Use GTK2 instead of GNOME in gnome-ssh-askpass
%global gtk2 1
# Use build6x options for older RHEL builds
# RHEL 7 not yet supported
%if 0%{?rhel} > 6
%global build6x 0
%else
%global build6x 1
%endif
%if 0%{?fedora} >= 26
%global compat_openssl 1
%else
%global compat_openssl 0
%endif
# Do we want kerberos5 support (1=yes 0=no)
%global kerberos5 1
# Reserve options to override askpass settings with:
# rpm -ba|--rebuild --define 'skip_xxx 1'
%{?skip_x11_askpass:%global no_x11_askpass 1}
%{?skip_gnome_askpass:%global no_gnome_askpass 1}
# Add option to build without GTK2 for older platforms with only GTK+.
# RedHat <= 7.2 and Red Hat Advanced Server 2.1 are examples.
# rpm -ba|--rebuild --define 'no_gtk2 1'
%{?no_gtk2:%global gtk2 0}
# Is this a build for RHL 6.x or earlier?
%{?build_6x:%global build6x 1}
# If this is RHL 6.x, the default configuration has sysconfdir in /usr/etc.
%if %{build6x}
%global _sysconfdir /etc
%endif
# Options for static OpenSSL link:
# rpm -ba|--rebuild --define "static_openssl 1"
%{?static_openssl:%global static_libcrypto 1}
# Options for Smartcard support: (needs libsectok and openssl-engine)
# rpm -ba|--rebuild --define "smartcard 1"
%{?smartcard:%global scard 1}
# Is this a build for the rescue CD (without PAM, with MD5)? (1=yes 0=no)
%global rescue 0
%{?build_rescue:%global rescue 1}
# Turn off some stuff for resuce builds
%if %{rescue}
%global kerberos5 0
%endif
Summary: The OpenSSH implementation of SSH protocol version 2.
Name: openssh
Version: %{ver}
%if %{rescue}
Release: %{rel}rescue
%else
Release: %{rel}
%endif
URL: https://www.openssh.com/portable.html
Source0: https://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz
Source1: http://www.jmknoble.net/software/x11-ssh-askpass/x11-ssh-askpass-%{aversion}.tar.gz
License: BSD
Group: Applications/Internet
BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
Obsoletes: ssh
%if %{build6x}
PreReq: initscripts >= 5.00
%else
Requires: initscripts >= 5.20
%endif
BuildRequires: perl
%if %{compat_openssl}
BuildRequires: compat-openssl10-devel
%else
BuildRequires: openssl-devel >= 1.0.1
BuildRequires: openssl-devel < 1.1
%endif
BuildRequires: /bin/login
%if ! %{build6x}
BuildRequires: glibc-devel, pam
%else
BuildRequires: /usr/include/security/pam_appl.h
%endif
%if ! %{no_x11_askpass}
BuildRequires: /usr/include/X11/Xlib.h
# Xt development tools
BuildRequires: libXt-devel
# Provides xmkmf
BuildRequires: imake
# Rely on relatively recent gtk
BuildRequires: gtk2-devel
%endif
%if ! %{no_gnome_askpass}
BuildRequires: pkgconfig
%endif
%if %{kerberos5}
BuildRequires: krb5-devel
BuildRequires: krb5-libs
%endif
%package clients
Summary: OpenSSH clients.
Requires: openssh = %{version}-%{release}
Group: Applications/Internet
Obsoletes: ssh-clients
%package server
Summary: The OpenSSH server daemon.
Group: System Environment/Daemons
Obsoletes: ssh-server
Requires: openssh = %{version}-%{release}, chkconfig >= 0.9
%if ! %{build6x}
Requires: /etc/pam.d/system-auth
%endif
%package askpass
Summary: A passphrase dialog for OpenSSH and X.
Group: Applications/Internet
Requires: openssh = %{version}-%{release}
Obsoletes: ssh-extras
%package askpass-gnome
Summary: A passphrase dialog for OpenSSH, X, and GNOME.
Group: Applications/Internet
Requires: openssh = %{version}-%{release}
Obsoletes: ssh-extras
%description
SSH (Secure SHell) is a program for logging into and executing
commands on a remote machine. SSH is intended to replace rlogin and
rsh, and to provide secure encrypted communications between two
untrusted hosts over an insecure network. X11 connections and
arbitrary TCP/IP ports can also be forwarded over the secure channel.
OpenSSH is OpenBSD's version of the last free version of SSH, bringing
it up to date in terms of security and features, as well as removing
all patented algorithms to separate libraries.
This package includes the core files necessary for both the OpenSSH
client and server. To make this package useful, you should also
install openssh-clients, openssh-server, or both.
%description clients
OpenSSH is a free version of SSH (Secure SHell), a program for logging
into and executing commands on a remote machine. This package includes
the clients necessary to make encrypted connections to SSH servers.
You'll also need to install the openssh package on OpenSSH clients.
%description server
OpenSSH is a free version of SSH (Secure SHell), a program for logging
into and executing commands on a remote machine. This package contains
the secure shell daemon (sshd). The sshd daemon allows SSH clients to
securely connect to your SSH server. You also need to have the openssh
package installed.
%description askpass
OpenSSH is a free version of SSH (Secure SHell), a program for logging
into and executing commands on a remote machine. This package contains
an X11 passphrase dialog for OpenSSH.
%description askpass-gnome
OpenSSH is a free version of SSH (Secure SHell), a program for logging
into and executing commands on a remote machine. This package contains
an X11 passphrase dialog for OpenSSH and the GNOME GUI desktop
environment.
%prep
%if ! %{no_x11_askpass}
%setup -q -a 1
%else
%setup -q
%endif
%build
%if %{rescue}
CFLAGS="$RPM_OPT_FLAGS -Os"; export CFLAGS
%endif
%configure \
--sysconfdir=%{_sysconfdir}/ssh \
--libexecdir=%{_libexecdir}/openssh \
--datadir=%{_datadir}/openssh \
--with-default-path=/usr/local/bin:/bin:/usr/bin \
--with-superuser-path=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin \
--with-privsep-path=%{_var}/empty/sshd \
--with-md5-passwords \
--mandir=%{_mandir} \
--with-mantype=man \
--disable-strip \
%if %{scard}
--with-smartcard \
%endif
%if %{rescue}
--without-pam \
%else
--with-pam \
%endif
%if %{kerberos5}
--with-kerberos5=$K5DIR \
%endif
%if %{static_libcrypto}
perl -pi -e "s|-lcrypto|%{_libdir}/libcrypto.a|g" Makefile
%endif
make
%if ! %{no_x11_askpass}
pushd x11-ssh-askpass-%{aversion}
%configure --libexecdir=%{_libexecdir}/openssh
xmkmf -a
make
popd
%endif
# Define a variable to toggle gnome1/gtk2 building. This is necessary
# because RPM doesn't handle nested %if statements.
%if %{gtk2}
gtk2=yes
%else
gtk2=no
%endif
%if ! %{no_gnome_askpass}
pushd contrib
if [ $gtk2 = yes ] ; then
make gnome-ssh-askpass2
mv gnome-ssh-askpass2 gnome-ssh-askpass
else
make gnome-ssh-askpass1
mv gnome-ssh-askpass1 gnome-ssh-askpass
fi
popd
%endif
%install
rm -rf $RPM_BUILD_ROOT
mkdir -p -m755 $RPM_BUILD_ROOT%{_sysconfdir}/ssh
mkdir -p -m755 $RPM_BUILD_ROOT%{_libexecdir}/openssh
mkdir -p -m755 $RPM_BUILD_ROOT%{_var}/empty/sshd
make install DESTDIR=$RPM_BUILD_ROOT
install -d $RPM_BUILD_ROOT/etc/pam.d/
install -d $RPM_BUILD_ROOT/etc/rc.d/init.d
install -d $RPM_BUILD_ROOT%{_libexecdir}/openssh
%if %{build6x}
install -m644 contrib/redhat/sshd.pam.old $RPM_BUILD_ROOT/etc/pam.d/sshd
%else
install -m644 contrib/redhat/sshd.pam $RPM_BUILD_ROOT/etc/pam.d/sshd
%endif
install -m755 contrib/redhat/sshd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/sshd
%if ! %{no_x11_askpass}
install x11-ssh-askpass-%{aversion}/x11-ssh-askpass $RPM_BUILD_ROOT%{_libexecdir}/openssh/x11-ssh-askpass
ln -s x11-ssh-askpass $RPM_BUILD_ROOT%{_libexecdir}/openssh/ssh-askpass
%endif
%if ! %{no_gnome_askpass}
install contrib/gnome-ssh-askpass $RPM_BUILD_ROOT%{_libexecdir}/openssh/gnome-ssh-askpass
%endif
%if ! %{scard}
rm -f $RPM_BUILD_ROOT/usr/share/openssh/Ssh.bin
%endif
%if ! %{no_gnome_askpass}
install -m 755 -d $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/
install -m 755 contrib/redhat/gnome-ssh-askpass.csh $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/
install -m 755 contrib/redhat/gnome-ssh-askpass.sh $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/
%endif
perl -pi -e "s|$RPM_BUILD_ROOT||g" $RPM_BUILD_ROOT%{_mandir}/man*/*
%clean
rm -rf $RPM_BUILD_ROOT
%triggerun server -- ssh-server
if [ "$1" != 0 -a -r /var/run/sshd.pid ] ; then
touch /var/run/sshd.restart
fi
%triggerun server -- openssh-server < 2.5.0p1
# Count the number of HostKey and HostDsaKey statements we have.
gawk 'BEGIN {IGNORECASE=1}
/^hostkey/ || /^hostdsakey/ {sawhostkey = sawhostkey + 1}
END {exit sawhostkey}' /etc/ssh/sshd_config
# And if we only found one, we know the client was relying on the old default
# behavior, which loaded the the SSH2 DSA host key when HostDsaKey wasn't
# specified. Now that HostKey is used for both SSH1 and SSH2 keys, specifying
# one nullifies the default, which would have loaded both.
if [ $? -eq 1 ] ; then
echo HostKey /etc/ssh/ssh_host_rsa_key >> /etc/ssh/sshd_config
echo HostKey /etc/ssh/ssh_host_dsa_key >> /etc/ssh/sshd_config
fi
%triggerpostun server -- ssh-server
if [ "$1" != 0 ] ; then
/sbin/chkconfig --add sshd
if test -f /var/run/sshd.restart ; then
rm -f /var/run/sshd.restart
/sbin/service sshd start > /dev/null 2>&1 || :
fi
fi
%pre server
%{_sbindir}/groupadd -r -g %{sshd_gid} sshd 2>/dev/null || :
%{_sbindir}/useradd -d /var/empty/sshd -s /bin/false -u %{sshd_uid} \
-g sshd -M -r sshd 2>/dev/null || :
%post server
/sbin/chkconfig --add sshd
%postun server
/sbin/service sshd condrestart > /dev/null 2>&1 || :
%preun server
if [ "$1" = 0 ]
then
/sbin/service sshd stop > /dev/null 2>&1 || :
/sbin/chkconfig --del sshd
fi
%files
%defattr(-,root,root)
%doc CREDITS ChangeLog INSTALL LICENCE OVERVIEW README* PROTOCOL* TODO
%attr(0755,root,root) %{_bindir}/scp
%attr(0644,root,root) %{_mandir}/man1/scp.1*
%attr(0755,root,root) %dir %{_sysconfdir}/ssh
%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ssh/moduli
%if ! %{rescue}
%attr(0755,root,root) %{_bindir}/ssh-keygen
%attr(0644,root,root) %{_mandir}/man1/ssh-keygen.1*
%attr(0755,root,root) %dir %{_libexecdir}/openssh
%attr(4711,root,root) %{_libexecdir}/openssh/ssh-keysign
%attr(0755,root,root) %{_libexecdir}/openssh/ssh-pkcs11-helper
%attr(0755,root,root) %{_libexecdir}/openssh/ssh-sk-helper
%attr(0644,root,root) %{_mandir}/man8/ssh-keysign.8*
%attr(0644,root,root) %{_mandir}/man8/ssh-pkcs11-helper.8*
%attr(0644,root,root) %{_mandir}/man8/ssh-sk-helper.8*
%endif
%if %{scard}
%attr(0755,root,root) %dir %{_datadir}/openssh
%attr(0644,root,root) %{_datadir}/openssh/Ssh.bin
%endif
%files clients
%defattr(-,root,root)
%attr(0755,root,root) %{_bindir}/ssh
%attr(0644,root,root) %{_mandir}/man1/ssh.1*
%attr(0644,root,root) %{_mandir}/man5/ssh_config.5*
%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ssh/ssh_config
%if ! %{rescue}
%attr(2755,root,nobody) %{_bindir}/ssh-agent
%attr(0755,root,root) %{_bindir}/ssh-add
%attr(0755,root,root) %{_bindir}/ssh-keyscan
%attr(0755,root,root) %{_bindir}/sftp
%attr(0644,root,root) %{_mandir}/man1/ssh-agent.1*
%attr(0644,root,root) %{_mandir}/man1/ssh-add.1*
%attr(0644,root,root) %{_mandir}/man1/ssh-keyscan.1*
%attr(0644,root,root) %{_mandir}/man1/sftp.1*
%endif
%if ! %{rescue}
%files server
%defattr(-,root,root)
%dir %attr(0111,root,root) %{_var}/empty/sshd
%attr(0755,root,root) %{_sbindir}/sshd
%attr(0755,root,root) %{_libexecdir}/openssh/sftp-server
%attr(0644,root,root) %{_mandir}/man8/sshd.8*
%attr(0644,root,root) %{_mandir}/man5/moduli.5*
%attr(0644,root,root) %{_mandir}/man5/sshd_config.5*
%attr(0644,root,root) %{_mandir}/man8/sftp-server.8*
%attr(0755,root,root) %dir %{_sysconfdir}/ssh
%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ssh/sshd_config
%attr(0600,root,root) %config(noreplace) /etc/pam.d/sshd
%attr(0755,root,root) %config /etc/rc.d/init.d/sshd
%endif
%if ! %{no_x11_askpass}
%files askpass
%defattr(-,root,root)
%doc x11-ssh-askpass-%{aversion}/README
%doc x11-ssh-askpass-%{aversion}/ChangeLog
%doc x11-ssh-askpass-%{aversion}/SshAskpass*.ad
%{_libexecdir}/openssh/ssh-askpass
%attr(0755,root,root) %{_libexecdir}/openssh/x11-ssh-askpass
%endif
%if ! %{no_gnome_askpass}
%files askpass-gnome
%defattr(-,root,root)
%attr(0755,root,root) %config %{_sysconfdir}/profile.d/gnome-ssh-askpass.*
%attr(0755,root,root) %{_libexecdir}/openssh/gnome-ssh-askpass
%endif
%changelog
* Mon Jul 20 2020 Damien Miller <djm@mindrto.org>
- Add ssh-sk-helper and corresponding manual page.
* Sat Feb 10 2018 Darren Tucker <dtucker@dtucker.net>
- Update openssl-devel dependency to match current requirements.
- Handle Fedora >=6 openssl 1.0 compat libs.
- Remove SSH1 from description.
- Don't strip binaries at build time so that debuginfo package can be
created.
* Sun Nov 16 2014 Nico Kadel-Garcia <nakdel@gmail.com>
- Add '--mandir' and '--with-mantype' for RHEL 5 compatibility
- Add 'dist' option to 'ver' so package names reflect OS at build time
- Always include x11-ssh-askpass tarball in SRPM
- Add openssh-x11-aspass BuildRequires for libXT-devel, imake, gtk2-devel
- Discard 'K5DIR' reporting, not usable inside 'mock' for RHEL 5 compatibility
- Discard obsolete '--with-rsh' configure option
- Update openssl-devel dependency to 0.9.8f, as found in autoconf
* Wed Jul 14 2010 Tim Rice <tim@multitalents.net>
- test for skip_x11_askpass (line 77) should have been for no_x11_askpass
* Mon Jun 2 2003 Damien Miller <djm@mindrot.org>
- Remove noip6 option. This may be controlled at run-time in client config
file using new AddressFamily directive
* Mon May 12 2003 Damien Miller <djm@mindrot.org>
- Don't install profile.d scripts when not building with GNOME/GTK askpass
(patch from bet@rahul.net)
* Tue Oct 01 2002 Damien Miller <djm@mindrot.org>
- Install ssh-agent setgid nobody to prevent ptrace() key theft attacks
* Mon Sep 30 2002 Damien Miller <djm@mindrot.org>
- Use contrib/ Makefile for building askpass programs
* Fri Jun 21 2002 Damien Miller <djm@mindrot.org>
- Merge in spec changes from seba@iq.pl (Sebastian Pachuta)
- Add new {ssh,sshd}_config.5 manpages
- Add new ssh-keysign program and remove setuid from ssh client
* Fri May 10 2002 Damien Miller <djm@mindrot.org>
- Merge in spec changes from RedHat, reorgansie a little
- Add Privsep user, group and directory
* Thu Mar 7 2002 Nalin Dahyabhai <nalin@redhat.com> 3.1p1-2
- bump and grind (through the build system)
* Thu Mar 7 2002 Nalin Dahyabhai <nalin@redhat.com> 3.1p1-1
- require sharutils for building (mindrot #137)
- require db1-devel only when building for 6.x (#55105), which probably won't
work anyway (3.1 requires OpenSSL 0.9.6 to build), but what the heck
- require pam-devel by file (not by package name) again
- add Markus's patch to compile with OpenSSL 0.9.5a (from
http://bugzilla.mindrot.org/show_bug.cgi?id=141) and apply it if we're
building for 6.x
* Thu Mar 7 2002 Nalin Dahyabhai <nalin@redhat.com> 3.1p1-0
- update to 3.1p1
* Tue Mar 5 2002 Nalin Dahyabhai <nalin@redhat.com> SNAP-20020305
- update to SNAP-20020305
- drop debug patch, fixed upstream
* Wed Feb 20 2002 Nalin Dahyabhai <nalin@redhat.com> SNAP-20020220
- update to SNAP-20020220 for testing purposes (you've been warned, if there's
anything to be warned about, gss patches won't apply, I don't mind)
* Wed Feb 13 2002 Nalin Dahyabhai <nalin@redhat.com> 3.0.2p1-3
- add patches from Simon Wilkinson and Nicolas Williams for GSSAPI key
exchange, authentication, and named key support
* Wed Jan 23 2002 Nalin Dahyabhai <nalin@redhat.com> 3.0.2p1-2
- remove dependency on db1-devel, which has just been swallowed up whole
by gnome-libs-devel
* Sat Dec 29 2001 Nalin Dahyabhai <nalin@redhat.com>
- adjust build dependencies so that build6x actually works right (fix
from Hugo van der Kooij)
* Tue Dec 4 2001 Nalin Dahyabhai <nalin@redhat.com> 3.0.2p1-1
- update to 3.0.2p1
* Fri Nov 16 2001 Nalin Dahyabhai <nalin@redhat.com> 3.0.1p1-1
- update to 3.0.1p1
* Tue Nov 13 2001 Nalin Dahyabhai <nalin@redhat.com>
- update to current CVS (not for use in distribution)
* Thu Nov 8 2001 Nalin Dahyabhai <nalin@redhat.com> 3.0p1-1
- merge some of Damien Miller <djm@mindrot.org> changes from the upstream
3.0p1 spec file and init script
* Wed Nov 7 2001 Nalin Dahyabhai <nalin@redhat.com>
- update to 3.0p1
- update to x11-ssh-askpass 1.2.4.1
- change build dependency on a file from pam-devel to the pam-devel package
- replace primes with moduli
* Thu Sep 27 2001 Nalin Dahyabhai <nalin@redhat.com> 2.9p2-9
- incorporate fix from Markus Friedl's advisory for IP-based authorization bugs
* Thu Sep 13 2001 Bernhard Rosenkraenzer <bero@redhat.com> 2.9p2-8
- Merge changes to rescue build from current sysadmin survival cd
* Thu Sep 6 2001 Nalin Dahyabhai <nalin@redhat.com> 2.9p2-7
- fix scp's server's reporting of file sizes, and build with the proper
preprocessor define to get large-file capable open(), stat(), etc.
(sftp has been doing this correctly all along) (#51827)
- configure without --with-ipv4-default on RHL 7.x and newer (#45987,#52247)
- pull cvs patch to fix support for /etc/nologin for non-PAM logins (#47298)
- mark profile.d scriptlets as config files (#42337)
- refer to Jason Stone's mail for zsh workaround for exit-hanging quasi-bug
- change a couple of log() statements to debug() statements (#50751)
- pull cvs patch to add -t flag to sshd (#28611)
- clear fd_sets correctly (one bit per FD, not one byte per FD) (#43221)
* Mon Aug 20 2001 Nalin Dahyabhai <nalin@redhat.com> 2.9p2-6
- add db1-devel as a BuildPrerequisite (noted by Hans Ecke)
* Thu Aug 16 2001 Nalin Dahyabhai <nalin@redhat.com>
- pull cvs patch to fix remote port forwarding with protocol 2
* Thu Aug 9 2001 Nalin Dahyabhai <nalin@redhat.com>
- pull cvs patch to add session initialization to no-pty sessions
- pull cvs patch to not cut off challengeresponse auth needlessly
- refuse to do X11 forwarding if xauth isn't there, handy if you enable
it by default on a system that doesn't have X installed (#49263)
* Wed Aug 8 2001 Nalin Dahyabhai <nalin@redhat.com>
- don't apply patches to code we don't intend to build (spotted by Matt Galgoci)
* Mon Aug 6 2001 Nalin Dahyabhai <nalin@redhat.com>
- pass OPTIONS correctly to initlog (#50151)
* Wed Jul 25 2001 Nalin Dahyabhai <nalin@redhat.com>
- switch to x11-ssh-askpass 1.2.2
* Wed Jul 11 2001 Nalin Dahyabhai <nalin@redhat.com>
- rebuild in new environment
* Mon Jun 25 2001 Nalin Dahyabhai <nalin@redhat.com>
- disable the gssapi patch
* Mon Jun 18 2001 Nalin Dahyabhai <nalin@redhat.com>
- update to 2.9p2
- refresh to a new version of the gssapi patch
* Thu Jun 7 2001 Nalin Dahyabhai <nalin@redhat.com>
- change Copyright: BSD to License: BSD
- add Markus Friedl's unverified patch for the cookie file deletion problem
so that we can verify it
- drop patch to check if xauth is present (was folded into cookie patch)
- don't apply gssapi patches for the errata candidate
- clear supplemental groups list at startup
* Fri May 25 2001 Nalin Dahyabhai <nalin@redhat.com>
- fix an error parsing the new default sshd_config
- add a fix from Markus Friedl (via openssh-unix-dev) for ssh-keygen not
dealing with comments right
* Thu May 24 2001 Nalin Dahyabhai <nalin@redhat.com>
- add in Simon Wilkinson's GSSAPI patch to give it some testing in-house,
to be removed before the next beta cycle because it's a big departure
from the upstream version
* Thu May 3 2001 Nalin Dahyabhai <nalin@redhat.com>
- finish marking strings in the init script for translation
- modify init script to source /etc/sysconfig/sshd and pass $OPTIONS to sshd
at startup (change merged from openssh.com init script, originally by
Pekka Savola)
- refuse to do X11 forwarding if xauth isn't there, handy if you enable
it by default on a system that doesn't have X installed
* Wed May 2 2001 Nalin Dahyabhai <nalin@redhat.com>
- update to 2.9
- drop various patches that came from or went upstream or to or from CVS
* Wed Apr 18 2001 Nalin Dahyabhai <nalin@redhat.com>
- only require initscripts 5.00 on 6.2 (reported by Peter Bieringer)
* Sun Apr 8 2001 Preston Brown <pbrown@redhat.com>
- remove explicit openssl requirement, fixes builddistro issue
- make initscript stop() function wait until sshd really dead to avoid
races in condrestart
* Mon Apr 2 2001 Nalin Dahyabhai <nalin@redhat.com>
- mention that challengereponse supports PAM, so disabling password doesn't
limit users to pubkey and rsa auth (#34378)
- bypass the daemon() function in the init script and call initlog directly,
because daemon() won't start a daemon it detects is already running (like
open connections)
- require the version of openssl we had when we were built
* Fri Mar 23 2001 Nalin Dahyabhai <nalin@redhat.com>
- make do_pam_setcred() smart enough to know when to establish creds and
when to reinitialize them
- add in a couple of other fixes from Damien for inclusion in the errata
* Thu Mar 22 2001 Nalin Dahyabhai <nalin@redhat.com>
- update to 2.5.2p2
- call setcred() again after initgroups, because the "creds" could actually
be group memberships
* Tue Mar 20 2001 Nalin Dahyabhai <nalin@redhat.com>
- update to 2.5.2p1 (includes endianness fixes in the rijndael implementation)
- don't enable challenge-response by default until we find a way to not
have too many userauth requests (we may make up to six pubkey and up to
three password attempts as it is)
- remove build dependency on rsh to match openssh.com's packages more closely
* Sat Mar 3 2001 Nalin Dahyabhai <nalin@redhat.com>
- remove dependency on openssl -- would need to be too precise
* Fri Mar 2 2001 Nalin Dahyabhai <nalin@redhat.com>
- rebuild in new environment
* Mon Feb 26 2001 Nalin Dahyabhai <nalin@redhat.com>
- Revert the patch to move pam_open_session.
- Init script and spec file changes from Pekka Savola. (#28750)
- Patch sftp to recognize '-o protocol' arguments. (#29540)
* Thu Feb 22 2001 Nalin Dahyabhai <nalin@redhat.com>
- Chuck the closing patch.
- Add a trigger to add host keys for protocol 2 to the config file, now that
configuration file syntax requires us to specify it with HostKey if we
specify any other HostKey values, which we do.
* Tue Feb 20 2001 Nalin Dahyabhai <nalin@redhat.com>
- Redo patch to move pam_open_session after the server setuid()s to the user.
- Rework the nopam patch to use be picked up by autoconf.
* Mon Feb 19 2001 Nalin Dahyabhai <nalin@redhat.com>
- Update for 2.5.1p1.
- Add init script mods from Pekka Savola.
- Tweak the init script to match the CVS contrib script more closely.
- Redo patch to ssh-add to try to adding both identity and id_dsa to also try
adding id_rsa.
* Fri Feb 16 2001 Nalin Dahyabhai <nalin@redhat.com>
- Update for 2.5.0p1.
- Use $RPM_OPT_FLAGS instead of -O when building gnome-ssh-askpass
- Resync with parts of Damien Miller's openssh.spec from CVS, including
update of x11 askpass to 1.2.0.
- Only require openssl (don't prereq) because we generate keys in the init
script now.
* Tue Feb 13 2001 Nalin Dahyabhai <nalin@redhat.com>
- Don't open a PAM session until we've forked and become the user (#25690).
- Apply Andrew Bartlett's patch for letting pam_authenticate() know which
host the user is attempting a login from.
- Resync with parts of Damien Miller's openssh.spec from CVS.
- Don't expose KbdInt responses in debug messages (from CVS).
- Detect and handle errors in rsa_{public,private}_decrypt (from CVS).
* Wed Feb 7 2001 Trond Eivind Glomsrxd <teg@redhat.com>
- i18n-tweak to initscript.
* Tue Jan 23 2001 Nalin Dahyabhai <nalin@redhat.com>
- More gettextizing.
- Close all files after going into daemon mode (needs more testing).
- Extract patch from CVS to handle auth banners (in the client).
- Extract patch from CVS to handle compat weirdness.
* Fri Jan 19 2001 Nalin Dahyabhai <nalin@redhat.com>
- Finish with the gettextizing.
* Thu Jan 18 2001 Nalin Dahyabhai <nalin@redhat.com>
- Fix a bug in auth2-pam.c (#23877)
- Gettextize the init script.
* Wed Dec 20 2000 Nalin Dahyabhai <nalin@redhat.com>
- Incorporate a switch for using PAM configs for 6.x, just in case.
* Tue Dec 5 2000 Nalin Dahyabhai <nalin@redhat.com>
- Incorporate Bero's changes for a build specifically for rescue CDs.
* Wed Nov 29 2000 Nalin Dahyabhai <nalin@redhat.com>
- Don't treat pam_setcred() failure as fatal unless pam_authenticate() has
succeeded, to allow public-key authentication after a failure with "none"
authentication. (#21268)
* Tue Nov 28 2000 Nalin Dahyabhai <nalin@redhat.com>
- Update to x11-askpass 1.1.1. (#21301)
- Don't second-guess fixpaths, which causes paths to get fixed twice. (#21290)
* Mon Nov 27 2000 Nalin Dahyabhai <nalin@redhat.com>
- Merge multiple PAM text messages into subsequent prompts when possible when
doing keyboard-interactive authentication.
* Sun Nov 26 2000 Nalin Dahyabhai <nalin@redhat.com>
- Disable the built-in MD5 password support. We're using PAM.
- Take a crack at doing keyboard-interactive authentication with PAM, and
enable use of it in the default client configuration so that the client
will try it when the server disallows password authentication.
- Build with debugging flags. Build root policies strip all binaries anyway.
* Tue Nov 21 2000 Nalin Dahyabhai <nalin@redhat.com>
- Use DESTDIR instead of %%makeinstall.
- Remove /usr/X11R6/bin from the path-fixing patch.
* Mon Nov 20 2000 Nalin Dahyabhai <nalin@redhat.com>
- Add the primes file from the latest snapshot to the main package (#20884).
- Add the dev package to the prereq list (#19984).
- Remove the default path and mimic login's behavior in the server itself.
* Fri Nov 17 2000 Nalin Dahyabhai <nalin@redhat.com>
- Resync with conditional options in Damien Miller's .spec file for an errata.
- Change libexecdir from %%{_libexecdir}/ssh to %%{_libexecdir}/openssh.
* Tue Nov 7 2000 Nalin Dahyabhai <nalin@redhat.com>
- Update to OpenSSH 2.3.0p1.
- Update to x11-askpass 1.1.0.
- Enable keyboard-interactive authentication.
* Mon Oct 30 2000 Nalin Dahyabhai <nalin@redhat.com>
- Update to ssh-askpass-x11 1.0.3.
- Change authentication related messages to be private (#19966).
* Tue Oct 10 2000 Nalin Dahyabhai <nalin@redhat.com>
- Patch ssh-keygen to be able to list signatures for DSA public key files
it generates.
* Thu Oct 5 2000 Nalin Dahyabhai <nalin@redhat.com>
- Add BuildRequires on /usr/include/security/pam_appl.h to be sure we always
build PAM authentication in.
- Try setting SSH_ASKPASS if gnome-ssh-askpass is installed.
- Clean out no-longer-used patches.
- Patch ssh-add to try to add both identity and id_dsa, and to error only
when neither exists.
* Mon Oct 2 2000 Nalin Dahyabhai <nalin@redhat.com>
- Update x11-askpass to 1.0.2. (#17835)
- Add BuildRequiress for /bin/login and /usr/bin/rsh so that configure will
always find them in the right place. (#17909)
- Set the default path to be the same as the one supplied by /bin/login, but
add /usr/X11R6/bin. (#17909)
- Try to handle obsoletion of ssh-server more cleanly. Package names
are different, but init script name isn't. (#17865)
* Wed Sep 6 2000 Nalin Dahyabhai <nalin@redhat.com>
- Update to 2.2.0p1. (#17835)
- Tweak the init script to allow proper restarting. (#18023)
* Wed Aug 23 2000 Nalin Dahyabhai <nalin@redhat.com>
- Update to 20000823 snapshot.
- Change subpackage requirements from %%{version} to %%{version}-%%{release}
- Back out the pipe patch.
* Mon Jul 17 2000 Nalin Dahyabhai <nalin@redhat.com>
- Update to 2.1.1p4, which includes fixes for config file parsing problems.
- Move the init script back.
- Add Damien's quick fix for wackiness.
* Wed Jul 12 2000 Nalin Dahyabhai <nalin@redhat.com>
- Update to 2.1.1p3, which includes fixes for X11 forwarding and strtok().
* Thu Jul 6 2000 Nalin Dahyabhai <nalin@redhat.com>
- Move condrestart to server postun.
- Move key generation to init script.
- Actually use the right patch for moving the key generation to the init script.
- Clean up the init script a bit.
* Wed Jul 5 2000 Nalin Dahyabhai <nalin@redhat.com>
- Fix X11 forwarding, from mail post by Chan Shih-Ping Richard.
* Sun Jul 2 2000 Nalin Dahyabhai <nalin@redhat.com>
- Update to 2.1.1p2.
- Use of strtok() considered harmful.
* Sat Jul 1 2000 Nalin Dahyabhai <nalin@redhat.com>
- Get the build root out of the man pages.
* Thu Jun 29 2000 Nalin Dahyabhai <nalin@redhat.com>
- Add and use condrestart support in the init script.
- Add newer initscripts as a prereq.
* Tue Jun 27 2000 Nalin Dahyabhai <nalin@redhat.com>
- Build in new environment (release 2)
- Move -clients subpackage to Applications/Internet group
* Fri Jun 9 2000 Nalin Dahyabhai <nalin@redhat.com>
- Update to 2.2.1p1
* Sat Jun 3 2000 Nalin Dahyabhai <nalin@redhat.com>
- Patch to build with neither RSA nor RSAref.
- Miscellaneous FHS-compliance tweaks.
- Fix for possibly-compressed man pages.
* Wed Mar 15 2000 Damien Miller <djm@ibs.com.au>
- Updated for new location
- Updated for new gnome-ssh-askpass build
* Sun Dec 26 1999 Damien Miller <djm@mindrot.org>
- Added Jim Knoble's <jmknoble@pobox.com> askpass
* Mon Nov 15 1999 Damien Miller <djm@mindrot.org>
- Split subpackages further based on patch from jim knoble <jmknoble@pobox.com>
* Sat Nov 13 1999 Damien Miller <djm@mindrot.org>
- Added 'Obsoletes' directives
* Tue Nov 09 1999 Damien Miller <djm@ibs.com.au>
- Use make install
- Subpackages
* Mon Nov 08 1999 Damien Miller <djm@ibs.com.au>
- Added links for slogin
- Fixed perms on manpages
* Sat Oct 30 1999 Damien Miller <djm@ibs.com.au>
- Renamed init script
* Fri Oct 29 1999 Damien Miller <djm@ibs.com.au>
- Back to old binary names
* Thu Oct 28 1999 Damien Miller <djm@ibs.com.au>
- Use autoconf
- New binary names
* Wed Oct 27 1999 Damien Miller <djm@ibs.com.au>
- Initial RPMification, based on Jan "Yenya" Kasprzak's <kas@fi.muni.cz> spec.
diff --git a/contrib/suse/openssh.spec b/contrib/suse/openssh.spec
index fe950303ee95..827eee6c270a 100644
--- a/contrib/suse/openssh.spec
+++ b/contrib/suse/openssh.spec
@@ -1,245 +1,245 @@
# Default values for additional components
%define build_x11_askpass 1
# Define the UID/GID to use for privilege separation
%define sshd_gid 65
%define sshd_uid 71
# The version of x11-ssh-askpass to use
%define xversion 1.2.4.1
# Allow the ability to override defaults with -D skip_xxx=1
%{?skip_x11_askpass:%define build_x11_askpass 0}
Summary: OpenSSH, a free Secure Shell (SSH) protocol implementation
Name: openssh
-Version: 8.5p1
+Version: 8.6p1
URL: https://www.openssh.com/
Release: 1
Source0: openssh-%{version}.tar.gz
Source1: x11-ssh-askpass-%{xversion}.tar.gz
License: BSD
Group: Productivity/Networking/SSH
BuildRoot: %{_tmppath}/openssh-%{version}-buildroot
PreReq: openssl
Obsoletes: ssh
Provides: ssh
#
# (Build[ing] Prereq[uisites] only work for RPM 2.95 and newer.)
# building prerequisites -- stuff for
# OpenSSL (openssl-devel),
# and Gnome (glibdev, gtkdev, and gnlibsd)
#
BuildPrereq: openssl
BuildPrereq: zlib-devel
#BuildPrereq: glibdev
#BuildPrereq: gtkdev
#BuildPrereq: gnlibsd
%package askpass
Summary: A passphrase dialog for OpenSSH and the X window System.
Group: Productivity/Networking/SSH
Requires: openssh = %{version}
Obsoletes: ssh-extras
Provides: openssh:${_libdir}/ssh/ssh-askpass
%if %{build_x11_askpass}
BuildPrereq: XFree86-devel
%endif
%description
Ssh (Secure Shell) is a program for logging into a remote machine and for
executing commands in a remote machine. It is intended to replace
rlogin and rsh, and provide secure encrypted communications between
two untrusted hosts over an insecure network. X11 connections and
arbitrary TCP/IP ports can also be forwarded over the secure channel.
OpenSSH is OpenBSD's rework of the last free version of SSH, bringing it
up to date in terms of security and features, as well as removing all
patented algorithms to separate libraries (OpenSSL).
This package includes all files necessary for both the OpenSSH
client and server.
%description askpass
Ssh (Secure Shell) is a program for logging into a remote machine and for
executing commands in a remote machine. It is intended to replace
rlogin and rsh, and provide secure encrypted communications between
two untrusted hosts over an insecure network. X11 connections and
arbitrary TCP/IP ports can also be forwarded over the secure channel.
OpenSSH is OpenBSD's rework of the last free version of SSH, bringing it
up to date in terms of security and features, as well as removing all
patented algorithms to separate libraries (OpenSSL).
This package contains an X Window System passphrase dialog for OpenSSH.
%changelog
* Mon Jul 20 2020 Damien Miller <djm@mindrto.org>
- Add ssh-sk-helper and corresponding manual page.
* Wed Oct 26 2005 Iain Morgan <imorgan@nas.nasa.gov>
- Removed accidental inclusion of --without-zlib-version-check
* Tue Oct 25 2005 Iain Morgan <imorgan@nas.nasa.gov>
- Overhaul to deal with newer versions of SuSE and OpenSSH
* Mon Jun 12 2000 Damien Miller <djm@mindrot.org>
- Glob manpages to catch compressed files
* Wed Mar 15 2000 Damien Miller <djm@ibs.com.au>
- Updated for new location
- Updated for new gnome-ssh-askpass build
* Sun Dec 26 1999 Chris Saia <csaia@wtower.com>
- Made symlink to gnome-ssh-askpass called ssh-askpass
* Wed Nov 24 1999 Chris Saia <csaia@wtower.com>
- Removed patches that included /etc/pam.d/sshd, /sbin/init.d/rc.sshd, and
/var/adm/fillup-templates/rc.config.sshd, since Damien merged these into
his released tarfile
- Changed permissions on ssh_config in the install procedure to 644 from 600
even though it was correct in the %files section and thus right in the RPMs
- Postinstall script for the server now only prints "Generating SSH host
key..." if we need to actually do this, in order to eliminate a confusing
message if an SSH host key is already in place
- Marked all manual pages as %doc(umentation)
* Mon Nov 22 1999 Chris Saia <csaia@wtower.com>
- Added flag to configure daemon with TCP Wrappers support
- Added building prerequisites (works in RPM 3.0 and newer)
* Thu Nov 18 1999 Chris Saia <csaia@wtower.com>
- Made this package correct for SuSE.
- Changed instances of pam_pwdb.so to pam_unix.so, since it works more properly
with SuSE, and lib_pwdb.so isn't installed by default.
* Mon Nov 15 1999 Damien Miller <djm@mindrot.org>
- Split subpackages further based on patch from jim knoble <jmknoble@pobox.com>
* Sat Nov 13 1999 Damien Miller <djm@mindrot.org>
- Added 'Obsoletes' directives
* Tue Nov 09 1999 Damien Miller <djm@ibs.com.au>
- Use make install
- Subpackages
* Mon Nov 08 1999 Damien Miller <djm@ibs.com.au>
- Added links for slogin
- Fixed perms on manpages
* Sat Oct 30 1999 Damien Miller <djm@ibs.com.au>
- Renamed init script
* Fri Oct 29 1999 Damien Miller <djm@ibs.com.au>
- Back to old binary names
* Thu Oct 28 1999 Damien Miller <djm@ibs.com.au>
- Use autoconf
- New binary names
* Wed Oct 27 1999 Damien Miller <djm@ibs.com.au>
- Initial RPMification, based on Jan "Yenya" Kasprzak's <kas@fi.muni.cz> spec.
%prep
%if %{build_x11_askpass}
%setup -q -a 1
%else
%setup -q
%endif
%build
CFLAGS="$RPM_OPT_FLAGS" \
%configure --prefix=/usr \
--sysconfdir=%{_sysconfdir}/ssh \
--mandir=%{_mandir} \
--with-privsep-path=/var/lib/empty \
--with-pam \
--libexecdir=%{_libdir}/ssh
make
%if %{build_x11_askpass}
cd x11-ssh-askpass-%{xversion}
%configure --mandir=/usr/X11R6/man \
--libexecdir=%{_libdir}/ssh
xmkmf -a
make
cd ..
%endif
%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT/
install -d $RPM_BUILD_ROOT/etc/pam.d/
install -d $RPM_BUILD_ROOT/etc/init.d/
install -d $RPM_BUILD_ROOT/var/adm/fillup-templates
install -m644 contrib/sshd.pam.generic $RPM_BUILD_ROOT/etc/pam.d/sshd
install -m744 contrib/suse/rc.sshd $RPM_BUILD_ROOT/etc/init.d/sshd
install -m744 contrib/suse/sysconfig.ssh \
$RPM_BUILD_ROOT/var/adm/fillup-templates
%if %{build_x11_askpass}
cd x11-ssh-askpass-%{xversion}
make install install.man BINDIR=%{_libdir}/ssh DESTDIR=$RPM_BUILD_ROOT/
rm -f $RPM_BUILD_ROOT/usr/share/Ssh.bin
%endif
%clean
rm -rf $RPM_BUILD_ROOT
%pre
/usr/sbin/groupadd -g %{sshd_gid} -o -r sshd 2> /dev/null || :
/usr/sbin/useradd -r -o -g sshd -u %{sshd_uid} -s /bin/false -c "SSH Privilege Separation User" -d /var/lib/sshd sshd 2> /dev/null || :
%post
/usr/bin/ssh-keygen -A
%{fillup_and_insserv -n -y ssh sshd}
%run_permissions
%verifyscript
%verify_permissions -e /etc/ssh/sshd_config -e /etc/ssh/ssh_config -e /usr/bin/ssh
%preun
%stop_on_removal sshd
%postun
%restart_on_update sshd
%{insserv_cleanup}
%files
%defattr(-,root,root)
%doc ChangeLog OVERVIEW README* PROTOCOL*
%doc TODO CREDITS LICENCE
%attr(0755,root,root) %dir %{_sysconfdir}/ssh
%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ssh/ssh_config
%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ssh/sshd_config
%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ssh/moduli
%attr(0644,root,root) %config(noreplace) /etc/pam.d/sshd
%attr(0755,root,root) %config /etc/init.d/sshd
%attr(0755,root,root) %{_bindir}/ssh-keygen
%attr(0755,root,root) %{_bindir}/scp
%attr(0755,root,root) %{_bindir}/ssh
%attr(0755,root,root) %{_bindir}/ssh-agent
%attr(0755,root,root) %{_bindir}/ssh-add
%attr(0755,root,root) %{_bindir}/ssh-keyscan
%attr(0755,root,root) %{_bindir}/sftp
%attr(0755,root,root) %{_sbindir}/sshd
%attr(0755,root,root) %dir %{_libdir}/ssh
%attr(0755,root,root) %{_libdir}/ssh/sftp-server
%attr(4711,root,root) %{_libdir}/ssh/ssh-keysign
%attr(0755,root,root) %{_libdir}/ssh/ssh-pkcs11-helper
%attr(0755,root,root) %{_libdir}/ssh/ssh-sk-helper
%attr(0644,root,root) %doc %{_mandir}/man1/scp.1*
%attr(0644,root,root) %doc %{_mandir}/man1/sftp.1*
%attr(0644,root,root) %doc %{_mandir}/man1/ssh.1*
%attr(0644,root,root) %doc %{_mandir}/man1/ssh-add.1*
%attr(0644,root,root) %doc %{_mandir}/man1/ssh-agent.1*
%attr(0644,root,root) %doc %{_mandir}/man1/ssh-keygen.1*
%attr(0644,root,root) %doc %{_mandir}/man1/ssh-keyscan.1*
%attr(0644,root,root) %doc %{_mandir}/man5/moduli.5*
%attr(0644,root,root) %doc %{_mandir}/man5/ssh_config.5*
%attr(0644,root,root) %doc %{_mandir}/man5/sshd_config.5*
%attr(0644,root,root) %doc %{_mandir}/man8/sftp-server.8*
%attr(0644,root,root) %doc %{_mandir}/man8/ssh-keysign.8*
%attr(0644,root,root) %doc %{_mandir}/man8/ssh-pkcs11-helper.8*
%attr(0644,root,root) %doc %{_mandir}/man8/ssh-sk-helper.8*
%attr(0644,root,root) %doc %{_mandir}/man8/sshd.8*
%attr(0644,root,root) /var/adm/fillup-templates/sysconfig.ssh
%if %{build_x11_askpass}
%files askpass
%defattr(-,root,root)
%doc x11-ssh-askpass-%{xversion}/README
%doc x11-ssh-askpass-%{xversion}/ChangeLog
%doc x11-ssh-askpass-%{xversion}/SshAskpass*.ad
%attr(0755,root,root) %{_libdir}/ssh/ssh-askpass
%attr(0755,root,root) %{_libdir}/ssh/x11-ssh-askpass
%attr(0644,root,root) %doc /usr/X11R6/man/man1/ssh-askpass.1x*
%attr(0644,root,root) %doc /usr/X11R6/man/man1/x11-ssh-askpass.1x*
%attr(0644,root,root) %config /usr/X11R6/lib/X11/app-defaults/SshAskpass
%endif
diff --git a/dh.c b/dh.c
index b5bb35e48243..ce2eb4725e65 100644
--- a/dh.c
+++ b/dh.c
@@ -1,492 +1,505 @@
-/* $OpenBSD: dh.c,v 1.72 2020/10/18 11:32:01 djm Exp $ */
+/* $OpenBSD: dh.c,v 1.74 2021/04/03 06:18:40 djm Exp $ */
/*
* Copyright (c) 2000 Niels Provos. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#ifdef WITH_OPENSSL
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include "dh.h"
#include "pathnames.h"
#include "log.h"
#include "misc.h"
#include "ssherr.h"
#include "openbsd-compat/openssl-compat.h"
+static const char *moduli_filename;
+
+void dh_set_moduli_file(const char *filename)
+{
+ moduli_filename = filename;
+}
+
+static const char * get_moduli_filename(void)
+{
+ return moduli_filename ? moduli_filename : _PATH_DH_MODULI;
+}
+
static int
parse_prime(int linenum, char *line, struct dhgroup *dhg)
{
char *cp, *arg;
char *strsize, *gen, *prime;
const char *errstr = NULL;
long long n;
dhg->p = dhg->g = NULL;
cp = line;
if ((arg = strdelim(&cp)) == NULL)
return 0;
/* Ignore leading whitespace */
if (*arg == '\0')
arg = strdelim(&cp);
if (!arg || !*arg || *arg == '#')
return 0;
/* time */
if (cp == NULL || *arg == '\0')
goto truncated;
arg = strsep(&cp, " "); /* type */
if (cp == NULL || *arg == '\0')
goto truncated;
/* Ensure this is a safe prime */
n = strtonum(arg, 0, 5, &errstr);
if (errstr != NULL || n != MODULI_TYPE_SAFE) {
error("moduli:%d: type is not %d", linenum, MODULI_TYPE_SAFE);
goto fail;
}
arg = strsep(&cp, " "); /* tests */
if (cp == NULL || *arg == '\0')
goto truncated;
/* Ensure prime has been tested and is not composite */
n = strtonum(arg, 0, 0x1f, &errstr);
if (errstr != NULL ||
(n & MODULI_TESTS_COMPOSITE) || !(n & ~MODULI_TESTS_COMPOSITE)) {
error("moduli:%d: invalid moduli tests flag", linenum);
goto fail;
}
arg = strsep(&cp, " "); /* tries */
if (cp == NULL || *arg == '\0')
goto truncated;
n = strtonum(arg, 0, 1<<30, &errstr);
if (errstr != NULL || n == 0) {
error("moduli:%d: invalid primality trial count", linenum);
goto fail;
}
strsize = strsep(&cp, " "); /* size */
if (cp == NULL || *strsize == '\0' ||
(dhg->size = (int)strtonum(strsize, 0, 64*1024, &errstr)) == 0 ||
errstr) {
error("moduli:%d: invalid prime length", linenum);
goto fail;
}
/* The whole group is one bit larger */
dhg->size++;
gen = strsep(&cp, " "); /* gen */
if (cp == NULL || *gen == '\0')
goto truncated;
prime = strsep(&cp, " "); /* prime */
if (cp != NULL || *prime == '\0') {
truncated:
error("moduli:%d: truncated", linenum);
goto fail;
}
if ((dhg->g = BN_new()) == NULL ||
(dhg->p = BN_new()) == NULL) {
error("parse_prime: BN_new failed");
goto fail;
}
if (BN_hex2bn(&dhg->g, gen) == 0) {
error("moduli:%d: could not parse generator value", linenum);
goto fail;
}
if (BN_hex2bn(&dhg->p, prime) == 0) {
error("moduli:%d: could not parse prime value", linenum);
goto fail;
}
if (BN_num_bits(dhg->p) != dhg->size) {
error("moduli:%d: prime has wrong size: actual %d listed %d",
linenum, BN_num_bits(dhg->p), dhg->size - 1);
goto fail;
}
if (BN_cmp(dhg->g, BN_value_one()) <= 0) {
error("moduli:%d: generator is invalid", linenum);
goto fail;
}
return 1;
fail:
BN_clear_free(dhg->g);
BN_clear_free(dhg->p);
dhg->g = dhg->p = NULL;
return 0;
}
DH *
choose_dh(int min, int wantbits, int max)
{
FILE *f;
char *line = NULL;
size_t linesize = 0;
int best, bestcount, which, linenum;
struct dhgroup dhg;
- if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL) {
+ if ((f = fopen(get_moduli_filename(), "r")) == NULL) {
logit("WARNING: could not open %s (%s), using fixed modulus",
- _PATH_DH_MODULI, strerror(errno));
+ get_moduli_filename(), strerror(errno));
return (dh_new_group_fallback(max));
}
linenum = 0;
best = bestcount = 0;
while (getline(&line, &linesize, f) != -1) {
linenum++;
if (!parse_prime(linenum, line, &dhg))
continue;
BN_clear_free(dhg.g);
BN_clear_free(dhg.p);
if (dhg.size > max || dhg.size < min)
continue;
if ((dhg.size > wantbits && dhg.size < best) ||
(dhg.size > best && best < wantbits)) {
best = dhg.size;
bestcount = 0;
}
if (dhg.size == best)
bestcount++;
}
free(line);
line = NULL;
linesize = 0;
rewind(f);
if (bestcount == 0) {
fclose(f);
- logit("WARNING: no suitable primes in %s", _PATH_DH_MODULI);
+ logit("WARNING: no suitable primes in %s",
+ get_moduli_filename());
return (dh_new_group_fallback(max));
}
which = arc4random_uniform(bestcount);
linenum = 0;
bestcount = 0;
while (getline(&line, &linesize, f) != -1) {
linenum++;
if (!parse_prime(linenum, line, &dhg))
continue;
if ((dhg.size > max || dhg.size < min) ||
dhg.size != best ||
bestcount++ != which) {
BN_clear_free(dhg.g);
BN_clear_free(dhg.p);
continue;
}
break;
}
free(line);
line = NULL;
fclose(f);
if (bestcount != which + 1) {
logit("WARNING: selected prime disappeared in %s, giving up",
- _PATH_DH_MODULI);
+ get_moduli_filename());
return (dh_new_group_fallback(max));
}
return (dh_new_group(dhg.g, dhg.p));
}
/* diffie-hellman-groupN-sha1 */
int
dh_pub_is_valid(const DH *dh, const BIGNUM *dh_pub)
{
int i;
int n = BN_num_bits(dh_pub);
int bits_set = 0;
BIGNUM *tmp;
const BIGNUM *dh_p;
DH_get0_pqg(dh, &dh_p, NULL, NULL);
if (BN_is_negative(dh_pub)) {
logit("invalid public DH value: negative");
return 0;
}
if (BN_cmp(dh_pub, BN_value_one()) != 1) { /* pub_exp <= 1 */
logit("invalid public DH value: <= 1");
return 0;
}
if ((tmp = BN_new()) == NULL) {
error_f("BN_new failed");
return 0;
}
if (!BN_sub(tmp, dh_p, BN_value_one()) ||
BN_cmp(dh_pub, tmp) != -1) { /* pub_exp > p-2 */
BN_clear_free(tmp);
logit("invalid public DH value: >= p-1");
return 0;
}
BN_clear_free(tmp);
for (i = 0; i <= n; i++)
if (BN_is_bit_set(dh_pub, i))
bits_set++;
debug2("bits set: %d/%d", bits_set, BN_num_bits(dh_p));
/*
* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial
*/
if (bits_set < 4) {
logit("invalid public DH value (%d/%d)",
- bits_set, BN_num_bits(dh_p));
+ bits_set, BN_num_bits(dh_p));
return 0;
}
return 1;
}
int
dh_gen_key(DH *dh, int need)
{
int pbits;
const BIGNUM *dh_p, *pub_key;
DH_get0_pqg(dh, &dh_p, NULL, NULL);
if (need < 0 || dh_p == NULL ||
(pbits = BN_num_bits(dh_p)) <= 0 ||
need > INT_MAX / 2 || 2 * need > pbits)
return SSH_ERR_INVALID_ARGUMENT;
if (need < 256)
need = 256;
/*
* Pollard Rho, Big step/Little Step attacks are O(sqrt(n)),
* so double requested need here.
*/
if (!DH_set_length(dh, MINIMUM(need * 2, pbits - 1)))
return SSH_ERR_LIBCRYPTO_ERROR;
if (DH_generate_key(dh) == 0)
return SSH_ERR_LIBCRYPTO_ERROR;
DH_get0_key(dh, &pub_key, NULL);
if (!dh_pub_is_valid(dh, pub_key))
return SSH_ERR_INVALID_FORMAT;
return 0;
}
DH *
dh_new_group_asc(const char *gen, const char *modulus)
{
DH *dh;
BIGNUM *dh_p = NULL, *dh_g = NULL;
if ((dh = DH_new()) == NULL)
return NULL;
if (BN_hex2bn(&dh_p, modulus) == 0 ||
BN_hex2bn(&dh_g, gen) == 0)
goto fail;
if (!DH_set0_pqg(dh, dh_p, NULL, dh_g))
goto fail;
return dh;
fail:
DH_free(dh);
BN_clear_free(dh_p);
BN_clear_free(dh_g);
return NULL;
}
/*
* This just returns the group, we still need to generate the exchange
* value.
*/
DH *
dh_new_group(BIGNUM *gen, BIGNUM *modulus)
{
DH *dh;
if ((dh = DH_new()) == NULL)
return NULL;
if (!DH_set0_pqg(dh, modulus, NULL, gen)) {
DH_free(dh);
return NULL;
}
return dh;
}
/* rfc2409 "Second Oakley Group" (1024 bits) */
DH *
dh_new_group1(void)
{
static char *gen = "2", *group1 =
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
"FFFFFFFF" "FFFFFFFF";
return (dh_new_group_asc(gen, group1));
}
/* rfc3526 group 14 "2048-bit MODP Group" */
DH *
dh_new_group14(void)
{
static char *gen = "2", *group14 =
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
"C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
"83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
"670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
"E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
"DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
"15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF";
return (dh_new_group_asc(gen, group14));
}
/* rfc3526 group 16 "4096-bit MODP Group" */
DH *
dh_new_group16(void)
{
static char *gen = "2", *group16 =
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
"C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
"83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
"670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
"E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
"DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
"15728E5A" "8AAAC42D" "AD33170D" "04507A33" "A85521AB" "DF1CBA64"
"ECFB8504" "58DBEF0A" "8AEA7157" "5D060C7D" "B3970F85" "A6E1E4C7"
"ABF5AE8C" "DB0933D7" "1E8C94E0" "4A25619D" "CEE3D226" "1AD2EE6B"
"F12FFA06" "D98A0864" "D8760273" "3EC86A64" "521F2B18" "177B200C"
"BBE11757" "7A615D6C" "770988C0" "BAD946E2" "08E24FA0" "74E5AB31"
"43DB5BFC" "E0FD108E" "4B82D120" "A9210801" "1A723C12" "A787E6D7"
"88719A10" "BDBA5B26" "99C32718" "6AF4E23C" "1A946834" "B6150BDA"
"2583E9CA" "2AD44CE8" "DBBBC2DB" "04DE8EF9" "2E8EFC14" "1FBECAA6"
"287C5947" "4E6BC05D" "99B2964F" "A090C3A2" "233BA186" "515BE7ED"
"1F612970" "CEE2D7AF" "B81BDD76" "2170481C" "D0069127" "D5B05AA9"
"93B4EA98" "8D8FDDC1" "86FFB7DC" "90A6C08F" "4DF435C9" "34063199"
"FFFFFFFF" "FFFFFFFF";
return (dh_new_group_asc(gen, group16));
}
/* rfc3526 group 18 "8192-bit MODP Group" */
DH *
dh_new_group18(void)
{
static char *gen = "2", *group18 =
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
"C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
"83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
"670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
"E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
"DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
"15728E5A" "8AAAC42D" "AD33170D" "04507A33" "A85521AB" "DF1CBA64"
"ECFB8504" "58DBEF0A" "8AEA7157" "5D060C7D" "B3970F85" "A6E1E4C7"
"ABF5AE8C" "DB0933D7" "1E8C94E0" "4A25619D" "CEE3D226" "1AD2EE6B"
"F12FFA06" "D98A0864" "D8760273" "3EC86A64" "521F2B18" "177B200C"
"BBE11757" "7A615D6C" "770988C0" "BAD946E2" "08E24FA0" "74E5AB31"
"43DB5BFC" "E0FD108E" "4B82D120" "A9210801" "1A723C12" "A787E6D7"
"88719A10" "BDBA5B26" "99C32718" "6AF4E23C" "1A946834" "B6150BDA"
"2583E9CA" "2AD44CE8" "DBBBC2DB" "04DE8EF9" "2E8EFC14" "1FBECAA6"
"287C5947" "4E6BC05D" "99B2964F" "A090C3A2" "233BA186" "515BE7ED"
"1F612970" "CEE2D7AF" "B81BDD76" "2170481C" "D0069127" "D5B05AA9"
"93B4EA98" "8D8FDDC1" "86FFB7DC" "90A6C08F" "4DF435C9" "34028492"
"36C3FAB4" "D27C7026" "C1D4DCB2" "602646DE" "C9751E76" "3DBA37BD"
"F8FF9406" "AD9E530E" "E5DB382F" "413001AE" "B06A53ED" "9027D831"
"179727B0" "865A8918" "DA3EDBEB" "CF9B14ED" "44CE6CBA" "CED4BB1B"
"DB7F1447" "E6CC254B" "33205151" "2BD7AF42" "6FB8F401" "378CD2BF"
"5983CA01" "C64B92EC" "F032EA15" "D1721D03" "F482D7CE" "6E74FEF6"
"D55E702F" "46980C82" "B5A84031" "900B1C9E" "59E7C97F" "BEC7E8F3"
"23A97A7E" "36CC88BE" "0F1D45B7" "FF585AC5" "4BD407B2" "2B4154AA"
"CC8F6D7E" "BF48E1D8" "14CC5ED2" "0F8037E0" "A79715EE" "F29BE328"
"06A1D58B" "B7C5DA76" "F550AA3D" "8A1FBFF0" "EB19CCB1" "A313D55C"
"DA56C9EC" "2EF29632" "387FE8D7" "6E3C0468" "043E8F66" "3F4860EE"
"12BF2D5B" "0B7474D6" "E694F91E" "6DBE1159" "74A3926F" "12FEE5E4"
"38777CB6" "A932DF8C" "D8BEC4D0" "73B931BA" "3BC832B6" "8D9DD300"
"741FA7BF" "8AFC47ED" "2576F693" "6BA42466" "3AAB639C" "5AE4F568"
"3423B474" "2BF1C978" "238F16CB" "E39D652D" "E3FDB8BE" "FC848AD9"
"22222E04" "A4037C07" "13EB57A8" "1A23F0C7" "3473FC64" "6CEA306B"
"4BCBC886" "2F8385DD" "FA9D4B7F" "A2C087E8" "79683303" "ED5BDD3A"
"062B3CF5" "B3A278A6" "6D2A13F8" "3F44F82D" "DF310EE0" "74AB6A36"
"4597E899" "A0255DC1" "64F31CC5" "0846851D" "F9AB4819" "5DED7EA1"
"B1D510BD" "7EE74D73" "FAF36BC3" "1ECFA268" "359046F4" "EB879F92"
"4009438B" "481C6CD7" "889A002E" "D5EE382B" "C9190DA6" "FC026E47"
"9558E447" "5677E9AA" "9E3050E2" "765694DF" "C81F56E8" "80B96E71"
"60C980DD" "98EDD3DF" "FFFFFFFF" "FFFFFFFF";
return (dh_new_group_asc(gen, group18));
}
/* Select fallback group used by DH-GEX if moduli file cannot be read. */
DH *
dh_new_group_fallback(int max)
{
debug3_f("requested max size %d", max);
if (max < 3072) {
debug3("using 2k bit group 14");
return dh_new_group14();
} else if (max < 6144) {
debug3("using 4k bit group 16");
return dh_new_group16();
}
debug3("using 8k bit group 18");
return dh_new_group18();
}
/*
* Estimates the group order for a Diffie-Hellman group that has an
* attack complexity approximately the same as O(2**bits).
* Values from NIST Special Publication 800-57: Recommendation for Key
* Management Part 1 (rev 3) limited by the recommended maximum value
* from RFC4419 section 3.
*/
u_int
dh_estimate(int bits)
{
if (bits <= 112)
return 2048;
if (bits <= 128)
return 3072;
if (bits <= 192)
return 7680;
return 8192;
}
#endif /* WITH_OPENSSL */
diff --git a/dh.h b/dh.h
index 5d6df6297011..c6326a39d532 100644
--- a/dh.h
+++ b/dh.h
@@ -1,83 +1,84 @@
-/* $OpenBSD: dh.h,v 1.18 2019/09/06 05:23:55 djm Exp $ */
+/* $OpenBSD: dh.h,v 1.19 2021/03/12 04:08:19 dtucker Exp $ */
/*
* Copyright (c) 2000 Niels Provos. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DH_H
#define DH_H
#ifdef WITH_OPENSSL
struct dhgroup {
int size;
BIGNUM *g;
BIGNUM *p;
};
DH *choose_dh(int, int, int);
DH *dh_new_group_asc(const char *, const char *);
DH *dh_new_group(BIGNUM *, BIGNUM *);
DH *dh_new_group1(void);
DH *dh_new_group14(void);
DH *dh_new_group16(void);
DH *dh_new_group18(void);
DH *dh_new_group_fallback(int);
int dh_gen_key(DH *, int);
int dh_pub_is_valid(const DH *, const BIGNUM *);
u_int dh_estimate(int);
+void dh_set_moduli_file(const char *);
/*
* Max value from RFC4419.
* Min value from RFC8270.
*/
#define DH_GRP_MIN 2048
#define DH_GRP_MAX 8192
/*
* Values for "type" field of moduli(5)
* Specifies the internal structure of the prime modulus.
*/
#define MODULI_TYPE_UNKNOWN (0)
#define MODULI_TYPE_UNSTRUCTURED (1)
#define MODULI_TYPE_SAFE (2)
#define MODULI_TYPE_SCHNORR (3)
#define MODULI_TYPE_SOPHIE_GERMAIN (4)
#define MODULI_TYPE_STRONG (5)
/*
* Values for "tests" field of moduli(5)
* Specifies the methods used in checking for primality.
* Usually, more than one test is used.
*/
#define MODULI_TESTS_UNTESTED (0x00)
#define MODULI_TESTS_COMPOSITE (0x01)
#define MODULI_TESTS_SIEVE (0x02)
#define MODULI_TESTS_MILLER_RABIN (0x04)
#define MODULI_TESTS_JACOBI (0x08)
#define MODULI_TESTS_ELLIPTIC (0x10)
#endif /* WITH_OPENSSL */
#endif /* DH_H */
diff --git a/hostfile.c b/hostfile.c
index f5d3dde9b325..5f0e3515d656 100644
--- a/hostfile.c
+++ b/hostfile.c
@@ -1,935 +1,935 @@
-/* $OpenBSD: hostfile.c,v 1.89 2021/01/26 00:51:30 djm Exp $ */
+/* $OpenBSD: hostfile.c,v 1.90 2021/04/03 06:58:30 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Functions for manipulating the known hosts files.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
*
* Copyright (c) 1999, 2000 Markus Friedl. All rights reserved.
* Copyright (c) 1999 Niels Provos. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <errno.h>
#include <resolv.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "xmalloc.h"
#include "match.h"
#include "sshkey.h"
#include "hostfile.h"
#include "log.h"
#include "misc.h"
#include "pathnames.h"
#include "ssherr.h"
#include "digest.h"
#include "hmac.h"
#include "sshbuf.h"
/* XXX hmac is too easy to dictionary attack; use bcrypt? */
static int
extract_salt(const char *s, u_int l, u_char *salt, size_t salt_len)
{
char *p, *b64salt;
u_int b64len;
int ret;
if (l < sizeof(HASH_MAGIC) - 1) {
debug2("extract_salt: string too short");
return (-1);
}
if (strncmp(s, HASH_MAGIC, sizeof(HASH_MAGIC) - 1) != 0) {
debug2("extract_salt: invalid magic identifier");
return (-1);
}
s += sizeof(HASH_MAGIC) - 1;
l -= sizeof(HASH_MAGIC) - 1;
if ((p = memchr(s, HASH_DELIM, l)) == NULL) {
debug2("extract_salt: missing salt termination character");
return (-1);
}
b64len = p - s;
/* Sanity check */
if (b64len == 0 || b64len > 1024) {
debug2("extract_salt: bad encoded salt length %u", b64len);
return (-1);
}
b64salt = xmalloc(1 + b64len);
memcpy(b64salt, s, b64len);
b64salt[b64len] = '\0';
ret = __b64_pton(b64salt, salt, salt_len);
free(b64salt);
if (ret == -1) {
debug2("extract_salt: salt decode error");
return (-1);
}
if (ret != (int)ssh_hmac_bytes(SSH_DIGEST_SHA1)) {
debug2("extract_salt: expected salt len %zd, got %d",
ssh_hmac_bytes(SSH_DIGEST_SHA1), ret);
return (-1);
}
return (0);
}
char *
host_hash(const char *host, const char *name_from_hostfile, u_int src_len)
{
struct ssh_hmac_ctx *ctx;
u_char salt[256], result[256];
char uu_salt[512], uu_result[512];
static char encoded[1024];
u_int len;
len = ssh_digest_bytes(SSH_DIGEST_SHA1);
if (name_from_hostfile == NULL) {
/* Create new salt */
arc4random_buf(salt, len);
} else {
/* Extract salt from known host entry */
if (extract_salt(name_from_hostfile, src_len, salt,
sizeof(salt)) == -1)
return (NULL);
}
if ((ctx = ssh_hmac_start(SSH_DIGEST_SHA1)) == NULL ||
ssh_hmac_init(ctx, salt, len) < 0 ||
ssh_hmac_update(ctx, host, strlen(host)) < 0 ||
ssh_hmac_final(ctx, result, sizeof(result)))
fatal_f("ssh_hmac failed");
ssh_hmac_free(ctx);
if (__b64_ntop(salt, len, uu_salt, sizeof(uu_salt)) == -1 ||
__b64_ntop(result, len, uu_result, sizeof(uu_result)) == -1)
fatal_f("__b64_ntop failed");
snprintf(encoded, sizeof(encoded), "%s%s%c%s", HASH_MAGIC, uu_salt,
HASH_DELIM, uu_result);
return (encoded);
}
/*
* Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the
* pointer over the key. Skips any whitespace at the beginning and at end.
*/
int
hostfile_read_key(char **cpp, u_int *bitsp, struct sshkey *ret)
{
char *cp;
/* Skip leading whitespace. */
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
;
if (sshkey_read(ret, &cp) != 0)
return 0;
/* Skip trailing whitespace. */
for (; *cp == ' ' || *cp == '\t'; cp++)
;
/* Return results. */
*cpp = cp;
if (bitsp != NULL)
*bitsp = sshkey_size(ret);
return 1;
}
static HostkeyMarker
check_markers(char **cpp)
{
char marker[32], *sp, *cp = *cpp;
int ret = MRK_NONE;
while (*cp == '@') {
/* Only one marker is allowed */
if (ret != MRK_NONE)
return MRK_ERROR;
/* Markers are terminated by whitespace */
if ((sp = strchr(cp, ' ')) == NULL &&
(sp = strchr(cp, '\t')) == NULL)
return MRK_ERROR;
/* Extract marker for comparison */
if (sp <= cp + 1 || sp >= cp + sizeof(marker))
return MRK_ERROR;
memcpy(marker, cp, sp - cp);
marker[sp - cp] = '\0';
if (strcmp(marker, CA_MARKER) == 0)
ret = MRK_CA;
else if (strcmp(marker, REVOKE_MARKER) == 0)
ret = MRK_REVOKE;
else
return MRK_ERROR;
/* Skip past marker and any whitespace that follows it */
cp = sp;
for (; *cp == ' ' || *cp == '\t'; cp++)
;
}
*cpp = cp;
return ret;
}
struct hostkeys *
init_hostkeys(void)
{
struct hostkeys *ret = xcalloc(1, sizeof(*ret));
ret->entries = NULL;
return ret;
}
struct load_callback_ctx {
const char *host;
u_long num_loaded;
struct hostkeys *hostkeys;
};
static int
record_hostkey(struct hostkey_foreach_line *l, void *_ctx)
{
struct load_callback_ctx *ctx = (struct load_callback_ctx *)_ctx;
struct hostkeys *hostkeys = ctx->hostkeys;
struct hostkey_entry *tmp;
if (l->status == HKF_STATUS_INVALID) {
/* XXX make this verbose() in the future */
debug("%s:%ld: parse error in hostkeys file",
l->path, l->linenum);
return 0;
}
debug3_f("found %skey type %s in file %s:%lu",
l->marker == MRK_NONE ? "" :
(l->marker == MRK_CA ? "ca " : "revoked "),
sshkey_type(l->key), l->path, l->linenum);
if ((tmp = recallocarray(hostkeys->entries, hostkeys->num_entries,
hostkeys->num_entries + 1, sizeof(*hostkeys->entries))) == NULL)
return SSH_ERR_ALLOC_FAIL;
hostkeys->entries = tmp;
hostkeys->entries[hostkeys->num_entries].host = xstrdup(ctx->host);
hostkeys->entries[hostkeys->num_entries].file = xstrdup(l->path);
hostkeys->entries[hostkeys->num_entries].line = l->linenum;
hostkeys->entries[hostkeys->num_entries].key = l->key;
l->key = NULL; /* steal it */
hostkeys->entries[hostkeys->num_entries].marker = l->marker;
hostkeys->entries[hostkeys->num_entries].note = l->note;
hostkeys->num_entries++;
ctx->num_loaded++;
return 0;
}
void
load_hostkeys_file(struct hostkeys *hostkeys, const char *host,
const char *path, FILE *f, u_int note)
{
int r;
struct load_callback_ctx ctx;
ctx.host = host;
ctx.num_loaded = 0;
ctx.hostkeys = hostkeys;
if ((r = hostkeys_foreach_file(path, f, record_hostkey, &ctx, host,
NULL, HKF_WANT_MATCH|HKF_WANT_PARSE_KEY, note)) != 0) {
if (r != SSH_ERR_SYSTEM_ERROR && errno != ENOENT)
debug_fr(r, "hostkeys_foreach failed for %s", path);
}
if (ctx.num_loaded != 0)
debug3_f("loaded %lu keys from %s", ctx.num_loaded, host);
}
void
load_hostkeys(struct hostkeys *hostkeys, const char *host, const char *path,
u_int note)
{
FILE *f;
if ((f = fopen(path, "r")) == NULL) {
debug_f("fopen %s: %s", path, strerror(errno));
return;
}
load_hostkeys_file(hostkeys, host, path, f, note);
fclose(f);
}
void
free_hostkeys(struct hostkeys *hostkeys)
{
u_int i;
for (i = 0; i < hostkeys->num_entries; i++) {
free(hostkeys->entries[i].host);
free(hostkeys->entries[i].file);
sshkey_free(hostkeys->entries[i].key);
explicit_bzero(hostkeys->entries + i, sizeof(*hostkeys->entries));
}
free(hostkeys->entries);
freezero(hostkeys, sizeof(*hostkeys));
}
static int
check_key_not_revoked(struct hostkeys *hostkeys, struct sshkey *k)
{
int is_cert = sshkey_is_cert(k);
u_int i;
for (i = 0; i < hostkeys->num_entries; i++) {
if (hostkeys->entries[i].marker != MRK_REVOKE)
continue;
if (sshkey_equal_public(k, hostkeys->entries[i].key))
return -1;
if (is_cert && k != NULL &&
sshkey_equal_public(k->cert->signature_key,
hostkeys->entries[i].key))
return -1;
}
return 0;
}
/*
* Match keys against a specified key, or look one up by key type.
*
* If looking for a keytype (key == NULL) and one is found then return
* HOST_FOUND, otherwise HOST_NEW.
*
* If looking for a key (key != NULL):
* 1. If the key is a cert and a matching CA is found, return HOST_OK
* 2. If the key is not a cert and a matching key is found, return HOST_OK
* 3. If no key matches but a key with a different type is found, then
* return HOST_CHANGED
* 4. If no matching keys are found, then return HOST_NEW.
*
* Finally, check any found key is not revoked.
*/
static HostStatus
check_hostkeys_by_key_or_type(struct hostkeys *hostkeys,
struct sshkey *k, int keytype, int nid, const struct hostkey_entry **found)
{
u_int i;
HostStatus end_return = HOST_NEW;
int want_cert = sshkey_is_cert(k);
HostkeyMarker want_marker = want_cert ? MRK_CA : MRK_NONE;
if (found != NULL)
*found = NULL;
for (i = 0; i < hostkeys->num_entries; i++) {
if (hostkeys->entries[i].marker != want_marker)
continue;
if (k == NULL) {
if (hostkeys->entries[i].key->type != keytype)
continue;
if (nid != -1 &&
sshkey_type_plain(keytype) == KEY_ECDSA &&
hostkeys->entries[i].key->ecdsa_nid != nid)
continue;
end_return = HOST_FOUND;
if (found != NULL)
*found = hostkeys->entries + i;
k = hostkeys->entries[i].key;
break;
}
if (want_cert) {
if (sshkey_equal_public(k->cert->signature_key,
hostkeys->entries[i].key)) {
/* A matching CA exists */
end_return = HOST_OK;
if (found != NULL)
*found = hostkeys->entries + i;
break;
}
} else {
if (sshkey_equal(k, hostkeys->entries[i].key)) {
end_return = HOST_OK;
if (found != NULL)
*found = hostkeys->entries + i;
break;
}
- /* A non-maching key exists */
+ /* A non-matching key exists */
end_return = HOST_CHANGED;
if (found != NULL)
*found = hostkeys->entries + i;
}
}
if (check_key_not_revoked(hostkeys, k) != 0) {
end_return = HOST_REVOKED;
if (found != NULL)
*found = NULL;
}
return end_return;
}
HostStatus
check_key_in_hostkeys(struct hostkeys *hostkeys, struct sshkey *key,
const struct hostkey_entry **found)
{
if (key == NULL)
fatal("no key to look up");
return check_hostkeys_by_key_or_type(hostkeys, key, 0, -1, found);
}
int
lookup_key_in_hostkeys_by_type(struct hostkeys *hostkeys, int keytype, int nid,
const struct hostkey_entry **found)
{
return (check_hostkeys_by_key_or_type(hostkeys, NULL, keytype, nid,
found) == HOST_FOUND);
}
int
lookup_marker_in_hostkeys(struct hostkeys *hostkeys, int want_marker)
{
u_int i;
for (i = 0; i < hostkeys->num_entries; i++) {
if (hostkeys->entries[i].marker == (HostkeyMarker)want_marker)
return 1;
}
return 0;
}
static int
write_host_entry(FILE *f, const char *host, const char *ip,
const struct sshkey *key, int store_hash)
{
int r, success = 0;
char *hashed_host = NULL, *lhost;
lhost = xstrdup(host);
lowercase(lhost);
if (store_hash) {
if ((hashed_host = host_hash(lhost, NULL, 0)) == NULL) {
error_f("host_hash failed");
free(lhost);
return 0;
}
fprintf(f, "%s ", hashed_host);
} else if (ip != NULL)
fprintf(f, "%s,%s ", lhost, ip);
else {
fprintf(f, "%s ", lhost);
}
free(lhost);
if ((r = sshkey_write(key, f)) == 0)
success = 1;
else
error_fr(r, "sshkey_write");
fputc('\n', f);
/* If hashing is enabled, the IP address needs to go on its own line */
if (success && store_hash && ip != NULL)
success = write_host_entry(f, ip, NULL, key, 1);
return success;
}
/*
* Create user ~/.ssh directory if it doesn't exist and we want to write to it.
* If notify is set, a message will be emitted if the directory is created.
*/
void
hostfile_create_user_ssh_dir(const char *filename, int notify)
{
char *dotsshdir = NULL, *p;
size_t len;
struct stat st;
if ((p = strrchr(filename, '/')) == NULL)
return;
len = p - filename;
dotsshdir = tilde_expand_filename("~/" _PATH_SSH_USER_DIR, getuid());
if (strlen(dotsshdir) > len || strncmp(filename, dotsshdir, len) != 0)
goto out; /* not ~/.ssh prefixed */
if (stat(dotsshdir, &st) == 0)
goto out; /* dir already exists */
else if (errno != ENOENT)
error("Could not stat %s: %s", dotsshdir, strerror(errno));
else {
#ifdef WITH_SELINUX
ssh_selinux_setfscreatecon(dotsshdir);
#endif
if (mkdir(dotsshdir, 0700) == -1)
error("Could not create directory '%.200s' (%s).",
dotsshdir, strerror(errno));
else if (notify)
logit("Created directory '%s'.", dotsshdir);
#ifdef WITH_SELINUX
ssh_selinux_setfscreatecon(NULL);
#endif
}
out:
free(dotsshdir);
}
/*
* Appends an entry to the host file. Returns false if the entry could not
* be appended.
*/
int
add_host_to_hostfile(const char *filename, const char *host,
const struct sshkey *key, int store_hash)
{
FILE *f;
int success;
if (key == NULL)
return 1; /* XXX ? */
hostfile_create_user_ssh_dir(filename, 0);
f = fopen(filename, "a");
if (!f)
return 0;
success = write_host_entry(f, host, NULL, key, store_hash);
fclose(f);
return success;
}
struct host_delete_ctx {
FILE *out;
int quiet;
const char *host, *ip;
u_int *match_keys; /* mask of HKF_MATCH_* for this key */
struct sshkey * const *keys;
size_t nkeys;
int modified;
};
static int
host_delete(struct hostkey_foreach_line *l, void *_ctx)
{
struct host_delete_ctx *ctx = (struct host_delete_ctx *)_ctx;
int loglevel = ctx->quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_VERBOSE;
size_t i;
/* Don't remove CA and revocation lines */
if (l->status == HKF_STATUS_MATCHED && l->marker == MRK_NONE) {
/*
* If this line contains one of the keys that we will be
* adding later, then don't change it and mark the key for
* skipping.
*/
for (i = 0; i < ctx->nkeys; i++) {
if (!sshkey_equal(ctx->keys[i], l->key))
continue;
ctx->match_keys[i] |= l->match;
fprintf(ctx->out, "%s\n", l->line);
debug3_f("%s key already at %s:%ld",
sshkey_type(l->key), l->path, l->linenum);
return 0;
}
/*
* Hostname matches and has no CA/revoke marker, delete it
* by *not* writing the line to ctx->out.
*/
do_log2(loglevel, "%s%s%s:%ld: Removed %s key for host %s",
ctx->quiet ? __func__ : "", ctx->quiet ? ": " : "",
l->path, l->linenum, sshkey_type(l->key), ctx->host);
ctx->modified = 1;
return 0;
}
/* Retain non-matching hosts and invalid lines when deleting */
if (l->status == HKF_STATUS_INVALID) {
do_log2(loglevel, "%s%s%s:%ld: invalid known_hosts entry",
ctx->quiet ? __func__ : "", ctx->quiet ? ": " : "",
l->path, l->linenum);
}
fprintf(ctx->out, "%s\n", l->line);
return 0;
}
int
hostfile_replace_entries(const char *filename, const char *host, const char *ip,
struct sshkey **keys, size_t nkeys, int store_hash, int quiet, int hash_alg)
{
int r, fd, oerrno = 0;
int loglevel = quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_VERBOSE;
struct host_delete_ctx ctx;
char *fp, *temp = NULL, *back = NULL;
const char *what;
mode_t omask;
size_t i;
u_int want;
omask = umask(077);
memset(&ctx, 0, sizeof(ctx));
ctx.host = host;
ctx.ip = ip;
ctx.quiet = quiet;
if ((ctx.match_keys = calloc(nkeys, sizeof(*ctx.match_keys))) == NULL)
return SSH_ERR_ALLOC_FAIL;
ctx.keys = keys;
ctx.nkeys = nkeys;
ctx.modified = 0;
/*
* Prepare temporary file for in-place deletion.
*/
if ((r = asprintf(&temp, "%s.XXXXXXXXXXX", filename)) == -1 ||
(r = asprintf(&back, "%s.old", filename)) == -1) {
r = SSH_ERR_ALLOC_FAIL;
goto fail;
}
if ((fd = mkstemp(temp)) == -1) {
oerrno = errno;
error_f("mkstemp: %s", strerror(oerrno));
r = SSH_ERR_SYSTEM_ERROR;
goto fail;
}
if ((ctx.out = fdopen(fd, "w")) == NULL) {
oerrno = errno;
close(fd);
error_f("fdopen: %s", strerror(oerrno));
r = SSH_ERR_SYSTEM_ERROR;
goto fail;
}
/* Remove stale/mismatching entries for the specified host */
if ((r = hostkeys_foreach(filename, host_delete, &ctx, host, ip,
HKF_WANT_PARSE_KEY, 0)) != 0) {
oerrno = errno;
error_fr(r, "hostkeys_foreach");
goto fail;
}
/* Re-add the requested keys */
want = HKF_MATCH_HOST | (ip == NULL ? 0 : HKF_MATCH_IP);
for (i = 0; i < nkeys; i++) {
if ((want & ctx.match_keys[i]) == want)
continue;
if ((fp = sshkey_fingerprint(keys[i], hash_alg,
SSH_FP_DEFAULT)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto fail;
}
/* write host/ip */
what = "";
if (ctx.match_keys[i] == 0) {
what = "Adding new key";
if (!write_host_entry(ctx.out, host, ip,
keys[i], store_hash)) {
r = SSH_ERR_INTERNAL_ERROR;
goto fail;
}
} else if ((want & ~ctx.match_keys[i]) == HKF_MATCH_HOST) {
what = "Fixing match (hostname)";
if (!write_host_entry(ctx.out, host, NULL,
keys[i], store_hash)) {
r = SSH_ERR_INTERNAL_ERROR;
goto fail;
}
} else if ((want & ~ctx.match_keys[i]) == HKF_MATCH_IP) {
what = "Fixing match (address)";
if (!write_host_entry(ctx.out, ip, NULL,
keys[i], store_hash)) {
r = SSH_ERR_INTERNAL_ERROR;
goto fail;
}
}
do_log2(loglevel, "%s%s%s for %s%s%s to %s: %s %s",
quiet ? __func__ : "", quiet ? ": " : "", what,
host, ip == NULL ? "" : ",", ip == NULL ? "" : ip, filename,
sshkey_ssh_name(keys[i]), fp);
free(fp);
ctx.modified = 1;
}
fclose(ctx.out);
ctx.out = NULL;
if (ctx.modified) {
/* Backup the original file and replace it with the temporary */
if (unlink(back) == -1 && errno != ENOENT) {
oerrno = errno;
error_f("unlink %.100s: %s", back, strerror(errno));
r = SSH_ERR_SYSTEM_ERROR;
goto fail;
}
if (link(filename, back) == -1) {
oerrno = errno;
error_f("link %.100s to %.100s: %s", filename,
back, strerror(errno));
r = SSH_ERR_SYSTEM_ERROR;
goto fail;
}
if (rename(temp, filename) == -1) {
oerrno = errno;
error_f("rename \"%s\" to \"%s\": %s", temp,
filename, strerror(errno));
r = SSH_ERR_SYSTEM_ERROR;
goto fail;
}
} else {
/* No changes made; just delete the temporary file */
if (unlink(temp) != 0)
error_f("unlink \"%s\": %s", temp, strerror(errno));
}
/* success */
r = 0;
fail:
if (temp != NULL && r != 0)
unlink(temp);
free(temp);
free(back);
if (ctx.out != NULL)
fclose(ctx.out);
free(ctx.match_keys);
umask(omask);
if (r == SSH_ERR_SYSTEM_ERROR)
errno = oerrno;
return r;
}
static int
match_maybe_hashed(const char *host, const char *names, int *was_hashed)
{
int hashed = *names == HASH_DELIM;
const char *hashed_host;
size_t nlen = strlen(names);
if (was_hashed != NULL)
*was_hashed = hashed;
if (hashed) {
if ((hashed_host = host_hash(host, names, nlen)) == NULL)
return -1;
return nlen == strlen(hashed_host) &&
strncmp(hashed_host, names, nlen) == 0;
}
return match_hostname(host, names) == 1;
}
int
hostkeys_foreach_file(const char *path, FILE *f, hostkeys_foreach_fn *callback,
void *ctx, const char *host, const char *ip, u_int options, u_int note)
{
char *line = NULL, ktype[128];
u_long linenum = 0;
char *cp, *cp2;
u_int kbits;
int hashed;
int s, r = 0;
struct hostkey_foreach_line lineinfo;
size_t linesize = 0, l;
memset(&lineinfo, 0, sizeof(lineinfo));
if (host == NULL && (options & HKF_WANT_MATCH) != 0)
return SSH_ERR_INVALID_ARGUMENT;
while (getline(&line, &linesize, f) != -1) {
linenum++;
line[strcspn(line, "\n")] = '\0';
free(lineinfo.line);
sshkey_free(lineinfo.key);
memset(&lineinfo, 0, sizeof(lineinfo));
lineinfo.path = path;
lineinfo.linenum = linenum;
lineinfo.line = xstrdup(line);
lineinfo.marker = MRK_NONE;
lineinfo.status = HKF_STATUS_OK;
lineinfo.keytype = KEY_UNSPEC;
lineinfo.note = note;
/* Skip any leading whitespace, comments and empty lines. */
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
;
if (!*cp || *cp == '#' || *cp == '\n') {
if ((options & HKF_WANT_MATCH) == 0) {
lineinfo.status = HKF_STATUS_COMMENT;
if ((r = callback(&lineinfo, ctx)) != 0)
break;
}
continue;
}
if ((lineinfo.marker = check_markers(&cp)) == MRK_ERROR) {
verbose_f("invalid marker at %s:%lu", path, linenum);
if ((options & HKF_WANT_MATCH) == 0)
goto bad;
continue;
}
/* Find the end of the host name portion. */
for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
;
lineinfo.hosts = cp;
*cp2++ = '\0';
/* Check if the host name matches. */
if (host != NULL) {
if ((s = match_maybe_hashed(host, lineinfo.hosts,
&hashed)) == -1) {
debug2_f("%s:%ld: bad host hash \"%.32s\"",
path, linenum, lineinfo.hosts);
goto bad;
}
if (s == 1) {
lineinfo.status = HKF_STATUS_MATCHED;
lineinfo.match |= HKF_MATCH_HOST |
(hashed ? HKF_MATCH_HOST_HASHED : 0);
}
/* Try matching IP address if supplied */
if (ip != NULL) {
if ((s = match_maybe_hashed(ip, lineinfo.hosts,
&hashed)) == -1) {
debug2_f("%s:%ld: bad ip hash "
"\"%.32s\"", path, linenum,
lineinfo.hosts);
goto bad;
}
if (s == 1) {
lineinfo.status = HKF_STATUS_MATCHED;
lineinfo.match |= HKF_MATCH_IP |
(hashed ? HKF_MATCH_IP_HASHED : 0);
}
}
/*
* Skip this line if host matching requested and
* neither host nor address matched.
*/
if ((options & HKF_WANT_MATCH) != 0 &&
lineinfo.status != HKF_STATUS_MATCHED)
continue;
}
/* Got a match. Skip host name and any following whitespace */
for (; *cp2 == ' ' || *cp2 == '\t'; cp2++)
;
if (*cp2 == '\0' || *cp2 == '#') {
debug2("%s:%ld: truncated before key type",
path, linenum);
goto bad;
}
lineinfo.rawkey = cp = cp2;
if ((options & HKF_WANT_PARSE_KEY) != 0) {
/*
* Extract the key from the line. This will skip
* any leading whitespace. Ignore badly formatted
* lines.
*/
if ((lineinfo.key = sshkey_new(KEY_UNSPEC)) == NULL) {
error_f("sshkey_new failed");
r = SSH_ERR_ALLOC_FAIL;
break;
}
if (!hostfile_read_key(&cp, &kbits, lineinfo.key)) {
goto bad;
}
lineinfo.keytype = lineinfo.key->type;
lineinfo.comment = cp;
} else {
/* Extract and parse key type */
l = strcspn(lineinfo.rawkey, " \t");
if (l <= 1 || l >= sizeof(ktype) ||
lineinfo.rawkey[l] == '\0')
goto bad;
memcpy(ktype, lineinfo.rawkey, l);
ktype[l] = '\0';
lineinfo.keytype = sshkey_type_from_name(ktype);
/*
* Assume legacy RSA1 if the first component is a short
* decimal number.
*/
if (lineinfo.keytype == KEY_UNSPEC && l < 8 &&
strspn(ktype, "0123456789") == l)
goto bad;
/*
* Check that something other than whitespace follows
* the key type. This won't catch all corruption, but
* it does catch trivial truncation.
*/
cp2 += l; /* Skip past key type */
for (; *cp2 == ' ' || *cp2 == '\t'; cp2++)
;
if (*cp2 == '\0' || *cp2 == '#') {
debug2("%s:%ld: truncated after key type",
path, linenum);
lineinfo.keytype = KEY_UNSPEC;
}
if (lineinfo.keytype == KEY_UNSPEC) {
bad:
sshkey_free(lineinfo.key);
lineinfo.key = NULL;
lineinfo.status = HKF_STATUS_INVALID;
if ((r = callback(&lineinfo, ctx)) != 0)
break;
continue;
}
}
if ((r = callback(&lineinfo, ctx)) != 0)
break;
}
sshkey_free(lineinfo.key);
free(lineinfo.line);
free(line);
return r;
}
int
hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
const char *host, const char *ip, u_int options, u_int note)
{
FILE *f;
int r, oerrno;
if ((f = fopen(path, "r")) == NULL)
return SSH_ERR_SYSTEM_ERROR;
debug3_f("reading file \"%s\"", path);
r = hostkeys_foreach_file(path, f, callback, ctx, host, ip,
options, note);
oerrno = errno;
fclose(f);
errno = oerrno;
return r;
}
diff --git a/kex.c b/kex.c
index 30425ab8ab9b..709a0ec63aa0 100644
--- a/kex.c
+++ b/kex.c
@@ -1,1379 +1,1379 @@
-/* $OpenBSD: kex.c,v 1.167 2021/01/31 22:55:29 djm Exp $ */
+/* $OpenBSD: kex.c,v 1.168 2021/04/03 06:18:40 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#ifdef WITH_OPENSSL
#include <openssl/crypto.h>
#include <openssl/dh.h>
#endif
#include "ssh.h"
#include "ssh2.h"
#include "atomicio.h"
#include "version.h"
#include "packet.h"
#include "compat.h"
#include "cipher.h"
#include "sshkey.h"
#include "kex.h"
#include "log.h"
#include "mac.h"
#include "match.h"
#include "misc.h"
#include "dispatch.h"
#include "monitor.h"
#include "ssherr.h"
#include "sshbuf.h"
#include "digest.h"
/* prototype */
static int kex_choose_conf(struct ssh *);
static int kex_input_newkeys(int, u_int32_t, struct ssh *);
static const char *proposal_names[PROPOSAL_MAX] = {
"KEX algorithms",
"host key algorithms",
"ciphers ctos",
"ciphers stoc",
"MACs ctos",
"MACs stoc",
"compression ctos",
"compression stoc",
"languages ctos",
"languages stoc",
};
struct kexalg {
char *name;
u_int type;
int ec_nid;
int hash_alg;
};
static const struct kexalg kexalgs[] = {
#ifdef WITH_OPENSSL
{ KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
{ KEX_DH14_SHA1, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
{ KEX_DH14_SHA256, KEX_DH_GRP14_SHA256, 0, SSH_DIGEST_SHA256 },
{ KEX_DH16_SHA512, KEX_DH_GRP16_SHA512, 0, SSH_DIGEST_SHA512 },
{ KEX_DH18_SHA512, KEX_DH_GRP18_SHA512, 0, SSH_DIGEST_SHA512 },
{ KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
#ifdef HAVE_EVP_SHA256
{ KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
#endif /* HAVE_EVP_SHA256 */
#ifdef OPENSSL_HAS_ECC
{ KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2,
NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
{ KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1,
SSH_DIGEST_SHA384 },
# ifdef OPENSSL_HAS_NISTP521
{ KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
SSH_DIGEST_SHA512 },
# endif /* OPENSSL_HAS_NISTP521 */
#endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
#if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL)
{ KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
{ KEX_CURVE25519_SHA256_OLD, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
#ifdef USE_SNTRUP761X25519
{ KEX_SNTRUP761X25519_SHA512, KEX_KEM_SNTRUP761X25519_SHA512, 0,
SSH_DIGEST_SHA512 },
#endif
#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
{ NULL, 0, -1, -1},
};
char *
kex_alg_list(char sep)
{
char *ret = NULL, *tmp;
size_t nlen, rlen = 0;
const struct kexalg *k;
for (k = kexalgs; k->name != NULL; k++) {
if (ret != NULL)
ret[rlen++] = sep;
nlen = strlen(k->name);
if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
free(ret);
return NULL;
}
ret = tmp;
memcpy(ret + rlen, k->name, nlen + 1);
rlen += nlen;
}
return ret;
}
static const struct kexalg *
kex_alg_by_name(const char *name)
{
const struct kexalg *k;
for (k = kexalgs; k->name != NULL; k++) {
if (strcmp(k->name, name) == 0)
return k;
}
return NULL;
}
/* Validate KEX method name list */
int
kex_names_valid(const char *names)
{
char *s, *cp, *p;
if (names == NULL || strcmp(names, "") == 0)
return 0;
if ((s = cp = strdup(names)) == NULL)
return 0;
for ((p = strsep(&cp, ",")); p && *p != '\0';
(p = strsep(&cp, ","))) {
if (kex_alg_by_name(p) == NULL) {
error("Unsupported KEX algorithm \"%.100s\"", p);
free(s);
return 0;
}
}
debug3("kex names ok: [%s]", names);
free(s);
return 1;
}
/*
* Concatenate algorithm names, avoiding duplicates in the process.
* Caller must free returned string.
*/
char *
kex_names_cat(const char *a, const char *b)
{
char *ret = NULL, *tmp = NULL, *cp, *p, *m;
size_t len;
if (a == NULL || *a == '\0')
return strdup(b);
if (b == NULL || *b == '\0')
return strdup(a);
if (strlen(b) > 1024*1024)
return NULL;
len = strlen(a) + strlen(b) + 2;
if ((tmp = cp = strdup(b)) == NULL ||
(ret = calloc(1, len)) == NULL) {
free(tmp);
return NULL;
}
strlcpy(ret, a, len);
for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) {
if ((m = match_list(ret, p, NULL)) != NULL) {
free(m);
continue; /* Algorithm already present */
}
if (strlcat(ret, ",", len) >= len ||
strlcat(ret, p, len) >= len) {
free(tmp);
free(ret);
return NULL; /* Shouldn't happen */
}
}
free(tmp);
return ret;
}
/*
* Assemble a list of algorithms from a default list and a string from a
* configuration file. The user-provided string may begin with '+' to
* indicate that it should be appended to the default, '-' that the
* specified names should be removed, or '^' that they should be placed
* at the head.
*/
int
kex_assemble_names(char **listp, const char *def, const char *all)
{
char *cp, *tmp, *patterns;
char *list = NULL, *ret = NULL, *matching = NULL, *opatterns = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
if (listp == NULL || def == NULL || all == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if (*listp == NULL || **listp == '\0') {
if ((*listp = strdup(def)) == NULL)
return SSH_ERR_ALLOC_FAIL;
return 0;
}
list = *listp;
*listp = NULL;
if (*list == '+') {
/* Append names to default list */
if ((tmp = kex_names_cat(def, list + 1)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto fail;
}
free(list);
list = tmp;
} else if (*list == '-') {
/* Remove names from default list */
if ((*listp = match_filter_denylist(def, list + 1)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto fail;
}
free(list);
/* filtering has already been done */
return 0;
} else if (*list == '^') {
/* Place names at head of default list */
if ((tmp = kex_names_cat(list + 1, def)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto fail;
}
free(list);
list = tmp;
} else {
/* Explicit list, overrides default - just use "list" as is */
}
/*
* The supplied names may be a pattern-list. For the -list case,
* the patterns are applied above. For the +list and explicit list
* cases we need to do it now.
*/
ret = NULL;
if ((patterns = opatterns = strdup(list)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto fail;
}
/* Apply positive (i.e. non-negated) patterns from the list */
while ((cp = strsep(&patterns, ",")) != NULL) {
if (*cp == '!') {
/* negated matches are not supported here */
r = SSH_ERR_INVALID_ARGUMENT;
goto fail;
}
free(matching);
if ((matching = match_filter_allowlist(all, cp)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto fail;
}
if ((tmp = kex_names_cat(ret, matching)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto fail;
}
free(ret);
ret = tmp;
}
if (ret == NULL || *ret == '\0') {
/* An empty name-list is an error */
/* XXX better error code? */
r = SSH_ERR_INVALID_ARGUMENT;
goto fail;
}
/* success */
*listp = ret;
ret = NULL;
r = 0;
fail:
free(matching);
free(opatterns);
free(list);
free(ret);
return r;
}
/* put algorithm proposal into buffer */
int
kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX])
{
u_int i;
int r;
sshbuf_reset(b);
/*
* add a dummy cookie, the cookie will be overwritten by
* kex_send_kexinit(), each time a kexinit is set
*/
for (i = 0; i < KEX_COOKIE_LEN; i++) {
if ((r = sshbuf_put_u8(b, 0)) != 0)
return r;
}
for (i = 0; i < PROPOSAL_MAX; i++) {
if ((r = sshbuf_put_cstring(b, proposal[i])) != 0)
return r;
}
if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */
(r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */
return r;
return 0;
}
/* parse buffer and return algorithm proposal */
int
kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp)
{
struct sshbuf *b = NULL;
u_char v;
u_int i;
char **proposal = NULL;
int r;
*propp = NULL;
if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((b = sshbuf_fromb(raw)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) { /* skip cookie */
error_fr(r, "consume cookie");
goto out;
}
/* extract kex init proposal strings */
for (i = 0; i < PROPOSAL_MAX; i++) {
if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) {
error_fr(r, "parse proposal %u", i);
goto out;
}
debug2("%s: %s", proposal_names[i], proposal[i]);
}
/* first kex follows / reserved */
if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */
(r = sshbuf_get_u32(b, &i)) != 0) { /* reserved */
error_fr(r, "parse");
goto out;
}
if (first_kex_follows != NULL)
*first_kex_follows = v;
debug2("first_kex_follows %d ", v);
debug2("reserved %u ", i);
r = 0;
*propp = proposal;
out:
if (r != 0 && proposal != NULL)
kex_prop_free(proposal);
sshbuf_free(b);
return r;
}
void
kex_prop_free(char **proposal)
{
u_int i;
if (proposal == NULL)
return;
for (i = 0; i < PROPOSAL_MAX; i++)
free(proposal[i]);
free(proposal);
}
/* ARGSUSED */
int
kex_protocol_error(int type, u_int32_t seq, struct ssh *ssh)
{
int r;
error("kex protocol error: type %d seq %u", type, seq);
if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
(r = sshpkt_put_u32(ssh, seq)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
return r;
return 0;
}
static void
kex_reset_dispatch(struct ssh *ssh)
{
ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN,
SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
}
static int
kex_send_ext_info(struct ssh *ssh)
{
int r;
char *algs;
debug("Sending SSH2_MSG_EXT_INFO");
if ((algs = sshkey_alg_list(0, 1, 1, ',')) == NULL)
return SSH_ERR_ALLOC_FAIL;
/* XXX filter algs list by allowed pubkey/hostbased types */
if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 ||
(r = sshpkt_put_u32(ssh, 1)) != 0 ||
(r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 ||
(r = sshpkt_put_cstring(ssh, algs)) != 0 ||
(r = sshpkt_send(ssh)) != 0) {
error_fr(r, "compose");
goto out;
}
/* success */
r = 0;
out:
free(algs);
return r;
}
int
kex_send_newkeys(struct ssh *ssh)
{
int r;
kex_reset_dispatch(ssh);
if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
return r;
debug("SSH2_MSG_NEWKEYS sent");
ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys);
if (ssh->kex->ext_info_c && (ssh->kex->flags & KEX_INITIAL) != 0)
if ((r = kex_send_ext_info(ssh)) != 0)
return r;
debug("expecting SSH2_MSG_NEWKEYS");
return 0;
}
int
kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
{
struct kex *kex = ssh->kex;
u_int32_t i, ninfo;
char *name;
u_char *val;
size_t vlen;
int r;
debug("SSH2_MSG_EXT_INFO received");
ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error);
if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0)
return r;
for (i = 0; i < ninfo; i++) {
if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0)
return r;
if ((r = sshpkt_get_string(ssh, &val, &vlen)) != 0) {
free(name);
return r;
}
if (strcmp(name, "server-sig-algs") == 0) {
/* Ensure no \0 lurking in value */
if (memchr(val, '\0', vlen) != NULL) {
error_f("nul byte in %s", name);
return SSH_ERR_INVALID_FORMAT;
}
debug_f("%s=<%s>", name, val);
kex->server_sig_algs = val;
val = NULL;
} else
debug_f("%s (unrecognised)", name);
free(name);
free(val);
}
return sshpkt_get_end(ssh);
}
static int
kex_input_newkeys(int type, u_int32_t seq, struct ssh *ssh)
{
struct kex *kex = ssh->kex;
int r;
debug("SSH2_MSG_NEWKEYS received");
ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error);
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
if ((r = sshpkt_get_end(ssh)) != 0)
return r;
if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0)
return r;
kex->done = 1;
kex->flags &= ~KEX_INITIAL;
sshbuf_reset(kex->peer);
/* sshbuf_reset(kex->my); */
kex->flags &= ~KEX_INIT_SENT;
free(kex->name);
kex->name = NULL;
return 0;
}
int
kex_send_kexinit(struct ssh *ssh)
{
u_char *cookie;
struct kex *kex = ssh->kex;
int r;
if (kex == NULL) {
error_f("no kex");
return SSH_ERR_INTERNAL_ERROR;
}
if (kex->flags & KEX_INIT_SENT)
return 0;
kex->done = 0;
/* generate a random cookie */
if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) {
error_f("bad kex length: %zu < %d",
sshbuf_len(kex->my), KEX_COOKIE_LEN);
return SSH_ERR_INVALID_FORMAT;
}
if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) {
error_f("buffer error");
return SSH_ERR_INTERNAL_ERROR;
}
arc4random_buf(cookie, KEX_COOKIE_LEN);
if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 ||
(r = sshpkt_putb(ssh, kex->my)) != 0 ||
(r = sshpkt_send(ssh)) != 0) {
error_fr(r, "compose reply");
return r;
}
debug("SSH2_MSG_KEXINIT sent");
kex->flags |= KEX_INIT_SENT;
return 0;
}
/* ARGSUSED */
int
kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
{
struct kex *kex = ssh->kex;
const u_char *ptr;
u_int i;
size_t dlen;
int r;
debug("SSH2_MSG_KEXINIT received");
if (kex == NULL) {
error_f("no kex");
return SSH_ERR_INTERNAL_ERROR;
}
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL);
ptr = sshpkt_ptr(ssh, &dlen);
if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
return r;
/* discard packet */
for (i = 0; i < KEX_COOKIE_LEN; i++) {
if ((r = sshpkt_get_u8(ssh, NULL)) != 0) {
error_fr(r, "discard cookie");
return r;
}
}
for (i = 0; i < PROPOSAL_MAX; i++) {
if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) {
error_fr(r, "discard proposal");
return r;
}
}
/*
* XXX RFC4253 sec 7: "each side MAY guess" - currently no supported
* KEX method has the server move first, but a server might be using
* a custom method or one that we otherwise don't support. We should
* be prepared to remember first_kex_follows here so we can eat a
* packet later.
* XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means
* for cases where the server *doesn't* go first. I guess we should
* ignore it when it is set for these cases, which is what we do now.
*/
if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */
(r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */
(r = sshpkt_get_end(ssh)) != 0)
return r;
if (!(kex->flags & KEX_INIT_SENT))
if ((r = kex_send_kexinit(ssh)) != 0)
return r;
if ((r = kex_choose_conf(ssh)) != 0)
return r;
if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL)
return (kex->kex[kex->kex_type])(ssh);
error_f("unknown kex type %u", kex->kex_type);
return SSH_ERR_INTERNAL_ERROR;
}
struct kex *
kex_new(void)
{
struct kex *kex;
if ((kex = calloc(1, sizeof(*kex))) == NULL ||
(kex->peer = sshbuf_new()) == NULL ||
(kex->my = sshbuf_new()) == NULL ||
(kex->client_version = sshbuf_new()) == NULL ||
(kex->server_version = sshbuf_new()) == NULL ||
(kex->session_id = sshbuf_new()) == NULL) {
kex_free(kex);
return NULL;
}
return kex;
}
void
kex_free_newkeys(struct newkeys *newkeys)
{
if (newkeys == NULL)
return;
if (newkeys->enc.key) {
explicit_bzero(newkeys->enc.key, newkeys->enc.key_len);
free(newkeys->enc.key);
newkeys->enc.key = NULL;
}
if (newkeys->enc.iv) {
explicit_bzero(newkeys->enc.iv, newkeys->enc.iv_len);
free(newkeys->enc.iv);
newkeys->enc.iv = NULL;
}
free(newkeys->enc.name);
explicit_bzero(&newkeys->enc, sizeof(newkeys->enc));
free(newkeys->comp.name);
explicit_bzero(&newkeys->comp, sizeof(newkeys->comp));
mac_clear(&newkeys->mac);
if (newkeys->mac.key) {
explicit_bzero(newkeys->mac.key, newkeys->mac.key_len);
free(newkeys->mac.key);
newkeys->mac.key = NULL;
}
free(newkeys->mac.name);
explicit_bzero(&newkeys->mac, sizeof(newkeys->mac));
freezero(newkeys, sizeof(*newkeys));
}
void
kex_free(struct kex *kex)
{
u_int mode;
if (kex == NULL)
return;
#ifdef WITH_OPENSSL
DH_free(kex->dh);
#ifdef OPENSSL_HAS_ECC
EC_KEY_free(kex->ec_client_key);
#endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
for (mode = 0; mode < MODE_MAX; mode++) {
kex_free_newkeys(kex->newkeys[mode]);
kex->newkeys[mode] = NULL;
}
sshbuf_free(kex->peer);
sshbuf_free(kex->my);
sshbuf_free(kex->client_version);
sshbuf_free(kex->server_version);
sshbuf_free(kex->client_pub);
sshbuf_free(kex->session_id);
free(kex->failed_choice);
free(kex->hostkey_alg);
free(kex->name);
free(kex);
}
int
kex_ready(struct ssh *ssh, char *proposal[PROPOSAL_MAX])
{
int r;
if ((r = kex_prop2buf(ssh->kex->my, proposal)) != 0)
return r;
ssh->kex->flags = KEX_INITIAL;
kex_reset_dispatch(ssh);
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
return 0;
}
int
kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX])
{
int r;
if ((r = kex_ready(ssh, proposal)) != 0)
return r;
if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */
kex_free(ssh->kex);
ssh->kex = NULL;
return r;
}
return 0;
}
/*
* Request key re-exchange, returns 0 on success or a ssherr.h error
* code otherwise. Must not be called if KEX is incomplete or in-progress.
*/
int
kex_start_rekex(struct ssh *ssh)
{
if (ssh->kex == NULL) {
error_f("no kex");
return SSH_ERR_INTERNAL_ERROR;
}
if (ssh->kex->done == 0) {
error_f("requested twice");
return SSH_ERR_INTERNAL_ERROR;
}
ssh->kex->done = 0;
return kex_send_kexinit(ssh);
}
static int
choose_enc(struct sshenc *enc, char *client, char *server)
{
char *name = match_list(client, server, NULL);
if (name == NULL)
return SSH_ERR_NO_CIPHER_ALG_MATCH;
if ((enc->cipher = cipher_by_name(name)) == NULL) {
error_f("unsupported cipher %s", name);
free(name);
return SSH_ERR_INTERNAL_ERROR;
}
enc->name = name;
enc->enabled = 0;
enc->iv = NULL;
enc->iv_len = cipher_ivlen(enc->cipher);
enc->key = NULL;
enc->key_len = cipher_keylen(enc->cipher);
enc->block_size = cipher_blocksize(enc->cipher);
return 0;
}
static int
choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server)
{
char *name = match_list(client, server, NULL);
if (name == NULL)
return SSH_ERR_NO_MAC_ALG_MATCH;
if (mac_setup(mac, name) < 0) {
error_f("unsupported MAC %s", name);
free(name);
return SSH_ERR_INTERNAL_ERROR;
}
mac->name = name;
mac->key = NULL;
mac->enabled = 0;
return 0;
}
static int
choose_comp(struct sshcomp *comp, char *client, char *server)
{
char *name = match_list(client, server, NULL);
if (name == NULL)
return SSH_ERR_NO_COMPRESS_ALG_MATCH;
#ifdef WITH_ZLIB
if (strcmp(name, "zlib@openssh.com") == 0) {
comp->type = COMP_DELAYED;
} else if (strcmp(name, "zlib") == 0) {
comp->type = COMP_ZLIB;
} else
#endif /* WITH_ZLIB */
if (strcmp(name, "none") == 0) {
comp->type = COMP_NONE;
} else {
error_f("unsupported compression scheme %s", name);
free(name);
return SSH_ERR_INTERNAL_ERROR;
}
comp->name = name;
return 0;
}
static int
choose_kex(struct kex *k, char *client, char *server)
{
const struct kexalg *kexalg;
k->name = match_list(client, server, NULL);
debug("kex: algorithm: %s", k->name ? k->name : "(no match)");
if (k->name == NULL)
return SSH_ERR_NO_KEX_ALG_MATCH;
if ((kexalg = kex_alg_by_name(k->name)) == NULL) {
error_f("unsupported KEX method %s", k->name);
return SSH_ERR_INTERNAL_ERROR;
}
k->kex_type = kexalg->type;
k->hash_alg = kexalg->hash_alg;
k->ec_nid = kexalg->ec_nid;
return 0;
}
static int
choose_hostkeyalg(struct kex *k, char *client, char *server)
{
free(k->hostkey_alg);
k->hostkey_alg = match_list(client, server, NULL);
debug("kex: host key algorithm: %s",
k->hostkey_alg ? k->hostkey_alg : "(no match)");
if (k->hostkey_alg == NULL)
return SSH_ERR_NO_HOSTKEY_ALG_MATCH;
k->hostkey_type = sshkey_type_from_name(k->hostkey_alg);
if (k->hostkey_type == KEY_UNSPEC) {
error_f("unsupported hostkey algorithm %s", k->hostkey_alg);
return SSH_ERR_INTERNAL_ERROR;
}
k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg);
return 0;
}
static int
proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
{
static int check[] = {
PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1
};
int *idx;
char *p;
for (idx = &check[0]; *idx != -1; idx++) {
if ((p = strchr(my[*idx], ',')) != NULL)
*p = '\0';
if ((p = strchr(peer[*idx], ',')) != NULL)
*p = '\0';
if (strcmp(my[*idx], peer[*idx]) != 0) {
debug2("proposal mismatch: my %s peer %s",
my[*idx], peer[*idx]);
return (0);
}
}
debug2("proposals match");
return (1);
}
static int
kex_choose_conf(struct ssh *ssh)
{
struct kex *kex = ssh->kex;
struct newkeys *newkeys;
char **my = NULL, **peer = NULL;
char **cprop, **sprop;
int nenc, nmac, ncomp;
u_int mode, ctos, need, dh_need, authlen;
int r, first_kex_follows;
debug2("local %s KEXINIT proposal", kex->server ? "server" : "client");
if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0)
goto out;
debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server");
if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0)
goto out;
if (kex->server) {
cprop=peer;
sprop=my;
} else {
cprop=my;
sprop=peer;
}
/* Check whether client supports ext_info_c */
if (kex->server && (kex->flags & KEX_INITIAL)) {
char *ext;
ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL);
kex->ext_info_c = (ext != NULL);
free(ext);
}
/* Algorithm Negotiation */
if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
sprop[PROPOSAL_KEX_ALGS])) != 0) {
kex->failed_choice = peer[PROPOSAL_KEX_ALGS];
peer[PROPOSAL_KEX_ALGS] = NULL;
goto out;
}
if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) {
kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS];
peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL;
goto out;
}
for (mode = 0; mode < MODE_MAX; mode++) {
if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
kex->newkeys[mode] = newkeys;
ctos = (!kex->server && mode == MODE_OUT) ||
(kex->server && mode == MODE_IN);
nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
if ((r = choose_enc(&newkeys->enc, cprop[nenc],
sprop[nenc])) != 0) {
kex->failed_choice = peer[nenc];
peer[nenc] = NULL;
goto out;
}
authlen = cipher_authlen(newkeys->enc.cipher);
/* ignore mac for authenticated encryption */
if (authlen == 0 &&
(r = choose_mac(ssh, &newkeys->mac, cprop[nmac],
sprop[nmac])) != 0) {
kex->failed_choice = peer[nmac];
peer[nmac] = NULL;
goto out;
}
if ((r = choose_comp(&newkeys->comp, cprop[ncomp],
sprop[ncomp])) != 0) {
kex->failed_choice = peer[ncomp];
peer[ncomp] = NULL;
goto out;
}
debug("kex: %s cipher: %s MAC: %s compression: %s",
ctos ? "client->server" : "server->client",
newkeys->enc.name,
authlen == 0 ? newkeys->mac.name : "<implicit>",
newkeys->comp.name);
}
need = dh_need = 0;
for (mode = 0; mode < MODE_MAX; mode++) {
newkeys = kex->newkeys[mode];
need = MAXIMUM(need, newkeys->enc.key_len);
need = MAXIMUM(need, newkeys->enc.block_size);
need = MAXIMUM(need, newkeys->enc.iv_len);
need = MAXIMUM(need, newkeys->mac.key_len);
dh_need = MAXIMUM(dh_need, cipher_seclen(newkeys->enc.cipher));
dh_need = MAXIMUM(dh_need, newkeys->enc.block_size);
dh_need = MAXIMUM(dh_need, newkeys->enc.iv_len);
dh_need = MAXIMUM(dh_need, newkeys->mac.key_len);
}
/* XXX need runden? */
kex->we_need = need;
kex->dh_need = dh_need;
/* ignore the next message if the proposals do not match */
if (first_kex_follows && !proposals_match(my, peer))
ssh->dispatch_skip_packets = 1;
r = 0;
out:
kex_prop_free(my);
kex_prop_free(peer);
return r;
}
static int
derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
const struct sshbuf *shared_secret, u_char **keyp)
{
struct kex *kex = ssh->kex;
struct ssh_digest_ctx *hashctx = NULL;
char c = id;
u_int have;
size_t mdsz;
u_char *digest;
int r;
if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0)
return SSH_ERR_INVALID_ARGUMENT;
if ((digest = calloc(1, ROUNDUP(need, mdsz))) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* K1 = HASH(K || H || "A" || session_id) */
if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
ssh_digest_update(hashctx, hash, hashlen) != 0 ||
ssh_digest_update(hashctx, &c, 1) != 0 ||
ssh_digest_update_buffer(hashctx, kex->session_id) != 0 ||
ssh_digest_final(hashctx, digest, mdsz) != 0) {
r = SSH_ERR_LIBCRYPTO_ERROR;
error_f("KEX hash failed");
goto out;
}
ssh_digest_free(hashctx);
hashctx = NULL;
/*
* expand key:
* Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
* Key = K1 || K2 || ... || Kn
*/
for (have = mdsz; need > have; have += mdsz) {
if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
ssh_digest_update(hashctx, hash, hashlen) != 0 ||
ssh_digest_update(hashctx, digest, have) != 0 ||
ssh_digest_final(hashctx, digest + have, mdsz) != 0) {
error_f("KDF failed");
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
ssh_digest_free(hashctx);
hashctx = NULL;
}
#ifdef DEBUG_KEX
fprintf(stderr, "key '%c'== ", c);
dump_digest("key", digest, need);
#endif
*keyp = digest;
digest = NULL;
r = 0;
out:
free(digest);
ssh_digest_free(hashctx);
return r;
}
#define NKEYS 6
int
kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen,
const struct sshbuf *shared_secret)
{
struct kex *kex = ssh->kex;
u_char *keys[NKEYS];
u_int i, j, mode, ctos;
int r;
/* save initial hash as session id */
if ((kex->flags & KEX_INITIAL) != 0) {
if (sshbuf_len(kex->session_id) != 0) {
error_f("already have session ID at kex");
return SSH_ERR_INTERNAL_ERROR;
}
if ((r = sshbuf_put(kex->session_id, hash, hashlen)) != 0)
return r;
} else if (sshbuf_len(kex->session_id) == 0) {
error_f("no session ID in rekex");
return SSH_ERR_INTERNAL_ERROR;
}
for (i = 0; i < NKEYS; i++) {
if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen,
shared_secret, &keys[i])) != 0) {
for (j = 0; j < i; j++)
free(keys[j]);
return r;
}
}
for (mode = 0; mode < MODE_MAX; mode++) {
ctos = (!kex->server && mode == MODE_OUT) ||
(kex->server && mode == MODE_IN);
kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1];
kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3];
kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5];
}
return 0;
}
int
kex_load_hostkey(struct ssh *ssh, struct sshkey **prvp, struct sshkey **pubp)
{
struct kex *kex = ssh->kex;
*pubp = NULL;
*prvp = NULL;
if (kex->load_host_public_key == NULL ||
kex->load_host_private_key == NULL) {
error_f("missing hostkey loader");
return SSH_ERR_INVALID_ARGUMENT;
}
*pubp = kex->load_host_public_key(kex->hostkey_type,
kex->hostkey_nid, ssh);
*prvp = kex->load_host_private_key(kex->hostkey_type,
kex->hostkey_nid, ssh);
if (*pubp == NULL)
return SSH_ERR_NO_HOSTKEY_LOADED;
return 0;
}
int
kex_verify_host_key(struct ssh *ssh, struct sshkey *server_host_key)
{
struct kex *kex = ssh->kex;
if (kex->verify_host_key == NULL) {
error_f("missing hostkey verifier");
return SSH_ERR_INVALID_ARGUMENT;
}
if (server_host_key->type != kex->hostkey_type ||
(kex->hostkey_type == KEY_ECDSA &&
server_host_key->ecdsa_nid != kex->hostkey_nid))
return SSH_ERR_KEY_TYPE_MISMATCH;
if (kex->verify_host_key(server_host_key, ssh) == -1)
return SSH_ERR_SIGNATURE_INVALID;
return 0;
}
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
void
dump_digest(const char *msg, const u_char *digest, int len)
{
fprintf(stderr, "%s\n", msg);
sshbuf_dump_data(digest, len, stderr);
}
#endif
/*
* Send a plaintext error message to the peer, suffixed by \r\n.
* Only used during banner exchange, and there only for the server.
*/
static void
send_error(struct ssh *ssh, char *msg)
{
char *crnl = "\r\n";
if (!ssh->kex->server)
return;
if (atomicio(vwrite, ssh_packet_get_connection_out(ssh),
msg, strlen(msg)) != strlen(msg) ||
atomicio(vwrite, ssh_packet_get_connection_out(ssh),
crnl, strlen(crnl)) != strlen(crnl))
error_f("write: %.100s", strerror(errno));
}
/*
* Sends our identification string and waits for the peer's. Will block for
* up to timeout_ms (or indefinitely if timeout_ms <= 0).
* Returns on 0 success or a ssherr.h code on failure.
*/
int
kex_exchange_identification(struct ssh *ssh, int timeout_ms,
const char *version_addendum)
{
int remote_major, remote_minor, mismatch, oerrno = 0;
size_t len, i, n;
int r, expect_nl;
u_char c;
struct sshbuf *our_version = ssh->kex->server ?
ssh->kex->server_version : ssh->kex->client_version;
struct sshbuf *peer_version = ssh->kex->server ?
ssh->kex->client_version : ssh->kex->server_version;
char *our_version_string = NULL, *peer_version_string = NULL;
char *cp, *remote_version = NULL;
/* Prepare and send our banner */
sshbuf_reset(our_version);
if (version_addendum != NULL && *version_addendum == '\0')
version_addendum = NULL;
if ((r = sshbuf_putf(our_version, "SSH-%d.%d-%.100s%s%s\r\n",
- PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION,
+ PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION,
version_addendum == NULL ? "" : " ",
version_addendum == NULL ? "" : version_addendum)) != 0) {
oerrno = errno;
error_fr(r, "sshbuf_putf");
goto out;
}
if (atomicio(vwrite, ssh_packet_get_connection_out(ssh),
sshbuf_mutable_ptr(our_version),
sshbuf_len(our_version)) != sshbuf_len(our_version)) {
oerrno = errno;
debug_f("write: %.100s", strerror(errno));
r = SSH_ERR_SYSTEM_ERROR;
goto out;
}
if ((r = sshbuf_consume_end(our_version, 2)) != 0) { /* trim \r\n */
oerrno = errno;
error_fr(r, "sshbuf_consume_end");
goto out;
}
our_version_string = sshbuf_dup_string(our_version);
if (our_version_string == NULL) {
error_f("sshbuf_dup_string failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
debug("Local version string %.100s", our_version_string);
/* Read other side's version identification. */
for (n = 0; ; n++) {
if (n >= SSH_MAX_PRE_BANNER_LINES) {
send_error(ssh, "No SSH identification string "
"received.");
error_f("No SSH version received in first %u lines "
"from server", SSH_MAX_PRE_BANNER_LINES);
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
sshbuf_reset(peer_version);
expect_nl = 0;
for (i = 0; ; i++) {
if (timeout_ms > 0) {
r = waitrfd(ssh_packet_get_connection_in(ssh),
&timeout_ms);
if (r == -1 && errno == ETIMEDOUT) {
send_error(ssh, "Timed out waiting "
"for SSH identification string.");
error("Connection timed out during "
"banner exchange");
r = SSH_ERR_CONN_TIMEOUT;
goto out;
} else if (r == -1) {
oerrno = errno;
error_f("%s", strerror(errno));
r = SSH_ERR_SYSTEM_ERROR;
goto out;
}
}
len = atomicio(read, ssh_packet_get_connection_in(ssh),
&c, 1);
if (len != 1 && errno == EPIPE) {
error_f("Connection closed by remote host");
r = SSH_ERR_CONN_CLOSED;
goto out;
} else if (len != 1) {
oerrno = errno;
error_f("read: %.100s", strerror(errno));
r = SSH_ERR_SYSTEM_ERROR;
goto out;
}
if (c == '\r') {
expect_nl = 1;
continue;
}
if (c == '\n')
break;
if (c == '\0' || expect_nl) {
error_f("banner line contains invalid "
"characters");
goto invalid;
}
if ((r = sshbuf_put_u8(peer_version, c)) != 0) {
oerrno = errno;
error_fr(r, "sshbuf_put");
goto out;
}
if (sshbuf_len(peer_version) > SSH_MAX_BANNER_LEN) {
error_f("banner line too long");
goto invalid;
}
}
/* Is this an actual protocol banner? */
if (sshbuf_len(peer_version) > 4 &&
memcmp(sshbuf_ptr(peer_version), "SSH-", 4) == 0)
break;
/* If not, then just log the line and continue */
if ((cp = sshbuf_dup_string(peer_version)) == NULL) {
error_f("sshbuf_dup_string failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* Do not accept lines before the SSH ident from a client */
if (ssh->kex->server) {
error_f("client sent invalid protocol identifier "
"\"%.256s\"", cp);
free(cp);
goto invalid;
}
debug_f("banner line %zu: %s", n, cp);
free(cp);
}
peer_version_string = sshbuf_dup_string(peer_version);
if (peer_version_string == NULL)
error_f("sshbuf_dup_string failed");
/* XXX must be same size for sscanf */
if ((remote_version = calloc(1, sshbuf_len(peer_version))) == NULL) {
error_f("calloc failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/*
* Check that the versions match. In future this might accept
* several versions and set appropriate flags to handle them.
*/
if (sscanf(peer_version_string, "SSH-%d.%d-%[^\n]\n",
&remote_major, &remote_minor, remote_version) != 3) {
error("Bad remote protocol version identification: '%.100s'",
peer_version_string);
invalid:
send_error(ssh, "Invalid SSH identification string.");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
debug("Remote protocol version %d.%d, remote software version %.100s",
remote_major, remote_minor, remote_version);
compat_banner(ssh, remote_version);
mismatch = 0;
switch (remote_major) {
case 2:
break;
case 1:
if (remote_minor != 99)
mismatch = 1;
break;
default:
mismatch = 1;
break;
}
if (mismatch) {
error("Protocol major versions differ: %d vs. %d",
PROTOCOL_MAJOR_2, remote_major);
send_error(ssh, "Protocol major versions differ.");
r = SSH_ERR_NO_PROTOCOL_VERSION;
goto out;
}
if (ssh->kex->server && (ssh->compat & SSH_BUG_PROBE) != 0) {
logit("probed from %s port %d with %s. Don't panic.",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
peer_version_string);
r = SSH_ERR_CONN_CLOSED; /* XXX */
goto out;
}
if (ssh->kex->server && (ssh->compat & SSH_BUG_SCANNER) != 0) {
logit("scanned from %s port %d with %s. Don't panic.",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
peer_version_string);
r = SSH_ERR_CONN_CLOSED; /* XXX */
goto out;
}
if ((ssh->compat & SSH_BUG_RSASIGMD5) != 0) {
logit("Remote version \"%.100s\" uses unsafe RSA signature "
"scheme; disabling use of RSA keys", remote_version);
}
/* success */
r = 0;
out:
free(our_version_string);
free(peer_version_string);
free(remote_version);
if (r == SSH_ERR_SYSTEM_ERROR)
errno = oerrno;
return r;
}
diff --git a/kexgen.c b/kexgen.c
index 35b83ccfb0f3..bde28053ddf1 100644
--- a/kexgen.c
+++ b/kexgen.c
@@ -1,346 +1,346 @@
-/* $OpenBSD: kexgen.c,v 1.6 2021/01/31 22:55:29 djm Exp $ */
+/* $OpenBSD: kexgen.c,v 1.7 2021/04/03 06:18:40 djm Exp $ */
/*
* Copyright (c) 2019 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include "sshkey.h"
#include "kex.h"
#include "log.h"
#include "packet.h"
#include "ssh2.h"
#include "sshbuf.h"
#include "digest.h"
#include "ssherr.h"
static int input_kex_gen_init(int, u_int32_t, struct ssh *);
static int input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh);
static int
kex_gen_hash(
int hash_alg,
const struct sshbuf *client_version,
const struct sshbuf *server_version,
const struct sshbuf *client_kexinit,
const struct sshbuf *server_kexinit,
const struct sshbuf *server_host_key_blob,
const struct sshbuf *client_pub,
const struct sshbuf *server_pub,
const struct sshbuf *shared_secret,
u_char *hash, size_t *hashlen)
{
struct sshbuf *b;
int r;
if (*hashlen < ssh_digest_bytes(hash_alg))
return SSH_ERR_INVALID_ARGUMENT;
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_stringb(b, client_version)) != 0 ||
(r = sshbuf_put_stringb(b, server_version)) != 0 ||
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
(r = sshbuf_put_u32(b, sshbuf_len(client_kexinit) + 1)) != 0 ||
(r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
(r = sshbuf_putb(b, client_kexinit)) != 0 ||
(r = sshbuf_put_u32(b, sshbuf_len(server_kexinit) + 1)) != 0 ||
(r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
(r = sshbuf_putb(b, server_kexinit)) != 0 ||
(r = sshbuf_put_stringb(b, server_host_key_blob)) != 0 ||
(r = sshbuf_put_stringb(b, client_pub)) != 0 ||
(r = sshbuf_put_stringb(b, server_pub)) != 0 ||
(r = sshbuf_putb(b, shared_secret)) != 0) {
sshbuf_free(b);
return r;
}
#ifdef DEBUG_KEX
sshbuf_dump(b, stderr);
#endif
if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) {
sshbuf_free(b);
return SSH_ERR_LIBCRYPTO_ERROR;
}
sshbuf_free(b);
*hashlen = ssh_digest_bytes(hash_alg);
#ifdef DEBUG_KEX
dump_digest("hash", hash, *hashlen);
#endif
return 0;
}
int
kex_gen_client(struct ssh *ssh)
{
struct kex *kex = ssh->kex;
int r;
switch (kex->kex_type) {
#ifdef WITH_OPENSSL
case KEX_DH_GRP1_SHA1:
case KEX_DH_GRP14_SHA1:
case KEX_DH_GRP14_SHA256:
case KEX_DH_GRP16_SHA512:
case KEX_DH_GRP18_SHA512:
r = kex_dh_keypair(kex);
break;
case KEX_ECDH_SHA2:
r = kex_ecdh_keypair(kex);
break;
#endif
case KEX_C25519_SHA256:
r = kex_c25519_keypair(kex);
break;
case KEX_KEM_SNTRUP761X25519_SHA512:
r = kex_kem_sntrup761x25519_keypair(kex);
break;
default:
r = SSH_ERR_INVALID_ARGUMENT;
break;
}
if (r != 0)
return r;
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_INIT)) != 0 ||
(r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
return r;
debug("expecting SSH2_MSG_KEX_ECDH_REPLY");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_gen_reply);
return 0;
}
static int
input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh)
{
struct kex *kex = ssh->kex;
struct sshkey *server_host_key = NULL;
struct sshbuf *shared_secret = NULL;
struct sshbuf *server_blob = NULL;
struct sshbuf *tmp = NULL, *server_host_key_blob = NULL;
u_char *signature = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH];
size_t slen, hashlen;
int r;
debug("SSH2_MSG_KEX_ECDH_REPLY received");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &kex_protocol_error);
/* hostkey */
if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
goto out;
/* sshkey_fromb() consumes its buffer, so make a copy */
if ((tmp = sshbuf_fromb(server_host_key_blob)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshkey_fromb(tmp, &server_host_key)) != 0)
goto out;
if ((r = kex_verify_host_key(ssh, server_host_key)) != 0)
goto out;
/* Q_S, server public key */
/* signed H */
if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 ||
(r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto out;
/* compute shared secret */
switch (kex->kex_type) {
#ifdef WITH_OPENSSL
case KEX_DH_GRP1_SHA1:
case KEX_DH_GRP14_SHA1:
case KEX_DH_GRP14_SHA256:
case KEX_DH_GRP16_SHA512:
case KEX_DH_GRP18_SHA512:
r = kex_dh_dec(kex, server_blob, &shared_secret);
break;
case KEX_ECDH_SHA2:
r = kex_ecdh_dec(kex, server_blob, &shared_secret);
break;
#endif
case KEX_C25519_SHA256:
r = kex_c25519_dec(kex, server_blob, &shared_secret);
break;
case KEX_KEM_SNTRUP761X25519_SHA512:
r = kex_kem_sntrup761x25519_dec(kex, server_blob,
&shared_secret);
break;
default:
r = SSH_ERR_INVALID_ARGUMENT;
break;
}
if (r !=0 )
goto out;
/* calc and verify H */
hashlen = sizeof(hash);
if ((r = kex_gen_hash(
kex->hash_alg,
kex->client_version,
kex->server_version,
kex->my,
kex->peer,
server_host_key_blob,
kex->client_pub,
server_blob,
shared_secret,
hash, &hashlen)) != 0)
goto out;
if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen,
kex->hostkey_alg, ssh->compat, NULL)) != 0)
goto out;
if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
r = kex_send_newkeys(ssh);
out:
explicit_bzero(hash, sizeof(hash));
explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key));
explicit_bzero(kex->sntrup761_client_key,
sizeof(kex->sntrup761_client_key));
sshbuf_free(server_host_key_blob);
free(signature);
sshbuf_free(tmp);
sshkey_free(server_host_key);
sshbuf_free(server_blob);
sshbuf_free(shared_secret);
sshbuf_free(kex->client_pub);
kex->client_pub = NULL;
return r;
}
int
kex_gen_server(struct ssh *ssh)
{
debug("expecting SSH2_MSG_KEX_ECDH_INIT");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_gen_init);
return 0;
}
static int
input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh)
{
struct kex *kex = ssh->kex;
struct sshkey *server_host_private, *server_host_public;
struct sshbuf *shared_secret = NULL;
struct sshbuf *server_pubkey = NULL;
struct sshbuf *client_pubkey = NULL;
struct sshbuf *server_host_key_blob = NULL;
u_char *signature = NULL, hash[SSH_DIGEST_MAX_LENGTH];
size_t slen, hashlen;
int r;
debug("SSH2_MSG_KEX_ECDH_INIT received");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &kex_protocol_error);
if ((r = kex_load_hostkey(ssh, &server_host_private,
&server_host_public)) != 0)
goto out;
if ((r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto out;
/* compute shared secret */
switch (kex->kex_type) {
#ifdef WITH_OPENSSL
case KEX_DH_GRP1_SHA1:
case KEX_DH_GRP14_SHA1:
case KEX_DH_GRP14_SHA256:
case KEX_DH_GRP16_SHA512:
case KEX_DH_GRP18_SHA512:
r = kex_dh_enc(kex, client_pubkey, &server_pubkey,
&shared_secret);
break;
case KEX_ECDH_SHA2:
r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey,
&shared_secret);
break;
#endif
case KEX_C25519_SHA256:
r = kex_c25519_enc(kex, client_pubkey, &server_pubkey,
&shared_secret);
break;
case KEX_KEM_SNTRUP761X25519_SHA512:
r = kex_kem_sntrup761x25519_enc(kex, client_pubkey,
&server_pubkey, &shared_secret);
break;
default:
r = SSH_ERR_INVALID_ARGUMENT;
break;
}
if (r !=0 )
goto out;
/* calc H */
if ((server_host_key_blob = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshkey_putb(server_host_public, server_host_key_blob)) != 0)
goto out;
hashlen = sizeof(hash);
if ((r = kex_gen_hash(
kex->hash_alg,
kex->client_version,
kex->server_version,
kex->peer,
kex->my,
server_host_key_blob,
client_pubkey,
server_pubkey,
shared_secret,
hash, &hashlen)) != 0)
goto out;
/* sign H */
if ((r = kex->sign(ssh, server_host_private, server_host_public,
- &signature, &slen, hash, hashlen, kex->hostkey_alg)) != 0)
+ &signature, &slen, hash, hashlen, kex->hostkey_alg)) != 0)
goto out;
/* send server hostkey, ECDH pubkey 'Q_S' and signed H */
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 ||
(r = sshpkt_put_stringb(ssh, server_host_key_blob)) != 0 ||
(r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 ||
(r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
goto out;
if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
r = kex_send_newkeys(ssh);
out:
explicit_bzero(hash, sizeof(hash));
sshbuf_free(server_host_key_blob);
free(signature);
sshbuf_free(shared_secret);
sshbuf_free(client_pubkey);
sshbuf_free(server_pubkey);
return r;
}
diff --git a/log.c b/log.c
index 4d786c2cf63b..165b486389dc 100644
--- a/log.c
+++ b/log.c
@@ -1,486 +1,496 @@
-/* $OpenBSD: log.c,v 1.56 2020/12/04 02:25:13 djm Exp $ */
+/* $OpenBSD: log.c,v 1.58 2021/04/15 16:24:31 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <errno.h>
#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
# include <vis.h>
#endif
#include "log.h"
#include "match.h"
static LogLevel log_level = SYSLOG_LEVEL_INFO;
static int log_on_stderr = 1;
static int log_stderr_fd = STDERR_FILENO;
static int log_facility = LOG_AUTH;
static const char *argv0;
static log_handler_fn *log_handler;
static void *log_handler_ctx;
static char **log_verbose;
static size_t nlog_verbose;
extern char *__progname;
#define LOG_SYSLOG_VIS (VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL)
#define LOG_STDERR_VIS (VIS_SAFE|VIS_OCTAL)
/* textual representation of log-facilities/levels */
static struct {
const char *name;
SyslogFacility val;
} log_facilities[] = {
{ "DAEMON", SYSLOG_FACILITY_DAEMON },
{ "USER", SYSLOG_FACILITY_USER },
{ "AUTH", SYSLOG_FACILITY_AUTH },
#ifdef LOG_AUTHPRIV
{ "AUTHPRIV", SYSLOG_FACILITY_AUTHPRIV },
#endif
{ "LOCAL0", SYSLOG_FACILITY_LOCAL0 },
{ "LOCAL1", SYSLOG_FACILITY_LOCAL1 },
{ "LOCAL2", SYSLOG_FACILITY_LOCAL2 },
{ "LOCAL3", SYSLOG_FACILITY_LOCAL3 },
{ "LOCAL4", SYSLOG_FACILITY_LOCAL4 },
{ "LOCAL5", SYSLOG_FACILITY_LOCAL5 },
{ "LOCAL6", SYSLOG_FACILITY_LOCAL6 },
{ "LOCAL7", SYSLOG_FACILITY_LOCAL7 },
{ NULL, SYSLOG_FACILITY_NOT_SET }
};
static struct {
const char *name;
LogLevel val;
} log_levels[] =
{
{ "QUIET", SYSLOG_LEVEL_QUIET },
{ "FATAL", SYSLOG_LEVEL_FATAL },
{ "ERROR", SYSLOG_LEVEL_ERROR },
{ "INFO", SYSLOG_LEVEL_INFO },
{ "VERBOSE", SYSLOG_LEVEL_VERBOSE },
{ "DEBUG", SYSLOG_LEVEL_DEBUG1 },
{ "DEBUG1", SYSLOG_LEVEL_DEBUG1 },
{ "DEBUG2", SYSLOG_LEVEL_DEBUG2 },
{ "DEBUG3", SYSLOG_LEVEL_DEBUG3 },
{ NULL, SYSLOG_LEVEL_NOT_SET }
};
LogLevel
log_level_get(void)
{
return log_level;
}
SyslogFacility
log_facility_number(char *name)
{
int i;
if (name != NULL)
for (i = 0; log_facilities[i].name; i++)
if (strcasecmp(log_facilities[i].name, name) == 0)
return log_facilities[i].val;
return SYSLOG_FACILITY_NOT_SET;
}
const char *
log_facility_name(SyslogFacility facility)
{
u_int i;
for (i = 0; log_facilities[i].name; i++)
if (log_facilities[i].val == facility)
return log_facilities[i].name;
return NULL;
}
LogLevel
log_level_number(char *name)
{
int i;
if (name != NULL)
for (i = 0; log_levels[i].name; i++)
if (strcasecmp(log_levels[i].name, name) == 0)
return log_levels[i].val;
return SYSLOG_LEVEL_NOT_SET;
}
const char *
log_level_name(LogLevel level)
{
u_int i;
for (i = 0; log_levels[i].name != NULL; i++)
if (log_levels[i].val == level)
return log_levels[i].name;
return NULL;
}
void
log_verbose_add(const char *s)
{
char **tmp;
/* Ignore failures here */
if ((tmp = recallocarray(log_verbose, nlog_verbose, nlog_verbose + 1,
sizeof(*log_verbose))) != NULL) {
log_verbose = tmp;
if ((log_verbose[nlog_verbose] = strdup(s)) != NULL)
nlog_verbose++;
}
}
void
log_verbose_reset(void)
{
size_t i;
for (i = 0; i < nlog_verbose; i++)
free(log_verbose[i]);
free(log_verbose);
log_verbose = NULL;
nlog_verbose = 0;
}
/*
* Initialize the log.
*/
void
log_init(const char *av0, LogLevel level, SyslogFacility facility,
int on_stderr)
{
#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
struct syslog_data sdata = SYSLOG_DATA_INIT;
#endif
argv0 = av0;
if (log_change_level(level) != 0) {
fprintf(stderr, "Unrecognized internal syslog level code %d\n",
(int) level);
exit(1);
}
log_handler = NULL;
log_handler_ctx = NULL;
log_on_stderr = on_stderr;
if (on_stderr)
return;
switch (facility) {
case SYSLOG_FACILITY_DAEMON:
log_facility = LOG_DAEMON;
break;
case SYSLOG_FACILITY_USER:
log_facility = LOG_USER;
break;
case SYSLOG_FACILITY_AUTH:
log_facility = LOG_AUTH;
break;
#ifdef LOG_AUTHPRIV
case SYSLOG_FACILITY_AUTHPRIV:
log_facility = LOG_AUTHPRIV;
break;
#endif
case SYSLOG_FACILITY_LOCAL0:
log_facility = LOG_LOCAL0;
break;
case SYSLOG_FACILITY_LOCAL1:
log_facility = LOG_LOCAL1;
break;
case SYSLOG_FACILITY_LOCAL2:
log_facility = LOG_LOCAL2;
break;
case SYSLOG_FACILITY_LOCAL3:
log_facility = LOG_LOCAL3;
break;
case SYSLOG_FACILITY_LOCAL4:
log_facility = LOG_LOCAL4;
break;
case SYSLOG_FACILITY_LOCAL5:
log_facility = LOG_LOCAL5;
break;
case SYSLOG_FACILITY_LOCAL6:
log_facility = LOG_LOCAL6;
break;
case SYSLOG_FACILITY_LOCAL7:
log_facility = LOG_LOCAL7;
break;
default:
fprintf(stderr,
"Unrecognized internal syslog facility code %d\n",
(int) facility);
exit(1);
}
/*
* If an external library (eg libwrap) attempts to use syslog
* immediately after reexec, syslog may be pointing to the wrong
* facility, so we force an open/close of syslog here.
*/
#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
closelog_r(&sdata);
#else
openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
closelog();
#endif
}
int
log_change_level(LogLevel new_log_level)
{
/* no-op if log_init has not been called */
if (argv0 == NULL)
return 0;
switch (new_log_level) {
case SYSLOG_LEVEL_QUIET:
case SYSLOG_LEVEL_FATAL:
case SYSLOG_LEVEL_ERROR:
case SYSLOG_LEVEL_INFO:
case SYSLOG_LEVEL_VERBOSE:
case SYSLOG_LEVEL_DEBUG1:
case SYSLOG_LEVEL_DEBUG2:
case SYSLOG_LEVEL_DEBUG3:
log_level = new_log_level;
return 0;
default:
return -1;
}
}
int
log_is_on_stderr(void)
{
return log_on_stderr && log_stderr_fd == STDERR_FILENO;
}
/* redirect what would usually get written to stderr to specified file */
void
log_redirect_stderr_to(const char *logfile)
{
int fd;
if (logfile == NULL) {
if (log_stderr_fd != STDERR_FILENO) {
close(log_stderr_fd);
log_stderr_fd = STDERR_FILENO;
}
return;
}
if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
fprintf(stderr, "Couldn't open logfile %s: %s\n", logfile,
- strerror(errno));
+ strerror(errno));
exit(1);
}
log_stderr_fd = fd;
}
#define MSGBUFSIZ 1024
void
set_log_handler(log_handler_fn *handler, void *ctx)
{
log_handler = handler;
log_handler_ctx = ctx;
}
static void
-do_log(const char *file, const char *func, int line, LogLevel level,
- int force, const char *suffix, const char *fmt, va_list args)
+do_log(LogLevel level, int force, const char *suffix, const char *fmt,
+ va_list args)
{
#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
struct syslog_data sdata = SYSLOG_DATA_INIT;
#endif
char msgbuf[MSGBUFSIZ];
char fmtbuf[MSGBUFSIZ];
char *txt = NULL;
int pri = LOG_INFO;
int saved_errno = errno;
log_handler_fn *tmp_handler;
if (!force && level > log_level)
return;
switch (level) {
case SYSLOG_LEVEL_FATAL:
if (!log_on_stderr)
txt = "fatal";
pri = LOG_CRIT;
break;
case SYSLOG_LEVEL_ERROR:
if (!log_on_stderr)
txt = "error";
pri = LOG_ERR;
break;
case SYSLOG_LEVEL_INFO:
pri = LOG_INFO;
break;
case SYSLOG_LEVEL_VERBOSE:
pri = LOG_INFO;
break;
case SYSLOG_LEVEL_DEBUG1:
txt = "debug1";
pri = LOG_DEBUG;
break;
case SYSLOG_LEVEL_DEBUG2:
txt = "debug2";
pri = LOG_DEBUG;
break;
case SYSLOG_LEVEL_DEBUG3:
txt = "debug3";
pri = LOG_DEBUG;
break;
default:
txt = "internal error";
pri = LOG_ERR;
break;
}
if (txt != NULL && log_handler == NULL) {
snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
} else {
vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
}
if (suffix != NULL) {
snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", msgbuf, suffix);
strlcpy(msgbuf, fmtbuf, sizeof(msgbuf));
}
strnvis(fmtbuf, msgbuf, sizeof(fmtbuf),
log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS);
if (log_handler != NULL) {
/* Avoid recursion */
tmp_handler = log_handler;
log_handler = NULL;
- tmp_handler(file, func, line, level, fmtbuf, log_handler_ctx);
+ tmp_handler(level, force, fmtbuf, log_handler_ctx);
log_handler = tmp_handler;
} else if (log_on_stderr) {
snprintf(msgbuf, sizeof msgbuf, "%.*s\r\n",
(int)sizeof msgbuf - 3, fmtbuf);
(void)write(log_stderr_fd, msgbuf, strlen(msgbuf));
} else {
#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
syslog_r(pri, &sdata, "%.500s", fmtbuf);
closelog_r(&sdata);
#else
openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
syslog(pri, "%.500s", fmtbuf);
closelog();
#endif
}
errno = saved_errno;
}
void
sshlog(const char *file, const char *func, int line, int showfunc,
LogLevel level, const char *suffix, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
sshlogv(file, func, line, showfunc, level, suffix, fmt, args);
va_end(args);
}
void
sshlogdie(const char *file, const char *func, int line, int showfunc,
LogLevel level, const char *suffix, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
sshlogv(file, func, line, showfunc, SYSLOG_LEVEL_INFO,
suffix, fmt, args);
va_end(args);
cleanup_exit(255);
}
void
sshsigdie(const char *file, const char *func, int line, int showfunc,
LogLevel level, const char *suffix, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
sshlogv(file, func, line, showfunc, SYSLOG_LEVEL_FATAL,
suffix, fmt, args);
va_end(args);
_exit(1);
}
void
sshlogv(const char *file, const char *func, int line, int showfunc,
LogLevel level, const char *suffix, const char *fmt, va_list args)
{
char tag[128], fmt2[MSGBUFSIZ + 128];
int forced = 0;
const char *cp;
size_t i;
snprintf(tag, sizeof(tag), "%.48s:%.48s():%d",
(cp = strrchr(file, '/')) == NULL ? file : cp + 1, func, line);
for (i = 0; i < nlog_verbose; i++) {
if (match_pattern_list(tag, log_verbose[i], 0) == 1) {
forced = 1;
break;
}
}
- if (log_handler == NULL && forced)
+ if (forced)
snprintf(fmt2, sizeof(fmt2), "%s: %s", tag, fmt);
else if (showfunc)
snprintf(fmt2, sizeof(fmt2), "%s: %s", func, fmt);
else
strlcpy(fmt2, fmt, sizeof(fmt2));
- do_log(file, func, line, level, forced, suffix, fmt2, args);
+ do_log(level, forced, suffix, fmt2, args);
+}
+
+void
+sshlogdirect(LogLevel level, int forced, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ do_log(level, forced, NULL, fmt, args);
+ va_end(args);
}
diff --git a/log.h b/log.h
index 5ec793ceef46..6218b4177a6f 100644
--- a/log.h
+++ b/log.h
@@ -1,131 +1,132 @@
-/* $OpenBSD: log.h,v 1.30 2020/12/04 02:25:13 djm Exp $ */
+/* $OpenBSD: log.h,v 1.33 2021/04/15 16:24:31 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#ifndef SSH_LOG_H
#define SSH_LOG_H
#include <stdarg.h> /* va_list */
-#include <ssherr.h> /* ssh_err() */
+#include "ssherr.h" /* ssh_err() */
/* Supported syslog facilities and levels. */
typedef enum {
SYSLOG_FACILITY_DAEMON,
SYSLOG_FACILITY_USER,
SYSLOG_FACILITY_AUTH,
#ifdef LOG_AUTHPRIV
SYSLOG_FACILITY_AUTHPRIV,
#endif
SYSLOG_FACILITY_LOCAL0,
SYSLOG_FACILITY_LOCAL1,
SYSLOG_FACILITY_LOCAL2,
SYSLOG_FACILITY_LOCAL3,
SYSLOG_FACILITY_LOCAL4,
SYSLOG_FACILITY_LOCAL5,
SYSLOG_FACILITY_LOCAL6,
SYSLOG_FACILITY_LOCAL7,
SYSLOG_FACILITY_NOT_SET = -1
} SyslogFacility;
typedef enum {
SYSLOG_LEVEL_QUIET,
SYSLOG_LEVEL_FATAL,
SYSLOG_LEVEL_ERROR,
SYSLOG_LEVEL_INFO,
SYSLOG_LEVEL_VERBOSE,
SYSLOG_LEVEL_DEBUG1,
SYSLOG_LEVEL_DEBUG2,
SYSLOG_LEVEL_DEBUG3,
SYSLOG_LEVEL_NOT_SET = -1
} LogLevel;
-typedef void (log_handler_fn)(const char *, const char *, int, LogLevel,
- const char *, void *);
+typedef void (log_handler_fn)(LogLevel, int, const char *, void *);
void log_init(const char *, LogLevel, SyslogFacility, int);
LogLevel log_level_get(void);
int log_change_level(LogLevel);
int log_is_on_stderr(void);
void log_redirect_stderr_to(const char *);
void log_verbose_add(const char *);
void log_verbose_reset(void);
SyslogFacility log_facility_number(char *);
-const char * log_facility_name(SyslogFacility);
+const char * log_facility_name(SyslogFacility);
LogLevel log_level_number(char *);
const char * log_level_name(LogLevel);
void set_log_handler(log_handler_fn *, void *);
void cleanup_exit(int) __attribute__((noreturn));
void sshlog(const char *, const char *, int, int,
LogLevel, const char *, const char *, ...)
__attribute__((format(printf, 7, 8)));
void sshlogv(const char *, const char *, int, int,
LogLevel, const char *, const char *, va_list);
void sshsigdie(const char *, const char *, int, int,
LogLevel, const char *, const char *, ...) __attribute__((noreturn))
__attribute__((format(printf, 7, 8)));
void sshlogdie(const char *, const char *, int, int,
LogLevel, const char *, const char *, ...) __attribute__((noreturn))
__attribute__((format(printf, 7, 8)));
void sshfatal(const char *, const char *, int, int,
LogLevel, const char *, const char *, ...) __attribute__((noreturn))
__attribute__((format(printf, 7, 8)));
+void sshlogdirect(LogLevel, int, const char *, ...)
+ __attribute__((format(printf, 3, 4)));
#define do_log2(level, ...) sshlog(__FILE__, __func__, __LINE__, 0, level, NULL, __VA_ARGS__)
#define debug3(...) sshlog(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_DEBUG3, NULL, __VA_ARGS__)
#define debug2(...) sshlog(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_DEBUG2, NULL, __VA_ARGS__)
#define debug(...) sshlog(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_DEBUG1, NULL, __VA_ARGS__)
#define verbose(...) sshlog(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_VERBOSE, NULL, __VA_ARGS__)
#define logit(...) sshlog(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_INFO, NULL, __VA_ARGS__)
#define error(...) sshlog(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_ERROR, NULL, __VA_ARGS__)
#define fatal(...) sshfatal(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_FATAL, NULL, __VA_ARGS__)
#define logdie(...) sshlogdie(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_ERROR, NULL, __VA_ARGS__)
#define sigdie(...) sshsigdie(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_ERROR, NULL, __VA_ARGS__)
/* Variants that prepend the caller's function */
#define do_log2_f(level, ...) sshlog(__FILE__, __func__, __LINE__, 1, level, NULL, __VA_ARGS__)
#define debug3_f(...) sshlog(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_DEBUG3, NULL, __VA_ARGS__)
#define debug2_f(...) sshlog(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_DEBUG2, NULL, __VA_ARGS__)
#define debug_f(...) sshlog(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_DEBUG1, NULL, __VA_ARGS__)
#define verbose_f(...) sshlog(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_VERBOSE, NULL, __VA_ARGS__)
#define logit_f(...) sshlog(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_INFO, NULL, __VA_ARGS__)
#define error_f(...) sshlog(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_ERROR, NULL, __VA_ARGS__)
#define fatal_f(...) sshfatal(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_FATAL, NULL, __VA_ARGS__)
#define logdie_f(...) sshlogdie(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_ERROR, NULL, __VA_ARGS__)
#define sigdie_f(...) sshsigdie(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_ERROR, NULL, __VA_ARGS__)
/* Variants that appends a ssh_err message */
#define do_log2_r(r, level, ...) sshlog(__FILE__, __func__, __LINE__, 0, level, ssh_err(r), __VA_ARGS__)
#define debug3_r(r, ...) sshlog(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_DEBUG3, ssh_err(r), __VA_ARGS__)
#define debug2_r(r, ...) sshlog(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_DEBUG2, ssh_err(r), __VA_ARGS__)
#define debug_r(r, ...) sshlog(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_DEBUG1, ssh_err(r), __VA_ARGS__)
#define verbose_r(r, ...) sshlog(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_VERBOSE, ssh_err(r), __VA_ARGS__)
#define logit_r(r, ...) sshlog(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_INFO, ssh_err(r), __VA_ARGS__)
#define error_r(r, ...) sshlog(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_ERROR, ssh_err(r), __VA_ARGS__)
#define fatal_r(r, ...) sshfatal(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_FATAL, ssh_err(r), __VA_ARGS__)
#define logdie_r(r, ...) sshlogdie(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_ERROR, ssh_err(r), __VA_ARGS__)
#define sigdie_r(r, ...) sshsigdie(__FILE__, __func__, __LINE__, 0, SYSLOG_LEVEL_ERROR, ssh_err(r), __VA_ARGS__)
#define do_log2_fr(r, level, ...) sshlog(__FILE__, __func__, __LINE__, 1, level, ssh_err(r), __VA_ARGS__)
#define debug3_fr(r, ...) sshlog(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_DEBUG3, ssh_err(r), __VA_ARGS__)
#define debug2_fr(r, ...) sshlog(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_DEBUG2, ssh_err(r), __VA_ARGS__)
#define debug_fr(r, ...) sshlog(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_DEBUG1, ssh_err(r), __VA_ARGS__)
#define verbose_fr(r, ...) sshlog(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_VERBOSE, ssh_err(r), __VA_ARGS__)
#define logit_fr(r, ...) sshlog(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_INFO, ssh_err(r), __VA_ARGS__)
#define error_fr(r, ...) sshlog(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_ERROR, ssh_err(r), __VA_ARGS__)
#define fatal_fr(r, ...) sshfatal(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_FATAL, ssh_err(r), __VA_ARGS__)
#define logdie_fr(r, ...) sshlogdie(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_ERROR, ssh_err(r), __VA_ARGS__)
#define sigdie_fr(r, ...) sshsigdie(__FILE__, __func__, __LINE__, 1, SYSLOG_LEVEL_ERROR, ssh_err(r), __VA_ARGS__)
#endif
diff --git a/loginrec.h b/loginrec.h
index 62cc0e78c945..02bceb604c7f 100644
--- a/loginrec.h
+++ b/loginrec.h
@@ -1,134 +1,134 @@
#ifndef _HAVE_LOGINREC_H_
#define _HAVE_LOGINREC_H_
/*
* Copyright (c) 2000 Andre Lucas. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
** loginrec.h: platform-independent login recording and lastlog retrieval
**/
#include "includes.h"
struct ssh;
/**
** you should use the login_* calls to work around platform dependencies
**/
/*
* login_netinfo structure
*/
union login_netinfo {
struct sockaddr sa;
struct sockaddr_in sa_in;
struct sockaddr_storage sa_storage;
};
/*
* * logininfo structure *
*/
/* types - different to utmp.h 'type' macros */
/* (though set to the same value as linux, openbsd and others...) */
#define LTYPE_LOGIN 7
#define LTYPE_LOGOUT 8
/* string lengths - set very long */
#define LINFO_PROGSIZE 64
#define LINFO_LINESIZE 64
#define LINFO_NAMESIZE 512
#define LINFO_HOSTSIZE 256
struct logininfo {
char progname[LINFO_PROGSIZE]; /* name of program (for PAM) */
int progname_null;
short int type; /* type of login (LTYPE_*) */
pid_t pid; /* PID of login process */
uid_t uid; /* UID of this user */
char line[LINFO_LINESIZE]; /* tty/pty name */
char username[LINFO_NAMESIZE]; /* login username */
char hostname[LINFO_HOSTSIZE]; /* remote hostname */
/* 'exit_status' structure components */
int exit; /* process exit status */
int termination; /* process termination status */
/* struct timeval (sys/time.h) isn't always available, if it isn't we'll
* use time_t's value as tv_sec and set tv_usec to 0
*/
unsigned int tv_sec;
unsigned int tv_usec;
union login_netinfo hostaddr; /* caller's host address(es) */
}; /* struct logininfo */
/*
* login recording functions
*/
/** 'public' functions */
/* construct a new login entry */
struct logininfo *login_alloc_entry(pid_t pid, const char *username,
const char *hostname, const char *line);
/* free a structure */
void login_free_entry(struct logininfo *li);
/* fill out a pre-allocated structure with useful information */
int login_init_entry(struct logininfo *li, pid_t pid, const char *username,
- const char *hostname, const char *line);
+ const char *hostname, const char *line);
/* place the current time in a logininfo struct */
void login_set_current_time(struct logininfo *li);
/* record the entry */
int login_login (struct logininfo *li);
int login_logout(struct logininfo *li);
#ifdef LOGIN_NEEDS_UTMPX
int login_utmp_only(struct logininfo *li);
#endif
/** End of public functions */
/* record the entry */
int login_write (struct logininfo *li);
int login_log_entry(struct logininfo *li);
/* set the network address based on network address type */
void login_set_addr(struct logininfo *li, const struct sockaddr *sa,
const unsigned int sa_size);
/*
* lastlog retrieval functions
*/
/* lastlog *entry* functions fill out a logininfo */
struct logininfo *login_get_lastlog(struct logininfo *li, const uid_t uid);
/* lastlog *time* functions return time_t equivalent (uint) */
unsigned int login_get_lastlog_time(const uid_t uid);
/* produce various forms of the line filename */
char *line_fullname(char *dst, const char *src, u_int dstsize);
char *line_stripname(char *dst, const char *src, int dstsize);
char *line_abbrevname(char *dst, const char *src, int dstsize);
void record_failed_login(struct ssh *, const char *, const char *,
const char *);
#endif /* _HAVE_LOGINREC_H_ */
diff --git a/logintest.c b/logintest.c
index 4897ae0f9e11..6ee1cdc23645 100644
--- a/logintest.c
+++ b/logintest.c
@@ -1,308 +1,308 @@
/*
* Copyright (c) 2000 Andre Lucas. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
** logintest.c: simple test driver for platform-independent login recording
** and lastlog retrieval
**/
#include "includes.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pwd.h>
#include <netdb.h>
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#include "loginrec.h"
extern char *__progname;
#define PAUSE_BEFORE_LOGOUT 3
int nologtest = 0;
int compile_opts_only = 0;
int be_verbose = 0;
/* Dump a logininfo to stdout. Assumes a tab size of 8 chars. */
void
dump_logininfo(struct logininfo *li, char *descname)
{
/* yes I know how nasty this is */
printf("struct logininfo %s = {\n\t"
- "progname\t'%s'\n\ttype\t\t%d\n\t"
- "pid\t\t%d\n\tuid\t\t%d\n\t"
- "line\t\t'%s'\n\tusername\t'%s'\n\t"
- "hostname\t'%s'\n\texit\t\t%d\n\ttermination\t%d\n\t"
- "tv_sec\t%d\n\ttv_usec\t%d\n\t"
- "struct login_netinfo hostaddr {\n\t\t"
- "struct sockaddr sa {\n"
- "\t\t\tfamily\t%d\n\t\t}\n"
- "\t}\n"
- "}\n",
- descname, li->progname, li->type,
- li->pid, li->uid, li->line,
- li->username, li->hostname, li->exit,
- li->termination, li->tv_sec, li->tv_usec,
- li->hostaddr.sa.sa_family);
+ "progname\t'%s'\n\ttype\t\t%d\n\t"
+ "pid\t\t%d\n\tuid\t\t%d\n\t"
+ "line\t\t'%s'\n\tusername\t'%s'\n\t"
+ "hostname\t'%s'\n\texit\t\t%d\n\ttermination\t%d\n\t"
+ "tv_sec\t%d\n\ttv_usec\t%d\n\t"
+ "struct login_netinfo hostaddr {\n\t\t"
+ "struct sockaddr sa {\n"
+ "\t\t\tfamily\t%d\n\t\t}\n"
+ "\t}\n"
+ "}\n",
+ descname, li->progname, li->type,
+ li->pid, li->uid, li->line,
+ li->username, li->hostname, li->exit,
+ li->termination, li->tv_sec, li->tv_usec,
+ li->hostaddr.sa.sa_family);
}
int
testAPI()
{
struct logininfo *li1;
struct passwd *pw;
struct hostent *he;
struct sockaddr_in sa_in4;
char cmdstring[256], stripline[8];
char username[32];
#ifdef HAVE_TIME_H
time_t t0, t1, t2, logintime, logouttime;
char s_t0[64],s_t1[64],s_t2[64];
char s_logintime[64], s_logouttime[64]; /* ctime() strings */
#endif
printf("**\n** Testing the API...\n**\n");
pw = getpwuid(getuid());
strlcpy(username, pw->pw_name, sizeof(username));
/* gethostname(hostname, sizeof(hostname)); */
printf("login_alloc_entry test (no host info):\n");
/* FIXME fake tty more effectively - this could upset some platforms */
li1 = login_alloc_entry((int)getpid(), username, NULL, ttyname(0));
strlcpy(li1->progname, "OpenSSH-logintest", sizeof(li1->progname));
if (be_verbose)
dump_logininfo(li1, "li1");
printf("Setting host address info for 'localhost' (may call out):\n");
if (! (he = gethostbyname("localhost"))) {
printf("Couldn't set hostname(lookup failed)\n");
} else {
/* NOTE: this is messy, but typically a program wouldn't have to set
* any of this, a sockaddr_in* would be already prepared */
memcpy((void *)&(sa_in4.sin_addr), (void *)&(he->h_addr_list[0][0]),
- sizeof(struct in_addr));
+ sizeof(struct in_addr));
login_set_addr(li1, (struct sockaddr *) &sa_in4, sizeof(sa_in4));
strlcpy(li1->hostname, "localhost", sizeof(li1->hostname));
}
if (be_verbose)
dump_logininfo(li1, "li1");
if ((int)geteuid() != 0) {
printf("NOT RUNNING LOGIN TESTS - you are not root!\n");
return 1;
}
if (nologtest)
return 1;
line_stripname(stripline, li1->line, sizeof(stripline));
printf("Performing an invalid login attempt (no type field)\n--\n");
login_write(li1);
printf("--\n(Should have written errors to stderr)\n");
#ifdef HAVE_TIME_H
(void)time(&t0);
strlcpy(s_t0, ctime(&t0), sizeof(s_t0));
t1 = login_get_lastlog_time(getuid());
strlcpy(s_t1, ctime(&t1), sizeof(s_t1));
printf("Before logging in:\n\tcurrent time is %d - %s\t"
- "lastlog time is %d - %s\n",
- (int)t0, s_t0, (int)t1, s_t1);
+ "lastlog time is %d - %s\n",
+ (int)t0, s_t0, (int)t1, s_t1);
#endif
printf("Performing a login on line %s ", stripline);
#ifdef HAVE_TIME_H
(void)time(&logintime);
strlcpy(s_logintime, ctime(&logintime), sizeof(s_logintime));
printf("at %d - %s", (int)logintime, s_logintime);
#endif
printf("--\n");
login_login(li1);
snprintf(cmdstring, sizeof(cmdstring), "who | grep '%s '",
stripline);
system(cmdstring);
printf("--\nPausing for %d second(s)...\n", PAUSE_BEFORE_LOGOUT);
sleep(PAUSE_BEFORE_LOGOUT);
printf("Performing a logout ");
#ifdef HAVE_TIME_H
(void)time(&logouttime);
strlcpy(s_logouttime, ctime(&logouttime), sizeof(s_logouttime));
printf("at %d - %s", (int)logouttime, s_logouttime);
#endif
printf("\nThe root login shown above should be gone.\n"
- "If the root login hasn't gone, but another user on the same\n"
- "pty has, this is OK - we're hacking it here, and there\n"
- "shouldn't be two users on one pty in reality...\n"
- "-- ('who' output follows)\n");
+ "If the root login hasn't gone, but another user on the same\n"
+ "pty has, this is OK - we're hacking it here, and there\n"
+ "shouldn't be two users on one pty in reality...\n"
+ "-- ('who' output follows)\n");
login_logout(li1);
system(cmdstring);
printf("-- ('who' output ends)\n");
#ifdef HAVE_TIME_H
t2 = login_get_lastlog_time(getuid());
strlcpy(s_t2, ctime(&t2), sizeof(s_t2));
printf("After logging in, lastlog time is %d - %s\n", (int)t2, s_t2);
if (t1 == t2)
printf("The lastlog times before and after logging in are the "
- "same.\nThis indicates that lastlog is ** NOT WORKING "
- "CORRECTLY **\n");
+ "same.\nThis indicates that lastlog is ** NOT WORKING "
+ "CORRECTLY **\n");
else if (t0 != t2)
/* We can be off by a second or so, even when recording works fine.
* I'm not 100% sure why, but it's true. */
printf("** The login time and the lastlog time differ.\n"
- "** This indicates that lastlog is either recording the "
- "wrong time,\n** or retrieving the wrong entry.\n"
- "If it's off by less than %d second(s) "
- "run the test again.\n", PAUSE_BEFORE_LOGOUT);
+ "** This indicates that lastlog is either recording the "
+ "wrong time,\n** or retrieving the wrong entry.\n"
+ "If it's off by less than %d second(s) "
+ "run the test again.\n", PAUSE_BEFORE_LOGOUT);
else
printf("lastlog agrees with the login time. This is a good thing.\n");
#endif
printf("--\nThe output of 'last' shown next should have "
- "an entry for root \n on %s for the time shown above:\n--\n",
- stripline);
+ "an entry for root \n on %s for the time shown above:\n--\n",
+ stripline);
snprintf(cmdstring, sizeof(cmdstring), "last | grep '%s ' | head -3",
stripline);
system(cmdstring);
printf("--\nEnd of login test.\n");
login_free_entry(li1);
return 1;
} /* testAPI() */
void
testLineName(char *line)
{
/* have to null-terminate - these functions are designed for
* structures with fixed-length char arrays, and don't null-term.*/
char full[17], strip[9], abbrev[5];
memset(full, '\0', sizeof(full));
memset(strip, '\0', sizeof(strip));
memset(abbrev, '\0', sizeof(abbrev));
line_fullname(full, line, sizeof(full)-1);
line_stripname(strip, full, sizeof(strip)-1);
line_abbrevname(abbrev, full, sizeof(abbrev)-1);
printf("%s: %s, %s, %s\n", line, full, strip, abbrev);
} /* testLineName() */
int
testOutput()
{
printf("**\n** Testing linename functions\n**\n");
testLineName("/dev/pts/1");
testLineName("pts/1");
testLineName("pts/999");
testLineName("/dev/ttyp00");
testLineName("ttyp00");
return 1;
} /* testOutput() */
/* show which options got compiled in */
void
showOptions(void)
{
printf("**\n** Compile-time options\n**\n");
printf("login recording methods selected:\n");
#ifdef USE_LOGIN
printf("\tUSE_LOGIN\n");
#endif
#ifdef USE_UTMP
printf("\tUSE_UTMP (UTMP_FILE=%s)\n", UTMP_FILE);
#endif
#ifdef USE_UTMPX
printf("\tUSE_UTMPX\n");
#endif
#ifdef USE_WTMP
printf("\tUSE_WTMP (WTMP_FILE=%s)\n", WTMP_FILE);
#endif
#ifdef USE_WTMPX
printf("\tUSE_WTMPX (WTMPX_FILE=%s)\n", WTMPX_FILE);
#endif
#ifdef USE_LASTLOG
printf("\tUSE_LASTLOG (LASTLOG_FILE=%s)\n", LASTLOG_FILE);
#endif
printf("\n");
} /* showOptions() */
int
main(int argc, char *argv[])
{
printf("Platform-independent login recording test driver\n");
__progname = ssh_get_progname(argv[0]);
if (argc == 2) {
if (strncmp(argv[1], "-i", 3) == 0)
compile_opts_only = 1;
else if (strncmp(argv[1], "-v", 3) == 0)
be_verbose=1;
}
if (!compile_opts_only) {
if (be_verbose && !testOutput())
return 1;
if (!testAPI())
return 1;
}
showOptions();
return 0;
} /* main() */
diff --git a/misc.c b/misc.c
index d988ce3b96c5..b0ece2442cc7 100644
--- a/misc.c
+++ b/misc.c
@@ -1,2676 +1,2673 @@
-/* $OpenBSD: misc.c,v 1.162 2021/02/28 01:50:47 dtucker Exp $ */
+/* $OpenBSD: misc.c,v 1.164 2021/04/03 06:18:40 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005-2020 Damien Miller. All rights reserved.
* Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <limits.h>
#ifdef HAVE_LIBGEN_H
# include <libgen.h>
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#include <pwd.h>
#endif
#ifdef SSH_TUN_OPENBSD
#include <net/if.h>
#endif
#include "xmalloc.h"
#include "misc.h"
#include "log.h"
#include "ssh.h"
#include "sshbuf.h"
#include "ssherr.h"
#include "platform.h"
/* remove newline at end of string */
char *
chop(char *s)
{
char *t = s;
while (*t) {
if (*t == '\n' || *t == '\r') {
*t = '\0';
return s;
}
t++;
}
return s;
}
/* set/unset filedescriptor to non-blocking */
int
set_nonblock(int fd)
{
int val;
val = fcntl(fd, F_GETFL);
if (val == -1) {
error("fcntl(%d, F_GETFL): %s", fd, strerror(errno));
return (-1);
}
if (val & O_NONBLOCK) {
debug3("fd %d is O_NONBLOCK", fd);
return (0);
}
debug2("fd %d setting O_NONBLOCK", fd);
val |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, val) == -1) {
debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd,
strerror(errno));
return (-1);
}
return (0);
}
int
unset_nonblock(int fd)
{
int val;
val = fcntl(fd, F_GETFL);
if (val == -1) {
error("fcntl(%d, F_GETFL): %s", fd, strerror(errno));
return (-1);
}
if (!(val & O_NONBLOCK)) {
debug3("fd %d is not O_NONBLOCK", fd);
return (0);
}
debug("fd %d clearing O_NONBLOCK", fd);
val &= ~O_NONBLOCK;
if (fcntl(fd, F_SETFL, val) == -1) {
debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s",
fd, strerror(errno));
return (-1);
}
return (0);
}
const char *
ssh_gai_strerror(int gaierr)
{
if (gaierr == EAI_SYSTEM && errno != 0)
return strerror(errno);
return gai_strerror(gaierr);
}
/* disable nagle on socket */
void
set_nodelay(int fd)
{
int opt;
socklen_t optlen;
optlen = sizeof opt;
if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
debug("getsockopt TCP_NODELAY: %.100s", strerror(errno));
return;
}
if (opt == 1) {
debug2("fd %d is TCP_NODELAY", fd);
return;
}
opt = 1;
debug2("fd %d setting TCP_NODELAY", fd);
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
}
/* Allow local port reuse in TIME_WAIT */
int
set_reuseaddr(int fd)
{
int on = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno));
return -1;
}
return 0;
}
/* Get/set routing domain */
char *
get_rdomain(int fd)
{
#if defined(HAVE_SYS_GET_RDOMAIN)
return sys_get_rdomain(fd);
#elif defined(__OpenBSD__)
int rtable;
char *ret;
socklen_t len = sizeof(rtable);
if (getsockopt(fd, SOL_SOCKET, SO_RTABLE, &rtable, &len) == -1) {
error("Failed to get routing domain for fd %d: %s",
fd, strerror(errno));
return NULL;
}
xasprintf(&ret, "%d", rtable);
return ret;
#else /* defined(__OpenBSD__) */
return NULL;
#endif
}
int
set_rdomain(int fd, const char *name)
{
#if defined(HAVE_SYS_SET_RDOMAIN)
return sys_set_rdomain(fd, name);
#elif defined(__OpenBSD__)
int rtable;
const char *errstr;
if (name == NULL)
return 0; /* default table */
rtable = (int)strtonum(name, 0, 255, &errstr);
if (errstr != NULL) {
/* Shouldn't happen */
error("Invalid routing domain \"%s\": %s", name, errstr);
return -1;
}
if (setsockopt(fd, SOL_SOCKET, SO_RTABLE,
&rtable, sizeof(rtable)) == -1) {
error("Failed to set routing domain %d on fd %d: %s",
rtable, fd, strerror(errno));
return -1;
}
return 0;
#else /* defined(__OpenBSD__) */
error("Setting routing domain is not supported on this platform");
return -1;
#endif
}
int
get_sock_af(int fd)
{
struct sockaddr_storage to;
socklen_t tolen = sizeof(to);
memset(&to, 0, sizeof(to));
if (getsockname(fd, (struct sockaddr *)&to, &tolen) == -1)
return -1;
#ifdef IPV4_IN_IPV6
if (to.ss_family == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&to)->sin6_addr))
return AF_INET;
#endif
return to.ss_family;
}
void
set_sock_tos(int fd, int tos)
{
#ifndef IP_TOS_IS_BROKEN
int af;
switch ((af = get_sock_af(fd))) {
case -1:
/* assume not a socket */
break;
case AF_INET:
# ifdef IP_TOS
debug3_f("set socket %d IP_TOS 0x%02x", fd, tos);
if (setsockopt(fd, IPPROTO_IP, IP_TOS,
&tos, sizeof(tos)) == -1) {
error("setsockopt socket %d IP_TOS %d: %s:",
fd, tos, strerror(errno));
}
# endif /* IP_TOS */
break;
case AF_INET6:
# ifdef IPV6_TCLASS
debug3_f("set socket %d IPV6_TCLASS 0x%02x", fd, tos);
if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS,
&tos, sizeof(tos)) == -1) {
error("setsockopt socket %d IPV6_TCLASS %d: %.100s:",
fd, tos, strerror(errno));
}
# endif /* IPV6_TCLASS */
break;
default:
debug2_f("unsupported socket family %d", af);
break;
}
#endif /* IP_TOS_IS_BROKEN */
}
/*
* Wait up to *timeoutp milliseconds for events on fd. Updates
* *timeoutp with time remaining.
* Returns 0 if fd ready or -1 on timeout or error (see errno).
*/
static int
waitfd(int fd, int *timeoutp, short events)
{
struct pollfd pfd;
struct timeval t_start;
int oerrno, r;
pfd.fd = fd;
pfd.events = events;
for (; *timeoutp >= 0;) {
monotime_tv(&t_start);
r = poll(&pfd, 1, *timeoutp);
oerrno = errno;
ms_subtract_diff(&t_start, timeoutp);
errno = oerrno;
if (r > 0)
return 0;
else if (r == -1 && errno != EAGAIN && errno != EINTR)
return -1;
else if (r == 0)
break;
}
/* timeout */
errno = ETIMEDOUT;
return -1;
}
/*
* Wait up to *timeoutp milliseconds for fd to be readable. Updates
* *timeoutp with time remaining.
* Returns 0 if fd ready or -1 on timeout or error (see errno).
*/
int
waitrfd(int fd, int *timeoutp) {
return waitfd(fd, timeoutp, POLLIN);
}
/*
* Attempt a non-blocking connect(2) to the specified address, waiting up to
* *timeoutp milliseconds for the connection to complete. If the timeout is
* <=0, then wait indefinitely.
*
* Returns 0 on success or -1 on failure.
*/
int
timeout_connect(int sockfd, const struct sockaddr *serv_addr,
socklen_t addrlen, int *timeoutp)
{
int optval = 0;
socklen_t optlen = sizeof(optval);
/* No timeout: just do a blocking connect() */
if (timeoutp == NULL || *timeoutp <= 0)
return connect(sockfd, serv_addr, addrlen);
set_nonblock(sockfd);
for (;;) {
if (connect(sockfd, serv_addr, addrlen) == 0) {
/* Succeeded already? */
unset_nonblock(sockfd);
return 0;
} else if (errno == EINTR)
continue;
else if (errno != EINPROGRESS)
return -1;
break;
}
if (waitfd(sockfd, timeoutp, POLLIN | POLLOUT) == -1)
return -1;
/* Completed or failed */
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1) {
debug("getsockopt: %s", strerror(errno));
return -1;
}
if (optval != 0) {
errno = optval;
return -1;
}
unset_nonblock(sockfd);
return 0;
}
/* Characters considered whitespace in strsep calls. */
#define WHITESPACE " \t\r\n"
#define QUOTE "\""
/* return next token in configuration line */
static char *
strdelim_internal(char **s, int split_equals)
{
char *old;
int wspace = 0;
if (*s == NULL)
return NULL;
old = *s;
*s = strpbrk(*s,
split_equals ? WHITESPACE QUOTE "=" : WHITESPACE QUOTE);
if (*s == NULL)
return (old);
if (*s[0] == '\"') {
memmove(*s, *s + 1, strlen(*s)); /* move nul too */
/* Find matching quote */
if ((*s = strpbrk(*s, QUOTE)) == NULL) {
return (NULL); /* no matching quote */
} else {
*s[0] = '\0';
*s += strspn(*s + 1, WHITESPACE) + 1;
return (old);
}
}
/* Allow only one '=' to be skipped */
if (split_equals && *s[0] == '=')
wspace = 1;
*s[0] = '\0';
/* Skip any extra whitespace after first token */
*s += strspn(*s + 1, WHITESPACE) + 1;
if (split_equals && *s[0] == '=' && !wspace)
*s += strspn(*s + 1, WHITESPACE) + 1;
return (old);
}
/*
* Return next token in configuration line; splts on whitespace or a
* single '=' character.
*/
char *
strdelim(char **s)
{
return strdelim_internal(s, 1);
}
/*
* Return next token in configuration line; splts on whitespace only.
*/
char *
strdelimw(char **s)
{
return strdelim_internal(s, 0);
}
struct passwd *
pwcopy(struct passwd *pw)
{
struct passwd *copy = xcalloc(1, sizeof(*copy));
copy->pw_name = xstrdup(pw->pw_name);
copy->pw_passwd = xstrdup(pw->pw_passwd);
#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
copy->pw_gecos = xstrdup(pw->pw_gecos);
#endif
copy->pw_uid = pw->pw_uid;
copy->pw_gid = pw->pw_gid;
#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
copy->pw_expire = pw->pw_expire;
#endif
#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
copy->pw_change = pw->pw_change;
#endif
#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
copy->pw_class = xstrdup(pw->pw_class);
#endif
copy->pw_dir = xstrdup(pw->pw_dir);
copy->pw_shell = xstrdup(pw->pw_shell);
return copy;
}
/*
* Convert ASCII string to TCP/IP port number.
* Port must be >=0 and <=65535.
* Return -1 if invalid.
*/
int
a2port(const char *s)
{
struct servent *se;
long long port;
const char *errstr;
port = strtonum(s, 0, 65535, &errstr);
if (errstr == NULL)
return (int)port;
if ((se = getservbyname(s, "tcp")) != NULL)
return ntohs(se->s_port);
return -1;
}
int
a2tun(const char *s, int *remote)
{
const char *errstr = NULL;
char *sp, *ep;
int tun;
if (remote != NULL) {
*remote = SSH_TUNID_ANY;
sp = xstrdup(s);
if ((ep = strchr(sp, ':')) == NULL) {
free(sp);
return (a2tun(s, NULL));
}
ep[0] = '\0'; ep++;
*remote = a2tun(ep, NULL);
tun = a2tun(sp, NULL);
free(sp);
return (*remote == SSH_TUNID_ERR ? *remote : tun);
}
if (strcasecmp(s, "any") == 0)
return (SSH_TUNID_ANY);
tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr);
if (errstr != NULL)
return (SSH_TUNID_ERR);
return (tun);
}
#define SECONDS 1
#define MINUTES (SECONDS * 60)
#define HOURS (MINUTES * 60)
#define DAYS (HOURS * 24)
#define WEEKS (DAYS * 7)
/*
* Convert a time string into seconds; format is
* a sequence of:
* time[qualifier]
*
* Valid time qualifiers are:
* <none> seconds
* s|S seconds
* m|M minutes
* h|H hours
* d|D days
* w|W weeks
*
* Examples:
* 90m 90 minutes
* 1h30m 90 minutes
* 2d 2 days
* 1w 1 week
*
* Return -1 if time string is invalid.
*/
int
convtime(const char *s)
{
long total, secs, multiplier;
const char *p;
char *endp;
errno = 0;
total = 0;
p = s;
if (p == NULL || *p == '\0')
return -1;
while (*p) {
secs = strtol(p, &endp, 10);
if (p == endp ||
(errno == ERANGE && (secs == INT_MIN || secs == INT_MAX)) ||
secs < 0)
return -1;
multiplier = 1;
switch (*endp++) {
case '\0':
endp--;
break;
case 's':
case 'S':
break;
case 'm':
case 'M':
multiplier = MINUTES;
break;
case 'h':
case 'H':
multiplier = HOURS;
break;
case 'd':
case 'D':
multiplier = DAYS;
break;
case 'w':
case 'W':
multiplier = WEEKS;
break;
default:
return -1;
}
if (secs > INT_MAX / multiplier)
return -1;
secs *= multiplier;
if (total > INT_MAX - secs)
return -1;
total += secs;
if (total < 0)
return -1;
p = endp;
}
return total;
}
#define TF_BUFS 8
#define TF_LEN 9
const char *
fmt_timeframe(time_t t)
{
char *buf;
static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */
static int idx = 0;
unsigned int sec, min, hrs, day;
unsigned long long week;
buf = tfbuf[idx++];
if (idx == TF_BUFS)
idx = 0;
week = t;
sec = week % 60;
week /= 60;
min = week % 60;
week /= 60;
hrs = week % 24;
week /= 24;
day = week % 7;
week /= 7;
if (week > 0)
snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs);
else if (day > 0)
snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
else
snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
return (buf);
}
/*
* Returns a standardized host+port identifier string.
* Caller must free returned string.
*/
char *
put_host_port(const char *host, u_short port)
{
char *hoststr;
if (port == 0 || port == SSH_DEFAULT_PORT)
return(xstrdup(host));
if (asprintf(&hoststr, "[%s]:%d", host, (int)port) == -1)
fatal("put_host_port: asprintf: %s", strerror(errno));
debug3("put_host_port: %s", hoststr);
return hoststr;
}
/*
* Search for next delimiter between hostnames/addresses and ports.
* Argument may be modified (for termination).
* Returns *cp if parsing succeeds.
* *cp is set to the start of the next field, if one was found.
* The delimiter char, if present, is stored in delim.
* If this is the last field, *cp is set to NULL.
*/
char *
hpdelim2(char **cp, char *delim)
{
char *s, *old;
if (cp == NULL || *cp == NULL)
return NULL;
old = s = *cp;
if (*s == '[') {
if ((s = strchr(s, ']')) == NULL)
return NULL;
else
s++;
} else if ((s = strpbrk(s, ":/")) == NULL)
s = *cp + strlen(*cp); /* skip to end (see first case below) */
switch (*s) {
case '\0':
*cp = NULL; /* no more fields*/
break;
case ':':
case '/':
if (delim != NULL)
*delim = *s;
*s = '\0'; /* terminate */
*cp = s + 1;
break;
default:
return NULL;
}
return old;
}
char *
hpdelim(char **cp)
{
return hpdelim2(cp, NULL);
}
char *
cleanhostname(char *host)
{
if (*host == '[' && host[strlen(host) - 1] == ']') {
host[strlen(host) - 1] = '\0';
return (host + 1);
} else
return host;
}
char *
colon(char *cp)
{
int flag = 0;
if (*cp == ':') /* Leading colon is part of file name. */
return NULL;
if (*cp == '[')
flag = 1;
for (; *cp; ++cp) {
if (*cp == '@' && *(cp+1) == '[')
flag = 1;
if (*cp == ']' && *(cp+1) == ':' && flag)
return (cp+1);
if (*cp == ':' && !flag)
return (cp);
if (*cp == '/')
return NULL;
}
return NULL;
}
/*
* Parse a [user@]host:[path] string.
* Caller must free returned user, host and path.
* Any of the pointer return arguments may be NULL (useful for syntax checking).
* If user was not specified then *userp will be set to NULL.
* If host was not specified then *hostp will be set to NULL.
* If path was not specified then *pathp will be set to ".".
* Returns 0 on success, -1 on failure.
*/
int
parse_user_host_path(const char *s, char **userp, char **hostp, char **pathp)
{
char *user = NULL, *host = NULL, *path = NULL;
char *sdup, *tmp;
int ret = -1;
if (userp != NULL)
*userp = NULL;
if (hostp != NULL)
*hostp = NULL;
if (pathp != NULL)
*pathp = NULL;
sdup = xstrdup(s);
/* Check for remote syntax: [user@]host:[path] */
if ((tmp = colon(sdup)) == NULL)
goto out;
/* Extract optional path */
*tmp++ = '\0';
if (*tmp == '\0')
tmp = ".";
path = xstrdup(tmp);
/* Extract optional user and mandatory host */
tmp = strrchr(sdup, '@');
if (tmp != NULL) {
*tmp++ = '\0';
host = xstrdup(cleanhostname(tmp));
if (*sdup != '\0')
user = xstrdup(sdup);
} else {
host = xstrdup(cleanhostname(sdup));
user = NULL;
}
/* Success */
if (userp != NULL) {
*userp = user;
user = NULL;
}
if (hostp != NULL) {
*hostp = host;
host = NULL;
}
if (pathp != NULL) {
*pathp = path;
path = NULL;
}
ret = 0;
out:
free(sdup);
free(user);
free(host);
free(path);
return ret;
}
/*
* Parse a [user@]host[:port] string.
* Caller must free returned user and host.
* Any of the pointer return arguments may be NULL (useful for syntax checking).
* If user was not specified then *userp will be set to NULL.
* If port was not specified then *portp will be -1.
* Returns 0 on success, -1 on failure.
*/
int
parse_user_host_port(const char *s, char **userp, char **hostp, int *portp)
{
char *sdup, *cp, *tmp;
char *user = NULL, *host = NULL;
int port = -1, ret = -1;
if (userp != NULL)
*userp = NULL;
if (hostp != NULL)
*hostp = NULL;
if (portp != NULL)
*portp = -1;
if ((sdup = tmp = strdup(s)) == NULL)
return -1;
/* Extract optional username */
if ((cp = strrchr(tmp, '@')) != NULL) {
*cp = '\0';
if (*tmp == '\0')
goto out;
if ((user = strdup(tmp)) == NULL)
goto out;
tmp = cp + 1;
}
/* Extract mandatory hostname */
if ((cp = hpdelim(&tmp)) == NULL || *cp == '\0')
goto out;
host = xstrdup(cleanhostname(cp));
/* Convert and verify optional port */
if (tmp != NULL && *tmp != '\0') {
if ((port = a2port(tmp)) <= 0)
goto out;
}
/* Success */
if (userp != NULL) {
*userp = user;
user = NULL;
}
if (hostp != NULL) {
*hostp = host;
host = NULL;
}
if (portp != NULL)
*portp = port;
ret = 0;
out:
free(sdup);
free(user);
free(host);
return ret;
}
/*
* Converts a two-byte hex string to decimal.
* Returns the decimal value or -1 for invalid input.
*/
static int
hexchar(const char *s)
{
unsigned char result[2];
int i;
for (i = 0; i < 2; i++) {
if (s[i] >= '0' && s[i] <= '9')
result[i] = (unsigned char)(s[i] - '0');
else if (s[i] >= 'a' && s[i] <= 'f')
result[i] = (unsigned char)(s[i] - 'a') + 10;
else if (s[i] >= 'A' && s[i] <= 'F')
result[i] = (unsigned char)(s[i] - 'A') + 10;
else
return -1;
}
return (result[0] << 4) | result[1];
}
/*
* Decode an url-encoded string.
* Returns a newly allocated string on success or NULL on failure.
*/
static char *
urldecode(const char *src)
{
char *ret, *dst;
int ch;
ret = xmalloc(strlen(src) + 1);
for (dst = ret; *src != '\0'; src++) {
switch (*src) {
case '+':
*dst++ = ' ';
break;
case '%':
if (!isxdigit((unsigned char)src[1]) ||
!isxdigit((unsigned char)src[2]) ||
(ch = hexchar(src + 1)) == -1) {
free(ret);
return NULL;
}
*dst++ = ch;
src += 2;
break;
default:
*dst++ = *src;
break;
}
}
*dst = '\0';
return ret;
}
/*
* Parse an (scp|ssh|sftp)://[user@]host[:port][/path] URI.
* See https://tools.ietf.org/html/draft-ietf-secsh-scp-sftp-ssh-uri-04
* Either user or path may be url-encoded (but not host or port).
* Caller must free returned user, host and path.
* Any of the pointer return arguments may be NULL (useful for syntax checking)
* but the scheme must always be specified.
* If user was not specified then *userp will be set to NULL.
* If port was not specified then *portp will be -1.
* If path was not specified then *pathp will be set to NULL.
* Returns 0 on success, 1 if non-uri/wrong scheme, -1 on error/invalid uri.
*/
int
parse_uri(const char *scheme, const char *uri, char **userp, char **hostp,
int *portp, char **pathp)
{
char *uridup, *cp, *tmp, ch;
char *user = NULL, *host = NULL, *path = NULL;
int port = -1, ret = -1;
size_t len;
len = strlen(scheme);
if (strncmp(uri, scheme, len) != 0 || strncmp(uri + len, "://", 3) != 0)
return 1;
uri += len + 3;
if (userp != NULL)
*userp = NULL;
if (hostp != NULL)
*hostp = NULL;
if (portp != NULL)
*portp = -1;
if (pathp != NULL)
*pathp = NULL;
uridup = tmp = xstrdup(uri);
/* Extract optional ssh-info (username + connection params) */
if ((cp = strchr(tmp, '@')) != NULL) {
char *delim;
*cp = '\0';
/* Extract username and connection params */
if ((delim = strchr(tmp, ';')) != NULL) {
/* Just ignore connection params for now */
*delim = '\0';
}
if (*tmp == '\0') {
/* Empty username */
goto out;
}
if ((user = urldecode(tmp)) == NULL)
goto out;
tmp = cp + 1;
}
/* Extract mandatory hostname */
if ((cp = hpdelim2(&tmp, &ch)) == NULL || *cp == '\0')
goto out;
host = xstrdup(cleanhostname(cp));
if (!valid_domain(host, 0, NULL))
goto out;
if (tmp != NULL && *tmp != '\0') {
if (ch == ':') {
/* Convert and verify port. */
if ((cp = strchr(tmp, '/')) != NULL)
*cp = '\0';
if ((port = a2port(tmp)) <= 0)
goto out;
tmp = cp ? cp + 1 : NULL;
}
if (tmp != NULL && *tmp != '\0') {
/* Extract optional path */
if ((path = urldecode(tmp)) == NULL)
goto out;
}
}
/* Success */
if (userp != NULL) {
*userp = user;
user = NULL;
}
if (hostp != NULL) {
*hostp = host;
host = NULL;
}
if (portp != NULL)
*portp = port;
if (pathp != NULL) {
*pathp = path;
path = NULL;
}
ret = 0;
out:
free(uridup);
free(user);
free(host);
free(path);
return ret;
}
/* function to assist building execv() arguments */
void
addargs(arglist *args, char *fmt, ...)
{
va_list ap;
char *cp;
u_int nalloc;
int r;
va_start(ap, fmt);
r = vasprintf(&cp, fmt, ap);
va_end(ap);
if (r == -1)
fatal("addargs: argument too long");
nalloc = args->nalloc;
if (args->list == NULL) {
nalloc = 32;
args->num = 0;
} else if (args->num+2 >= nalloc)
nalloc *= 2;
args->list = xrecallocarray(args->list, args->nalloc, nalloc, sizeof(char *));
args->nalloc = nalloc;
args->list[args->num++] = cp;
args->list[args->num] = NULL;
}
void
replacearg(arglist *args, u_int which, char *fmt, ...)
{
va_list ap;
char *cp;
int r;
va_start(ap, fmt);
r = vasprintf(&cp, fmt, ap);
va_end(ap);
if (r == -1)
fatal("replacearg: argument too long");
if (which >= args->num)
fatal("replacearg: tried to replace invalid arg %d >= %d",
which, args->num);
free(args->list[which]);
args->list[which] = cp;
}
void
freeargs(arglist *args)
{
u_int i;
if (args->list != NULL) {
for (i = 0; i < args->num; i++)
free(args->list[i]);
free(args->list);
args->nalloc = args->num = 0;
args->list = NULL;
}
}
/*
* Expands tildes in the file name. Returns data allocated by xmalloc.
* Warning: this calls getpw*.
*/
char *
tilde_expand_filename(const char *filename, uid_t uid)
{
const char *path, *sep;
char user[128], *ret;
struct passwd *pw;
u_int len, slash;
if (*filename != '~')
return (xstrdup(filename));
filename++;
path = strchr(filename, '/');
if (path != NULL && path > filename) { /* ~user/path */
slash = path - filename;
if (slash > sizeof(user) - 1)
fatal("tilde_expand_filename: ~username too long");
memcpy(user, filename, slash);
user[slash] = '\0';
if ((pw = getpwnam(user)) == NULL)
fatal("tilde_expand_filename: No such user %s", user);
} else if ((pw = getpwuid(uid)) == NULL) /* ~/path */
fatal("tilde_expand_filename: No such uid %ld", (long)uid);
/* Make sure directory has a trailing '/' */
len = strlen(pw->pw_dir);
if (len == 0 || pw->pw_dir[len - 1] != '/')
sep = "/";
else
sep = "";
/* Skip leading '/' from specified path */
if (path != NULL)
filename = path + 1;
if (xasprintf(&ret, "%s%s%s", pw->pw_dir, sep, filename) >= PATH_MAX)
fatal("tilde_expand_filename: Path too long");
return (ret);
}
/*
* Expand a string with a set of %[char] escapes and/or ${ENVIRONMENT}
* substitutions. A number of escapes may be specified as
* (char *escape_chars, char *replacement) pairs. The list must be terminated
* by a NULL escape_char. Returns replaced string in memory allocated by
* xmalloc which the caller must free.
*/
static char *
vdollar_percent_expand(int *parseerror, int dollar, int percent,
const char *string, va_list ap)
{
#define EXPAND_MAX_KEYS 16
u_int num_keys = 0, i;
struct {
const char *key;
const char *repl;
} keys[EXPAND_MAX_KEYS];
struct sshbuf *buf;
int r, missingvar = 0;
char *ret = NULL, *var, *varend, *val;
size_t len;
if ((buf = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if (parseerror == NULL)
fatal_f("null parseerror arg");
*parseerror = 1;
/* Gather keys if we're doing percent expansion. */
if (percent) {
for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
keys[num_keys].key = va_arg(ap, char *);
if (keys[num_keys].key == NULL)
break;
keys[num_keys].repl = va_arg(ap, char *);
if (keys[num_keys].repl == NULL) {
fatal_f("NULL replacement for token %s",
keys[num_keys].key);
}
}
if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
fatal_f("too many keys");
if (num_keys == 0)
fatal_f("percent expansion without token list");
}
/* Expand string */
for (i = 0; *string != '\0'; string++) {
/* Optionally process ${ENVIRONMENT} expansions. */
if (dollar && string[0] == '$' && string[1] == '{') {
string += 2; /* skip over '${' */
if ((varend = strchr(string, '}')) == NULL) {
error_f("environment variable '%s' missing "
- "closing '}'", string);
+ "closing '}'", string);
goto out;
}
len = varend - string;
if (len == 0) {
error_f("zero-length environment variable");
goto out;
}
var = xmalloc(len + 1);
(void)strlcpy(var, string, len + 1);
if ((val = getenv(var)) == NULL) {
error_f("env var ${%s} has no value", var);
missingvar = 1;
} else {
debug3_f("expand ${%s} -> '%s'", var, val);
if ((r = sshbuf_put(buf, val, strlen(val))) !=0)
fatal_fr(r, "sshbuf_put ${}");
}
free(var);
string += len;
continue;
}
/*
* Process percent expansions if we have a list of TOKENs.
* If we're not doing percent expansion everything just gets
* appended here.
*/
if (*string != '%' || !percent) {
append:
if ((r = sshbuf_put_u8(buf, *string)) != 0)
fatal_fr(r, "sshbuf_put_u8 %%");
continue;
}
string++;
/* %% case */
if (*string == '%')
goto append;
if (*string == '\0') {
error_f("invalid format");
goto out;
}
for (i = 0; i < num_keys; i++) {
if (strchr(keys[i].key, *string) != NULL) {
if ((r = sshbuf_put(buf, keys[i].repl,
strlen(keys[i].repl))) != 0)
fatal_fr(r, "sshbuf_put %%-repl");
break;
}
}
if (i >= num_keys) {
error_f("unknown key %%%c", *string);
goto out;
}
}
if (!missingvar && (ret = sshbuf_dup_string(buf)) == NULL)
fatal_f("sshbuf_dup_string failed");
*parseerror = 0;
out:
sshbuf_free(buf);
return *parseerror ? NULL : ret;
#undef EXPAND_MAX_KEYS
}
/*
* Expand only environment variables.
* Note that although this function is variadic like the other similar
* functions, any such arguments will be unused.
*/
char *
dollar_expand(int *parseerr, const char *string, ...)
{
char *ret;
int err;
va_list ap;
va_start(ap, string);
ret = vdollar_percent_expand(&err, 1, 0, string, ap);
va_end(ap);
if (parseerr != NULL)
*parseerr = err;
return ret;
}
/*
* Returns expanded string or NULL if a specified environment variable is
* not defined, or calls fatal if the string is invalid.
*/
char *
percent_expand(const char *string, ...)
{
char *ret;
int err;
va_list ap;
va_start(ap, string);
ret = vdollar_percent_expand(&err, 0, 1, string, ap);
va_end(ap);
if (err)
fatal_f("failed");
return ret;
}
/*
* Returns expanded string or NULL if a specified environment variable is
* not defined, or calls fatal if the string is invalid.
*/
char *
percent_dollar_expand(const char *string, ...)
{
char *ret;
int err;
va_list ap;
va_start(ap, string);
ret = vdollar_percent_expand(&err, 1, 1, string, ap);
va_end(ap);
if (err)
fatal_f("failed");
return ret;
}
int
tun_open(int tun, int mode, char **ifname)
{
#if defined(CUSTOM_SYS_TUN_OPEN)
return (sys_tun_open(tun, mode, ifname));
#elif defined(SSH_TUN_OPENBSD)
struct ifreq ifr;
char name[100];
int fd = -1, sock;
const char *tunbase = "tun";
if (ifname != NULL)
*ifname = NULL;
if (mode == SSH_TUNMODE_ETHERNET)
tunbase = "tap";
/* Open the tunnel device */
if (tun <= SSH_TUNID_MAX) {
snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun);
fd = open(name, O_RDWR);
} else if (tun == SSH_TUNID_ANY) {
for (tun = 100; tun >= 0; tun--) {
snprintf(name, sizeof(name), "/dev/%s%d",
tunbase, tun);
if ((fd = open(name, O_RDWR)) >= 0)
break;
}
} else {
debug_f("invalid tunnel %u", tun);
return -1;
}
if (fd == -1) {
debug_f("%s open: %s", name, strerror(errno));
return -1;
}
debug_f("%s mode %d fd %d", name, mode, fd);
/* Bring interface up if it is not already */
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun);
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
goto failed;
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) {
debug_f("get interface %s flags: %s", ifr.ifr_name,
strerror(errno));
goto failed;
}
if (!(ifr.ifr_flags & IFF_UP)) {
ifr.ifr_flags |= IFF_UP;
if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
debug_f("activate interface %s: %s", ifr.ifr_name,
strerror(errno));
goto failed;
}
}
if (ifname != NULL)
*ifname = xstrdup(ifr.ifr_name);
close(sock);
return fd;
failed:
if (fd >= 0)
close(fd);
if (sock >= 0)
close(sock);
return -1;
#else
error("Tunnel interfaces are not supported on this platform");
return (-1);
#endif
}
void
sanitise_stdfd(void)
{
int nullfd, dupfd;
if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
fprintf(stderr, "Couldn't open /dev/null: %s\n",
strerror(errno));
exit(1);
}
while (++dupfd <= STDERR_FILENO) {
/* Only populate closed fds. */
if (fcntl(dupfd, F_GETFL) == -1 && errno == EBADF) {
if (dup2(nullfd, dupfd) == -1) {
fprintf(stderr, "dup2: %s\n", strerror(errno));
exit(1);
}
}
}
if (nullfd > STDERR_FILENO)
close(nullfd);
}
char *
tohex(const void *vp, size_t l)
{
const u_char *p = (const u_char *)vp;
char b[3], *r;
size_t i, hl;
if (l > 65536)
return xstrdup("tohex: length > 65536");
hl = l * 2 + 1;
r = xcalloc(1, hl);
for (i = 0; i < l; i++) {
snprintf(b, sizeof(b), "%02x", p[i]);
strlcat(r, b, hl);
}
return (r);
}
/*
* Extend string *sp by the specified format. If *sp is not NULL (or empty),
* then the separator 'sep' will be prepended before the formatted arguments.
* Extended strings are heap allocated.
*/
void
xextendf(char **sp, const char *sep, const char *fmt, ...)
{
va_list ap;
char *tmp1, *tmp2;
va_start(ap, fmt);
xvasprintf(&tmp1, fmt, ap);
va_end(ap);
if (*sp == NULL || **sp == '\0') {
free(*sp);
*sp = tmp1;
return;
}
xasprintf(&tmp2, "%s%s%s", *sp, sep == NULL ? "" : sep, tmp1);
free(tmp1);
free(*sp);
*sp = tmp2;
}
u_int64_t
get_u64(const void *vp)
{
const u_char *p = (const u_char *)vp;
u_int64_t v;
v = (u_int64_t)p[0] << 56;
v |= (u_int64_t)p[1] << 48;
v |= (u_int64_t)p[2] << 40;
v |= (u_int64_t)p[3] << 32;
v |= (u_int64_t)p[4] << 24;
v |= (u_int64_t)p[5] << 16;
v |= (u_int64_t)p[6] << 8;
v |= (u_int64_t)p[7];
return (v);
}
u_int32_t
get_u32(const void *vp)
{
const u_char *p = (const u_char *)vp;
u_int32_t v;
v = (u_int32_t)p[0] << 24;
v |= (u_int32_t)p[1] << 16;
v |= (u_int32_t)p[2] << 8;
v |= (u_int32_t)p[3];
return (v);
}
u_int32_t
get_u32_le(const void *vp)
{
const u_char *p = (const u_char *)vp;
u_int32_t v;
v = (u_int32_t)p[0];
v |= (u_int32_t)p[1] << 8;
v |= (u_int32_t)p[2] << 16;
v |= (u_int32_t)p[3] << 24;
return (v);
}
u_int16_t
get_u16(const void *vp)
{
const u_char *p = (const u_char *)vp;
u_int16_t v;
v = (u_int16_t)p[0] << 8;
v |= (u_int16_t)p[1];
return (v);
}
void
put_u64(void *vp, u_int64_t v)
{
u_char *p = (u_char *)vp;
p[0] = (u_char)(v >> 56) & 0xff;
p[1] = (u_char)(v >> 48) & 0xff;
p[2] = (u_char)(v >> 40) & 0xff;
p[3] = (u_char)(v >> 32) & 0xff;
p[4] = (u_char)(v >> 24) & 0xff;
p[5] = (u_char)(v >> 16) & 0xff;
p[6] = (u_char)(v >> 8) & 0xff;
p[7] = (u_char)v & 0xff;
}
void
put_u32(void *vp, u_int32_t v)
{
u_char *p = (u_char *)vp;
p[0] = (u_char)(v >> 24) & 0xff;
p[1] = (u_char)(v >> 16) & 0xff;
p[2] = (u_char)(v >> 8) & 0xff;
p[3] = (u_char)v & 0xff;
}
void
put_u32_le(void *vp, u_int32_t v)
{
u_char *p = (u_char *)vp;
p[0] = (u_char)v & 0xff;
p[1] = (u_char)(v >> 8) & 0xff;
p[2] = (u_char)(v >> 16) & 0xff;
p[3] = (u_char)(v >> 24) & 0xff;
}
void
put_u16(void *vp, u_int16_t v)
{
u_char *p = (u_char *)vp;
p[0] = (u_char)(v >> 8) & 0xff;
p[1] = (u_char)v & 0xff;
}
void
ms_subtract_diff(struct timeval *start, int *ms)
{
struct timeval diff, finish;
monotime_tv(&finish);
timersub(&finish, start, &diff);
*ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
}
void
ms_to_timeval(struct timeval *tv, int ms)
{
if (ms < 0)
ms = 0;
tv->tv_sec = ms / 1000;
tv->tv_usec = (ms % 1000) * 1000;
}
void
monotime_ts(struct timespec *ts)
{
struct timeval tv;
#if defined(HAVE_CLOCK_GETTIME) && (defined(CLOCK_BOOTTIME) || \
defined(CLOCK_MONOTONIC) || defined(CLOCK_REALTIME))
static int gettime_failed = 0;
if (!gettime_failed) {
# ifdef CLOCK_BOOTTIME
if (clock_gettime(CLOCK_BOOTTIME, ts) == 0)
return;
# endif /* CLOCK_BOOTTIME */
# ifdef CLOCK_MONOTONIC
if (clock_gettime(CLOCK_MONOTONIC, ts) == 0)
return;
# endif /* CLOCK_MONOTONIC */
# ifdef CLOCK_REALTIME
/* Not monotonic, but we're almost out of options here. */
if (clock_gettime(CLOCK_REALTIME, ts) == 0)
return;
# endif /* CLOCK_REALTIME */
debug3("clock_gettime: %s", strerror(errno));
gettime_failed = 1;
}
#endif /* HAVE_CLOCK_GETTIME && (BOOTTIME || MONOTONIC || REALTIME) */
gettimeofday(&tv, NULL);
ts->tv_sec = tv.tv_sec;
ts->tv_nsec = (long)tv.tv_usec * 1000;
}
void
monotime_tv(struct timeval *tv)
{
struct timespec ts;
monotime_ts(&ts);
tv->tv_sec = ts.tv_sec;
tv->tv_usec = ts.tv_nsec / 1000;
}
time_t
monotime(void)
{
struct timespec ts;
monotime_ts(&ts);
return ts.tv_sec;
}
double
monotime_double(void)
{
struct timespec ts;
monotime_ts(&ts);
return ts.tv_sec + ((double)ts.tv_nsec / 1000000000);
}
void
bandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen)
{
bw->buflen = buflen;
bw->rate = kbps;
bw->thresh = buflen;
bw->lamt = 0;
timerclear(&bw->bwstart);
timerclear(&bw->bwend);
}
/* Callback from read/write loop to insert bandwidth-limiting delays */
void
bandwidth_limit(struct bwlimit *bw, size_t read_len)
{
u_int64_t waitlen;
struct timespec ts, rm;
bw->lamt += read_len;
if (!timerisset(&bw->bwstart)) {
monotime_tv(&bw->bwstart);
return;
}
if (bw->lamt < bw->thresh)
return;
monotime_tv(&bw->bwend);
timersub(&bw->bwend, &bw->bwstart, &bw->bwend);
if (!timerisset(&bw->bwend))
return;
bw->lamt *= 8;
waitlen = (double)1000000L * bw->lamt / bw->rate;
bw->bwstart.tv_sec = waitlen / 1000000L;
bw->bwstart.tv_usec = waitlen % 1000000L;
if (timercmp(&bw->bwstart, &bw->bwend, >)) {
timersub(&bw->bwstart, &bw->bwend, &bw->bwend);
/* Adjust the wait time */
if (bw->bwend.tv_sec) {
bw->thresh /= 2;
if (bw->thresh < bw->buflen / 4)
bw->thresh = bw->buflen / 4;
} else if (bw->bwend.tv_usec < 10000) {
bw->thresh *= 2;
if (bw->thresh > bw->buflen * 8)
bw->thresh = bw->buflen * 8;
}
TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts);
while (nanosleep(&ts, &rm) == -1) {
if (errno != EINTR)
break;
ts = rm;
}
}
bw->lamt = 0;
monotime_tv(&bw->bwstart);
}
/* Make a template filename for mk[sd]temp() */
void
mktemp_proto(char *s, size_t len)
{
const char *tmpdir;
int r;
if ((tmpdir = getenv("TMPDIR")) != NULL) {
r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir);
if (r > 0 && (size_t)r < len)
return;
}
r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX");
if (r < 0 || (size_t)r >= len)
fatal_f("template string too short");
}
static const struct {
const char *name;
int value;
} ipqos[] = {
{ "none", INT_MAX }, /* can't use 0 here; that's CS0 */
{ "af11", IPTOS_DSCP_AF11 },
{ "af12", IPTOS_DSCP_AF12 },
{ "af13", IPTOS_DSCP_AF13 },
{ "af21", IPTOS_DSCP_AF21 },
{ "af22", IPTOS_DSCP_AF22 },
{ "af23", IPTOS_DSCP_AF23 },
{ "af31", IPTOS_DSCP_AF31 },
{ "af32", IPTOS_DSCP_AF32 },
{ "af33", IPTOS_DSCP_AF33 },
{ "af41", IPTOS_DSCP_AF41 },
{ "af42", IPTOS_DSCP_AF42 },
{ "af43", IPTOS_DSCP_AF43 },
{ "cs0", IPTOS_DSCP_CS0 },
{ "cs1", IPTOS_DSCP_CS1 },
{ "cs2", IPTOS_DSCP_CS2 },
{ "cs3", IPTOS_DSCP_CS3 },
{ "cs4", IPTOS_DSCP_CS4 },
{ "cs5", IPTOS_DSCP_CS5 },
{ "cs6", IPTOS_DSCP_CS6 },
{ "cs7", IPTOS_DSCP_CS7 },
{ "ef", IPTOS_DSCP_EF },
{ "le", IPTOS_DSCP_LE },
{ "lowdelay", IPTOS_LOWDELAY },
{ "throughput", IPTOS_THROUGHPUT },
{ "reliability", IPTOS_RELIABILITY },
{ NULL, -1 }
};
int
parse_ipqos(const char *cp)
{
u_int i;
char *ep;
long val;
if (cp == NULL)
return -1;
for (i = 0; ipqos[i].name != NULL; i++) {
if (strcasecmp(cp, ipqos[i].name) == 0)
return ipqos[i].value;
}
/* Try parsing as an integer */
val = strtol(cp, &ep, 0);
if (*cp == '\0' || *ep != '\0' || val < 0 || val > 255)
return -1;
return val;
}
const char *
iptos2str(int iptos)
{
int i;
static char iptos_str[sizeof "0xff"];
for (i = 0; ipqos[i].name != NULL; i++) {
if (ipqos[i].value == iptos)
return ipqos[i].name;
}
snprintf(iptos_str, sizeof iptos_str, "0x%02x", iptos);
return iptos_str;
}
void
lowercase(char *s)
{
for (; *s; s++)
*s = tolower((u_char)*s);
}
int
unix_listener(const char *path, int backlog, int unlink_first)
{
struct sockaddr_un sunaddr;
int saved_errno, sock;
memset(&sunaddr, 0, sizeof(sunaddr));
sunaddr.sun_family = AF_UNIX;
if (strlcpy(sunaddr.sun_path, path,
sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) {
error_f("path \"%s\" too long for Unix domain socket", path);
errno = ENAMETOOLONG;
return -1;
}
sock = socket(PF_UNIX, SOCK_STREAM, 0);
if (sock == -1) {
saved_errno = errno;
error_f("socket: %.100s", strerror(errno));
errno = saved_errno;
return -1;
}
if (unlink_first == 1) {
if (unlink(path) != 0 && errno != ENOENT)
error("unlink(%s): %.100s", path, strerror(errno));
}
if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
saved_errno = errno;
error_f("cannot bind to path %s: %s", path, strerror(errno));
close(sock);
errno = saved_errno;
return -1;
}
if (listen(sock, backlog) == -1) {
saved_errno = errno;
error_f("cannot listen on path %s: %s", path, strerror(errno));
close(sock);
unlink(path);
errno = saved_errno;
return -1;
}
return sock;
}
void
sock_set_v6only(int s)
{
#if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
int on = 1;
debug3("%s: set socket %d IPV6_V6ONLY", __func__, s);
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1)
error("setsockopt IPV6_V6ONLY: %s", strerror(errno));
#endif
}
/*
* Compares two strings that maybe be NULL. Returns non-zero if strings
* are both NULL or are identical, returns zero otherwise.
*/
static int
strcmp_maybe_null(const char *a, const char *b)
{
if ((a == NULL && b != NULL) || (a != NULL && b == NULL))
return 0;
if (a != NULL && strcmp(a, b) != 0)
return 0;
return 1;
}
/*
* Compare two forwards, returning non-zero if they are identical or
* zero otherwise.
*/
int
forward_equals(const struct Forward *a, const struct Forward *b)
{
if (strcmp_maybe_null(a->listen_host, b->listen_host) == 0)
return 0;
if (a->listen_port != b->listen_port)
return 0;
if (strcmp_maybe_null(a->listen_path, b->listen_path) == 0)
return 0;
if (strcmp_maybe_null(a->connect_host, b->connect_host) == 0)
return 0;
if (a->connect_port != b->connect_port)
return 0;
if (strcmp_maybe_null(a->connect_path, b->connect_path) == 0)
return 0;
/* allocated_port and handle are not checked */
return 1;
}
/* returns 1 if process is already daemonized, 0 otherwise */
int
daemonized(void)
{
int fd;
if ((fd = open(_PATH_TTY, O_RDONLY | O_NOCTTY)) >= 0) {
close(fd);
return 0; /* have controlling terminal */
}
if (getppid() != 1)
return 0; /* parent is not init */
if (getsid(0) != getpid())
return 0; /* not session leader */
debug3("already daemonized");
return 1;
}
/*
* Splits 's' into an argument vector. Handles quoted string and basic
* escape characters (\\, \", \'). Caller must free the argument vector
* and its members.
*/
int
argv_split(const char *s, int *argcp, char ***argvp)
{
int r = SSH_ERR_INTERNAL_ERROR;
int argc = 0, quote, i, j;
char *arg, **argv = xcalloc(1, sizeof(*argv));
*argvp = NULL;
*argcp = 0;
for (i = 0; s[i] != '\0'; i++) {
/* Skip leading whitespace */
if (s[i] == ' ' || s[i] == '\t')
continue;
/* Start of a token */
quote = 0;
- if (s[i] == '\\' &&
- (s[i + 1] == '\'' || s[i + 1] == '\"' || s[i + 1] == '\\'))
- i++;
- else if (s[i] == '\'' || s[i] == '"')
- quote = s[i++];
argv = xreallocarray(argv, (argc + 2), sizeof(*argv));
arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1);
argv[argc] = NULL;
/* Copy the token in, removing escapes */
for (j = 0; s[i] != '\0'; i++) {
if (s[i] == '\\') {
if (s[i + 1] == '\'' ||
s[i + 1] == '\"' ||
s[i + 1] == '\\') {
i++; /* Skip '\' */
arg[j++] = s[i];
} else {
/* Unrecognised escape */
arg[j++] = s[i];
}
} else if (quote == 0 && (s[i] == ' ' || s[i] == '\t'))
break; /* done */
+ else if (quote == 0 && (s[i] == '\"' || s[i] == '\''))
+ quote = s[i]; /* quote start */
else if (quote != 0 && s[i] == quote)
- break; /* done */
+ quote = 0; /* quote end */
else
arg[j++] = s[i];
}
if (s[i] == '\0') {
if (quote != 0) {
/* Ran out of string looking for close quote */
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
break;
}
}
/* Success */
*argcp = argc;
*argvp = argv;
argc = 0;
argv = NULL;
r = 0;
out:
if (argc != 0 && argv != NULL) {
for (i = 0; i < argc; i++)
free(argv[i]);
free(argv);
}
return r;
}
/*
* Reassemble an argument vector into a string, quoting and escaping as
* necessary. Caller must free returned string.
*/
char *
argv_assemble(int argc, char **argv)
{
int i, j, ws, r;
char c, *ret;
struct sshbuf *buf, *arg;
if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
for (i = 0; i < argc; i++) {
ws = 0;
sshbuf_reset(arg);
for (j = 0; argv[i][j] != '\0'; j++) {
r = 0;
c = argv[i][j];
switch (c) {
case ' ':
case '\t':
ws = 1;
r = sshbuf_put_u8(arg, c);
break;
case '\\':
case '\'':
case '"':
if ((r = sshbuf_put_u8(arg, '\\')) != 0)
break;
/* FALLTHROUGH */
default:
r = sshbuf_put_u8(arg, c);
break;
}
if (r != 0)
fatal_fr(r, "sshbuf_put_u8");
}
if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) ||
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) ||
(r = sshbuf_putb(buf, arg)) != 0 ||
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0))
fatal_fr(r, "assemble");
}
if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL)
fatal_f("malloc failed");
memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf));
ret[sshbuf_len(buf)] = '\0';
sshbuf_free(buf);
sshbuf_free(arg);
return ret;
}
/* Returns 0 if pid exited cleanly, non-zero otherwise */
int
exited_cleanly(pid_t pid, const char *tag, const char *cmd, int quiet)
{
int status;
while (waitpid(pid, &status, 0) == -1) {
if (errno != EINTR) {
error("%s waitpid: %s", tag, strerror(errno));
return -1;
}
}
if (WIFSIGNALED(status)) {
error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status));
return -1;
} else if (WEXITSTATUS(status) != 0) {
do_log2(quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO,
"%s %s failed, status %d", tag, cmd, WEXITSTATUS(status));
return -1;
}
return 0;
}
/*
* Check a given path for security. This is defined as all components
* of the path to the file must be owned by either the owner of
* of the file or root and no directories must be group or world writable.
*
* XXX Should any specific check be done for sym links ?
*
* Takes a file name, its stat information (preferably from fstat() to
* avoid races), the uid of the expected owner, their home directory and an
* error buffer plus max size as arguments.
*
* Returns 0 on success and -1 on failure
*/
int
safe_path(const char *name, struct stat *stp, const char *pw_dir,
uid_t uid, char *err, size_t errlen)
{
char buf[PATH_MAX], homedir[PATH_MAX];
char *cp;
int comparehome = 0;
struct stat st;
if (realpath(name, buf) == NULL) {
snprintf(err, errlen, "realpath %s failed: %s", name,
strerror(errno));
return -1;
}
if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
comparehome = 1;
if (!S_ISREG(stp->st_mode)) {
snprintf(err, errlen, "%s is not a regular file", buf);
return -1;
}
if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
(stp->st_mode & 022) != 0) {
snprintf(err, errlen, "bad ownership or modes for file %s",
buf);
return -1;
}
/* for each component of the canonical path, walking upwards */
for (;;) {
if ((cp = dirname(buf)) == NULL) {
snprintf(err, errlen, "dirname() failed");
return -1;
}
strlcpy(buf, cp, sizeof(buf));
if (stat(buf, &st) == -1 ||
(!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) ||
(st.st_mode & 022) != 0) {
snprintf(err, errlen,
"bad ownership or modes for directory %s", buf);
return -1;
}
/* If are past the homedir then we can stop */
if (comparehome && strcmp(homedir, buf) == 0)
break;
/*
* dirname should always complete with a "/" path,
* but we can be paranoid and check for "." too
*/
if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
break;
}
return 0;
}
/*
* Version of safe_path() that accepts an open file descriptor to
* avoid races.
*
* Returns 0 on success and -1 on failure
*/
int
safe_path_fd(int fd, const char *file, struct passwd *pw,
char *err, size_t errlen)
{
struct stat st;
/* check the open file to avoid races */
if (fstat(fd, &st) == -1) {
snprintf(err, errlen, "cannot stat file %s: %s",
file, strerror(errno));
return -1;
}
return safe_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
}
/*
* Sets the value of the given variable in the environment. If the variable
* already exists, its value is overridden.
*/
void
child_set_env(char ***envp, u_int *envsizep, const char *name,
const char *value)
{
char **env;
u_int envsize;
u_int i, namelen;
if (strchr(name, '=') != NULL) {
error("Invalid environment variable \"%.100s\"", name);
return;
}
/*
* If we're passed an uninitialized list, allocate a single null
* entry before continuing.
*/
if (*envp == NULL && *envsizep == 0) {
*envp = xmalloc(sizeof(char *));
*envp[0] = NULL;
*envsizep = 1;
}
/*
* Find the slot where the value should be stored. If the variable
* already exists, we reuse the slot; otherwise we append a new slot
* at the end of the array, expanding if necessary.
*/
env = *envp;
namelen = strlen(name);
for (i = 0; env[i]; i++)
if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
break;
if (env[i]) {
/* Reuse the slot. */
free(env[i]);
} else {
/* New variable. Expand if necessary. */
envsize = *envsizep;
if (i >= envsize - 1) {
if (envsize >= 1000)
fatal("child_set_env: too many env vars");
envsize += 50;
env = (*envp) = xreallocarray(env, envsize, sizeof(char *));
*envsizep = envsize;
}
/* Need to set the NULL pointer at end of array beyond the new slot. */
env[i + 1] = NULL;
}
/* Allocate space and format the variable in the appropriate slot. */
/* XXX xasprintf */
env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
}
/*
* Check and optionally lowercase a domain name, also removes trailing '.'
* Returns 1 on success and 0 on failure, storing an error message in errstr.
*/
int
valid_domain(char *name, int makelower, const char **errstr)
{
size_t i, l = strlen(name);
u_char c, last = '\0';
static char errbuf[256];
if (l == 0) {
strlcpy(errbuf, "empty domain name", sizeof(errbuf));
goto bad;
}
if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0])) {
snprintf(errbuf, sizeof(errbuf), "domain name \"%.100s\" "
"starts with invalid character", name);
goto bad;
}
for (i = 0; i < l; i++) {
c = tolower((u_char)name[i]);
if (makelower)
name[i] = (char)c;
if (last == '.' && c == '.') {
snprintf(errbuf, sizeof(errbuf), "domain name "
"\"%.100s\" contains consecutive separators", name);
goto bad;
}
if (c != '.' && c != '-' && !isalnum(c) &&
c != '_') /* technically invalid, but common */ {
snprintf(errbuf, sizeof(errbuf), "domain name "
"\"%.100s\" contains invalid characters", name);
goto bad;
}
last = c;
}
if (name[l - 1] == '.')
name[l - 1] = '\0';
if (errstr != NULL)
*errstr = NULL;
return 1;
bad:
if (errstr != NULL)
*errstr = errbuf;
return 0;
}
/*
* Verify that a environment variable name (not including initial '$') is
* valid; consisting of one or more alphanumeric or underscore characters only.
* Returns 1 on valid, 0 otherwise.
*/
int
valid_env_name(const char *name)
{
const char *cp;
if (name[0] == '\0')
return 0;
for (cp = name; *cp != '\0'; cp++) {
if (!isalnum((u_char)*cp) && *cp != '_')
return 0;
}
return 1;
}
const char *
atoi_err(const char *nptr, int *val)
{
const char *errstr = NULL;
long long num;
if (nptr == NULL || *nptr == '\0')
return "missing";
num = strtonum(nptr, 0, INT_MAX, &errstr);
if (errstr == NULL)
*val = (int)num;
return errstr;
}
int
parse_absolute_time(const char *s, uint64_t *tp)
{
struct tm tm;
time_t tt;
char buf[32], *fmt;
*tp = 0;
/*
* POSIX strptime says "The application shall ensure that there
* is white-space or other non-alphanumeric characters between
* any two conversion specifications" so arrange things this way.
*/
switch (strlen(s)) {
case 8: /* YYYYMMDD */
fmt = "%Y-%m-%d";
snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6);
break;
case 12: /* YYYYMMDDHHMM */
fmt = "%Y-%m-%dT%H:%M";
snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s",
s, s + 4, s + 6, s + 8, s + 10);
break;
case 14: /* YYYYMMDDHHMMSS */
fmt = "%Y-%m-%dT%H:%M:%S";
snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s",
s, s + 4, s + 6, s + 8, s + 10, s + 12);
break;
default:
return SSH_ERR_INVALID_FORMAT;
}
memset(&tm, 0, sizeof(tm));
if (strptime(buf, fmt, &tm) == NULL)
return SSH_ERR_INVALID_FORMAT;
if ((tt = mktime(&tm)) < 0)
return SSH_ERR_INVALID_FORMAT;
/* success */
*tp = (uint64_t)tt;
return 0;
}
void
format_absolute_time(uint64_t t, char *buf, size_t len)
{
time_t tt = t > INT_MAX ? INT_MAX : t; /* XXX revisit in 2038 :P */
struct tm tm;
localtime_r(&tt, &tm);
strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm);
}
/* check if path is absolute */
int
path_absolute(const char *path)
{
return (*path == '/') ? 1 : 0;
}
void
skip_space(char **cpp)
{
char *cp;
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
;
*cpp = cp;
}
/* authorized_key-style options parsing helpers */
/*
* Match flag 'opt' in *optsp, and if allow_negate is set then also match
* 'no-opt'. Returns -1 if option not matched, 1 if option matches or 0
* if negated option matches.
* If the option or negated option matches, then *optsp is updated to
* point to the first character after the option.
*/
int
opt_flag(const char *opt, int allow_negate, const char **optsp)
{
size_t opt_len = strlen(opt);
const char *opts = *optsp;
int negate = 0;
if (allow_negate && strncasecmp(opts, "no-", 3) == 0) {
opts += 3;
negate = 1;
}
if (strncasecmp(opts, opt, opt_len) == 0) {
*optsp = opts + opt_len;
return negate ? 0 : 1;
}
return -1;
}
char *
opt_dequote(const char **sp, const char **errstrp)
{
const char *s = *sp;
char *ret;
size_t i;
*errstrp = NULL;
if (*s != '"') {
*errstrp = "missing start quote";
return NULL;
}
s++;
if ((ret = malloc(strlen((s)) + 1)) == NULL) {
*errstrp = "memory allocation failed";
return NULL;
}
for (i = 0; *s != '\0' && *s != '"';) {
if (s[0] == '\\' && s[1] == '"')
s++;
ret[i++] = *s++;
}
if (*s == '\0') {
*errstrp = "missing end quote";
free(ret);
return NULL;
}
ret[i] = '\0';
s++;
*sp = s;
return ret;
}
int
opt_match(const char **opts, const char *term)
{
if (strncasecmp((*opts), term, strlen(term)) == 0 &&
(*opts)[strlen(term)] == '=') {
*opts += strlen(term) + 1;
return 1;
}
return 0;
}
void
opt_array_append2(const char *file, const int line, const char *directive,
char ***array, int **iarray, u_int *lp, const char *s, int i)
{
if (*lp >= INT_MAX)
fatal("%s line %d: Too many %s entries", file, line, directive);
if (iarray != NULL) {
*iarray = xrecallocarray(*iarray, *lp, *lp + 1,
sizeof(**iarray));
(*iarray)[*lp] = i;
}
*array = xrecallocarray(*array, *lp, *lp + 1, sizeof(**array));
(*array)[*lp] = xstrdup(s);
(*lp)++;
}
void
opt_array_append(const char *file, const int line, const char *directive,
char ***array, u_int *lp, const char *s)
{
opt_array_append2(file, line, directive, array, NULL, lp, s, 0);
}
sshsig_t
ssh_signal(int signum, sshsig_t handler)
{
struct sigaction sa, osa;
/* mask all other signals while in handler */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sigfillset(&sa.sa_mask);
#if defined(SA_RESTART) && !defined(NO_SA_RESTART)
if (signum != SIGALRM)
sa.sa_flags = SA_RESTART;
#endif
if (sigaction(signum, &sa, &osa) == -1) {
debug3("sigaction(%s): %s", strsignal(signum), strerror(errno));
return SIG_ERR;
}
return osa.sa_handler;
}
int
stdfd_devnull(int do_stdin, int do_stdout, int do_stderr)
{
int devnull, ret = 0;
if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
error_f("open %s: %s", _PATH_DEVNULL,
strerror(errno));
return -1;
}
if ((do_stdin && dup2(devnull, STDIN_FILENO) == -1) ||
(do_stdout && dup2(devnull, STDOUT_FILENO) == -1) ||
(do_stderr && dup2(devnull, STDERR_FILENO) == -1)) {
error_f("dup2: %s", strerror(errno));
ret = -1;
}
if (devnull > STDERR_FILENO)
close(devnull);
return ret;
}
/*
* Runs command in a subprocess with a minimal environment.
* Returns pid on success, 0 on failure.
* The child stdout and stderr maybe captured, left attached or sent to
* /dev/null depending on the contents of flags.
* "tag" is prepended to log messages.
* NB. "command" is only used for logging; the actual command executed is
* av[0].
*/
pid_t
subprocess(const char *tag, const char *command,
int ac, char **av, FILE **child, u_int flags,
struct passwd *pw, privdrop_fn *drop_privs, privrestore_fn *restore_privs)
{
FILE *f = NULL;
struct stat st;
int fd, devnull, p[2], i;
pid_t pid;
char *cp, errmsg[512];
u_int nenv = 0;
char **env = NULL;
/* If dropping privs, then must specify user and restore function */
if (drop_privs != NULL && (pw == NULL || restore_privs == NULL)) {
error("%s: inconsistent arguments", tag); /* XXX fatal? */
return 0;
}
if (pw == NULL && (pw = getpwuid(getuid())) == NULL) {
error("%s: no user for current uid", tag);
return 0;
}
if (child != NULL)
*child = NULL;
debug3_f("%s command \"%s\" running as %s (flags 0x%x)",
tag, command, pw->pw_name, flags);
/* Check consistency */
if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 &&
(flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) {
error_f("inconsistent flags");
return 0;
}
if (((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) != (child == NULL)) {
error_f("inconsistent flags/output");
return 0;
}
/*
* If executing an explicit binary, then verify the it exists
* and appears safe-ish to execute
*/
if (!path_absolute(av[0])) {
error("%s path is not absolute", tag);
return 0;
}
if (drop_privs != NULL)
drop_privs(pw);
if (stat(av[0], &st) == -1) {
error("Could not stat %s \"%s\": %s", tag,
av[0], strerror(errno));
goto restore_return;
}
if ((flags & SSH_SUBPROCESS_UNSAFE_PATH) == 0 &&
safe_path(av[0], &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) {
error("Unsafe %s \"%s\": %s", tag, av[0], errmsg);
goto restore_return;
}
/* Prepare to keep the child's stdout if requested */
if (pipe(p) == -1) {
error("%s: pipe: %s", tag, strerror(errno));
restore_return:
if (restore_privs != NULL)
restore_privs();
return 0;
}
if (restore_privs != NULL)
restore_privs();
switch ((pid = fork())) {
case -1: /* error */
error("%s: fork: %s", tag, strerror(errno));
close(p[0]);
close(p[1]);
return 0;
case 0: /* child */
/* Prepare a minimal environment for the child. */
if ((flags & SSH_SUBPROCESS_PRESERVE_ENV) == 0) {
nenv = 5;
env = xcalloc(sizeof(*env), nenv);
child_set_env(&env, &nenv, "PATH", _PATH_STDPATH);
child_set_env(&env, &nenv, "USER", pw->pw_name);
child_set_env(&env, &nenv, "LOGNAME", pw->pw_name);
child_set_env(&env, &nenv, "HOME", pw->pw_dir);
if ((cp = getenv("LANG")) != NULL)
child_set_env(&env, &nenv, "LANG", cp);
}
for (i = 1; i < NSIG; i++)
ssh_signal(i, SIG_DFL);
if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
error("%s: open %s: %s", tag, _PATH_DEVNULL,
strerror(errno));
_exit(1);
}
if (dup2(devnull, STDIN_FILENO) == -1) {
error("%s: dup2: %s", tag, strerror(errno));
_exit(1);
}
/* Set up stdout as requested; leave stderr in place for now. */
fd = -1;
if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0)
fd = p[1];
else if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0)
fd = devnull;
if (fd != -1 && dup2(fd, STDOUT_FILENO) == -1) {
error("%s: dup2: %s", tag, strerror(errno));
_exit(1);
}
closefrom(STDERR_FILENO + 1);
if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) {
error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid,
strerror(errno));
_exit(1);
}
if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) {
error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid,
strerror(errno));
_exit(1);
}
/* stdin is pointed to /dev/null at this point */
if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 &&
dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
error("%s: dup2: %s", tag, strerror(errno));
_exit(1);
}
if (env != NULL)
execve(av[0], av, env);
else
execv(av[0], av);
error("%s %s \"%s\": %s", tag, env == NULL ? "execv" : "execve",
command, strerror(errno));
_exit(127);
default: /* parent */
break;
}
close(p[1]);
if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0)
close(p[0]);
else if ((f = fdopen(p[0], "r")) == NULL) {
error("%s: fdopen: %s", tag, strerror(errno));
close(p[0]);
/* Don't leave zombie child */
kill(pid, SIGTERM);
while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
;
return 0;
}
/* Success */
debug3_f("%s pid %ld", tag, (long)pid);
if (child != NULL)
*child = f;
return pid;
}
diff --git a/misc.h b/misc.h
index 2de7eb5bfae2..58914bd7f128 100644
--- a/misc.h
+++ b/misc.h
@@ -1,223 +1,224 @@
-/* $OpenBSD: misc.h,v 1.93 2021/02/15 20:36:35 markus Exp $ */
+/* $OpenBSD: misc.h,v 1.95 2021/04/03 06:18:40 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#ifndef _MISC_H
#define _MISC_H
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <stdio.h>
/* Data structure for representing a forwarding request. */
struct Forward {
char *listen_host; /* Host (address) to listen on. */
int listen_port; /* Port to forward. */
char *listen_path; /* Path to bind domain socket. */
char *connect_host; /* Host to connect. */
int connect_port; /* Port to connect on connect_host. */
char *connect_path; /* Path to connect domain socket. */
int allocated_port; /* Dynamically allocated listen port */
int handle; /* Handle for dynamic listen ports */
};
int forward_equals(const struct Forward *, const struct Forward *);
int daemonized(void);
/* Common server and client forwarding options. */
struct ForwardOptions {
int gateway_ports; /* Allow remote connects to forwarded ports. */
mode_t streamlocal_bind_mask; /* umask for streamlocal binds */
int streamlocal_bind_unlink; /* unlink socket before bind */
};
/* misc.c */
char *chop(char *);
void skip_space(char **);
char *strdelim(char **);
char *strdelimw(char **);
int set_nonblock(int);
int unset_nonblock(int);
void set_nodelay(int);
int set_reuseaddr(int);
char *get_rdomain(int);
int set_rdomain(int, const char *);
int get_sock_af(int);
void set_sock_tos(int, int);
int waitrfd(int, int *);
int timeout_connect(int, const struct sockaddr *, socklen_t, int *);
int a2port(const char *);
int a2tun(const char *, int *);
char *put_host_port(const char *, u_short);
char *hpdelim2(char **, char *);
char *hpdelim(char **);
char *cleanhostname(char *);
char *colon(char *);
int parse_user_host_path(const char *, char **, char **, char **);
int parse_user_host_port(const char *, char **, char **, int *);
int parse_uri(const char *, const char *, char **, char **, int *, char **);
int convtime(const char *);
const char *fmt_timeframe(time_t t);
char *tilde_expand_filename(const char *, uid_t);
char *dollar_expand(int *, const char *string, ...);
char *percent_expand(const char *, ...) __attribute__((__sentinel__));
char *percent_dollar_expand(const char *, ...) __attribute__((__sentinel__));
char *tohex(const void *, size_t);
void xextendf(char **s, const char *sep, const char *fmt, ...)
__attribute__((__format__ (printf, 3, 4))) __attribute__((__nonnull__ (3)));
void sanitise_stdfd(void);
void ms_subtract_diff(struct timeval *, int *);
void ms_to_timeval(struct timeval *, int);
void monotime_ts(struct timespec *);
void monotime_tv(struct timeval *);
time_t monotime(void);
double monotime_double(void);
void lowercase(char *s);
int unix_listener(const char *, int, int);
int valid_domain(char *, int, const char **);
int valid_env_name(const char *);
const char *atoi_err(const char *, int *);
int parse_absolute_time(const char *, uint64_t *);
void format_absolute_time(uint64_t, char *, size_t);
int path_absolute(const char *);
int stdfd_devnull(int, int, int);
void sock_set_v6only(int);
struct passwd *pwcopy(struct passwd *);
const char *ssh_gai_strerror(int);
typedef void privdrop_fn(struct passwd *);
typedef void privrestore_fn(void);
#define SSH_SUBPROCESS_STDOUT_DISCARD (1) /* Discard stdout */
#define SSH_SUBPROCESS_STDOUT_CAPTURE (1<<1) /* Redirect stdout */
#define SSH_SUBPROCESS_STDERR_DISCARD (1<<2) /* Discard stderr */
#define SSH_SUBPROCESS_UNSAFE_PATH (1<<3) /* Don't check for safe cmd */
#define SSH_SUBPROCESS_PRESERVE_ENV (1<<4) /* Keep parent environment */
pid_t subprocess(const char *, const char *, int, char **, FILE **, u_int,
struct passwd *, privdrop_fn *, privrestore_fn *);
typedef struct arglist arglist;
struct arglist {
char **list;
u_int num;
u_int nalloc;
};
void addargs(arglist *, char *, ...)
- __attribute__((format(printf, 2, 3)));
+ __attribute__((format(printf, 2, 3)));
void replacearg(arglist *, u_int, char *, ...)
- __attribute__((format(printf, 3, 4)));
+ __attribute__((format(printf, 3, 4)));
void freeargs(arglist *);
int tun_open(int, int, char **);
/* Common definitions for ssh tunnel device forwarding */
#define SSH_TUNMODE_NO 0x00
#define SSH_TUNMODE_POINTOPOINT 0x01
#define SSH_TUNMODE_ETHERNET 0x02
#define SSH_TUNMODE_DEFAULT SSH_TUNMODE_POINTOPOINT
#define SSH_TUNMODE_YES (SSH_TUNMODE_POINTOPOINT|SSH_TUNMODE_ETHERNET)
#define SSH_TUNID_ANY 0x7fffffff
#define SSH_TUNID_ERR (SSH_TUNID_ANY - 1)
#define SSH_TUNID_MAX (SSH_TUNID_ANY - 2)
/* Fake port to indicate that host field is really a path. */
#define PORT_STREAMLOCAL -2
/* Functions to extract or store big-endian words of various sizes */
u_int64_t get_u64(const void *)
__attribute__((__bounded__( __minbytes__, 1, 8)));
u_int32_t get_u32(const void *)
__attribute__((__bounded__( __minbytes__, 1, 4)));
u_int16_t get_u16(const void *)
__attribute__((__bounded__( __minbytes__, 1, 2)));
void put_u64(void *, u_int64_t)
__attribute__((__bounded__( __minbytes__, 1, 8)));
void put_u32(void *, u_int32_t)
__attribute__((__bounded__( __minbytes__, 1, 4)));
void put_u16(void *, u_int16_t)
__attribute__((__bounded__( __minbytes__, 1, 2)));
/* Little-endian store/load, used by umac.c */
u_int32_t get_u32_le(const void *)
__attribute__((__bounded__(__minbytes__, 1, 4)));
void put_u32_le(void *, u_int32_t)
__attribute__((__bounded__(__minbytes__, 1, 4)));
struct bwlimit {
size_t buflen;
u_int64_t rate; /* desired rate in kbit/s */
u_int64_t thresh; /* threshold after which we'll check timers */
u_int64_t lamt; /* amount written in last timer interval */
struct timeval bwstart, bwend;
};
void bandwidth_limit_init(struct bwlimit *, u_int64_t, size_t);
void bandwidth_limit(struct bwlimit *, size_t);
int parse_ipqos(const char *);
const char *iptos2str(int);
void mktemp_proto(char *, size_t);
void child_set_env(char ***envp, u_int *envsizep, const char *name,
- const char *value);
+ const char *value);
int argv_split(const char *, int *, char ***);
char *argv_assemble(int, char **argv);
int exited_cleanly(pid_t, const char *, const char *, int);
struct stat;
int safe_path(const char *, struct stat *, const char *, uid_t,
- char *, size_t);
+ char *, size_t);
int safe_path_fd(int, const char *, struct passwd *,
- char *err, size_t errlen);
+ char *err, size_t errlen);
/* authorized_key-style options parsing helpers */
int opt_flag(const char *opt, int allow_negate, const char **optsp);
char *opt_dequote(const char **sp, const char **errstrp);
int opt_match(const char **opts, const char *term);
/* readconf/servconf option lists */
void opt_array_append(const char *file, const int line,
const char *directive, char ***array, u_int *lp, const char *s);
void opt_array_append2(const char *file, const int line,
const char *directive, char ***array, int **iarray, u_int *lp,
const char *s, int i);
/* readpass.c */
#define RP_ECHO 0x0001
#define RP_ALLOW_STDIN 0x0002
#define RP_ALLOW_EOF 0x0004
#define RP_USE_ASKPASS 0x0008
struct notifier_ctx;
char *read_passphrase(const char *, int);
int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2)));
struct notifier_ctx *notify_start(int, const char *, ...)
__attribute__((format(printf, 2, 3)));
void notify_complete(struct notifier_ctx *, const char *, ...)
__attribute__((format(printf, 2, 3)));
#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
typedef void (*sshsig_t)(int);
sshsig_t ssh_signal(int, sshsig_t);
#endif /* _MISC_H */
diff --git a/moduli b/moduli
index 6103e989cefc..5b788a88385f 100644
--- a/moduli
+++ b/moduli
@@ -1,407 +1,447 @@
-# $OpenBSD: moduli,v 1.28 2020/09/30 09:11:38 dtucker Exp $
+# $OpenBSD: moduli,v 1.29 2021/03/10 06:32:27 dtucker Exp $
# Time Type Tests Tries Size Generator Modulus
-20200603013151 2 6 100 2047 5 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B598E0A26F
-20200603013238 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B5992253EB
-20200603013253 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59936A07B
-20200603013341 2 6 100 2047 5 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59979324F
-20200603013412 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B5999ADA8B
-20200603013518 2 6 100 2047 5 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59A02A39F
-20200603013530 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59A123243
-20200603013735 2 6 100 2047 5 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59AD6F947
-20200603013748 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59AE8D8E3
-20200603013933 2 6 100 2047 5 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59B86B667
-20200603014014 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59BBA6DEB
-20200603014054 2 6 100 2047 5 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59C01B8A7
-20200603014128 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59C29951B
-20200603014140 2 6 100 2047 5 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59C375247
-20200603014240 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59C962533
-20200603014320 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59CC3D1B3
-20200603014419 2 6 100 2047 5 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59D1CF107
-20200603014455 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59D5BEF33
-20200603014535 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59D8CD76B
-20200603014539 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59D8CEC9B
-20200603014547 2 6 100 2047 5 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59D94AC97
-20200603014600 2 6 100 2047 5 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59DA41237
-20200603014618 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59DAD23B3
-20200603014629 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59DB9A6AB
-20200603014640 2 6 100 2047 5 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59DC72D17
-20200603014646 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59DCA93E3
-20200603014713 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59DE24DDB
-20200603014735 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59E04C08B
-20200603014834 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59E5D24E3
-20200603015049 2 6 100 2047 5 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59F359287
-20200603015117 2 6 100 2047 5 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59F4EB0D7
-20200603015124 2 6 100 2047 5 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59F547E4F
-20200603015250 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B59FDE260B
-20200603015443 2 6 100 2047 5 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B5A088C767
-20200603015517 2 6 100 2047 2 C1B5AE12216BF36E172F949757150831C974F0D9589CAA6E6639754A321243ED9FF7846C2BEE736D420BB5A049A0E14EEB8A578C79B5482963D405610BF6F23FBEE7E4BFBF1FDA04EBC69CAEFB767366C057B2F1ECFAD374E5D7079EC99B1FDFB19177920DDFA0991354FF3603E184A05E7756025E7A856B5B80E5252036E8048180264DE4BD9D96C318332F7C20CE30CFBFEDE1CE02874FA4D05AE76F4767EA65999BCBE0BF7C46924671B181917E80B035EBE5DEF7263447CC0546B9CE0D38198C4A5B73DD6C82DB4DF902167166C05486FBE4EAA8A8096CC0465EC0A061D9C8DAB0B24AE58C5AD652A31233832E0FF90385BD62FBFE7D558B18B5A0ADBCE3
-20200603015616 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC1F54FE3
-20200603015632 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC20D92BB
-20200603015714 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC2466F63
-20200603015737 2 6 100 2047 5 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC26D42FF
-20200603015759 2 6 100 2047 5 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC290CFC7
-20200603015826 2 6 100 2047 5 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC2A9F777
-20200603015926 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC302E2AB
-20200603020047 2 6 100 2047 5 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC385317F
-20200603020153 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC3ED4683
-20200603020330 2 6 100 2047 5 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC47C42DF
-20200603020424 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC4C763EB
-20200603020516 2 6 100 2047 5 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC51127D7
-20200603020716 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC5C96ADB
-20200603020724 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC5D27F33
-20200603020757 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC608698B
-20200603020857 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC662C493
-20200603021019 2 6 100 2047 5 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC6CD731F
-20200603021029 2 6 100 2047 5 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC6D98B37
-20200603021126 2 6 100 2047 5 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC72C56AF
-20200603021137 2 6 100 2047 5 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC73B2487
-20200603021230 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC783A09B
-20200603021237 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC78AB273
-20200603021248 2 6 100 2047 5 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC79749E7
-20200603021336 2 6 100 2047 5 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC7D6F6C7
-20200603021349 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC7E7DE83
-20200603021433 2 6 100 2047 5 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC81FC717
-20200603021555 2 6 100 2047 5 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC8A2E197
-20200603021648 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC8EF5243
-20200603021748 2 6 100 2047 5 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC9466C5F
-20200603021817 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC962284B
-20200603021848 2 6 100 2047 2 CC80BBBF39CE11FCF95392238D15C8FDD1707D9F1DE408CF64661BD7C14D5BABD6A9D01F7EB2182781ADFB99C4DBBFB0071D129521E454B9C6921F5FBAE54B10342C246AFB288D93AF265CC213E0416C1E0CCBC279DD84AE7B6F56A6FA1D243A8719334B6D625C30012E2115114A40C2244B1AF7051B2FFB3BE46E7A291F49CE0B67C92F544BBC5DAEDA5DBABDA8CBDDE03AFEDFEF63D06B4787A4FB4A4666147A5A9469F7F37387493C7E64E75ABBB5CF94966E091EC529CAEB18481C109BC28003E779DABD1973006D2929B4A6DAA6AA14B1606D42C02AFB6357D16FE7F74109E6D15D47A7F135D11523698F648B28E8B4504711D7BA60096A6A7DC99760E3
-20200603024052 2 6 100 3071 5 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A91FDFFF9AF
-20200603024236 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A91FE2CF7AB
-20200603030816 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A9201780DFB
-20200603031241 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A9202073643
-20200603031336 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A92021B4CD3
-20200603031841 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A9202BDA763
-20200603032328 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A9203510ECB
-20200603032520 2 6 100 3071 5 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920388C3E7
-20200603032842 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A9203F56F83
-20200603033217 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920460103B
-20200603033521 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A9204BFC103
-20200603033736 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920502CC63
-20200603034230 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A92059BD8AB
-20200603034313 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A9205A947E3
-20200603034452 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A9205DD15C3
-20200603034648 2 6 100 3071 5 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920616CA47
-20200603035115 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A92069C9C2B
-20200603035225 2 6 100 3071 5 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A9206BB9E4F
-20200603035500 2 6 100 3071 5 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A92070DE93F
-20200603035636 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920737396B
-20200603040133 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A9207D5E89B
-20200603040227 2 6 100 3071 5 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A9207EC8EE7
-20200603040625 2 6 100 3071 5 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A9208640D27
-20200603041338 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920945B5AB
-20200603041419 2 6 100 3071 5 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920951AE07
-20200603041640 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920999446B
-20200603043156 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920B8735AB
-20200603043319 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920BA8BB73
-20200603043430 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920BC8D263
-20200603044252 2 6 100 3071 5 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920CD96A5F
-20200603044815 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920D7CF1BB
-20200603045034 2 6 100 3071 5 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920DC0D2E7
-20200603045100 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920DC9043B
-20200603045746 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920EA22D0B
-20200603045832 2 6 100 3071 2 ECFB72C76B880DAD52A24F83637D85C1B8B3093B51B9031D7890D582E25F700EB8ED2D3640F376A0F6A76FFD283EF55B9747F37C049BEF03F1D1B0B4FAD2B989D4FF02BD1A64AA734DF85A8AD94CC8D74BA8010B989416D2F169AF55EF984E592EA0D449DAF774A2536519623C079164FF5B703A0F429AEC32A42755E28B36E5F5848D14696A8491AF3784AA6945F73498FE2E6443ADE4E65909A863587DF150B5E9D960D9EEFBAF7BFCC768EBED9B2F79D3A1A365DAB065909A97132FC7354B446CCF9AA3A1BED03606C8D0F4DDDC4A862CA839E98754273191313F7BE1B5966F271FCFBEE91EEEAA83AE69A4D42D3B3FF57991AC9FE1B815F6CC366B5793E5CFFA9116FEC3C4D9B79F68D4B16B7945942B20B6AFE011B8687820BF257CB551B6591D84D4087C191907DE481D14C0815954416F98D3C677A2FDEDE4BB1C2DA18DA3BD1DC34958168F9C9336B805ECC25136246264FAE1B92540573F4DA8FC26D03DC3456ABCB5F289A8D3F81D1BD2510CB8035D1DB5C9C13F428A920EAFE143
-20200603050921 2 6 100 3071 5 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17EECACD1F
-20200603052247 2 6 100 3071 5 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F081C487
-20200603053129 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F1987E43
-20200603053245 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F1BC8503
-20200603053449 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F1F91A73
-20200603053857 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F27C8A43
-20200603053957 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F2955523
-20200603054803 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F394838B
-20200603055727 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F4BF9BE3
-20200603060437 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F5A887B3
-20200603060919 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F63DC10B
-20200603061739 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F74CFFCB
-20200603062124 2 6 100 3071 5 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F7BE3FD7
-20200603062244 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F7E219A3
-20200603062352 2 6 100 3071 5 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F800A877
-20200603062854 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F8A5CD2B
-20200603063441 2 6 100 3071 5 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F957937F
-20200603063639 2 6 100 3071 5 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17F98ED287
-20200603064225 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17FA46F36B
-20200603064300 2 6 100 3071 5 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17FA53E86F
-20200603064723 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17FAD9840B
-20200603065325 2 6 100 3071 5 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17FB991D57
-20200603065827 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17FC383623
-20200603065922 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17FC4B78A3
-20200603070014 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17FC5D3D33
-20200603070257 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17FCB2934B
-20200603070528 2 6 100 3071 5 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17FCF8C26F
-20200603070954 2 6 100 3071 5 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17FD83D0B7
-20200603071417 2 6 100 3071 5 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17FE089B4F
-20200603071755 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED17FE7F6E9B
-20200603073423 2 6 100 3071 2 E1D5789FC337053CEECF601ABA6CD8DC9625FAF3A8CBAFF40FB3C7B27FD61854C1E1D3D8D577F0FD466C911CA0550678F15A839C419F026ECE2B2C51828108F687DEEABF39748763AA1964D7F2D251756B10ECBDD78A1020B8E08AF0590A2E83661E53931ABD6A5193EB154051DE3B4329969AE835D7AB44C4E202C70FD202372384D4F3464ED486C85F1A3660B881923AC9B9C10733703F2BC7B76A04251E399D26EBA2AF41C76AD9FDA0C0BC63B0442E1A91239660B1B2A91885C7329A07E5EAA0B4727A793A0B2794F62E18FC3F563E89E91EA38FE55B0A9BF74FF6065CA7DFBAAC535384BCD7A19530B62ECC61979EB332C0677C600F128ECE2C38921814358AADFF5ECCE38761713D0537CAC626FF0D6DE6A58094451AE1ED53802170837EF38FA63FF3F3AF9989089B990D047E95A5AE436FBB00AD85D6B235B66FE21C8B19C2AAD7FEFC3132361210FDA9EEBABD0507CD95AF6079E29435626299064E793BCF766CD007C6442E67E035B779D7F2A756A02C6209C014A8ED180093BC73
-20200603081916 2 6 100 4095 5 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBB2D4D797
-20200603083145 2 6 100 4095 5 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBB388F177
-20200603083521 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBB3B5C34B
-20200603084043 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBB40162F3
-20200603084749 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBB4655173
-20200603092034 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBB64D516B
-20200603095055 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBB8176DB3
-20200603095144 2 6 100 4095 5 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBB81A12B7
-20200603095539 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBB84BE7E3
-20200603095824 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBB86B8F43
-20200603101512 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBB960938B
-20200603104916 2 6 100 4095 5 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBBB5FE757
-20200603105710 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBBBCCBA53
-20200603105827 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBBBD8F413
-20200603105917 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBBBDBA9EB
-20200603110729 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBBC4E8FFB
-20200603111137 2 6 100 4095 5 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBBC861FF7
-20200603111642 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBBCC73993
-20200603111836 2 6 100 4095 5 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBBCDAA5EF
-20200603113326 2 6 100 4095 5 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBBDB5695F
-20200603115340 2 6 100 4095 5 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBBEDE1F7F
-20200603120124 2 6 100 4095 5 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBBF484387
-20200603120350 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBBF66044B
-20200603122542 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBC0A9B2D3
-20200603123932 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBC1727CEB
-20200603130016 2 6 100 4095 5 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBC2A4BC9F
-20200603133721 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBC4C82B83
-20200603134150 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBC50278E3
-20200603134315 2 6 100 4095 5 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBC50E06EF
-20200603135758 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBC5E92E73
-20200603140431 2 6 100 4095 5 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBC641B467
-20200603141500 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBC6D1EF0B
-20200603142240 2 6 100 4095 5 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBC73D85CF
-20200603144519 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBC88AA813
-20200603152458 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBCAB4342B
-20200603154356 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBCBB51E33
-20200603155251 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBCC2FFA63
-20200603160553 2 6 100 4095 5 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBCCE8D70F
-20200603160829 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBCD05EF5B
-20200603164544 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBCF2AA323
-20200603164741 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBCF3E737B
-20200603170255 2 6 100 4095 2 FADB8928A550514C5D83CCCD98141A2A1EBC81D9B298AE4FB11CA19942682C2D72B29897BF77CA0A39B85130EAEB705C59BCBCB677FC6B08B7048FCFF55BFB6F1C6C44984002438FE3763B9342588649D2A79048975FCAF9C5BE658A3B73BA732768977A10565B597A1F3F58503384637A525369A00A4E50986780C66C8007D76523914FE52F7E4C479D86466A266317B8607665F49BE434643A528D177B57409ACBD387BCF8ED3609F8770933921F873F620771034774F41DDB33C3334747497F146529034F71563360B6778FD98614A67C6605D1D0540F10843516A3AF6E8F7DC81EE9EA3D61E8A6A54866E25EB6BEFAD1FEB08BBE2D3AF023471C249A6CE5112F3862F18A1DD3816298EAD7B9F064E243C01736866D06B1103C3FED190799DF25569F419019C98195D771DFF5FD82C01DB7883C3840B784F635F66B285116E4F84207930F0FCD05D8F07AAA3FAC67DAAE83B38F7AC1BDB719CBB1BAB1A735B567784BC7A3DD5A84C27C4F9443071AD03E4887A9354F2A4DDE965F4AF4325184857DC74A398AE4284777086CE88A7D0D20D2F23DB1CF4AD9D74A45719DC3162D50D27824283DAB31E7D58967E9F575F46F235733501200986AA4D0A94735F15330198EB804B39577F43E4F34D31385BA1D5B96A769BBA1616923421B8B277E26DEF215090EDB1174D99AAA7D3D1A2443D28EB5BF6E90A6C4E24BFBD016BC53
-20200603174159 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DDF71B183
-20200603175329 2 6 100 4095 5 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DE0166EB7
-20200603175916 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DE062F643
-20200603184324 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DE2FC12A3
-20200603184429 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DE3055C0B
-20200603185842 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DE3D8A083
-20200603192814 2 6 100 4095 5 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DE58A7357
-20200603193254 2 6 100 4095 5 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DE5CB2ABF
-20200603193621 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DE5F55FC3
-20200603200025 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DE75DAE53
-20200603201138 2 6 100 4095 5 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DE7FDB23F
-20200603202852 2 6 100 4095 5 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DE8FADA4F
-20200603203058 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DE914E293
-20200603203547 2 6 100 4095 5 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DE955F197
-20200603204018 2 6 100 4095 5 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DE990327F
-20200603214442 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DED4B6E1B
-20200603220036 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DEE2C08C3
-20200603222135 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DEF66B02B
-20200603222250 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DEF70AB3B
-20200603223212 2 6 100 4095 5 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DEFF51C3F
-20200603230927 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DF211A5D3
-20200603231319 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DF2433C9B
-20200603231528 2 6 100 4095 5 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DF25BCB27
-20200603231746 2 6 100 4095 5 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DF276CF2F
-20200603232250 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DF2BD6513
-20200603233720 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DF38497EB
-20200603235438 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DF47D8963
-20200604001143 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DF570FF3B
-20200604002250 2 6 100 4095 5 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DF60F878F
-20200604002438 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DF620B41B
-20200604055558 2 6 100 4095 5 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DFA633BBF
-20200604061051 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DFB397083
-20200604061554 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DFB7C2FDB
-20200604063226 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DFC65DF23
-20200604065024 2 6 100 4095 2 C313DC332CA881BD902A99A7D1BD21F3A30E3F7AB0CDFB5621C8040C10FCAE7B7CB62418B22FFE72A2010022D54C0D961ED8388D6B951A77F65CC83436C94D13AA701404ACAC2D205529444489AF0F6DBFD3BF9DFEE48ED180447017A5ED1BFA553B9307D6D8A7C5B9CEA439A293469433B5E42265D19DB8ABFD8C5A210ED8D0356FE9EBCEE90BE901A4485A621A5E76DE1D97A2F96E4BFF6BFC5A2E6D35F9294B1E9AD8A03EF4DE74B4474D7427F6D22D1D92D4308000D7D710A87C6005886BB5E09D8B5C6617C46BF3676B95DE7BBD8B4E9F600CF3D0D0692341FA0807451215C57AF94A0871D73564FEAAEF46B0B11440BE867734C7909523C48C31EB72BFFE4B4FBFDCAF6AE67E8D5EF5CC0FD343C3C7BA2058F666A9911C499EBAA19676D0911CC8ED919265EFB99ED650F88834EE52FE3FAB09D92F5B9B7A5B3C0B7682B9339416344913BE9851681E5941E92DC93AEF7D777C9A066D1B58EFC7D83573BC9030BDAC0C4FE2D6DD6C46CB53FC0790E198B62853DBE0DA046475292D627C2D71E8B0067F537EF9AD5BEA0070F873F840BD6ACD9BED642FB47C43A268C1E57EB16F7AA1DD6392025180C94606D6C2E5D9479DCE96DD90563A8897A237514953596B1319493BEBFD62F6F7FE94B0F1427A38B777ED1F98973740141F5E524F462BF20D7BF3B5F802FA1C071A5FD5E3FD6A35CFACF6D4351E4BF41DFD6980B3
-20200604082734 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB31F961E9F
-20200604084249 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB31FDC7AF3
-20200604091259 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB3206DC3DF
-20200604101647 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB321ACC813
-20200604103215 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB321F009F7
-20200604111534 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB322C70503
-20200604125038 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB324A52B33
-20200604170714 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB329B0AADF
-20200604201954 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB32D7E3A0F
-20200604225914 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB330A536DF
-20200604235825 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB331C4B13B
-20200605002513 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB3324381DF
-20200605020140 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB33424AE3F
-20200605174721 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB33BBFFA77
-20200605181350 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB33C39E413
-20200605211751 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB33FBA22CF
-20200605220744 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB340A69BAB
-20200605222038 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB340DC3917
-20200605224624 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB3414FBDF7
-20200606004552 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB343904617
-20200606010539 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB343E728E3
-20200606041215 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB34773F577
-20200606043519 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB347DDC483
-20200606060158 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB349792CCF
-20200606061048 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB349995E23
-20200606072525 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB34AFC43A3
-20200606110034 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB34EE5592B
-20200606132049 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB351770B4B
-20200606143556 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB352D19757
-20200606155651 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB3543BDFC7
-20200606165831 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB3554B535B
-20200606212229 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB359FD9073
-20200606220136 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB35AA7E8EB
-20200606223830 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB35B464AFF
-20200607002602 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB35D27674B
-20200607041439 2 6 100 6143 5 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB3612F4687
-20200607090802 2 6 100 6143 2 C023C230380A2DADB3604BF16B0820515CAC3A56D4C81478C7A7F2C2A9447DA4CBF5D0322D1BAF511FBB97BDB4B548B1D011DF098DA0129BD4600767F8B691D569A167CA70FE65DEEC95923C9E4749103769BE8A03C021153D1A90E65F5B48A480E10733DEDD1A122ED26636D60F553090AB3DBE65D5E8D8ABCAC5E55E84F2FA8440847DC1F5B01EAE345E50CCF88FC765BF392F2C296980BD89AB34F9A7347DDFEBAFB710CF9264B9E0E2DB8EB44B525028C595136E87E45947096BA64053B2FE9E3415FE32DF3068467044BB9DC36A70846D7659D153403F5B3B57DFABF4D0459A9CEA5BD3BFDEEC00714A9F333F016B425338C68CD639E2215D40C98CEFB3790F1ED1696A6FF63D656759678ABEED75227423A4DECB18CAD41253D73EAC54E5F078CF31B195E1E7277A8EF677EE41786B2CFF84C95964F830546808222AF588561556C214853836C8B6818BEE0D1934C38F5A01030F98F57A3FB9C951F752E04045B7ADDF367A6C173624A6F42FEB27FE01E932D2E02DF7C46E1B664EE05A531BCD219CF734A26D10F98BCC313F58CA03B97E78E6F6B8F51CB7A563244E22318CF371383E5B20C36831097C00BBDA9440AA528090B1AE9D3A49DDCEA29B458CF63E22307125205538629FCBBCF7166881C7C238869629DD1D153E429D2D6A77E1E8599D26F9EF7DA4C499256FFCB32E8D7E488038A00737C6896D16C50C243AACC6AF29D1BD2F86C56C5A5DA77CF2676AA5ACF2223529DAA33BC137E65D943C263FA98788481E82D58281A7681E6A9E2F645EF229A7FA7407F31E459CF96AF1AFDAE863FDBA1C0072BB970CFF30491816DBD8D54B2A7683C3BA968B49812611BC4A0DC437EA791BF202E030355D1C52466171CBEDDB06ECA66E891D6A6417F4E33D7F586FC6043F92A8C9C526270F0552F08CA46374AED948437216B84F474FE2A8869FC4121DAA099BEDE62BE7A234617132FB6C22E6ACF13C6E0AFEB18AB556682B5331ED7B280985B38A3FFF7DFCDEC7535887CB2F9042298EB5D1B18841282A4552EF9292A58011644619D72C294FA4AA3E4930FDC32DCDB3666D9ED3
-20200607105240 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C4651481AC9A3
-20200607133637 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46514B532A43
-20200607163856 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46514EDA94F3
-20200607192855 2 6 100 6143 5 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C465152143C87
-20200607195432 2 6 100 6143 5 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46515283AF8F
-20200607230617 2 6 100 6143 5 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46515617BC0F
-20200608012123 2 6 100 6143 5 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46515893FD67
-20200608021859 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C4651599AB89B
-20200608035721 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46515B642983
-20200608044119 2 6 100 6143 5 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46515C305197
-20200608063659 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46515E6DD31B
-20200608082941 2 6 100 6143 5 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C4651609244BF
-20200608110527 2 6 100 6143 5 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46516389D057
-20200608121159 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C465164C740DB
-20200608180046 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46516B604DCB
-20200608181840 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46516BAD8D9B
-20200608185332 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46516C4C7C13
-20200608191623 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46516CB2720B
-20200608222523 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C4651703AD573
-20200609002530 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46517274C703
-20200609024353 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C4651750D2B73
-20200609030451 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C465175677013
-20200609033613 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C465175F369F3
-20200609040050 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C465176620273
-20200609062156 2 6 100 6143 5 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C465178F038AF
-20200609070757 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C465179BF4683
-20200609094557 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46517C97C613
-20200609143727 2 6 100 6143 5 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C465181B85657
-20200609145622 2 6 100 6143 5 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46518205D68F
-20200609150740 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46518231FE23
-20200609230217 2 6 100 6143 5 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46518A94E1BF
-20200610010357 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46518CBBC813
-20200610013612 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46518D487AA3
-20200610014250 2 6 100 6143 2 C57F2CBC0C6147F572B0F48F4F8E26DABE9C61EB3DC99B6753A587B3C215984DAF3F996960C81C4B0DE94FA300D19F5373E4067CFDA4A885C57A30F412A1872ECC06BF86E74FA687836333C5A5C8AE8A0540D031EB84E11DEF9F08138D6D82321531829463B35F627979753D085580082D86C7B37C1AB72EA78333609505F508BE0C50347DF9E30D97FDFB6D9F6EC81174AD46695E913FED9AF505529ADB913FEA5795ED206275B356BB3718FC479DE36048F49619ED7ED09C1D43F1B74B7DA182B5D771987A5A0C5244B8379F966E3BF7E2053FF2055B67A4F42E8A4E16908DB847F5B9CF8801BB7031B03FC7041F67242E69D91C12BB5ED64C2FE5786D4A5F71E2DAC5A1E4860EC08D6D0769A26E6D6B03515DF82827C2BB6AD32A1B6F27AC7A3F8ECF39F4BA2B52A93E2606C31151B49E7B1830748B57C3E0B0CB5EB3F3AC15E13CFF02CFB10D75D37EA636BEA0924500879404F70628BD2950239996F409AD1F56F16443437184250D9C8BE3BC41B61407EE724BFE36D1B8C0D295B128AC3B279C2022B52CDFB6D24900789161048DC6123C21E5C1678F4B3B8D22CB4056CB1EF88C6CD8077BC19CEA36347DA42BC9442642A9227C06D3C2C8151F1DD501C50F4653131826C83F7220C15B5D0D967102DA6F9F565E6AA82E6086BDEF70A910646A90625E941CFD28B9ACF5CB9146A8E9ED55567A0037B5836AB354505357A0DE604A21ACC65A69C1FB52493F520F8CE8E307213DC83E72E1C996A8A2131EE08B863A31AA5E2431CE5D2051B3D3C713B76CAB9A396C885335422EDD2C7056AC91060EABCD70620BE7717C4C977C419D2B07A9D6D41E2FB5D698CCFD8B932E4748AC0120E35467BC774660CE678F04C64D59CAEF3112E7E1B766A2CF49D6B6C841131BBC42755899F5EB96BCB33AD4593B7EFD0E41A4B9517667F1305B9D9A84C9C9E9A4F1EA70CCC7649D63C2E611954F5A9DE6AA4C176FAF32044E268FC664B5378D314BC510D16B41A81C1342F902F295E68B7B16E3BB22CBEB3D59391EBEC058FCA8C9FB62D1E4FB9445706362C54EB804B89646A1A46C46518D5EFC23
-20200610044251 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A654DB7CCF
-20200610045738 2 6 100 7679 2 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A654FA9813
-20200610071715 2 6 100 7679 2 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A6567C3163
-20200610215424 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A65FFF83B7
-20200610224823 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A6608D79FF
-20200617060930 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A663CE8807
-20200617091256 2 6 100 7679 2 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A665DBFE4B
-20200617113153 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A6676B33F7
-20200617170511 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A66B179027
-20200617224324 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A66EDBCFA7
-20200618013140 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A670B46447
-20200618133142 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A678A89E8F
-20200619002228 2 6 100 7679 2 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A67FC1FBF3
-20200619052551 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A6830B759F
-20200620020539 2 6 100 7679 2 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A68A981AF3
-20200620090325 2 6 100 7679 2 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A68EFF0E13
-20200620190400 2 6 100 7679 2 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A6955464D3
-20200620192646 2 6 100 7679 2 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A69585D693
-20200620194126 2 6 100 7679 2 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A695A1BFA3
-20200620235757 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A698313E5F
-20200621064953 2 6 100 7679 2 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A69C626CE3
-20200623073839 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A6B44F5CDF
-20200623133511 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A6B7E45A07
-20200623163036 2 6 100 7679 2 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A6B9949D03
-20200623171631 2 6 100 7679 2 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A6BA0088F3
-20200623190013 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A6BAFE9BB7
-20200623200819 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A6BBA63F8F
-20200623233346 2 6 100 7679 2 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A6BDAF193B
-20200624020817 2 6 100 7679 5 D9BDD28997D5CC2F34E75DB842230C8FEC671AF277140D4FA40FAC7618EA985F1F139D1D841B2D700173C78CDA1C4E7F8DAC16978D221EBA202B0B031CE0A66DA50EB015F8043028E99D4FA6D28D0C19E13822826DC669C1EC83F1B1BEDEDB0BDE18C99679C0A5658D1AF3A45349B0FBB68032242B11A530B532EA98BCA093E5ABFABB04BCB9B54E69C998C8145DEA14B5C0DBFB954F729B7C773C31C66E16649B14CDAEF76F64D1CC85E820B0015E4BDAD3F88E7FEBD64B153B8C2F5B580E60F94DDC3D9B8651A7847DF8AC0A458187265B86B7C363FD98671688956EDCB44EA5972C041DA42D04E8EF460744576DBB25BFC5F14D4C657055D59E1A22942D700E3A29B23730FC475C595DCA4F83DC7106F2C9D290F78C5CA26700B6D39CB0B27C60A1F4B6F0F7E6AAF4E0B02F567652313BD5BE594972364E158C1FF57F2081257DFC04E9D3365906355495A2D1AD063D14FA7F6F374ACF8336F055F47140FEAC995957A776CE16573C53932E9D537A9AD4419F94C1A53912452D761D0652FCB9580CFBBD293A7EFC80FEF3632F850DBF631C61CFE1A473E0B708513267764F5621BBB1AEB8AB055324CA910996469161108AC348ABBF9A22C61B1F42DE07DE8DA6E1B906D73FD71CBC5CBF006F72067044E7FF625C28AFD2F77AB0B991E7B4331A7B8E88C9B917F0BB167BCBC7BD1F0A84327BEAB988D818FC3A35B32BBC92E3D61347D76729AA98B6A51D24DADF6580A28629935D2057912C805BA7B55F76A064DA257F6E6EEE21BD919F17EB1B8BBB1D640C0B38E436AADD8DCB72080F9A837363E59ED252BB522AD98D9AE6E2F074D2D3719A49E1026E1B096B0CF974DEDC462997394C03FE11C766EB09C37AC37034C8A05568EFD9D6099DAB338551B320B103488F3757ECEEED3331402335444099535E4E06893C020D2096CF2DEC75EB3978B052179E495B573A032A5201BEFFB843463DEF35E06BDD1A9E00AD49C20B5B4DB9926DBA60DBF7F48FF63BC08C176CB384A10D9EFF2E3F6F912516B902B60F857DAF600A2E8ADE99254456790D270ECB95FB2E8CF7967F94B2C34B24472EC1E56789D17529D907DF57874652E2FA223DB8656570973E6239222E5FDB3B949D559679F938F622090FF0C97091959E93013F51C00E1AE31E0466E0A21C4B1CA98A18343E5386077FFC276AB3FD37C511D2C978C01B62E5F2FFE460515CD7B271AFB8244667AFBF26C09E6F6C7F9719F973A65E3FC3354A0FCC49336361BFAB9E0EB276FA1B5215E9C5C60CDE67DDB9CD6D2ED5A829CDEB8713A6962C1F781770EDE447C23A0AF1768BCFB2FF84B4B96F0662714772D79BB660A6BF306ADF
-20200624120025 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9A48268CB
-20200624212659 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9AAFA0B53
-20200625054216 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9B08B8B4B
-20200625123632 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9B52A385B
-20200625172019 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9B8463B1B
-20200626052613 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9C027DE2B
-20200626101643 2 6 100 7679 5 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9C11E420F
-20200626115032 2 6 100 7679 5 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9C21BE90F
-20200626121646 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9C259D8AB
-20200626221832 2 6 100 7679 5 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9C8D6C58F
-20200627003443 2 6 100 7679 5 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9CA48A947
-20200627072751 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9CEBA2483
-20200627132611 2 6 100 7679 5 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9D172E21F
-20200628074151 2 6 100 7679 5 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9DCE587D7
-20200628192017 2 6 100 7679 5 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9E443C567
-20200628211535 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9E564FA5B
-20200629022616 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9E87B2F13
-20200629030222 2 6 100 7679 5 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9E8D05DBF
-20200629054955 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9EA889CF3
-20200629085314 2 6 100 7679 5 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9EC71DF2F
-20200629090539 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9EC8B1483
-20200629125524 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9EEE0A61B
-20200629171748 2 6 100 7679 5 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9F18A7977
-20200630033559 2 6 100 7679 5 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189C9F7F90DBF
-20200701005327 2 6 100 7679 5 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189CA052CA8BF
-20200701141753 2 6 100 7679 5 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189CA0D5D91DF
-20200701180117 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189CA0F982473
-20200701222250 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189CA12381BA3
-20200702010052 2 6 100 7679 5 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189CA13C5E40F
-20200702020447 2 6 100 7679 2 F33B0F0818B623E831020BF1F21033CEDB49A00241324323E0D768AF68E1C989D401A834784F31ED3A332581A0589712AA215602B2811B35F6916664586EF5797ACF114313A4CF6E5A4AFB4307CD4C119AC0A1D2E6861E5A7E3D16BEA5ED82BB1801A68F2E77E9C5964D9E7CDEBAE4D292CCB458B9D2CE312149EE34B485835EC5A071C5AFF9FA8134D562FDA0381B03F987BB226F9CF647EB496096630362D97E165EB47D874F921EFDB408D88B132E10D99F5920C718DE8A5EECD228D030C7FC3EC712243C4C75E13299300C165962724C4B1CBA811B9158CB01402DCEADDD6849FEE51DEEC74A065EF226A2E41D4F6075C6C4C4466AAB2CFD00E8B7CD3EA75656D7F316F13E924FA133370CFBF59BCE94C2CA0F5F4595E4B3C9CBA040733AAAA53BCC2E2F30BF3A59D25613EC1DD0C373B9F256BA110FD7DDE5DE1697E79AE46956B2EB064E48C63EBA205AB1DBE65F39511F33DC0A7111B03B50AC1921A3EB1A321297BCFC28C6848F55597AFD510A0A2551D3275CB84EABA8624909CB135A2F25EC7352646B0C60DECAAB24C1B95C4E91BC1390E4BD6B420413B3909F8B5593CED45D91A1D462ECCFFC29D4BF9F23928E76672D6EE93148916DDB24C440DFAB01AA2942B4A249BB731C169A76A107D7F6A66F624D7507671E2C9507DA1819A6EBA212B13CC233EDE2BB7883441394A12A95A61BF6876061766913191B33597F1E8BF85AB5A26471C021B5029B34485E7B2D18186638F18EE0B85E72D4A9A866FF634C0652CF1F6BCA9C35669345E983D641A8C6FC6516D8772EC78622F950E175BC8577E99257D009FD8374EEC65507FA9034CCB7376858DDF91A97E5E826A563CB4F11A8C83DC92842F397FDC9861404BDFFFBFFD16ADDB85820123296EA52184C82D062EF68D37A6857473B0A93DFB48DF6CB19938945509F29E88D7C3BF6381AB154F5182E41C58E97341925F6CB545A86C15E4E04F155641BB12169E12B4800F89059746557C8432D08A8E2928EFB9EFA7A8CCB9BD1E55A85E0BDB872703626A89206DA36D5EE99E9BE711E20562150F9B35C0C7F262970F60C7CA5668D7FEEEEF31D6C9360830C656BBC72012DA0E9DE5D364F17EDAA261AC0489B2D39D7F9F54500583BA348CBF28875054017621F795EF7F0B20AE88C50768D981AB9EDFFD6A2B9C144CC815BDB01133138E7FE93D6B5167B164366B76783B68B7A383DC0856F29F35308AB5A6E092CCD238553E9ADF130706488FA95441D367BEFF42B90E590157E31C5D14BE574F674328EB835C8DF1C84A4CD39E31B545843F885B1F68D2F7C769FB67E3AF89ED0728D2F8C49DB7B5A079EC189CA14610AFB
-20200702141056 2 6 100 8191 5 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B8092131717
-20200702144742 2 6 100 8191 5 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B8092635E07
-20200704195421 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80A98AA7BB
-20200705044459 2 6 100 8191 5 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80AE337807
-20200709044115 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80B1103903
-20200709111031 2 6 100 8191 5 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80B4BB063F
-20200709122228 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80B560D2AB
-20200709231042 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80BB820B4B
-20200710011425 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80BCA15883
-20200710070834 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80BFE94DD3
-20200711010355 2 6 100 8191 5 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80C9C858F7
-20200711154230 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80D1BFF01B
-20200711210958 2 6 100 8191 5 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80D49EC027
-20200711221130 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80D51FBF5B
-20200712012057 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80D6C56D7B
-20200712025849 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80D79C8BD3
-20200712085111 2 6 100 8191 5 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80DAB1DE77
-20200712111154 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80DBE208A3
-20200712170032 2 6 100 8191 5 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80DEF05C2F
-20200712205950 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80E0F0E3AB
-20200713042732 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80E4A95523
-20200713054611 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80E54D52DB
-20200713111019 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80E80C304B
-20200713231114 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80EE498EEB
-20200713232228 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80EE59CF2B
-20200714023100 2 6 100 8191 5 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80EFF07CC7
-20200714031313 2 6 100 8191 5 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80F044017F
-20200714041520 2 6 100 8191 5 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80F0C471DF
-20200714043639 2 6 100 8191 5 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80F0EA175F
-20200714065444 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80F21223F3
-20200714133000 2 6 100 8191 5 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80F56A8F2F
-20200715042829 2 6 100 8191 5 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B80FD035EBF
-20200715170628 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B81000F34CB
-20200716042653 2 6 100 8191 2 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B8105A24213
-20200716044620 2 6 100 8191 5 FE8395C9AE4A595356F452E45DF7D762D3A014FEB24E19186365D2BB8740C384EE385601E524A910DC320C4B96D1FAECE8367AE226290C6484B2F9297F185D266063904ED73A257DC9A653750213D524AF0C46B2C13D51A95088B225BAED46BF3C451B9666D7371264E07A9269ED050B75DF602699A41083DA7B55E29B9A4D97DEB07F3731C7D56EBB26A8E4A980F1D085772A9779DF0B0C6D70D84A9422B4DA7118418C649B1CB4427D2BB1EE67710ECEFD41D0C4F5E4A7D87DEB4D5CA502DD56E1FE22F0BA53C3420566C7862D4A7E969958B3E935B73A323DDF7FC4839BD89AB696FEDD5299631C1DC15E849B753829A99CBA301A8DB3601203862059E33B1256D233E830BC2E4441B1458027BA97D0218B4B31D3EA350F550E328E5C32B8C36BE6F1E7F18B13F55BC42C54F6A5530255E206CC6CFC52CFC521B9B3355C9705BD66355310F89A4B70D44317E67C4B06D60001849E965E38F1F9C58AF177DFE3EB6048A54D02AD99E203C004714E97BFAF0163215DBAA9B1A262183B7109B60C975135D8DC02F6F48839EE2588BBBAD9D7C2126837B1C50019A721FD3D498979F10472BBC28FECA5AFF0560AECCE5249D809514B707DC9A57B358ACFAEB5A393E28AB752FE583DED0FCB40119702BD1E7CEFEC11980F64D034612B050919CA3121B2A9F1C4F66530EED3658CEEB0A7822A72DE37123AFD94BE8D7B6A9C2941AE9917697BA07B45815D0662491AF90222880878101792A8CB31926D9F66E6560B7E8273F213EA79311CE9261EBB9483E6FB8582650F69B834E792A614DB7D9ADEAA6E88368B8E72DB948E302420480E3F5B574F16CFA0F336555B649BFF5A3596D887DBAC229791FE5B194D95635709062C457261264B7B559D644D63CE12EA4FF7708D9B087453B318B57BC537E6FF3B8BBC408A5CD8DE6F3C628A0ECB5B9A020FB99A009C127861D54949B3BC068E2FCE802FFD69A8FBA34B474880532B88033B0F63D98F6BA5B455861FFE031A66427891E1492E999CB77C05F66E7458B5643DC43DAABDAA6A8BB4119A7C11B9B155820D5BE8CD91AD052769D73391D2FCE46F0BEADD6B62312C64ECD4613E5D1423F0EC56435BBFE0C43366BF60C361381AB1D8CAEC44D13C9DABE6937EF0018D689EE3F791CB1956CA46C32D293BD901BE4C95F4895525298C4D9D7EDA0E4840F81F458F520A0779CF09F45AE156C83195ECC82D85D4E71E535C6EF8933912A6459782923F2A7927919EDC80F5469DB628DE323D72881757FCF9BCC81D3E121A1BBF593A7B2EF10A2766FCF735FC993CF1303ADFE78D914A66CEDC64F606FD326B2DC501984CE64FE82DD4353AB1F7A3A2F556E73982D19CBF504E0901547D7F4B4E41B58E3F537774799DF4423B8376FE8D7760E3DBBD73E1D5DCB1499789711A90BE26D0DB48AA89E72B8105C3235F
-20200717004114 2 6 100 8191 2 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E2563B2FF3
-20200717235130 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E25DEE6EFF
-20200718065353 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E261E56D0F
-20200719061659 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E26EE97997
-20200719174532 2 6 100 8191 2 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E2753B7F7B
-20200719233549 2 6 100 8191 2 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E278465B13
-20200720193256 2 6 100 8191 2 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E27EAF2603
-20200720221223 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E28016951F
-20200720225043 2 6 100 8191 2 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E280684433
-20200721051511 2 6 100 8191 2 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E283E5442B
-20200721202027 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E28BF7EF47
-20200722031754 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E28FA5D78F
-20200722033316 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E28FBF971F
-20200722065544 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E2917E7E8F
-20200722082838 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E292454C9F
-20200722174034 2 6 100 8191 2 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E297121163
-20200723025424 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E29BB02057
-20200723041739 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E29C6C06E7
-20200723052236 2 6 100 8191 2 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E29CFC7C53
-20200723065956 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E29DD62887
-20200723141158 2 6 100 8191 2 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E2A1DEDC7B
-20200723143438 2 6 100 8191 2 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E2A20B359B
-20200723180649 2 6 100 8191 2 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E2A3FDE2C3
-20200723182158 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E2A41A0857
-20200724142608 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E2AF0F839F
-20200724163612 2 6 100 8191 2 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E2B034D293
-20200726001643 2 6 100 8191 2 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E2C133FD8B
-20200726175941 2 6 100 8191 2 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E2CA996EAB
-20200726180625 2 6 100 8191 2 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E2CA9DE833
-20200727032532 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E2CF5B2087
-20200727053855 2 6 100 8191 5 F80E15DF775E74500D293272136D58EC8D062AB4FCF79FE676D1E7C31466BBF53DB66029B5AA4C527F0D59D3D00BEE81CF126FD0F8CC2FB19017E9F6B02D75BE094347756941901536C84FF90D5E14953AABD9D6A660404C8164C9EFE33B0BD6B2CAC083F7EDD115393E43A2DD6CCE66037ACC14D987EB1F6B23A77BC2EBC3621B160C2561DCDED8E51CCDC7B2C6ABA4ED99F686218D9B925231626619CB61452D83FD6A0AD8CC12698777BD28762038D45399B1D0E06930D87444D4DD3EFE94287F34557D021077ED3E8F61E9FE6138F1BA7335198FE5D06373E5FFDAB4058E3697BC4A013C91F8B1DD1C9409A5A7D9A3707B958DF6E83052881C36724D98E8FA98C83FD8FBBFCD8B0C09B31ECDFE9D7884DCCD6F7E192A8B6F0DE93CB12891872DF631E1C4E5DF3C9B5A7FB773F9165236D776CCE0E80E61AC842D6B01AAA82856DA6E4581D542709C702FCBC2FE8C28B546BB21F42AF475076BAF67B21F92BB70703A0941962EE5D9DFDFC620DA16DEB0EBC166DB869E956AF4EAAF008BD2B78AA77474A481AFED15AB98751F3431A815C4B606F6A34423A0DA4236FB1339177FD9FB3AFBC8166E313FD8C02C12D8DE0184F3E6CEE043685B8372E14B84100A7BB3536460E3FF851F73E2ED904953F6481D33D7B4BD8A9C829F92911FDFAD6CA31EBC1B70E4CD3D964E7A922BFAD0A828959F3AAD1708E742F68FD8B5DA90558D9F8222DFC1765B835DBF7FF5785F0645D04B56EE67A76EEAF04243A1E4EE47787328EFAA880A463D064B203CB70CDEFF554D281A6E161D3EB55967763DD09F5A68FC23B8D3660C8EFB705706B699F9A9FED5F16E77E060220F5572F11564B7D5F27BCCA81A1052A9745A4C7C37B776BAA4CEE950513577300A0CBBF9C555DBD0D83BB49E51EBE66405A404B19A5CC18577A2ED5DE05AA2F459CB78A92845F4A4C0CC8559B8E0338425D7988E1FA4572D67BBD9B9AD3B7156FD8C079E18C1285DF894426BD702804C4C468726420EAAB61C82E33BAC8613D541DA5B767B0877C5C8607BE72B5EA322EC00A4575606E959051CC658322287D255786C5C21E9799E7B8E5F0C93BCF0A267CB4C48C8F4271DF0A34ED2BB9C2FD8091375FD1B3E61D7A3F2F71F4D33226331DF2B7F22E48D2D831C2EA0383D8A7481191780DADD0ED5AFC6F28ADC8796B8B558A1DA2FCB838BC167A0A0377A7ACCF0E30B87111F9DB1760F3C0D16F097DDD3330D6A9369E8A6E57CAE4E5EB290A3370E55202C08EBA5A4D06C01996BDC06BBE027EBF746DF1579F82BF3A3A2765EA4AA989B56F82D4812539182AFFC8F5A8CAC826D2A7720CC2327521075CC8C7084B2CCA30DF574CAC8C44148DF989B7B1E940CBFFE47EB3892147920C3D93AE764B769F2A71AC2A2A2C4E05C60C887151CE4B8947FBA7C756D6F69F5394A3106F3E2D07FAFE7
+20200930103859 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AA67732B
+20200930104218 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AAEC16F3
+20200930104319 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AB1310F3
+20200930104333 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AB14C093
+20200930104405 2 6 100 2047 5 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AB297677
+20200930104620 2 6 100 2047 5 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AB8E47BF
+20200930104658 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37ABA427AB
+20200930104713 2 6 100 2047 5 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37ABA93727
+20200930104858 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37ABEB0CD3
+20200930104955 2 6 100 2047 5 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AC09DF6F
+20200930105245 2 6 100 2047 5 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37ACB5C36F
+20200930105334 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37ACCD80EB
+20200930105514 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AD0A024B
+20200930105705 2 6 100 2047 5 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AD4DA807
+20200930105838 2 6 100 2047 5 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AD8515A7
+20200930105923 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AD99A2F3
+20200930110024 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37ADB9659B
+20200930110055 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37ADC6CD9B
+20200930110307 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AE16257B
+20200930110335 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AE200B43
+20200930110447 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AE487643
+20200930110501 2 6 100 2047 5 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AE49A30F
+20200930110640 2 6 100 2047 5 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AE7CB41F
+20200930110705 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AE850193
+20200930110828 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AEAFC643
+20200930110947 2 6 100 2047 5 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AED939F7
+20200930111052 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AEF8958B
+20200930111318 2 6 100 2047 5 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AF484B07
+20200930111345 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AF506FB3
+20200930111558 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37AF9D1DEB
+20200930111857 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37B006FBA3
+20200930112128 2 6 100 2047 5 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37B05EE957
+20200930112416 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37B0C3E9BB
+20200930112439 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37B0CC77D3
+20200930112529 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37B0E3D873
+20200930112751 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37B13355D3
+20200930112903 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37B15BABBB
+20200930113019 2 6 100 2047 2 DD19D852DB5639810688F04A26C29999BB806D2F7C80880AE35BD4C2EBBD49BC5D2A326B03C5BF96777DE50D0F5C2AA928A46F550D5F5DF6AD619FB1F38E432B4EBB3B39FD49A6A8F187DD4BC7E541B6390033BFAE92E64020DF00C57DE1F9A51B66686EDADAD07C72CAAE33110A635484746BBF6A592A9A14B7A96754FDF1FFA3AE383A60927C0E03B9F959396D1FC452A404C1BF28BB914EAF591452865923778A99AA3608F899057C9DDAD66206E89621BDEEF2BFEB7B2D045CE3BA93AAA7A89121A5ED43C2CED0F22E271964741193E83C51DDCEE04A3ACD21C954EDFAF578547F85A4A62FE6B62D20BC2C6803302ACE817B64189EC9677C2D37B184B2A3
+20200930113412 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC5488ED437
+20200930113500 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC548A601CB
+20200930113748 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC549036A23
+20200930113832 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC549165F87
+20200930113959 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC549496DBB
+20200930114037 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC5495B861B
+20200930114050 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC5495C68CB
+20200930114255 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC549A6EB2B
+20200930114431 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC549E07B43
+20200930114445 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC549E2CF23
+20200930114719 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54A3E7F8F
+20200930114810 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54A563DEF
+20200930115248 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54B012D4B
+20200930115431 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54B397777
+20200930115527 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54B553237
+20200930115559 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54B625363
+20200930115639 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54B764653
+20200930115714 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54B85426F
+20200930115814 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54BA69D8F
+20200930120314 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54C7285E3
+20200930120351 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54C86F583
+20200930120424 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54C93ECD3
+20200930120459 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54CA6ADC3
+20200930120535 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54CB82843
+20200930120634 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54CDD2F6B
+20200930120740 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54D05106B
+20200930120808 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54D124907
+20200930120902 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54D35556B
+20200930121004 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54D5D58A3
+20200930121027 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54D66AA1B
+20200930121059 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54D798D2B
+20200930121232 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54DB2997F
+20200930121533 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54E249FBB
+20200930121602 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54E30E23F
+20200930121739 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54E67F36F
+20200930121847 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54E8E56D3
+20200930122206 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54F05DEC7
+20200930122413 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54F513B07
+20200930122512 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54F712233
+20200930122719 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54FBCFD33
+20200930122737 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC54FC0216F
+20200930122956 2 6 100 2047 5 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC550170507
+20200930123106 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC5503F0863
+20200930123146 2 6 100 2047 2 D9F77C62B924E4DC2FFF6682F124D0F01627EC2634654DF4A2447BF0F88EE3DE63675303C39FFEC329B8AB02FA7A4E35210B3AD9805B032A5AFC0835D65DA3A522477694920B4328A2EF80DCAD164A4A80AFDFD6E2D47020282DBB4F1CF132226C07C27E4948057A504B0B52FF665FA792E1DE498B3931270A6244FE4F116407BA08B00AC2CAFBF6D3C6C37EF7F5B9D155545E1D014F7D057F820182EB35B125669E9B87569A55EBE6DF6DC3230B31ACC0560EF1D4BEC78CBE46E203E57086AC96A74FFFD90F545E7845236E71E4329ED8281CF3819CA14B162D51CC58EC73BF462AE605FC548E41DE2479E3A006EA0E9EDB4ABAEFB5A7C0FA976FC5504FBFFB
+20200930131958 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BBCE046BF
+20200930133333 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BBDB3497F
+20200930134619 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BBE93B7DB
+20200930134843 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BBEB9F86B
+20200930140124 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BBFB429AB
+20200930140701 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC025DBE7
+20200930141445 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC0B94697
+20200930141618 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC0D070FB
+20200930142039 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC12AB823
+20200930142500 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC18EE2A3
+20200930143133 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC2223D33
+20200930143655 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC2914A47
+20200930144031 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC2DF100F
+20200930145023 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC3CD7DDF
+20200930145245 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC40476EB
+20200930145745 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC47CF4D3
+20200930150246 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC4F4DC13
+20200930150400 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC50F13BB
+20200930151224 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC5D3446B
+20200930151334 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC5E84957
+20200930151946 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC67BC6EB
+20200930152246 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC6BE4C0B
+20200930152442 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC6E58FEB
+20200930152517 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC6EC7283
+20200930152544 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC6EFB5D3
+20200930153147 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC76614BB
+20200930154247 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC876E263
+20200930154655 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC8D835FF
+20200930155510 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC9A5DD53
+20200930155644 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC9C54223
+20200930155841 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BC9EF4E9B
+20200930155951 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCA0893BB
+20200930160156 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCA39256B
+20200930160335 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCA58F26F
+20200930160458 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCA79E25B
+20200930161250 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCB3CD967
+20200930161643 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCB9AE923
+20200930162043 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCBFC8D17
+20200930162137 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCC0AE5BF
+20200930162454 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCC5E286B
+20200930162948 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCCD410A3
+20200930163811 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCDA71C3F
+20200930163852 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCDAE81E7
+20200930164250 2 6 100 3071 5 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCE0B29AF
+20200930164410 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCE25DA3B
+20200930164557 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCE4CECFB
+20200930164800 2 6 100 3071 2 D0F2B3CC37A29DF5AD1623D003ABD0987230EA8A417A02839C436A9E9C7A0581A9234176BC0F0F2F450158718D0C2F35AD83181A4C36AD0483D8FA07EB282666AF859B9DC8FF9F9EACBC804D8114277653AD082DF50DC8A4E1A7F012922A198E6677002FDB48F92F84A794C19621BA3997975245D6A441A0C3D92F742719B67C5C356F6EB229A0F004CF1A5F7908F18EB783934B5E3311593CCC3B88C41010CD5F0D0B63BB169E0410D9C5C1FF4E5798ADAFDE92ACEB42C0147EA12DCD59EDC0C354CF167219C9D2C7A2CEF76FECB233986FD48AAF3B9379537D8EDDD67C517A7134F188307C8C16E6D125425EB82E23625D51851463A06A71E0C91A1BB78BAF49535DFB51195C9755F3EAAC761A17803FB292A228E1109FCA837A8B8F7A9696F981F6EF48A6F285C00EB5750D8C61414C742EDDAEC16661219315B9D9A10AA81CDC496B273B0238BC77649D156AF9A031B11FE2B981FABEAEB102802BA8EFA4D743042FBB8C91F0D892469826C60CCBEE44C8167D664672492D564BCE7942D3
+20200930165856 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED3633990233
+20200930170645 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED36344A3E63
+20200930171201 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED3634D3E62B
+20200930171432 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED3635088CD7
+20200930171818 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED36355FD633
+20200930172759 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED36365E0643
+20200930173548 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED36372023FF
+20200930173839 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED36375FB73B
+20200930174243 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED3637C3C17B
+20200930174555 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363812F603
+20200930175037 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363880305B
+20200930175131 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED36388E6AA3
+20200930175228 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED36389FD95F
+20200930180050 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363972ACC7
+20200930180301 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED3639A594D3
+20200930180756 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363A2043C7
+20200930180835 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363A25D30B
+20200930180925 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363A32CB4B
+20200930181538 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363AD672E7
+20200930181644 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363AEC260F
+20200930182258 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363B8D9FCF
+20200930182834 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363C161663
+20200930182932 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363C26369F
+20200930183140 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363C575C93
+20200930183452 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363CA60763
+20200930184439 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363D9F9553
+20200930185118 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363E462B5B
+20200930185600 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363EC13C83
+20200930185646 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363ECAC29F
+20200930185830 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363EED78B7
+20200930190150 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363F41A293
+20200930190554 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363FA9D6C3
+20200930190652 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363FBA5D77
+20200930190818 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED363FD4D617
+20200930192133 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED36413128DF
+20200930192506 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED36418D031B
+20200930192844 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED3641E7B13F
+20200930193716 2 6 100 3071 2 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED3642C5CDB3
+20200930195325 2 6 100 3071 5 E1009A27E8B33EC315331CCC6530EA1D6D434442F56A84A4F51EA47D915025BFF9A55E9225FD0D3829930D7469978A8BFC8DCC85703DD2C4B5297BE134E93D7EA72E4B7D18D62F10DFB196707CF4975EAE036E83D6302A61568111787BBAEEA6C483F9F68601017B48932924651B07EF5509BB5B208B298927A43A96E12E110C3EA911693EF9DB4094834D862A8C9AE60C3D21507E2E634573DA325298D02D99130007973CC2F7C95C0BAA1B2B4644D0E9E21880F665498462D8F041B6D2C95085AB34A8E490411014B3573AB9902F2F70FD3A48C7A7B0076AD1C8B073295851A590D578DE130CDAD896ABD2AEEDE74FB72D1A842B84A47C045248ABE149D10E1B7CD67F78B65573EA15B0088026C22D41CCF95E2F7CCDCBD70F3B685805186B7241568C03F2DE6BE72EB1FF91F9B811E168CF1A0DC6B1D2D9AC69AFB450583E8FFB2682158E10B120D750C75159058D04B27F1350012B484FFF93FDAAEB819C9D0F632E3358AE410E242494713E715E3F9150FE0882CC06153EED36447A6037
+20200930203427 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D121E283097
+20200930212141 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D12206F330F
+20200930213623 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D12211E084B
+20200930221333 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D1221896A17
+20200930221945 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D1221B2485B
+20200930232214 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D12227A70A3
+20201001002356 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D1222FF2E9F
+20201001004540 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D12235AC837
+20201001004636 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D12235B75FB
+20201001043411 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D1225B50D17
+20201001043728 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D1225CB099B
+20201001050054 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D12268D7CA7
+20201001054849 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D12282033E3
+20201001070929 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D122AF5291F
+20201001072234 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D122B6EFDEB
+20201001075250 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D122C8CF0D3
+20201001075437 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D122C94354B
+20201001080649 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D122D0186B3
+20201001081829 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D122D66125F
+20201001093449 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D123048EE7F
+20201001093748 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D12305B5857
+20201001094150 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D12307B06CB
+20201001095043 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D1230C795B3
+20201001100350 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D12313BC2DB
+20201001104031 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D1232922ECF
+20201001105657 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D12332F3B07
+20201001112635 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D12344498B7
+20201001112836 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D12344E3D63
+20201001114337 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D1234D9384F
+20201001115808 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D12355D26AF
+20201001120939 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D1235C35313
+20201001122331 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D12363C302F
+20201001124432 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D1236FFFF6B
+20201001125356 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D123754B623
+20201001130844 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D1237DAB06F
+20201001131243 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D1237F8E297
+20201001133149 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D1238A92C87
+20201001140357 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D1239DBC1AF
+20201001142245 2 6 100 4095 2 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D123A811F7B
+20201001150145 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D123BDFE8AF
+20201001153400 2 6 100 4095 5 FF1950A9D266D427EB8A232ACAF44612A47682EB0B8C89257EAE4D9F586CFC514878E79DF5A708945A9B2C5441A7708EC3904EC7C6C31424F23D30B14791B5A1DE417FAC45773E1A4FDFEC320C0BE611CE6BF0CFCD5EA9DB5F1878E04094441A35F9D22109EDBCE9AB6B9E433B1301C6A7921AF2590E84434B58DC8CEB83FD24C080D1998E9A6BBF7BB9BFB218FBFB6B0BC2CA7CCC260D7E1443E18B85CFF71724F21B9C855557CDC2C490A496D31E0746CAC6A6012553E013B38CE7F394E664034E137AA4750C72A5560F4DBE9B0B28D82D5EB560FE4211F5280F35811C65365C386CEA8B30B8AEAE43D61B053AAB32C41B582B24D0C1FADC212DBD52559CC8E1AC18A548D1A6EDBC47AB15E86CCEF826776C09E07262777147308C407D5DFC7E1A1364370FFA5B5D57845F148C2FD86C4CF7EA2173AC66BE202F3A1C33E68F1151328271B058974D26F7755D2114BC0D96E5B15025D0B0F66221F391AA4FDF8AE7C99C1FD4B54B42AE06EA094ACB81D66C37B628136525D31AE7CD4A63CB35DE81B7D33D8B721915DE58689F4D7D182619361CA5F76680F2B85D674DDF3875C0520B22A6C8EF96CB304D9CB2461F152AAEA09F8E976B9A46E98F7BFF7F29F09129107B2C3F427E71DB802B8EF9A8BCFB819BADDFDD8CC9AAD1EB51E78C5C31BD1176727C2538313AED63F01FF037E26AE225EEF011392B64BD2D123CFF695F
+20201001160243 2 6 100 4095 2 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607F92DE577B
+20201001170341 2 6 100 4095 2 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607F95291CDB
+20201001180757 2 6 100 4095 2 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607F9796CF73
+20201001181955 2 6 100 4095 5 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607F97FF1F0F
+20201001182457 2 6 100 4095 2 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607F9828801B
+20201001184200 2 6 100 4095 5 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607F98C75E07
+20201001210558 2 6 100 4095 5 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607F9E43BE07
+20201001212737 2 6 100 4095 5 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607F9F0A37B7
+20201001212838 2 6 100 4095 5 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607F9F0B5457
+20201001213858 2 6 100 4095 5 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607F9F68AB57
+20201001214136 2 6 100 4095 2 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607F9F761B13
+20201001221702 2 6 100 4095 2 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607FA0C0896B
+20201001224659 2 6 100 4095 5 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607FA1D48B9F
+20201001231459 2 6 100 4095 5 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607FA2DCDC9F
+20201002001557 2 6 100 4095 5 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607FA5293EC7
+20201002011559 2 6 100 4095 2 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607FA768B563
+20201002011835 2 6 100 4095 2 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607FA774F6BB
+20201002014757 2 6 100 4095 5 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607FA88C774F
+20201002015750 2 6 100 4095 5 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607FA8E1C2FF
+20201002024356 2 6 100 4095 2 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607FAA91DF73
+20201002024735 2 6 100 4095 5 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607FAAA9836F
+20201002024957 2 6 100 4095 2 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607FAABA24AB
+20201002031500 2 6 100 4095 2 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607FABA7157B
+20201002040434 2 6 100 4095 5 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607FAD709107
+20201002045704 2 6 100 4095 2 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607FAF572503
+20201002061053 2 6 100 4095 2 E2C28B8617B3FEA1703BB9D3CB9518575094744626E5585F741511C44A4DBF419A7B4EAFBBD14DBBA20CD669577AC7CFEB5C93E951D6F2A5A194FC3C16282C2C0DF160DBB439B67D6D49AF4F7879F8D679923E29E4063872399198A86EEDA598C481B77427CE7EF3E56BE86A00460DE9834E8B40B205B3380BD392A83B927C4A49644C801A3568496CB2687B08091553DD8059D8FD8C21604067A3A0223E5188FEE3064BE5C678C7CA9EA9ADA446AF462A6412B11EBA7DAFC7886A2B9D1FC494ECFA41A5D4830FDAEFA3F1168753E9FF51DE1C3390A00C29AAC16630397A61B96B7D5A18FD5B57A18A5271A8C2FC25BBEF730CCB2DE2B590B9491161B4DE310EABD2D60C4DF8CA703D19A13DE58D562B7561EAA4E27B25BE5B61D71F97CFF4B0F3FC0DC89622B0EF252E1C9616F0447553CFF22FD7198483652D901BB9316F5B713BA475DD9BFFA8501B19B2BC79EDD41320AFB94B48F274F0C5822A02EF1D53A94EAE036FCCB8082AF1E58EEFA617D22FAF56FFB0A9501367737D1DD337BAC4E4E72DFDBF90F6A256E7ABD09FBAE7D54E092005838DE90324B1DE72C547FC4C755E3374F24600B7180E8AD18FFAB46ACD869BB04FCED13EE9697BEF19FFD3B072D90C67F2D5E250B4272487A84F4F4BAD3B2CE442B6C43C6BAD6769B557DBBA81C7FDBDF968C4E573BE3EC843616EA72654B9B3FAFD7B7BFFB7607FB20F6B6B
+20201002074332 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC346552B8B83
+20201002074853 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC346553476CB
+20201002091337 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3465645C7CB
+20201002142139 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3465A322A33
+20201002152133 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3465AEC6C1B
+20201002153735 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3465B14A583
+20201002232438 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34660F939B3
+20201003163937 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34662F17E83
+20201003174335 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34663EDC143
+20201003181552 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC346646B5843
+20201003183800 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34664C050D7
+20201003204020 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34666AA62F7
+20201003205151 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34666D033EB
+20201004015235 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3466BE5911F
+20201004021543 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3466C4163AB
+20201004024523 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3466CBA09CB
+20201004035043 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3466DD63DE3
+20201004082640 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34672816CD7
+20201004090437 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC346731E155B
+20201004093742 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34673A25113
+20201004131132 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3467738EC47
+20201004145042 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34678D108D3
+20201004163923 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3467A690F9F
+20201004230643 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC346800C7B27
+20201004235413 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34680AEEF73
+20201005014706 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3468252BDFF
+20201005024434 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3468341BA4F
+20201005030558 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34683932AF3
+20201005055647 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC346865E7FA3
+20201005061138 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34686945117
+20201005062031 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34686B2CB93
+20201005064657 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC346871DBCEB
+20201005070706 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC346876960BF
+20201005071036 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC346876F40F7
+20201005091658 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC346897E0C33
+20201005145338 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3468EF9163F
+20201005190527 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3469321BB4F
+20201005205529 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34694F47DC7
+20201005224734 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34696CF509F
+20201005230339 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC346970CE03B
+20201005230714 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3469713E643
+20201006014521 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34699AA76D7
+20201006015351 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC34699C5B68B
+20201006025138 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3469ABB46E3
+20201006031630 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3469B1F8423
+20201006034858 2 6 100 6143 5 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3469BA1ABAF
+20201006051131 2 6 100 6143 2 E5AFFE1F31466A1BE4039398F290C9CEE2D03FBDED18E2E034E872E714AB7B7FB8F2E9A798D0E2C53B49722FE0AA884A349ADD9FA7A8D4F1FD3E38C1D35697F054D96566127016CF7C0618E8B3C4F875D08E61359923B77E8012F43F2FE10E538F0BD34644F84F2F545DA683C0D148BAE62FC69A7D3EE24A6B5726BBF970A711091105B4084DAA923AE2C1DBF9D8C024E2F641BDDCFD8FB96B4B46C6D279B26E45CA8CF335448422A3F20C65BC05A12F62229F9FED22B1B912A0390DFF1360012528E3C287E09C1C89AA140F524804915FA0C84715F887615F5AE67D7D63BA48C75E192BD364C6E0C0F0377B788017879CB352FD50786C34DABA7F7AB6CF6455A90577DCDC5B06586A06E2A14E6447697FD09D0A9F1B92B831CD4EEAAD0105C6BE0168753106AEA5479A73054E76CFC2566F0284E3157444E05C61A5261A10B736B63EDA6BA54DE994F78877F13882FA53362C3819A4F3903E7BF7A5368EA4F5C20FDE4027AF86B6427FBB0FA76EDCA0D9568A1F489A14B3E2D32F8EAB69AB7968BAC3854FE2438697E75C80B02DDB654E3415B5DD7679B961DB83E6780B761FAB21952531180E55E950FA857B92AEC62AB206192AADD19E3C15B8535DBDFCA6E0EDF3C78B19DF447DF55544CF0DBFFCAD14F2DCF04CAE3BF8F114B0C9840A71F0E6164C4D794576F784AB8B02181E91C7889FFC5E07B7DA8A020768BE1A1C38FECA405AEEC5CAFF565580C7BD8F3B253F644AE36D4CAB288D722E75FE3589816633E51CB5B3006502BD334817F52F4A4EDA5000550E112C1FF20C8FEB1B3817B1962D0A6C4DDB0962481137105CC8578655CAB1F9AFF21E940334BFD6865818B1DF6FDC45366919AF6FB090A7A8F462432475DBDBF7283299841923BA6C8FD898FC3E1265200454277B982A2448E7A1FF988987FBB28EE99B6C23CD90616BCFAE9C6F37FE76ABE02471ABD2893E1463DE6B5D9CAF5834626DBAD677EDEBD9F9F12D49806EAC5F47EE3478E9FF807988A0A660949904DD56181347E9C51084746AB0091D1D1971C6D3114628AF5436671FB9081BE04E9203193DC3469CFA587B
+20201006053954 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741001ECC7BF5B
+20201006064528 2 6 100 6143 5 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741001EDF81BAF
+20201006093842 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741001F11E3503
+20201006121934 2 6 100 6143 5 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741001F3FF0177
+20201006153835 2 6 100 6143 5 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741001F786BCDF
+20201006170235 2 6 100 6143 5 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741001F901D577
+20201006182016 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741001FA6168FB
+20201006191339 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741001FB522CBB
+20201006195142 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741001FBF4754B
+20201006211554 2 6 100 6143 5 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741001FD6BE76F
+20201006212227 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741001FD7FE12B
+20201007024718 2 6 100 6143 5 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741002032B9907
+20201007045343 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D74100204BFAA1B
+20201007051121 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D74100205076413
+20201007100412 2 6 100 6143 5 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D74100208CEB647
+20201007105152 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741002099A8B4B
+20201007184739 2 6 100 6143 5 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D74100211D63A67
+20201007185842 2 6 100 6143 5 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D7410021200590F
+20201007203729 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D74100213B2D4BB
+20201007222649 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741002158A0683
+20201007223626 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D74100215AD592B
+20201008020122 2 6 100 6143 5 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D74100218F8249F
+20201008032338 2 6 100 6143 5 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D74100219D09A5F
+20201008043839 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D7410021ABC6F43
+20201008075139 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D7410021BF1E2F3
+20201008170038 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D7410021F0268C3
+20201008213147 2 6 100 6143 5 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D7410022246D527
+20201009054743 2 6 100 6143 5 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741002281358D7
+20201009131236 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D7410022A23103B
+20201009144009 2 6 100 6143 5 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D7410022B121897
+20201009171246 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D7410022CBB3DEB
+20201009192053 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D7410022E25ED7B
+20201010012452 2 6 100 6143 5 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D741002322EB987
+20201010035137 2 6 100 6143 2 F410017F9AF266B6BCEF66D7F7275A68046DB5CC083716B6FF98473EC618ADA763E5597D86382DFDBB196A85A0052A538B3F9EE034D42C5F3E853E5FADEBB28906808929594908915DA9E30C5D536E32DE63422019874E7CA4E78D40377CCEC9195334FFE9154A2EB1BF284125D96884A83C6E40E6C5E95EDF8F8B9D216EEB8A1E4C23AED0E369EC8F539E448BDB2FDAB8A6FB1D3028761215BAFDE14FAC330E5BE737CF21EC2B404E662CC938176B9397C834CA1542FDC38B5B3318A81EB5AC8953EB2F1A1C44FAEE2B3BD8F4873AE5EDEEB6873A5BB0C6839A40DB49B8E31A7FFF887506CBCE5F073C9EF4FC4800E56BB398EE503592B4D7B125D9810A144F0C311F086237324EAB4C44FC58488FB9743A1C7FD9159B229EDD210F6A867EBDE32540227EFC30079EE523D0C2B8F1741F23D146F2C5AB1C65E6BA70AE84CB95855A7D36141C5F1E99A1C50F80164E2F395972C0987200A9FA69A2186F4F40F3A59D7AEF13F21EC0F6991B25C8EA953C8686FA8D33FD9925478A6FB47881DAE26BAE33242B7B56640E218D0B72C46B99EBCCE6067927811488E503F65F5475DAE38F9501A4EA15C01E8535C1BC3F26129DF44DBE2296AB2D9A5C2F5964F1DA39C9632B7C47C2849431DEC1CC36A318A2272152D12955F1FF3D778C6AE74D788CC123045413F03E5018C7FD4E910CC74573D6D13B37770CFCC6185DA667F1F407559A03255F0A6A3502AC9C90CF2905D3FE21F2007D46B44B834D4AF582A3C16866FF3328C3AD95C3664A80676F78403DF76493C6444FD0C99C634C99B0DDB77C269EE24F52A2AC9D1D07B4BF9D026BD9C7EB3ED69EED20DF479A4746E2AE8C15950D641838A48C8C62363C28B7E92D1825C761BF1E23EEAEFA39FE7E37B7A4F924CB5EBB5E4F1C242E23E543DEDB682A5DAB7A135D06E26F540A27E3D810A6AF98BDBB4F9019A6AC0B5BAF69D5F1D9252B828D765DB1E27D84C523B8A03D786639B49C6C1F689BE8705E81E81DAC297F3E27F3A1AB8DE6415AE57A223426653BB252CE66D84E72111098F2EFAD3D1A5070E6401A95AEC2BC2D74100233C8CA3B
+20201010075246 2 6 100 7679 5 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842CD9AF6FAF
+20201011005752 2 6 100 7679 5 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842CE072FD57
+20201011035835 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842CE1ABACE3
+20201011045403 2 6 100 7679 5 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842CE206506F
+20201011060537 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842CE27A97FB
+20201011115031 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842CE4C9A3CB
+20201011133049 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842CE56A800B
+20201011140549 2 6 100 7679 5 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842CE5A2017F
+20201011155546 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842CE6582D4B
+20201012201951 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842CEF20BA0B
+20201012210958 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842CEF6C1183
+20201013021520 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842CF1335633
+20201013102151 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842CF2D63E73
+20201013194804 2 6 100 7679 5 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842CF7E6D4C7
+20201015013344 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D06CDC71B
+20201015042038 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D083DF63B
+20201015181014 2 6 100 7679 5 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D0F9A17D7
+20201016000141 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D12B0733B
+20201016010059 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D13320473
+20201016060609 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D15D95FFB
+20201016203844 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D1CB8A8DB
+20201017073647 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D20D7DD0B
+20201017091847 2 6 100 7679 5 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D219EE067
+20201017175021 2 6 100 7679 5 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D24FD1EC7
+20201017203342 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D263E40C3
+20201018020027 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D28F52363
+20201018123438 2 6 100 7679 5 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D2E5C85F7
+20201019034610 2 6 100 7679 5 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D33CD718F
+20201019040103 2 6 100 7679 2 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D33DD1DD3
+20201019172329 2 6 100 7679 5 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D39DA76EF
+20201020150153 2 6 100 7679 5 E0E88C8B4130B3D284A584051788589172810660E9C906C4C2ECCDEA00D86E8937D6BBC63E3440099A392243F42DCBE6A4F61BBCDED0ACBAFD932A02F5D9FF92A497E674EE5FF2BC962FDE0112C4D1856CAD9DA2D5A405B00D39B485E2E548895A2A2131FF7233B5FAADA6FD0DC8F8974837FEB9BE4E249C59A7D4AD006A7D6B9113DCEBB39800DF767CD0349403FAE188B6275F2BB0DDF6DE071E0A9D449FBCCD9F4E228EE2D9B2CEA92B4D00A642A76015EA7D32B8E6EFE9D0D97147725C5F934F634C21F72FAF6F88333CE15F2C7C802E4AFB1EEE46B2F73B2826D910D073761C5BD591083B15B2AE1125B73A1ACBAAD9F0D960B07A7878205FC7D0836A3F2B19E7F12751428DC3172566569E66693B934052927487642B35E69352078C9E3D43CB67C4FB0FB4C94187301CBBDAD8BE2F79B7D935F94D14DD3B112BB8B547422DE7EF283F238C3788AE1598DBA603AF0056B4542BA3539E679719274002E3686E7E635867EB522522E6FAD9FD0E8706226EE54B5C5466B64CD75221AE3B5733C0B5C89915696D3298FC6D170FC5E47F8573A467BC1E874A602F8E03404509A267A19DCD37FDEC7CB493FAF0304E119C1A7F5B8422B869DEE218B104C548FC13B1A929D0CD8648A48F178667509D8C9BBE96AEB662963297E0113A73E8F2F8E7111FC0360D225D24683D6B61FD0021C71AB81287BD22484C595D07D61C086D3DD25D1C3ECAF9AF055FB787792714913C6581A3036170636A140FD591BACE3DD50B9699F5BA74982CEDE088597EC321E0E4557DF6BC22E7F222C2D8856C2A86C98F5D035EA9895405487FFF99131D579F8851AFB137A164549DB4032611CA1006EAE41B32FF6C1CA9D06E39B9F28DAEC34CBE306CB06BFAB4593E00BA1F94C8B39F63AE2527370133AD2F4D677D513B0A7197050742AC1B4DA61E74C233607B609FBB4A76A84DC20B946053984CD2FD84650CD643E5ABA45FD8745F8F75BEE5EDE53F41ED1B988867C3E7035575A36BCE0D850403D667084AE568A748DE9A5B4BCBDAE177E01DB757B0E3D49CBF43ECBC60AC03948B0310F62DF81E11F6354301EDA8AC224A8B7A29DC47F3555FE8EF4984EBDD6366B4F5EF70C45F8E5328FA95524115BF6FEC4744BF0CA3157312B06BBAE6556F593C47AB882BAC8D08DA7C344ADB8783750EA2430E6B4E2D91AF27DF76849E99E6A65A8559A90D8B5CD3824F797CA5B8AB558ED8445D7F712BD2D52333D8DBCAA4276FF707DE6EA058A24A9C5E9AB670DE852D4B27AE34E240249117E55300D841AA98259DE5BD8DFA314593105A5F021CF851531EBB2801B0DD9E461BBC950F85287E2664842D4103CA8F
+20201021183337 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E131FE7B74B3
+20201021202448 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E131FF319DAF
+20201021213639 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E131FFA89A0B
+20201022063057 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E132034F99D3
+20201022115254 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E132057AB2E7
+20201023091548 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E1320E388F3B
+20201023155346 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E13210E51F83
+20201023164559 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E1321134EC0F
+20201023191235 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E132122BB8FF
+20201024021831 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E132151C7F0F
+20201024074540 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E13217561F0F
+20201024125958 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E132197854A3
+20201025030550 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E1321EE79E7B
+20201025032329 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E1321EFD314B
+20201025071942 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E13220971ACF
+20201025154749 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E132240A521B
+20201025212128 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E13225E3DBA7
+20201026101451 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E1322BA1534B
+20201026144219 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E1322E1B43E7
+20201026175052 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E1322FD9F0E3
+20201027065946 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E1323743774F
+20201027075829 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E13237C8D247
+20201027091325 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E132386EF5D7
+20201027182322 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E1323D730207
+20201027192352 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E1323DFBCC5F
+20201028065039 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E1324455CE7B
+20201028072438 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E132449B6C73
+20201029012952 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E1324DE7EFEB
+20201029151546 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E1324FFF1267
+20201030020447 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E132541F7A77
+20201030080540 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E132565E434F
+20201030145946 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E132590127CB
+20201030213938 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E1325B8DAC6F
+20201031043834 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E1325E3A7FFB
+20201031135651 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E13261DCB697
+20201031191235 2 6 100 7679 5 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E13263B62007
+20201101074141 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E13267FD28B3
+20201101124549 2 6 100 7679 2 EC2D59C5C4EEEDEB50FE8CC4EDB2661541C6FB7B76D2C764FA9BDC7EEC91874D2F03EFF1E495C8E6E28F6D2774C47823A3F735D4C9E2235E6A09D12BE2D44EFE02749DDDD578EFEC411AB997793A43AA266B4C54F2E4A950A810194D3482361F063952E3B2ADC024CF691EE36FEDCA94ED5CBF45FC5B08F766164719991EBDFA75C96975E3D6528AA19154F11F066E56969F9132CA6B0AFA6FB7032853CCC760530E0380E68CA3C1AC755693E25F4A45E80EF3D5F711746A204A48E5C6E92DC0A928C96F5E77FA41BFF01D66CA8A86C21CD2651ED3548225F5EB5F1B2C0BB7CDE4A6E7CCDE9CAF0CB1B779385A4EE55B845D23B5958950154DFCC45640EC6E821C1E67B8E1408B574DEEA98D3258664F351B390C71476E47FECA8ED24F3C8860867A952B5586018C417B527F2E86EF3D0EFCDAFC8B7D21B62521905BF3FE47F6B90A86D19FA57562692189E20B66788DC67DB045B8C5D75032F932616E838B267E2686FD15DAC391B7CFF9BC8B7C64C32D1D95553BE7C39238C2D80E9C63796B474BD9F270ECD0F79137C20DA0E5349B8C20F224115CC24020BFFF7FC2238E83894DFCF0760BC07618A95B35E996840B1655F9826BE3E0E2D993C7E653555697B528B2E9FA1C177728278E56C447C6B783437830EDDB938B931D6DAF9DEA98574720346741A7635D8B7C1010666AD6E108C1AC05F6EF15DD04E6A3B16DE1798F2B61C491D52862B6517AD01353909BDB10D83837EFAC26838ED308474E75207FE738070D7CAA3FD8DBE8480507D8E6C21660DB2A7E933B600C2C8F0EDCED45D9D7E3A05E7A0DB7EE728882AA40D332E2BECD9D48B48C349D48712FCBA01D5804C8F290DB60AD0AF9E3B1E7DC968F11CF96729578A43FEB1317FFE321A8CC1ACF62C290B5DF621FFA4BCABB228ABEF5D573F7CA7123651C126B6DB1CD7A54F7E9C79041B763AC8831C1C0DB2EFA4BCEC3E2A4E21C7BA3D8DA09C6444B4B00254C70D650B59AF22764C71BCBA012B45AC429D8463E2B5708004BF05DB42990C7368B3DE5D9109E8C1301D342FFDCAC9713C78F23AB73922A0C1FF41B8D22F64EB07B60580D34DAB63A43DFA90CFD6AB493917BBB6AD0B9075AB2C34E02CF7375C5499FDCCD7DEE23A201F62AA8474D7F38221CD202507663D0033087FA156E5DE7BE1E8CE9BFAA8955F254B97853C2FB45098A14EB0A51DA2BAA41C0F6A172AAF39839C4B0965AA0FBB92E755590F72B6EE24A0E006170AC9ED4CCC1D9DA4711FB1AE2019F4AFE4FD4D942E3FE04AA995E0F153518C5772CDAEB0545D4ED0C539CAA693968342D2BF4718CA134B2339FC404C0A6EF98E4D1F41810E13269E893A3
+20201102211136 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE3517F41C1B
+20201104100232 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE3524190003
+20201105060459 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE352B3534C3
+20201105221348 2 6 100 8191 5 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE3530AF83DF
+20201106144432 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE3532F388EB
+20201106185057 2 6 100 8191 5 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE353439AA67
+20201106205758 2 6 100 8191 5 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE3534DBDE9F
+20201108084639 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE353FE7CAAB
+20201108111802 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE3540A8BEE3
+20201110061156 2 6 100 8191 5 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE354999F6FF
+20201110093838 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE354AA4B823
+20201110151143 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE354C50D693
+20201111171657 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE3552F4F60B
+20201112131542 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE3557968743
+20201112142355 2 6 100 8191 5 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE3557E37967
+20201114080059 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE356084D88B
+20201114083959 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE3560ACB6BB
+20201115001553 2 6 100 8191 5 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE3564EE2F57
+20201120223033 2 6 100 8191 5 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE356F28AE3F
+20201121022848 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE3570473673
+20201122013144 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE357695B923
+20201122062444 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE3577F6EA23
+20201122185950 2 6 100 8191 5 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE357B47DF37
+20201123124747 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE357FD02753
+20201123192135 2 6 100 8191 5 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE35819E1A87
+20201124212459 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE35891DC76B
+20201126010742 2 6 100 8191 2 F1B12D9320A14F9678850067F9130D8767B7A6E198931A99000937CFE7EEDE8605377479AB32BB47AD82183273900757DBEE9BBDC91459257355DBD3E523235F97FEA3162BAA5F020B81E12CFC85D2DE52517F7CF6448C64597E60675DBFE632696B1C21818EC5E35EF2002FEEC0E061E0C2782549B1BBFD6409CDF616F7D3283FEE82D16E1D44A6FB7802DAB848AFA33E308EB4B517CD239C86205B652B89328746AEB81211CFCFE70B64876D2F6BBA9D74C45D5CE3AA96EC016FCFC13B99C5C55DD4ABB60B35431C90F8BDB281BE1EBBE0054423FB91DB94DEC350598976AF244D86C07E97A171469DE89714F5944C21E92489374CA4C45BDD6A0278750B0FCB29177FF27A382A946CBA9931A98A2676469011B25D0ECBACA7CE710CFCA47C2ED2E9D7DE22E49F56ED7D7D1218C54266720741A687DF37F18ED39A56A067E13D9A8886A67ADEFED30D05F6D0EEA6138CBBF9DD738B406957E08FBB7D6BEC2047DBB314484CA3A4838CA57803F89D90A5130A9CA79364485F58C63AC85D4154A287DEB324D240D253036A17A07AB818535BD7DE1E57DB2646714789447C4A6EBE1538D569DF267BA4CB1DFD3EDFF71D7AF4BFDEADE2912EF0790ACABDFE5B87C7EADED47A0C06B889B47FA85A9F9CC2038C048F930A30772A09991C910DECCAB3F7AF1814F2DF3FF2AE66686E8A010DD4ABF3825491DB8EAEA4D7A957D1F4BF3A060AD3D20F821D76C9F60410E32AA67D1798ECF3F514ED3DCF62348F7739A6ECEC53010A3B656D45A808237ACECE87377C8EA21D89E350D2CB4E31A017981C70718BF681D0A4E216ACF7D950615B4E4B48BA1AD10C436BD466DEB6F61222003FB6C42017A98E780C272DAE2AEE4C3291B0C112918F287BADAB2A22A7DCC78B10D55AB6BF4FD4651F0A8BD9F2CCA24D07BA33B09928C77ADE6F73D1C36247C8D5CC568A337721F9073515B65DB7E7555BADE6F201545EB766A97C3E0780FA67B042DBFBF208F409ABEEAFC6D4C4A9D89693A4E6C041C98A3C200576F4BF22D7C03376FBEB972ECBE96B156212E4A91925515D0C0707C61826C1386D8B7C6F210EF51D566BD847554C47B364C1BC97EC1F316AB9EFCA7B3D2AD326C3E00D4A2A01F1F559119C9702DDA5D1651A83E4107EDDA43FCD824B47591CA2DE11F356C9FB90DFEAF2B625FE65F070171CC558DAB5A1305286274BDCFE6A80155A80025D0CFEE151CD96197E35D2763B59DC20FA90F99597460E60D1069977F9CDCD3F942BAC1178AF9002425CDE4F83CFEFD8288F0154FA615D22D2573FE7C9E66FBD012C9D8FCD1447C095FA3F14A23A6E3A264EC35F97A868828A1ED87DC0434855AD9442DB6FD833CD92CE182691DE15762A973CE94E6E50033B0FC41DE50699848DF71B67A25B42AB8F53CBC348E797FE141BA21ED856ACF2BEE1A2DE358F8CD93B
+20201126112257 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52C39B7333
+20201126140745 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52C45E6703
+20201126214355 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52C6780D9B
+20201130015948 2 6 100 8191 5 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52D6D7FA8F
+20201130065350 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52D840F33B
+20201130145645 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52DABEE3A3
+20201201235732 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52E5502703
+20201202082252 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52E817B86B
+20201202104859 2 6 100 8191 5 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52E8D8B1BF
+20201202160137 2 6 100 8191 5 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52EA838D97
+20201203002758 2 6 100 8191 5 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52ED4610C7
+20201203025251 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52EE01CD03
+20201203041751 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52EE6A8983
+20201203111152 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52F0A4F47B
+20201203145545 2 6 100 8191 5 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52F1CBE427
+20201205170601 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F52FEF5ADC3
+20201206111756 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F5304585883
+20201206134442 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F5304DFD00B
+20201206210155 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F5307041CE3
+20201211131928 2 6 100 8191 5 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F530E903C57
+20201211155555 2 6 100 8191 5 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F530FB34647
+20201212050222 2 6 100 8191 5 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F53159567A7
+20201212065249 2 6 100 8191 5 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F5316666907
+20201212112957 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F5318743CAB
+20201213055402 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F53209F5C8B
+20201213092727 2 6 100 8191 5 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F53222C28F7
+20201213111750 2 6 100 8191 5 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F5322F62BB7
+20201214024800 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F5329702E43
+20201214140453 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F532D4542E3
+20201214145631 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F532D9AB18B
+20201215023044 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F5332A0951B
+20201219175046 2 6 100 8191 5 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F5338F2214F
+20201220100836 2 6 100 8191 2 D9DDC7C88FDE577A58F31AEE0835F0FB225841D9D09B3C82716C06C36FBC0F0402761E9F90D2CC5488C1BB87DCBBD138B1CBC24B1A052C8A2F8BE13EDE229AC234A5FDBDB26E73547264DA65F1B4CF41CDCE8D4EBF88CEEC4EFD23CEC8955B06DA81AA15889746DCFB193CD3BECE98DCFC1E429C87F7B72D8AB5C18EC3DDC80020C5246593B9E9BF898EA44485CA1D355188C14042AC06A7FDBCFF51F554AB06B3F8169429C660109DD4B36F6717F9CE25838244000C417BB9802011D9416ADB8A00F0F71A50E50A58CA97F08A6C1EABEEC8B3BD0980E1AD6A7ED70A71E5B5CC7EC87B4EA621CF8EE85FA9B5EB936F890AC6BFAB56CBA7B6E5F5BC758398F4FF239A4FBB300FCCF380CDEDEC74FE498188D9BAC3CA512813F9E2266D4B60C8A5F151ED4BD9753D5FA904C663893F0A859BF467EAC5C3B4F0006F5012EA5A0C65F5110972942A91DE30C1B0B320C54A0A261DB041650A6218A722FA409A839EE1C9F2C96A579B19FBBE420F96E803ACF5A6ADFAEB706AE8262187A436B7ECA3023564A62D5172A0C332EE9F2E46D935C2815F8405F988C5C48017048F9A1C24002D5D72A18C3652D5FE8DA864401A25FAA6EF257C86E501641C3F34FC5614EF5D0F69485E425FC954B83071687E6B752207014BDE88ED10061556D1B6694519AA04BDC6A38D1D57A0A3051DE893FB6BDF70AD8ED60075E7E2C616BF2CB96BE77EA8901464B97C3CF8CE183406FB15ACC9AE372BB6496BFAD79AE677CA62428A8735A8A8730EEA89838F3338A7F596A0BEA48DE878CB867D2BDAF2F40BB67FDCBEF2FEB56907E6567BF2C45B574C8A37049643B78CA2B31AB90AC13EBBCACA3630DE646260C6E37D3D64600E9FB73139ACE1C2FD22FF05B8E4F1E603E98C1BB37BDABDE4704B94121F50F9E1848829E342150406D8545FF66162938162866926937DF23C5F1AC81F0517578C0D9B8CC1D28CA8FDA0E920FA222C67D313CE63F95FF6304E8ECDD595CB796B3771554F90C16FDD7D76F2B231D2FE711D3C088E36E52300B19A82C4B60BECC37DBA9CCD2150F46FF49142DE3F422B1CE5D7AC3B33300C7EE67C19299DB467E37EC6C5F3C6CD33BD98646C35B645528F6DC3FD356E49596989E444C6B8462A9F69DF7F83C26240D51AA7D1707DBFD92E1729794259D966D69F6934427F7C3A86706ECAE13ED69F4B104DD5BA70E36BE82EF52D6E8EE420C11E7C6ABEF4CBF61E61AD071243D6A8B13C4B107150C8D2DA91544D71F3F6B3108D25FD0A3116F65E92E45684BFD7EE7D939CEF0A02675B5B44DED75E336CF2ECC39C72458930E48DDAC2AF194C79EA0CE4EB5181549EFB8B098F9768119B42932945C782512FDE8BD6C39E3BF76120BB926CACE17DFADFE9FECAAEE6ED339C87C05CA8EC214FE9000A6D72A2602DE6110BAF0AB5E30AADB07F53402DD333
diff --git a/moduli.0 b/moduli.0
index dbbac1830eeb..15d7899ffc84 100644
--- a/moduli.0
+++ b/moduli.0
@@ -1,74 +1,74 @@
MODULI(5) File Formats Manual MODULI(5)
NAME
moduli M-bM-^@M-^S Diffie-Hellman moduli
DESCRIPTION
The /etc/moduli file contains prime numbers and generators for use by
sshd(8) in the Diffie-Hellman Group Exchange key exchange method.
New moduli may be generated with ssh-keygen(1) using a two-step process.
An initial candidate generation pass, using ssh-keygen -G, calculates
numbers that are likely to be useful. A second primality testing pass,
using ssh-keygen -T, provides a high degree of assurance that the numbers
are prime and are safe for use in Diffie-Hellman operations by sshd(8).
This moduli format is used as the output from each pass.
The file consists of newline-separated records, one per modulus,
containing seven space-separated fields. These fields are as follows:
timestamp The time that the modulus was last processed as
YYYYMMDDHHMMSS.
type Decimal number specifying the internal structure of
the prime modulus. Supported types are:
0 Unknown, not tested.
2 "Safe" prime; (p-1)/2 is also prime.
4 Sophie Germain; 2p+1 is also prime.
Moduli candidates initially produced by ssh-keygen(1)
are Sophie Germain primes (type 4). Further primality
testing with ssh-keygen(1) produces safe prime moduli
(type 2) that are ready for use in sshd(8). Other
types are not used by OpenSSH.
tests Decimal number indicating the type of primality tests
that the number has been subjected to represented as a
bitmask of the following values:
0x00 Not tested.
0x01 Composite number M-bM-^@M-^S not prime.
0x02 Sieve of Eratosthenes.
0x04 Probabilistic Miller-Rabin primality tests.
The ssh-keygen(1) moduli candidate generation uses the
Sieve of Eratosthenes (flag 0x02). Subsequent
ssh-keygen(1) primality tests are Miller-Rabin tests
(flag 0x04).
trials Decimal number indicating the number of primality
trials that have been performed on the modulus.
size Decimal number indicating the size of the prime in
bits.
generator The recommended generator for use with this modulus
(hexadecimal).
modulus The modulus itself in hexadecimal.
When performing Diffie-Hellman Group Exchange, sshd(8) first estimates
the size of the modulus required to produce enough Diffie-Hellman output
to sufficiently key the selected symmetric cipher. sshd(8) then randomly
selects a modulus from /etc/moduli that best meets the size requirement.
SEE ALSO
ssh-keygen(1), sshd(8)
STANDARDS
M. Friedl, N. Provos, and W. Simpson, Diffie-Hellman Group Exchange for
the Secure Shell (SSH) Transport Layer Protocol, RFC 4419, March 2006,
2006.
-OpenBSD 6.8 September 26, 2012 OpenBSD 6.8
+OpenBSD 6.9 September 26, 2012 OpenBSD 6.9
diff --git a/monitor.c b/monitor.c
index f6d6efc1b1b7..1a00d4591733 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1,1949 +1,1945 @@
-/* $OpenBSD: monitor.c,v 1.223 2021/01/27 10:05:28 djm Exp $ */
+/* $OpenBSD: monitor.c,v 1.225 2021/04/15 16:24:31 markus Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#include <pwd.h>
#include <signal.h>
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#else
# ifdef HAVE_SYS_POLL_H
# include <sys/poll.h>
# endif
#endif
#ifdef WITH_OPENSSL
#include <openssl/dh.h>
#endif
#include "openbsd-compat/sys-tree.h"
#include "openbsd-compat/sys-queue.h"
#include "openbsd-compat/openssl-compat.h"
#include "atomicio.h"
#include "xmalloc.h"
#include "ssh.h"
#include "sshkey.h"
#include "sshbuf.h"
#include "hostfile.h"
#include "auth.h"
#include "cipher.h"
#include "kex.h"
#include "dh.h"
#include "auth-pam.h"
#include "packet.h"
#include "auth-options.h"
#include "sshpty.h"
#include "channels.h"
#include "session.h"
#include "sshlogin.h"
#include "canohost.h"
#include "log.h"
#include "misc.h"
#include "servconf.h"
#include "monitor.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
#include "monitor_wrap.h"
#include "monitor_fdpass.h"
#include "compat.h"
#include "ssh2.h"
#include "authfd.h"
#include "match.h"
#include "ssherr.h"
#include "sk-api.h"
#ifdef GSSAPI
static Gssctxt *gsscontext = NULL;
#endif
/* Imports */
extern ServerOptions options;
extern u_int utmp_len;
extern struct sshbuf *loginmsg;
extern struct sshauthopt *auth_opts; /* XXX move to permanent ssh->authctxt? */
/* State exported from the child */
static struct sshbuf *child_state;
/* Functions on the monitor that answer unprivileged requests */
int mm_answer_moduli(struct ssh *, int, struct sshbuf *);
int mm_answer_sign(struct ssh *, int, struct sshbuf *);
int mm_answer_pwnamallow(struct ssh *, int, struct sshbuf *);
int mm_answer_auth2_read_banner(struct ssh *, int, struct sshbuf *);
int mm_answer_authserv(struct ssh *, int, struct sshbuf *);
int mm_answer_authpassword(struct ssh *, int, struct sshbuf *);
int mm_answer_bsdauthquery(struct ssh *, int, struct sshbuf *);
int mm_answer_bsdauthrespond(struct ssh *, int, struct sshbuf *);
int mm_answer_skeyquery(struct ssh *, int, struct sshbuf *);
int mm_answer_skeyrespond(struct ssh *, int, struct sshbuf *);
int mm_answer_keyallowed(struct ssh *, int, struct sshbuf *);
int mm_answer_keyverify(struct ssh *, int, struct sshbuf *);
int mm_answer_pty(struct ssh *, int, struct sshbuf *);
int mm_answer_pty_cleanup(struct ssh *, int, struct sshbuf *);
int mm_answer_term(struct ssh *, int, struct sshbuf *);
int mm_answer_rsa_keyallowed(struct ssh *, int, struct sshbuf *);
int mm_answer_rsa_challenge(struct ssh *, int, struct sshbuf *);
int mm_answer_rsa_response(struct ssh *, int, struct sshbuf *);
int mm_answer_sesskey(struct ssh *, int, struct sshbuf *);
int mm_answer_sessid(struct ssh *, int, struct sshbuf *);
#ifdef USE_PAM
int mm_answer_pam_start(struct ssh *, int, struct sshbuf *);
int mm_answer_pam_account(struct ssh *, int, struct sshbuf *);
int mm_answer_pam_init_ctx(struct ssh *, int, struct sshbuf *);
int mm_answer_pam_query(struct ssh *, int, struct sshbuf *);
int mm_answer_pam_respond(struct ssh *, int, struct sshbuf *);
int mm_answer_pam_free_ctx(struct ssh *, int, struct sshbuf *);
#endif
#ifdef GSSAPI
int mm_answer_gss_setup_ctx(struct ssh *, int, struct sshbuf *);
int mm_answer_gss_accept_ctx(struct ssh *, int, struct sshbuf *);
int mm_answer_gss_userok(struct ssh *, int, struct sshbuf *);
int mm_answer_gss_checkmic(struct ssh *, int, struct sshbuf *);
#endif
#ifdef SSH_AUDIT_EVENTS
int mm_answer_audit_event(struct ssh *, int, struct sshbuf *);
int mm_answer_audit_command(struct ssh *, int, struct sshbuf *);
#endif
static Authctxt *authctxt;
/* local state for key verify */
static u_char *key_blob = NULL;
static size_t key_bloblen = 0;
-static int key_blobtype = MM_NOKEY;
+static u_int key_blobtype = MM_NOKEY;
static struct sshauthopt *key_opts = NULL;
static char *hostbased_cuser = NULL;
static char *hostbased_chost = NULL;
static char *auth_method = "unknown";
static char *auth_submethod = NULL;
static u_int session_id2_len = 0;
static u_char *session_id2 = NULL;
static pid_t monitor_child_pid;
struct mon_table {
enum monitor_reqtype type;
int flags;
int (*f)(struct ssh *, int, struct sshbuf *);
};
#define MON_ISAUTH 0x0004 /* Required for Authentication */
#define MON_AUTHDECIDE 0x0008 /* Decides Authentication */
#define MON_ONCE 0x0010 /* Disable after calling */
#define MON_ALOG 0x0020 /* Log auth attempt without authenticating */
#define MON_AUTH (MON_ISAUTH|MON_AUTHDECIDE)
#define MON_PERMIT 0x1000 /* Request is permitted */
static int monitor_read(struct ssh *, struct monitor *, struct mon_table *,
struct mon_table **);
static int monitor_read_log(struct monitor *);
struct mon_table mon_dispatch_proto20[] = {
#ifdef WITH_OPENSSL
{MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli},
#endif
{MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
{MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
{MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
{MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
{MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
#ifdef USE_PAM
{MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
{MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
{MONITOR_REQ_PAM_INIT_CTX, MON_ONCE, mm_answer_pam_init_ctx},
{MONITOR_REQ_PAM_QUERY, 0, mm_answer_pam_query},
{MONITOR_REQ_PAM_RESPOND, MON_ONCE, mm_answer_pam_respond},
{MONITOR_REQ_PAM_FREE_CTX, MON_ONCE|MON_AUTHDECIDE, mm_answer_pam_free_ctx},
#endif
#ifdef SSH_AUDIT_EVENTS
{MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
#endif
#ifdef BSD_AUTH
{MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
{MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH, mm_answer_bsdauthrespond},
#endif
{MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed},
{MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify},
#ifdef GSSAPI
{MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx},
{MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
{MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok},
{MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic},
#endif
{0, 0, NULL}
};
struct mon_table mon_dispatch_postauth20[] = {
#ifdef WITH_OPENSSL
{MONITOR_REQ_MODULI, 0, mm_answer_moduli},
#endif
{MONITOR_REQ_SIGN, 0, mm_answer_sign},
{MONITOR_REQ_PTY, 0, mm_answer_pty},
{MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup},
{MONITOR_REQ_TERM, 0, mm_answer_term},
#ifdef SSH_AUDIT_EVENTS
{MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
{MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command},
#endif
{0, 0, NULL}
};
struct mon_table *mon_dispatch;
/* Specifies if a certain message is allowed at the moment */
static void
monitor_permit(struct mon_table *ent, enum monitor_reqtype type, int permit)
{
while (ent->f != NULL) {
if (ent->type == type) {
ent->flags &= ~MON_PERMIT;
ent->flags |= permit ? MON_PERMIT : 0;
return;
}
ent++;
}
}
static void
monitor_permit_authentications(int permit)
{
struct mon_table *ent = mon_dispatch;
while (ent->f != NULL) {
if (ent->flags & MON_AUTH) {
ent->flags &= ~MON_PERMIT;
ent->flags |= permit ? MON_PERMIT : 0;
}
ent++;
}
}
void
monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor)
{
struct mon_table *ent;
int authenticated = 0, partial = 0;
debug3("preauth child monitor started");
if (pmonitor->m_recvfd >= 0)
close(pmonitor->m_recvfd);
if (pmonitor->m_log_sendfd >= 0)
close(pmonitor->m_log_sendfd);
pmonitor->m_log_sendfd = pmonitor->m_recvfd = -1;
authctxt = (Authctxt *)ssh->authctxt;
memset(authctxt, 0, sizeof(*authctxt));
ssh->authctxt = authctxt;
authctxt->loginmsg = loginmsg;
mon_dispatch = mon_dispatch_proto20;
/* Permit requests for moduli and signatures */
monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
/* The first few requests do not require asynchronous access */
while (!authenticated) {
partial = 0;
auth_method = "unknown";
auth_submethod = NULL;
auth2_authctxt_reset_info(authctxt);
authenticated = (monitor_read(ssh, pmonitor,
mon_dispatch, &ent) == 1);
/* Special handling for multiple required authentications */
if (options.num_auth_methods != 0) {
if (authenticated &&
!auth2_update_methods_lists(authctxt,
auth_method, auth_submethod)) {
debug3_f("method %s: partial", auth_method);
authenticated = 0;
partial = 1;
}
}
if (authenticated) {
if (!(ent->flags & MON_AUTHDECIDE))
fatal_f("unexpected authentication from %d",
ent->type);
if (authctxt->pw->pw_uid == 0 &&
!auth_root_allowed(ssh, auth_method))
authenticated = 0;
#ifdef USE_PAM
/* PAM needs to perform account checks after auth */
if (options.use_pam && authenticated) {
struct sshbuf *m;
if ((m = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed",
__func__);
mm_request_receive_expect(pmonitor->m_sendfd,
MONITOR_REQ_PAM_ACCOUNT, m);
authenticated = mm_answer_pam_account(
ssh, pmonitor->m_sendfd, m);
sshbuf_free(m);
}
#endif
}
if (ent->flags & (MON_AUTHDECIDE|MON_ALOG)) {
auth_log(ssh, authenticated, partial,
auth_method, auth_submethod);
if (!partial && !authenticated)
authctxt->failures++;
if (authenticated || partial) {
auth2_update_session_info(authctxt,
auth_method, auth_submethod);
}
}
}
if (!authctxt->valid)
fatal_f("authenticated invalid user");
if (strcmp(auth_method, "unknown") == 0)
fatal_f("authentication method name unknown");
debug_f("user %s authenticated by privileged process", authctxt->user);
ssh->authctxt = NULL;
ssh_packet_set_log_preamble(ssh, "user %s", authctxt->user);
mm_get_keystate(ssh, pmonitor);
/* Drain any buffered messages from the child */
while (pmonitor->m_log_recvfd != -1 && monitor_read_log(pmonitor) == 0)
;
if (pmonitor->m_recvfd >= 0)
close(pmonitor->m_recvfd);
if (pmonitor->m_log_sendfd >= 0)
close(pmonitor->m_log_sendfd);
pmonitor->m_sendfd = pmonitor->m_log_recvfd = -1;
}
static void
monitor_set_child_handler(pid_t pid)
{
monitor_child_pid = pid;
}
static void
monitor_child_handler(int sig)
{
kill(monitor_child_pid, sig);
}
void
monitor_child_postauth(struct ssh *ssh, struct monitor *pmonitor)
{
close(pmonitor->m_recvfd);
pmonitor->m_recvfd = -1;
monitor_set_child_handler(pmonitor->m_pid);
ssh_signal(SIGHUP, &monitor_child_handler);
ssh_signal(SIGTERM, &monitor_child_handler);
ssh_signal(SIGINT, &monitor_child_handler);
#ifdef SIGXFSZ
ssh_signal(SIGXFSZ, SIG_IGN);
#endif
mon_dispatch = mon_dispatch_postauth20;
/* Permit requests for moduli and signatures */
monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
if (auth_opts->permit_pty_flag) {
monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1);
}
for (;;)
monitor_read(ssh, pmonitor, mon_dispatch, NULL);
}
static int
monitor_read_log(struct monitor *pmonitor)
{
struct sshbuf *logmsg;
- u_int len, level, line;
- char *msg, *file, *func;
+ u_int len, level, forced;
+ char *msg;
u_char *p;
int r;
if ((logmsg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
/* Read length */
if ((r = sshbuf_reserve(logmsg, 4, &p)) != 0)
fatal_fr(r, "reserve len");
if (atomicio(read, pmonitor->m_log_recvfd, p, 4) != 4) {
if (errno == EPIPE) {
sshbuf_free(logmsg);
debug_f("child log fd closed");
close(pmonitor->m_log_recvfd);
pmonitor->m_log_recvfd = -1;
return -1;
}
fatal_f("log fd read: %s", strerror(errno));
}
if ((r = sshbuf_get_u32(logmsg, &len)) != 0)
fatal_fr(r, "parse len");
if (len <= 4 || len > 8192)
fatal_f("invalid log message length %u", len);
/* Read severity, message */
sshbuf_reset(logmsg);
if ((r = sshbuf_reserve(logmsg, len, &p)) != 0)
fatal_fr(r, "reserve msg");
if (atomicio(read, pmonitor->m_log_recvfd, p, len) != len)
fatal_f("log fd read: %s", strerror(errno));
- if ((r = sshbuf_get_cstring(logmsg, &file, NULL)) != 0 ||
- (r = sshbuf_get_cstring(logmsg, &func, NULL)) != 0 ||
- (r = sshbuf_get_u32(logmsg, &line)) != 0 ||
- (r = sshbuf_get_u32(logmsg, &level)) != 0 ||
+ if ((r = sshbuf_get_u32(logmsg, &level)) != 0 ||
+ (r = sshbuf_get_u32(logmsg, &forced)) != 0 ||
(r = sshbuf_get_cstring(logmsg, &msg, NULL)) != 0)
fatal_fr(r, "parse");
/* Log it */
if (log_level_name(level) == NULL)
fatal_f("invalid log level %u (corrupted message?)", level);
- sshlog(file, func, line, 0, level, NULL, "%s [preauth]", msg);
+ sshlogdirect(level, forced, "%s [preauth]", msg);
sshbuf_free(logmsg);
- free(file);
- free(func);
free(msg);
return 0;
}
static int
monitor_read(struct ssh *ssh, struct monitor *pmonitor, struct mon_table *ent,
struct mon_table **pent)
{
struct sshbuf *m;
int r, ret;
u_char type;
struct pollfd pfd[2];
for (;;) {
memset(&pfd, 0, sizeof(pfd));
pfd[0].fd = pmonitor->m_sendfd;
pfd[0].events = POLLIN;
pfd[1].fd = pmonitor->m_log_recvfd;
pfd[1].events = pfd[1].fd == -1 ? 0 : POLLIN;
if (poll(pfd, pfd[1].fd == -1 ? 1 : 2, -1) == -1) {
if (errno == EINTR || errno == EAGAIN)
continue;
fatal_f("poll: %s", strerror(errno));
}
if (pfd[1].revents) {
/*
* Drain all log messages before processing next
* monitor request.
*/
monitor_read_log(pmonitor);
continue;
}
if (pfd[0].revents)
break; /* Continues below */
}
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
mm_request_receive(pmonitor->m_sendfd, m);
if ((r = sshbuf_get_u8(m, &type)) != 0)
fatal_fr(r, "parse type");
debug3_f("checking request %d", type);
while (ent->f != NULL) {
if (ent->type == type)
break;
ent++;
}
if (ent->f != NULL) {
if (!(ent->flags & MON_PERMIT))
fatal_f("unpermitted request %d", type);
ret = (*ent->f)(ssh, pmonitor->m_sendfd, m);
sshbuf_free(m);
/* The child may use this request only once, disable it */
if (ent->flags & MON_ONCE) {
debug2_f("%d used once, disabling now", type);
ent->flags &= ~MON_PERMIT;
}
if (pent != NULL)
*pent = ent;
return ret;
}
fatal_f("unsupported request: %d", type);
/* NOTREACHED */
return (-1);
}
/* allowed key state */
static int
monitor_allowed_key(const u_char *blob, u_int bloblen)
{
/* make sure key is allowed */
if (key_blob == NULL || key_bloblen != bloblen ||
timingsafe_bcmp(key_blob, blob, key_bloblen))
return (0);
return (1);
}
static void
monitor_reset_key_state(void)
{
/* reset state */
free(key_blob);
free(hostbased_cuser);
free(hostbased_chost);
sshauthopt_free(key_opts);
key_blob = NULL;
key_bloblen = 0;
key_blobtype = MM_NOKEY;
key_opts = NULL;
hostbased_cuser = NULL;
hostbased_chost = NULL;
}
#ifdef WITH_OPENSSL
int
mm_answer_moduli(struct ssh *ssh, int sock, struct sshbuf *m)
{
DH *dh;
const BIGNUM *dh_p, *dh_g;
int r;
u_int min, want, max;
if ((r = sshbuf_get_u32(m, &min)) != 0 ||
(r = sshbuf_get_u32(m, &want)) != 0 ||
(r = sshbuf_get_u32(m, &max)) != 0)
fatal_fr(r, "parse");
debug3_f("got parameters: %d %d %d", min, want, max);
/* We need to check here, too, in case the child got corrupted */
if (max < min || want < min || max < want)
fatal_f("bad parameters: %d %d %d", min, want, max);
sshbuf_reset(m);
dh = choose_dh(min, want, max);
if (dh == NULL) {
if ((r = sshbuf_put_u8(m, 0)) != 0)
fatal_fr(r, "assemble empty");
return (0);
} else {
/* Send first bignum */
DH_get0_pqg(dh, &dh_p, NULL, &dh_g);
if ((r = sshbuf_put_u8(m, 1)) != 0 ||
(r = sshbuf_put_bignum2(m, dh_p)) != 0 ||
(r = sshbuf_put_bignum2(m, dh_g)) != 0)
fatal_fr(r, "assemble");
DH_free(dh);
}
mm_request_send(sock, MONITOR_ANS_MODULI, m);
return (0);
}
#endif
int
mm_answer_sign(struct ssh *ssh, int sock, struct sshbuf *m)
{
extern int auth_sock; /* XXX move to state struct? */
struct sshkey *key;
struct sshbuf *sigbuf = NULL;
u_char *p = NULL, *signature = NULL;
char *alg = NULL;
size_t datlen, siglen, alglen;
int r, is_proof = 0;
u_int keyid, compat;
const char proof_req[] = "hostkeys-prove-00@openssh.com";
debug3_f("entering");
if ((r = sshbuf_get_u32(m, &keyid)) != 0 ||
(r = sshbuf_get_string(m, &p, &datlen)) != 0 ||
(r = sshbuf_get_cstring(m, &alg, &alglen)) != 0 ||
(r = sshbuf_get_u32(m, &compat)) != 0)
fatal_fr(r, "parse");
if (keyid > INT_MAX)
fatal_f("invalid key ID");
/*
* Supported KEX types use SHA1 (20 bytes), SHA256 (32 bytes),
* SHA384 (48 bytes) and SHA512 (64 bytes).
*
* Otherwise, verify the signature request is for a hostkey
* proof.
*
* XXX perform similar check for KEX signature requests too?
* it's not trivial, since what is signed is the hash, rather
* than the full kex structure...
*/
if (datlen != 20 && datlen != 32 && datlen != 48 && datlen != 64) {
/*
* Construct expected hostkey proof and compare it to what
* the client sent us.
*/
if (session_id2_len == 0) /* hostkeys is never first */
fatal_f("bad data length: %zu", datlen);
if ((key = get_hostkey_public_by_index(keyid, ssh)) == NULL)
fatal_f("no hostkey for index %d", keyid);
if ((sigbuf = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_put_cstring(sigbuf, proof_req)) != 0 ||
(r = sshbuf_put_string(sigbuf, session_id2,
session_id2_len)) != 0 ||
(r = sshkey_puts(key, sigbuf)) != 0)
fatal_fr(r, "assemble private key proof");
if (datlen != sshbuf_len(sigbuf) ||
memcmp(p, sshbuf_ptr(sigbuf), sshbuf_len(sigbuf)) != 0)
fatal_f("bad data length: %zu, hostkey proof len %zu",
datlen, sshbuf_len(sigbuf));
sshbuf_free(sigbuf);
is_proof = 1;
}
/* save session id, it will be passed on the first call */
if (session_id2_len == 0) {
session_id2_len = datlen;
session_id2 = xmalloc(session_id2_len);
memcpy(session_id2, p, session_id2_len);
}
if ((key = get_hostkey_by_index(keyid)) != NULL) {
if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, alg,
options.sk_provider, NULL, compat)) != 0)
fatal_fr(r, "sign");
} else if ((key = get_hostkey_public_by_index(keyid, ssh)) != NULL &&
auth_sock > 0) {
if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen,
p, datlen, alg, compat)) != 0)
fatal_fr(r, "agent sign");
} else
fatal_f("no hostkey from index %d", keyid);
debug3_f("%s signature %p(%zu)", is_proof ? "hostkey proof" : "KEX",
signature, siglen);
sshbuf_reset(m);
if ((r = sshbuf_put_string(m, signature, siglen)) != 0)
fatal_fr(r, "assemble");
free(alg);
free(p);
free(signature);
mm_request_send(sock, MONITOR_ANS_SIGN, m);
/* Turn on permissions for getpwnam */
monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
return (0);
}
#define PUTPW(b, id) \
do { \
if ((r = sshbuf_put_string(b, \
&pwent->id, sizeof(pwent->id))) != 0) \
fatal_fr(r, "assemble %s", #id); \
} while (0)
/* Retrieves the password entry and also checks if the user is permitted */
int
mm_answer_pwnamallow(struct ssh *ssh, int sock, struct sshbuf *m)
{
char *username;
struct passwd *pwent;
int r, allowed = 0;
u_int i;
debug3_f("entering");
if (authctxt->attempt++ != 0)
fatal_f("multiple attempts for getpwnam");
if ((r = sshbuf_get_cstring(m, &username, NULL)) != 0)
fatal_fr(r, "parse");
pwent = getpwnamallow(ssh, username);
authctxt->user = xstrdup(username);
setproctitle("%s [priv]", pwent ? username : "unknown");
free(username);
sshbuf_reset(m);
if (pwent == NULL) {
if ((r = sshbuf_put_u8(m, 0)) != 0)
fatal_fr(r, "assemble fakepw");
authctxt->pw = fakepw();
goto out;
}
allowed = 1;
authctxt->pw = pwent;
authctxt->valid = 1;
/* XXX send fake class/dir/shell, etc. */
if ((r = sshbuf_put_u8(m, 1)) != 0)
fatal_fr(r, "assemble ok");
PUTPW(m, pw_uid);
PUTPW(m, pw_gid);
#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
PUTPW(m, pw_change);
#endif
#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
PUTPW(m, pw_expire);
#endif
if ((r = sshbuf_put_cstring(m, pwent->pw_name)) != 0 ||
(r = sshbuf_put_cstring(m, "*")) != 0 ||
#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
(r = sshbuf_put_cstring(m, pwent->pw_gecos)) != 0 ||
#endif
#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
(r = sshbuf_put_cstring(m, pwent->pw_class)) != 0 ||
#endif
(r = sshbuf_put_cstring(m, pwent->pw_dir)) != 0 ||
(r = sshbuf_put_cstring(m, pwent->pw_shell)) != 0)
fatal_fr(r, "assemble pw");
out:
ssh_packet_set_log_preamble(ssh, "%suser %s",
authctxt->valid ? "authenticating" : "invalid ", authctxt->user);
if ((r = sshbuf_put_string(m, &options, sizeof(options))) != 0)
fatal_fr(r, "assemble options");
#define M_CP_STROPT(x) do { \
if (options.x != NULL && \
(r = sshbuf_put_cstring(m, options.x)) != 0) \
fatal_fr(r, "assemble %s", #x); \
} while (0)
#define M_CP_STRARRAYOPT(x, nx) do { \
for (i = 0; i < options.nx; i++) { \
if ((r = sshbuf_put_cstring(m, options.x[i])) != 0) \
fatal_fr(r, "assemble %s", #x); \
} \
} while (0)
/* See comment in servconf.h */
COPY_MATCH_STRING_OPTS();
#undef M_CP_STROPT
#undef M_CP_STRARRAYOPT
/* Create valid auth method lists */
if (auth2_setup_methods_lists(authctxt) != 0) {
/*
* The monitor will continue long enough to let the child
* run to it's packet_disconnect(), but it must not allow any
* authentication to succeed.
*/
debug_f("no valid authentication method lists");
}
debug3_f("sending MONITOR_ANS_PWNAM: %d", allowed);
mm_request_send(sock, MONITOR_ANS_PWNAM, m);
/* Allow service/style information on the auth context */
monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1);
#ifdef USE_PAM
if (options.use_pam)
monitor_permit(mon_dispatch, MONITOR_REQ_PAM_START, 1);
#endif
return (0);
}
int mm_answer_auth2_read_banner(struct ssh *ssh, int sock, struct sshbuf *m)
{
char *banner;
int r;
sshbuf_reset(m);
banner = auth2_read_banner();
if ((r = sshbuf_put_cstring(m, banner != NULL ? banner : "")) != 0)
fatal_fr(r, "assemble");
mm_request_send(sock, MONITOR_ANS_AUTH2_READ_BANNER, m);
free(banner);
return (0);
}
int
mm_answer_authserv(struct ssh *ssh, int sock, struct sshbuf *m)
{
int r;
monitor_permit_authentications(1);
if ((r = sshbuf_get_cstring(m, &authctxt->service, NULL)) != 0 ||
(r = sshbuf_get_cstring(m, &authctxt->style, NULL)) != 0)
fatal_fr(r, "parse");
debug3_f("service=%s, style=%s", authctxt->service, authctxt->style);
if (strlen(authctxt->style) == 0) {
free(authctxt->style);
authctxt->style = NULL;
}
return (0);
}
/*
* Check that the key type appears in the supplied pattern list, ignoring
* mismatches in the signature algorithm. (Signature algorithm checks are
* performed in the unprivileged authentication code).
* Returns 1 on success, 0 otherwise.
*/
static int
key_base_type_match(const char *method, const struct sshkey *key,
const char *list)
{
char *s, *l, *ol = xstrdup(list);
int found = 0;
l = ol;
for ((s = strsep(&l, ",")); s && *s != '\0'; (s = strsep(&l, ","))) {
if (sshkey_type_from_name(s) == key->type) {
found = 1;
break;
}
}
if (!found) {
error("%s key type %s is not in permitted list %s", method,
sshkey_ssh_name(key), list);
}
free(ol);
return found;
}
int
mm_answer_authpassword(struct ssh *ssh, int sock, struct sshbuf *m)
{
static int call_count;
char *passwd;
int r, authenticated;
size_t plen;
if (!options.password_authentication)
fatal_f("password authentication not enabled");
if ((r = sshbuf_get_cstring(m, &passwd, &plen)) != 0)
fatal_fr(r, "parse");
/* Only authenticate if the context is valid */
authenticated = options.password_authentication &&
auth_password(ssh, passwd);
freezero(passwd, plen);
sshbuf_reset(m);
if ((r = sshbuf_put_u32(m, authenticated)) != 0)
fatal_fr(r, "assemble");
#ifdef USE_PAM
if ((r = sshbuf_put_u32(m, sshpam_get_maxtries_reached())) != 0)
fatal_fr(r, "assemble PAM");
#endif
debug3("%s: sending result %d", __func__, authenticated);
debug3_f("sending result %d", authenticated);
mm_request_send(sock, MONITOR_ANS_AUTHPASSWORD, m);
call_count++;
if (plen == 0 && call_count == 1)
auth_method = "none";
else
auth_method = "password";
/* Causes monitor loop to terminate if authenticated */
return (authenticated);
}
#ifdef BSD_AUTH
int
mm_answer_bsdauthquery(struct ssh *ssh, int sock, struct sshbuf *m)
{
char *name, *infotxt;
u_int numprompts, *echo_on, success;
char **prompts;
int r;
if (!options.kbd_interactive_authentication)
fatal_f("kbd-int authentication not enabled");
success = bsdauth_query(authctxt, &name, &infotxt, &numprompts,
&prompts, &echo_on) < 0 ? 0 : 1;
sshbuf_reset(m);
if ((r = sshbuf_put_u32(m, success)) != 0)
fatal_fr(r, "assemble");
if (success) {
if ((r = sshbuf_put_cstring(m, prompts[0])) != 0)
fatal_fr(r, "assemble prompt");
}
debug3_f("sending challenge success: %u", success);
mm_request_send(sock, MONITOR_ANS_BSDAUTHQUERY, m);
if (success) {
free(name);
free(infotxt);
free(prompts);
free(echo_on);
}
return (0);
}
int
mm_answer_bsdauthrespond(struct ssh *ssh, int sock, struct sshbuf *m)
{
char *response;
int r, authok;
if (!options.kbd_interactive_authentication)
fatal_f("kbd-int authentication not enabled");
if (authctxt->as == NULL)
fatal_f("no bsd auth session");
if ((r = sshbuf_get_cstring(m, &response, NULL)) != 0)
fatal_fr(r, "parse");
authok = options.challenge_response_authentication &&
auth_userresponse(authctxt->as, response, 0);
authctxt->as = NULL;
debug3_f("<%s> = <%d>", response, authok);
free(response);
sshbuf_reset(m);
if ((r = sshbuf_put_u32(m, authok)) != 0)
fatal_fr(r, "assemble");
debug3_f("sending authenticated: %d", authok);
mm_request_send(sock, MONITOR_ANS_BSDAUTHRESPOND, m);
auth_method = "keyboard-interactive";
auth_submethod = "bsdauth";
return (authok != 0);
}
#endif
#ifdef USE_PAM
int
mm_answer_pam_start(struct ssh *ssh, int sock, struct sshbuf *m)
{
if (!options.use_pam)
fatal("UsePAM not set, but ended up in %s anyway", __func__);
start_pam(ssh);
monitor_permit(mon_dispatch, MONITOR_REQ_PAM_ACCOUNT, 1);
if (options.kbd_interactive_authentication)
monitor_permit(mon_dispatch, MONITOR_REQ_PAM_INIT_CTX, 1);
return (0);
}
int
mm_answer_pam_account(struct ssh *ssh, int sock, struct sshbuf *m)
{
u_int ret;
int r;
if (!options.use_pam)
fatal("%s: PAM not enabled", __func__);
ret = do_pam_account();
if ((r = sshbuf_put_u32(m, ret)) != 0 ||
(r = sshbuf_put_stringb(m, loginmsg)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
mm_request_send(sock, MONITOR_ANS_PAM_ACCOUNT, m);
return (ret);
}
static void *sshpam_ctxt, *sshpam_authok;
extern KbdintDevice sshpam_device;
int
mm_answer_pam_init_ctx(struct ssh *ssh, int sock, struct sshbuf *m)
{
u_int ok = 0;
int r;
debug3("%s", __func__);
if (!options.kbd_interactive_authentication)
fatal("%s: kbd-int authentication not enabled", __func__);
if (sshpam_ctxt != NULL)
fatal("%s: already called", __func__);
sshpam_ctxt = (sshpam_device.init_ctx)(authctxt);
sshpam_authok = NULL;
sshbuf_reset(m);
if (sshpam_ctxt != NULL) {
monitor_permit(mon_dispatch, MONITOR_REQ_PAM_FREE_CTX, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_PAM_QUERY, 1);
ok = 1;
}
if ((r = sshbuf_put_u32(m, ok)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
mm_request_send(sock, MONITOR_ANS_PAM_INIT_CTX, m);
return (0);
}
int
mm_answer_pam_query(struct ssh *ssh, int sock, struct sshbuf *m)
{
char *name = NULL, *info = NULL, **prompts = NULL;
u_int i, num = 0, *echo_on = 0;
int r, ret;
debug3("%s", __func__);
sshpam_authok = NULL;
if (sshpam_ctxt == NULL)
fatal("%s: no context", __func__);
ret = (sshpam_device.query)(sshpam_ctxt, &name, &info,
&num, &prompts, &echo_on);
if (ret == 0 && num == 0)
sshpam_authok = sshpam_ctxt;
if (num > 1 || name == NULL || info == NULL)
fatal("sshpam_device.query failed");
monitor_permit(mon_dispatch, MONITOR_REQ_PAM_RESPOND, 1);
sshbuf_reset(m);
if ((r = sshbuf_put_u32(m, ret)) != 0 ||
(r = sshbuf_put_cstring(m, name)) != 0 ||
(r = sshbuf_put_cstring(m, info)) != 0 ||
(r = sshbuf_put_u32(m, sshpam_get_maxtries_reached())) != 0 ||
(r = sshbuf_put_u32(m, num)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
free(name);
free(info);
for (i = 0; i < num; ++i) {
if ((r = sshbuf_put_cstring(m, prompts[i])) != 0 ||
(r = sshbuf_put_u32(m, echo_on[i])) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
free(prompts[i]);
}
free(prompts);
free(echo_on);
auth_method = "keyboard-interactive";
auth_submethod = "pam";
mm_request_send(sock, MONITOR_ANS_PAM_QUERY, m);
return (0);
}
int
mm_answer_pam_respond(struct ssh *ssh, int sock, struct sshbuf *m)
{
char **resp;
u_int i, num;
int r, ret;
debug3("%s", __func__);
if (sshpam_ctxt == NULL)
fatal("%s: no context", __func__);
sshpam_authok = NULL;
if ((r = sshbuf_get_u32(m, &num)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
if (num > 0) {
resp = xcalloc(num, sizeof(char *));
for (i = 0; i < num; ++i) {
if ((r = sshbuf_get_cstring(m, &(resp[i]), NULL)) != 0)
fatal("%s: buffer error: %s",
__func__, ssh_err(r));
}
ret = (sshpam_device.respond)(sshpam_ctxt, num, resp);
for (i = 0; i < num; ++i)
free(resp[i]);
free(resp);
} else {
ret = (sshpam_device.respond)(sshpam_ctxt, num, NULL);
}
sshbuf_reset(m);
if ((r = sshbuf_put_u32(m, ret)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
mm_request_send(sock, MONITOR_ANS_PAM_RESPOND, m);
auth_method = "keyboard-interactive";
auth_submethod = "pam";
if (ret == 0)
sshpam_authok = sshpam_ctxt;
return (0);
}
int
mm_answer_pam_free_ctx(struct ssh *ssh, int sock, struct sshbuf *m)
{
int r = sshpam_authok != NULL && sshpam_authok == sshpam_ctxt;
debug3("%s", __func__);
if (sshpam_ctxt == NULL)
fatal("%s: no context", __func__);
(sshpam_device.free_ctx)(sshpam_ctxt);
sshpam_ctxt = sshpam_authok = NULL;
sshbuf_reset(m);
mm_request_send(sock, MONITOR_ANS_PAM_FREE_CTX, m);
/* Allow another attempt */
monitor_permit(mon_dispatch, MONITOR_REQ_PAM_INIT_CTX, 1);
auth_method = "keyboard-interactive";
auth_submethod = "pam";
return r;
}
#endif
int
mm_answer_keyallowed(struct ssh *ssh, int sock, struct sshbuf *m)
{
struct sshkey *key = NULL;
char *cuser, *chost;
u_int pubkey_auth_attempt;
- enum mm_keytype type = 0;
+ u_int type = 0;
int r, allowed = 0;
struct sshauthopt *opts = NULL;
debug3_f("entering");
if ((r = sshbuf_get_u32(m, &type)) != 0 ||
(r = sshbuf_get_cstring(m, &cuser, NULL)) != 0 ||
(r = sshbuf_get_cstring(m, &chost, NULL)) != 0 ||
(r = sshkey_froms(m, &key)) != 0 ||
(r = sshbuf_get_u32(m, &pubkey_auth_attempt)) != 0)
fatal_fr(r, "parse");
debug3_f("key_from_blob: %p", key);
if (key != NULL && authctxt->valid) {
/* These should not make it past the privsep child */
if (sshkey_type_plain(key->type) == KEY_RSA &&
(ssh->compat & SSH_BUG_RSASIGMD5) != 0)
fatal_f("passed a SSH_BUG_RSASIGMD5 key");
switch (type) {
case MM_USERKEY:
auth_method = "publickey";
if (!options.pubkey_authentication)
break;
if (auth2_key_already_used(authctxt, key))
break;
if (!key_base_type_match(auth_method, key,
options.pubkey_accepted_algos))
break;
allowed = user_key_allowed(ssh, authctxt->pw, key,
pubkey_auth_attempt, &opts);
break;
case MM_HOSTKEY:
auth_method = "hostbased";
if (!options.hostbased_authentication)
break;
if (auth2_key_already_used(authctxt, key))
break;
if (!key_base_type_match(auth_method, key,
options.hostbased_accepted_algos))
break;
allowed = hostbased_key_allowed(ssh, authctxt->pw,
cuser, chost, key);
auth2_record_info(authctxt,
"client user \"%.100s\", client host \"%.100s\"",
cuser, chost);
break;
default:
- fatal_f("unknown key type %d", type);
+ fatal_f("unknown key type %u", type);
break;
}
}
debug3_f("%s authentication%s: %s key is %s", auth_method,
pubkey_auth_attempt ? "" : " test",
(key == NULL || !authctxt->valid) ? "invalid" : sshkey_type(key),
allowed ? "allowed" : "not allowed");
auth2_record_key(authctxt, 0, key);
/* clear temporarily storage (used by verify) */
monitor_reset_key_state();
if (allowed) {
/* Save temporarily for comparison in verify */
if ((r = sshkey_to_blob(key, &key_blob, &key_bloblen)) != 0)
fatal_fr(r, "sshkey_to_blob");
key_blobtype = type;
key_opts = opts;
hostbased_cuser = cuser;
hostbased_chost = chost;
} else {
/* Log failed attempt */
auth_log(ssh, 0, 0, auth_method, NULL);
free(cuser);
free(chost);
}
sshkey_free(key);
sshbuf_reset(m);
if ((r = sshbuf_put_u32(m, allowed)) != 0)
fatal_fr(r, "assemble");
if (opts != NULL && (r = sshauthopt_serialise(opts, m, 1)) != 0)
fatal_fr(r, "sshauthopt_serialise");
mm_request_send(sock, MONITOR_ANS_KEYALLOWED, m);
if (!allowed)
sshauthopt_free(opts);
return (0);
}
static int
monitor_valid_userblob(struct ssh *ssh, const u_char *data, u_int datalen)
{
struct sshbuf *b;
const u_char *p;
char *userstyle, *cp;
size_t len;
u_char type;
int r, fail = 0;
if ((b = sshbuf_from(data, datalen)) == NULL)
fatal_f("sshbuf_from");
if (ssh->compat & SSH_OLD_SESSIONID) {
p = sshbuf_ptr(b);
len = sshbuf_len(b);
if ((session_id2 == NULL) ||
(len < session_id2_len) ||
(timingsafe_bcmp(p, session_id2, session_id2_len) != 0))
fail++;
if ((r = sshbuf_consume(b, session_id2_len)) != 0)
fatal_fr(r, "consume");
} else {
if ((r = sshbuf_get_string_direct(b, &p, &len)) != 0)
fatal_fr(r, "parse sessionid");
if ((session_id2 == NULL) ||
(len != session_id2_len) ||
(timingsafe_bcmp(p, session_id2, session_id2_len) != 0))
fail++;
}
if ((r = sshbuf_get_u8(b, &type)) != 0)
fatal_fr(r, "parse type");
if (type != SSH2_MSG_USERAUTH_REQUEST)
fail++;
if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0)
fatal_fr(r, "parse userstyle");
xasprintf(&userstyle, "%s%s%s", authctxt->user,
authctxt->style ? ":" : "",
authctxt->style ? authctxt->style : "");
if (strcmp(userstyle, cp) != 0) {
logit("wrong user name passed to monitor: "
"expected %s != %.100s", userstyle, cp);
fail++;
}
free(userstyle);
free(cp);
if ((r = sshbuf_skip_string(b)) != 0 || /* service */
(r = sshbuf_get_cstring(b, &cp, NULL)) != 0)
fatal_fr(r, "parse method");
if (strcmp("publickey", cp) != 0)
fail++;
free(cp);
if ((r = sshbuf_get_u8(b, &type)) != 0)
fatal_fr(r, "parse pktype");
if (type == 0)
fail++;
if ((r = sshbuf_skip_string(b)) != 0 || /* pkalg */
(r = sshbuf_skip_string(b)) != 0) /* pkblob */
fatal_fr(r, "parse pk");
if (sshbuf_len(b) != 0)
fail++;
sshbuf_free(b);
return (fail == 0);
}
static int
monitor_valid_hostbasedblob(const u_char *data, u_int datalen,
const char *cuser, const char *chost)
{
struct sshbuf *b;
const u_char *p;
char *cp, *userstyle;
size_t len;
int r, fail = 0;
u_char type;
if ((b = sshbuf_from(data, datalen)) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_get_string_direct(b, &p, &len)) != 0)
fatal_fr(r, "parse sessionid");
if ((session_id2 == NULL) ||
(len != session_id2_len) ||
(timingsafe_bcmp(p, session_id2, session_id2_len) != 0))
fail++;
if ((r = sshbuf_get_u8(b, &type)) != 0)
fatal_fr(r, "parse type");
if (type != SSH2_MSG_USERAUTH_REQUEST)
fail++;
if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0)
fatal_fr(r, "parse userstyle");
xasprintf(&userstyle, "%s%s%s", authctxt->user,
authctxt->style ? ":" : "",
authctxt->style ? authctxt->style : "");
if (strcmp(userstyle, cp) != 0) {
logit("wrong user name passed to monitor: "
"expected %s != %.100s", userstyle, cp);
fail++;
}
free(userstyle);
free(cp);
if ((r = sshbuf_skip_string(b)) != 0 || /* service */
(r = sshbuf_get_cstring(b, &cp, NULL)) != 0)
fatal_fr(r, "parse method");
if (strcmp(cp, "hostbased") != 0)
fail++;
free(cp);
if ((r = sshbuf_skip_string(b)) != 0 || /* pkalg */
(r = sshbuf_skip_string(b)) != 0) /* pkblob */
fatal_fr(r, "parse pk");
/* verify client host, strip trailing dot if necessary */
if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0)
fatal_fr(r, "parse host");
if (((len = strlen(cp)) > 0) && cp[len - 1] == '.')
cp[len - 1] = '\0';
if (strcmp(cp, chost) != 0)
fail++;
free(cp);
/* verify client user */
if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0)
fatal_fr(r, "parse ruser");
if (strcmp(cp, cuser) != 0)
fail++;
free(cp);
if (sshbuf_len(b) != 0)
fail++;
sshbuf_free(b);
return (fail == 0);
}
int
mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m)
{
struct sshkey *key;
const u_char *signature, *data, *blob;
char *sigalg = NULL, *fp = NULL;
size_t signaturelen, datalen, bloblen;
int r, ret, req_presence = 0, req_verify = 0, valid_data = 0;
int encoded_ret;
struct sshkey_sig_details *sig_details = NULL;
if ((r = sshbuf_get_string_direct(m, &blob, &bloblen)) != 0 ||
(r = sshbuf_get_string_direct(m, &signature, &signaturelen)) != 0 ||
(r = sshbuf_get_string_direct(m, &data, &datalen)) != 0 ||
(r = sshbuf_get_cstring(m, &sigalg, NULL)) != 0)
fatal_fr(r, "parse");
if (hostbased_cuser == NULL || hostbased_chost == NULL ||
!monitor_allowed_key(blob, bloblen))
fatal_f("bad key, not previously allowed");
/* Empty signature algorithm means NULL. */
if (*sigalg == '\0') {
free(sigalg);
sigalg = NULL;
}
/* XXX use sshkey_froms here; need to change key_blob, etc. */
if ((r = sshkey_from_blob(blob, bloblen, &key)) != 0)
fatal_fr(r, "parse key");
switch (key_blobtype) {
case MM_USERKEY:
valid_data = monitor_valid_userblob(ssh, data, datalen);
auth_method = "publickey";
break;
case MM_HOSTKEY:
valid_data = monitor_valid_hostbasedblob(data, datalen,
hostbased_cuser, hostbased_chost);
auth_method = "hostbased";
break;
default:
valid_data = 0;
break;
}
if (!valid_data)
fatal_f("bad %s signature data blob",
key_blobtype == MM_USERKEY ? "userkey" :
(key_blobtype == MM_HOSTKEY ? "hostkey" : "unknown"));
if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
SSH_FP_DEFAULT)) == NULL)
fatal_f("sshkey_fingerprint failed");
ret = sshkey_verify(key, signature, signaturelen, data, datalen,
sigalg, ssh->compat, &sig_details);
debug3_f("%s %p signature %s%s%s", auth_method, key,
(ret == 0) ? "verified" : "unverified",
(ret != 0) ? ": " : "", (ret != 0) ? ssh_err(ret) : "");
if (ret == 0 && key_blobtype == MM_USERKEY && sig_details != NULL) {
req_presence = (options.pubkey_auth_options &
PUBKEYAUTH_TOUCH_REQUIRED) ||
!key_opts->no_require_user_presence;
if (req_presence &&
(sig_details->sk_flags & SSH_SK_USER_PRESENCE_REQD) == 0) {
error("public key %s %s signature for %s%s from %.128s "
"port %d rejected: user presence "
"(authenticator touch) requirement not met ",
sshkey_type(key), fp,
authctxt->valid ? "" : "invalid user ",
authctxt->user, ssh_remote_ipaddr(ssh),
ssh_remote_port(ssh));
ret = SSH_ERR_SIGNATURE_INVALID;
}
req_verify = (options.pubkey_auth_options &
PUBKEYAUTH_VERIFY_REQUIRED) || key_opts->require_verify;
if (req_verify &&
(sig_details->sk_flags & SSH_SK_USER_VERIFICATION_REQD) == 0) {
error("public key %s %s signature for %s%s from %.128s "
"port %d rejected: user verification requirement "
"not met ", sshkey_type(key), fp,
authctxt->valid ? "" : "invalid user ",
authctxt->user, ssh_remote_ipaddr(ssh),
ssh_remote_port(ssh));
ret = SSH_ERR_SIGNATURE_INVALID;
}
}
auth2_record_key(authctxt, ret == 0, key);
if (key_blobtype == MM_USERKEY)
auth_activate_options(ssh, key_opts);
monitor_reset_key_state();
sshbuf_reset(m);
/* encode ret != 0 as positive integer, since we're sending u32 */
encoded_ret = (ret != 0);
if ((r = sshbuf_put_u32(m, encoded_ret)) != 0 ||
(r = sshbuf_put_u8(m, sig_details != NULL)) != 0)
fatal_fr(r, "assemble");
if (sig_details != NULL) {
if ((r = sshbuf_put_u32(m, sig_details->sk_counter)) != 0 ||
(r = sshbuf_put_u8(m, sig_details->sk_flags)) != 0)
fatal_fr(r, "assemble sk");
}
sshkey_sig_details_free(sig_details);
mm_request_send(sock, MONITOR_ANS_KEYVERIFY, m);
free(sigalg);
free(fp);
sshkey_free(key);
return ret == 0;
}
static void
mm_record_login(struct ssh *ssh, Session *s, struct passwd *pw)
{
socklen_t fromlen;
struct sockaddr_storage from;
/*
* Get IP address of client. If the connection is not a socket, let
* the address be 0.0.0.0.
*/
memset(&from, 0, sizeof(from));
fromlen = sizeof(from);
if (ssh_packet_connection_is_on_socket(ssh)) {
if (getpeername(ssh_packet_get_connection_in(ssh),
(struct sockaddr *)&from, &fromlen) == -1) {
debug("getpeername: %.100s", strerror(errno));
cleanup_exit(255);
}
}
/* Record that there was a login on that tty from the remote host. */
record_login(s->pid, s->tty, pw->pw_name, pw->pw_uid,
session_get_remote_name_or_ip(ssh, utmp_len, options.use_dns),
(struct sockaddr *)&from, fromlen);
}
static void
mm_session_close(Session *s)
{
debug3_f("session %d pid %ld", s->self, (long)s->pid);
if (s->ttyfd != -1) {
debug3_f("tty %s ptyfd %d", s->tty, s->ptyfd);
session_pty_cleanup2(s);
}
session_unused(s->self);
}
int
mm_answer_pty(struct ssh *ssh, int sock, struct sshbuf *m)
{
extern struct monitor *pmonitor;
Session *s;
int r, res, fd0;
debug3_f("entering");
sshbuf_reset(m);
s = session_new();
if (s == NULL)
goto error;
s->authctxt = authctxt;
s->pw = authctxt->pw;
s->pid = pmonitor->m_pid;
res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty));
if (res == 0)
goto error;
pty_setowner(authctxt->pw, s->tty);
if ((r = sshbuf_put_u32(m, 1)) != 0 ||
(r = sshbuf_put_cstring(m, s->tty)) != 0)
fatal_fr(r, "assemble");
/* We need to trick ttyslot */
if (dup2(s->ttyfd, 0) == -1)
fatal_f("dup2");
mm_record_login(ssh, s, authctxt->pw);
/* Now we can close the file descriptor again */
close(0);
/* send messages generated by record_login */
if ((r = sshbuf_put_stringb(m, loginmsg)) != 0)
fatal_fr(r, "assemble loginmsg");
sshbuf_reset(loginmsg);
mm_request_send(sock, MONITOR_ANS_PTY, m);
if (mm_send_fd(sock, s->ptyfd) == -1 ||
mm_send_fd(sock, s->ttyfd) == -1)
fatal_f("send fds failed");
/* make sure nothing uses fd 0 */
if ((fd0 = open(_PATH_DEVNULL, O_RDONLY)) == -1)
fatal_f("open(/dev/null): %s", strerror(errno));
if (fd0 != 0)
error_f("fd0 %d != 0", fd0);
/* slave side of pty is not needed */
close(s->ttyfd);
s->ttyfd = s->ptyfd;
/* no need to dup() because nobody closes ptyfd */
s->ptymaster = s->ptyfd;
debug3_f("tty %s ptyfd %d", s->tty, s->ttyfd);
return (0);
error:
if (s != NULL)
mm_session_close(s);
if ((r = sshbuf_put_u32(m, 0)) != 0)
fatal_fr(r, "assemble 0");
mm_request_send(sock, MONITOR_ANS_PTY, m);
return (0);
}
int
mm_answer_pty_cleanup(struct ssh *ssh, int sock, struct sshbuf *m)
{
Session *s;
char *tty;
int r;
debug3_f("entering");
if ((r = sshbuf_get_cstring(m, &tty, NULL)) != 0)
fatal_fr(r, "parse tty");
if ((s = session_by_tty(tty)) != NULL)
mm_session_close(s);
sshbuf_reset(m);
free(tty);
return (0);
}
int
mm_answer_term(struct ssh *ssh, int sock, struct sshbuf *req)
{
extern struct monitor *pmonitor;
int res, status;
debug3_f("tearing down sessions");
/* The child is terminating */
session_destroy_all(ssh, &mm_session_close);
#ifdef USE_PAM
if (options.use_pam)
sshpam_cleanup();
#endif
while (waitpid(pmonitor->m_pid, &status, 0) == -1)
if (errno != EINTR)
exit(1);
res = WIFEXITED(status) ? WEXITSTATUS(status) : 1;
/* Terminate process */
exit(res);
}
#ifdef SSH_AUDIT_EVENTS
/* Report that an audit event occurred */
int
mm_answer_audit_event(struct ssh *ssh, int socket, struct sshbuf *m)
{
u_int n;
ssh_audit_event_t event;
int r;
debug3("%s entering", __func__);
if ((r = sshbuf_get_u32(m, &n)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
event = (ssh_audit_event_t)n;
switch (event) {
case SSH_AUTH_FAIL_PUBKEY:
case SSH_AUTH_FAIL_HOSTBASED:
case SSH_AUTH_FAIL_GSSAPI:
case SSH_LOGIN_EXCEED_MAXTRIES:
case SSH_LOGIN_ROOT_DENIED:
case SSH_CONNECTION_CLOSE:
case SSH_INVALID_USER:
audit_event(ssh, event);
break;
default:
fatal("Audit event type %d not permitted", event);
}
return (0);
}
int
mm_answer_audit_command(struct ssh *ssh, int socket, struct sshbuf *m)
{
char *cmd;
int r;
debug3("%s entering", __func__);
if ((r = sshbuf_get_cstring(m, &cmd, NULL)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
/* sanity check command, if so how? */
audit_run_command(cmd);
free(cmd);
return (0);
}
#endif /* SSH_AUDIT_EVENTS */
void
monitor_clear_keystate(struct ssh *ssh, struct monitor *pmonitor)
{
ssh_clear_newkeys(ssh, MODE_IN);
ssh_clear_newkeys(ssh, MODE_OUT);
sshbuf_free(child_state);
child_state = NULL;
}
void
monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor)
{
struct kex *kex;
int r;
debug3_f("packet_set_state");
if ((r = ssh_packet_set_state(ssh, child_state)) != 0)
fatal_fr(r, "packet_set_state");
sshbuf_free(child_state);
child_state = NULL;
if ((kex = ssh->kex) == NULL)
fatal_f("internal error: ssh->kex == NULL");
if (session_id2_len != sshbuf_len(ssh->kex->session_id)) {
fatal_f("incorrect session id length %zu (expected %u)",
sshbuf_len(ssh->kex->session_id), session_id2_len);
}
if (memcmp(sshbuf_ptr(ssh->kex->session_id), session_id2,
session_id2_len) != 0)
fatal_f("session ID mismatch");
/* XXX set callbacks */
#ifdef WITH_OPENSSL
kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server;
kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server;
kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_server;
kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_server;
kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_server;
kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
# ifdef OPENSSL_HAS_ECC
kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
# endif
#endif /* WITH_OPENSSL */
kex->kex[KEX_C25519_SHA256] = kex_gen_server;
kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server;
kex->load_host_public_key=&get_hostkey_public_by_type;
kex->load_host_private_key=&get_hostkey_private_by_type;
kex->host_key_index=&get_hostkey_index;
kex->sign = sshd_hostkey_sign;
}
/* This function requires careful sanity checking */
void
mm_get_keystate(struct ssh *ssh, struct monitor *pmonitor)
{
debug3_f("Waiting for new keys");
if ((child_state = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT,
child_state);
debug3_f("GOT new keys");
}
/* XXX */
#define FD_CLOSEONEXEC(x) do { \
if (fcntl(x, F_SETFD, FD_CLOEXEC) == -1) \
fatal("fcntl(%d, F_SETFD)", x); \
} while (0)
static void
monitor_openfds(struct monitor *mon, int do_logfds)
{
int pair[2];
#ifdef SO_ZEROIZE
int on = 1;
#endif
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
fatal_f("socketpair: %s", strerror(errno));
#ifdef SO_ZEROIZE
if (setsockopt(pair[0], SOL_SOCKET, SO_ZEROIZE, &on, sizeof(on)) == -1)
error("setsockopt SO_ZEROIZE(0): %.100s", strerror(errno));
if (setsockopt(pair[1], SOL_SOCKET, SO_ZEROIZE, &on, sizeof(on)) == -1)
error("setsockopt SO_ZEROIZE(1): %.100s", strerror(errno));
#endif
FD_CLOSEONEXEC(pair[0]);
FD_CLOSEONEXEC(pair[1]);
mon->m_recvfd = pair[0];
mon->m_sendfd = pair[1];
if (do_logfds) {
if (pipe(pair) == -1)
fatal_f("pipe: %s", strerror(errno));
FD_CLOSEONEXEC(pair[0]);
FD_CLOSEONEXEC(pair[1]);
mon->m_log_recvfd = pair[0];
mon->m_log_sendfd = pair[1];
} else
mon->m_log_recvfd = mon->m_log_sendfd = -1;
}
#define MM_MEMSIZE 65536
struct monitor *
monitor_init(void)
{
struct monitor *mon;
mon = xcalloc(1, sizeof(*mon));
monitor_openfds(mon, 1);
return mon;
}
void
monitor_reinit(struct monitor *mon)
{
monitor_openfds(mon, 0);
}
#ifdef GSSAPI
int
mm_answer_gss_setup_ctx(struct ssh *ssh, int sock, struct sshbuf *m)
{
gss_OID_desc goid;
OM_uint32 major;
size_t len;
u_char *p;
int r;
if (!options.gss_authentication)
fatal_f("GSSAPI authentication not enabled");
if ((r = sshbuf_get_string(m, &p, &len)) != 0)
fatal_fr(r, "parse");
goid.elements = p;
goid.length = len;
major = ssh_gssapi_server_ctx(&gsscontext, &goid);
free(goid.elements);
sshbuf_reset(m);
if ((r = sshbuf_put_u32(m, major)) != 0)
fatal_fr(r, "assemble");
mm_request_send(sock, MONITOR_ANS_GSSSETUP, m);
/* Now we have a context, enable the step */
monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 1);
return (0);
}
int
mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m)
{
gss_buffer_desc in;
gss_buffer_desc out = GSS_C_EMPTY_BUFFER;
OM_uint32 major, minor;
OM_uint32 flags = 0; /* GSI needs this */
int r;
if (!options.gss_authentication)
fatal_f("GSSAPI authentication not enabled");
if ((r = ssh_gssapi_get_buffer_desc(m, &in)) != 0)
fatal_fr(r, "ssh_gssapi_get_buffer_desc");
major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
free(in.value);
sshbuf_reset(m);
if ((r = sshbuf_put_u32(m, major)) != 0 ||
(r = sshbuf_put_string(m, out.value, out.length)) != 0 ||
(r = sshbuf_put_u32(m, flags)) != 0)
fatal_fr(r, "assemble");
mm_request_send(sock, MONITOR_ANS_GSSSTEP, m);
gss_release_buffer(&minor, &out);
if (major == GSS_S_COMPLETE) {
monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
}
return (0);
}
int
mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m)
{
gss_buffer_desc gssbuf, mic;
OM_uint32 ret;
int r;
if (!options.gss_authentication)
fatal_f("GSSAPI authentication not enabled");
if ((r = ssh_gssapi_get_buffer_desc(m, &gssbuf)) != 0 ||
(r = ssh_gssapi_get_buffer_desc(m, &mic)) != 0)
fatal_fr(r, "ssh_gssapi_get_buffer_desc");
ret = ssh_gssapi_checkmic(gsscontext, &gssbuf, &mic);
free(gssbuf.value);
free(mic.value);
sshbuf_reset(m);
if ((r = sshbuf_put_u32(m, ret)) != 0)
fatal_fr(r, "assemble");
mm_request_send(sock, MONITOR_ANS_GSSCHECKMIC, m);
if (!GSS_ERROR(ret))
monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
return (0);
}
int
mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m)
{
int r, authenticated;
const char *displayname;
if (!options.gss_authentication)
fatal_f("GSSAPI authentication not enabled");
authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
sshbuf_reset(m);
if ((r = sshbuf_put_u32(m, authenticated)) != 0)
fatal_fr(r, "assemble");
debug3_f("sending result %d", authenticated);
mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m);
auth_method = "gssapi-with-mic";
if ((displayname = ssh_gssapi_displayname()) != NULL)
auth2_record_info(authctxt, "%s", displayname);
/* Monitor loop will terminate if authenticated */
return (authenticated);
}
#endif /* GSSAPI */
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 1226dfd0e401..748333c75e59 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1,1024 +1,1021 @@
-/* $OpenBSD: monitor_wrap.c,v 1.122 2020/11/27 00:37:10 djm Exp $ */
+/* $OpenBSD: monitor_wrap.c,v 1.123 2021/04/15 16:24:31 markus Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/uio.h>
#include <errno.h>
#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#ifdef WITH_OPENSSL
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/evp.h>
#endif
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "ssh.h"
#ifdef WITH_OPENSSL
#include "dh.h"
#endif
#include "sshbuf.h"
#include "sshkey.h"
#include "cipher.h"
#include "kex.h"
#include "hostfile.h"
#include "auth.h"
#include "auth-options.h"
#include "packet.h"
#include "mac.h"
#include "log.h"
#include "auth-pam.h"
#include "monitor.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
#include "monitor_wrap.h"
#include "atomicio.h"
#include "monitor_fdpass.h"
#include "misc.h"
#include "channels.h"
#include "session.h"
#include "servconf.h"
#include "ssherr.h"
/* Imports */
extern struct monitor *pmonitor;
extern struct sshbuf *loginmsg;
extern ServerOptions options;
void
-mm_log_handler(const char *file, const char *func, int line,
- LogLevel level, const char *msg, void *ctx)
+mm_log_handler(LogLevel level, int forced, const char *msg, void *ctx)
{
struct sshbuf *log_msg;
struct monitor *mon = (struct monitor *)ctx;
int r;
size_t len;
if (mon->m_log_sendfd == -1)
fatal_f("no log channel");
if ((log_msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u32(log_msg, 0)) != 0 || /* length; filled below */
- (r = sshbuf_put_cstring(log_msg, file)) != 0 ||
- (r = sshbuf_put_cstring(log_msg, func)) != 0 ||
- (r = sshbuf_put_u32(log_msg, (u_int)line)) != 0 ||
(r = sshbuf_put_u32(log_msg, level)) != 0 ||
+ (r = sshbuf_put_u32(log_msg, forced)) != 0 ||
(r = sshbuf_put_cstring(log_msg, msg)) != 0)
fatal_fr(r, "assemble");
if ((len = sshbuf_len(log_msg)) < 4 || len > 0xffffffff)
fatal_f("bad length %zu", len);
POKE_U32(sshbuf_mutable_ptr(log_msg), len - 4);
if (atomicio(vwrite, mon->m_log_sendfd,
sshbuf_mutable_ptr(log_msg), len) != len)
fatal_f("write: %s", strerror(errno));
sshbuf_free(log_msg);
}
int
mm_is_monitor(void)
{
/*
* m_pid is only set in the privileged part, and
* points to the unprivileged child.
*/
return (pmonitor && pmonitor->m_pid > 0);
}
void
mm_request_send(int sock, enum monitor_reqtype type, struct sshbuf *m)
{
size_t mlen = sshbuf_len(m);
u_char buf[5];
debug3_f("entering, type %d", type);
if (mlen >= 0xffffffff)
fatal_f("bad length %zu", mlen);
POKE_U32(buf, mlen + 1);
buf[4] = (u_char) type; /* 1st byte of payload is mesg-type */
if (atomicio(vwrite, sock, buf, sizeof(buf)) != sizeof(buf))
fatal_f("write: %s", strerror(errno));
if (atomicio(vwrite, sock, sshbuf_mutable_ptr(m), mlen) != mlen)
fatal_f("write: %s", strerror(errno));
}
void
mm_request_receive(int sock, struct sshbuf *m)
{
u_char buf[4], *p = NULL;
u_int msg_len;
int r;
debug3_f("entering");
if (atomicio(read, sock, buf, sizeof(buf)) != sizeof(buf)) {
if (errno == EPIPE)
cleanup_exit(255);
fatal_f("read: %s", strerror(errno));
}
msg_len = PEEK_U32(buf);
if (msg_len > 256 * 1024)
fatal_f("read: bad msg_len %d", msg_len);
sshbuf_reset(m);
if ((r = sshbuf_reserve(m, msg_len, &p)) != 0)
fatal_fr(r, "reserve");
if (atomicio(read, sock, p, msg_len) != msg_len)
fatal_f("read: %s", strerror(errno));
}
void
mm_request_receive_expect(int sock, enum monitor_reqtype type, struct sshbuf *m)
{
u_char rtype;
int r;
debug3_f("entering, type %d", type);
mm_request_receive(sock, m);
if ((r = sshbuf_get_u8(m, &rtype)) != 0)
fatal_fr(r, "parse");
if (rtype != type)
fatal_f("read: rtype %d != type %d", rtype, type);
}
#ifdef WITH_OPENSSL
DH *
mm_choose_dh(int min, int nbits, int max)
{
BIGNUM *p, *g;
int r;
u_char success = 0;
struct sshbuf *m;
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u32(m, min)) != 0 ||
(r = sshbuf_put_u32(m, nbits)) != 0 ||
(r = sshbuf_put_u32(m, max)) != 0)
fatal_fr(r, "assemble");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_MODULI, m);
debug3_f("waiting for MONITOR_ANS_MODULI");
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_MODULI, m);
if ((r = sshbuf_get_u8(m, &success)) != 0)
fatal_fr(r, "parse success");
if (success == 0)
fatal_f("MONITOR_ANS_MODULI failed");
if ((r = sshbuf_get_bignum2(m, &p)) != 0 ||
(r = sshbuf_get_bignum2(m, &g)) != 0)
fatal_fr(r, "parse group");
debug3_f("remaining %zu", sshbuf_len(m));
sshbuf_free(m);
return (dh_new_group(g, p));
}
#endif
int
mm_sshkey_sign(struct ssh *ssh, struct sshkey *key, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, const char *hostkey_alg,
const char *sk_provider, const char *sk_pin, u_int compat)
{
struct kex *kex = *pmonitor->m_pkex;
struct sshbuf *m;
u_int ndx = kex->host_key_index(key, 0, ssh);
int r;
debug3_f("entering");
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u32(m, ndx)) != 0 ||
(r = sshbuf_put_string(m, data, datalen)) != 0 ||
(r = sshbuf_put_cstring(m, hostkey_alg)) != 0 ||
(r = sshbuf_put_u32(m, compat)) != 0)
fatal_fr(r, "assemble");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SIGN, m);
debug3_f("waiting for MONITOR_ANS_SIGN");
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_SIGN, m);
if ((r = sshbuf_get_string(m, sigp, lenp)) != 0)
fatal_fr(r, "parse");
sshbuf_free(m);
return (0);
}
#define GETPW(b, id) \
do { \
if ((r = sshbuf_get_string_direct(b, &p, &len)) != 0) \
fatal_fr(r, "parse pw %s", #id); \
if (len != sizeof(pw->id)) \
fatal_fr(r, "bad length for %s", #id); \
memcpy(&pw->id, p, len); \
} while (0)
struct passwd *
mm_getpwnamallow(struct ssh *ssh, const char *username)
{
struct sshbuf *m;
struct passwd *pw;
size_t len;
u_int i;
ServerOptions *newopts;
int r;
u_char ok;
const u_char *p;
debug3_f("entering");
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_cstring(m, username)) != 0)
fatal_fr(r, "assemble");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PWNAM, m);
debug3_f("waiting for MONITOR_ANS_PWNAM");
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PWNAM, m);
if ((r = sshbuf_get_u8(m, &ok)) != 0)
fatal_fr(r, "parse success");
if (ok == 0) {
pw = NULL;
goto out;
}
/* XXX don't like passing struct passwd like this */
pw = xcalloc(sizeof(*pw), 1);
GETPW(m, pw_uid);
GETPW(m, pw_gid);
#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
GETPW(m, pw_change);
#endif
#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
GETPW(m, pw_expire);
#endif
if ((r = sshbuf_get_cstring(m, &pw->pw_name, NULL)) != 0 ||
(r = sshbuf_get_cstring(m, &pw->pw_passwd, NULL)) != 0 ||
#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
(r = sshbuf_get_cstring(m, &pw->pw_gecos, NULL)) != 0 ||
#endif
#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
(r = sshbuf_get_cstring(m, &pw->pw_class, NULL)) != 0 ||
#endif
(r = sshbuf_get_cstring(m, &pw->pw_dir, NULL)) != 0 ||
(r = sshbuf_get_cstring(m, &pw->pw_shell, NULL)) != 0)
fatal_fr(r, "parse pw");
out:
/* copy options block as a Match directive may have changed some */
if ((r = sshbuf_get_string_direct(m, &p, &len)) != 0)
fatal_fr(r, "parse opts");
if (len != sizeof(*newopts))
fatal_f("option block size mismatch");
newopts = xcalloc(sizeof(*newopts), 1);
memcpy(newopts, p, sizeof(*newopts));
#define M_CP_STROPT(x) do { \
if (newopts->x != NULL && \
(r = sshbuf_get_cstring(m, &newopts->x, NULL)) != 0) \
fatal_fr(r, "parse %s", #x); \
} while (0)
#define M_CP_STRARRAYOPT(x, nx) do { \
newopts->x = newopts->nx == 0 ? \
NULL : xcalloc(newopts->nx, sizeof(*newopts->x)); \
for (i = 0; i < newopts->nx; i++) { \
if ((r = sshbuf_get_cstring(m, \
&newopts->x[i], NULL)) != 0) \
fatal_fr(r, "parse %s", #x); \
} \
} while (0)
/* See comment in servconf.h */
COPY_MATCH_STRING_OPTS();
#undef M_CP_STROPT
#undef M_CP_STRARRAYOPT
copy_set_server_options(&options, newopts, 1);
log_change_level(options.log_level);
log_verbose_reset();
for (i = 0; i < options.num_log_verbose; i++)
log_verbose_add(options.log_verbose[i]);
process_permitopen(ssh, &options);
free(newopts);
sshbuf_free(m);
return (pw);
}
char *
mm_auth2_read_banner(void)
{
struct sshbuf *m;
char *banner;
int r;
debug3_f("entering");
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTH2_READ_BANNER, m);
sshbuf_reset(m);
mm_request_receive_expect(pmonitor->m_recvfd,
MONITOR_ANS_AUTH2_READ_BANNER, m);
if ((r = sshbuf_get_cstring(m, &banner, NULL)) != 0)
fatal_fr(r, "parse");
sshbuf_free(m);
/* treat empty banner as missing banner */
if (strlen(banner) == 0) {
free(banner);
banner = NULL;
}
return (banner);
}
/* Inform the privileged process about service and style */
void
mm_inform_authserv(char *service, char *style)
{
struct sshbuf *m;
int r;
debug3_f("entering");
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_cstring(m, service)) != 0 ||
(r = sshbuf_put_cstring(m, style ? style : "")) != 0)
fatal_fr(r, "assemble");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHSERV, m);
sshbuf_free(m);
}
/* Do the password authentication */
int
mm_auth_password(struct ssh *ssh, char *password)
{
struct sshbuf *m;
int r, authenticated = 0;
#ifdef USE_PAM
u_int maxtries = 0;
#endif
debug3_f("entering");
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_cstring(m, password)) != 0)
fatal_fr(r, "assemble");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHPASSWORD, m);
debug3_f("waiting for MONITOR_ANS_AUTHPASSWORD");
mm_request_receive_expect(pmonitor->m_recvfd,
MONITOR_ANS_AUTHPASSWORD, m);
if ((r = sshbuf_get_u32(m, &authenticated)) != 0)
fatal_fr(r, "parse");
#ifdef USE_PAM
if ((r = sshbuf_get_u32(m, &maxtries)) != 0)
fatal_fr(r, "parse PAM");
if (maxtries > INT_MAX)
fatal_fr(r, "bad maxtries");
sshpam_set_maxtries_reached(maxtries);
#endif
sshbuf_free(m);
debug3_f("user %sauthenticated", authenticated ? "" : "not ");
return (authenticated);
}
int
mm_user_key_allowed(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
int pubkey_auth_attempt, struct sshauthopt **authoptp)
{
return (mm_key_allowed(MM_USERKEY, NULL, NULL, key,
pubkey_auth_attempt, authoptp));
}
int
mm_hostbased_key_allowed(struct ssh *ssh, struct passwd *pw,
const char *user, const char *host, struct sshkey *key)
{
return (mm_key_allowed(MM_HOSTKEY, user, host, key, 0, NULL));
}
int
mm_key_allowed(enum mm_keytype type, const char *user, const char *host,
struct sshkey *key, int pubkey_auth_attempt, struct sshauthopt **authoptp)
{
struct sshbuf *m;
int r, allowed = 0;
struct sshauthopt *opts = NULL;
debug3_f("entering");
if (authoptp != NULL)
*authoptp = NULL;
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u32(m, type)) != 0 ||
(r = sshbuf_put_cstring(m, user ? user : "")) != 0 ||
(r = sshbuf_put_cstring(m, host ? host : "")) != 0 ||
(r = sshkey_puts(key, m)) != 0 ||
(r = sshbuf_put_u32(m, pubkey_auth_attempt)) != 0)
fatal_fr(r, "assemble");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYALLOWED, m);
debug3_f("waiting for MONITOR_ANS_KEYALLOWED");
mm_request_receive_expect(pmonitor->m_recvfd,
MONITOR_ANS_KEYALLOWED, m);
if ((r = sshbuf_get_u32(m, &allowed)) != 0)
fatal_fr(r, "parse");
if (allowed && type == MM_USERKEY &&
(r = sshauthopt_deserialise(m, &opts)) != 0)
fatal_fr(r, "sshauthopt_deserialise");
sshbuf_free(m);
if (authoptp != NULL) {
*authoptp = opts;
opts = NULL;
}
sshauthopt_free(opts);
return allowed;
}
/*
* This key verify needs to send the key type along, because the
* privileged parent makes the decision if the key is allowed
* for authentication.
*/
int
mm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen,
const u_char *data, size_t datalen, const char *sigalg, u_int compat,
struct sshkey_sig_details **sig_detailsp)
{
struct sshbuf *m;
u_int encoded_ret = 0;
int r;
u_char sig_details_present, flags;
u_int counter;
debug3_f("entering");
if (sig_detailsp != NULL)
*sig_detailsp = NULL;
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshkey_puts(key, m)) != 0 ||
(r = sshbuf_put_string(m, sig, siglen)) != 0 ||
(r = sshbuf_put_string(m, data, datalen)) != 0 ||
(r = sshbuf_put_cstring(m, sigalg == NULL ? "" : sigalg)) != 0)
fatal_fr(r, "assemble");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYVERIFY, m);
debug3_f("waiting for MONITOR_ANS_KEYVERIFY");
mm_request_receive_expect(pmonitor->m_recvfd,
MONITOR_ANS_KEYVERIFY, m);
if ((r = sshbuf_get_u32(m, &encoded_ret)) != 0 ||
(r = sshbuf_get_u8(m, &sig_details_present)) != 0)
fatal_fr(r, "parse");
if (sig_details_present && encoded_ret == 0) {
if ((r = sshbuf_get_u32(m, &counter)) != 0 ||
(r = sshbuf_get_u8(m, &flags)) != 0)
fatal_fr(r, "parse sig_details");
if (sig_detailsp != NULL) {
*sig_detailsp = xcalloc(1, sizeof(**sig_detailsp));
(*sig_detailsp)->sk_counter = counter;
(*sig_detailsp)->sk_flags = flags;
}
}
sshbuf_free(m);
if (encoded_ret != 0)
return SSH_ERR_SIGNATURE_INVALID;
return 0;
}
void
mm_send_keystate(struct ssh *ssh, struct monitor *monitor)
{
struct sshbuf *m;
int r;
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = ssh_packet_get_state(ssh, m)) != 0)
fatal_fr(r, "ssh_packet_get_state");
mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYEXPORT, m);
debug3_f("Finished sending state");
sshbuf_free(m);
}
int
mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
{
struct sshbuf *m;
char *p, *msg;
int success = 0, tmp1 = -1, tmp2 = -1, r;
/* Kludge: ensure there are fds free to receive the pty/tty */
if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 ||
(tmp2 = dup(pmonitor->m_recvfd)) == -1) {
error_f("cannot allocate fds for pty");
if (tmp1 > 0)
close(tmp1);
if (tmp2 > 0)
close(tmp2);
return 0;
}
close(tmp1);
close(tmp2);
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PTY, m);
debug3_f("waiting for MONITOR_ANS_PTY");
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PTY, m);
if ((r = sshbuf_get_u32(m, &success)) != 0)
fatal_fr(r, "parse success");
if (success == 0) {
debug3_f("pty alloc failed");
sshbuf_free(m);
return (0);
}
if ((r = sshbuf_get_cstring(m, &p, NULL)) != 0 ||
(r = sshbuf_get_cstring(m, &msg, NULL)) != 0)
fatal_fr(r, "parse");
sshbuf_free(m);
strlcpy(namebuf, p, namebuflen); /* Possible truncation */
free(p);
if ((r = sshbuf_put(loginmsg, msg, strlen(msg))) != 0)
fatal_fr(r, "put loginmsg");
free(msg);
if ((*ptyfd = mm_receive_fd(pmonitor->m_recvfd)) == -1 ||
(*ttyfd = mm_receive_fd(pmonitor->m_recvfd)) == -1)
fatal_f("receive fds failed");
/* Success */
return (1);
}
void
mm_session_pty_cleanup2(Session *s)
{
struct sshbuf *m;
int r;
if (s->ttyfd == -1)
return;
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_cstring(m, s->tty)) != 0)
fatal_fr(r, "assmble");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PTYCLEANUP, m);
sshbuf_free(m);
/* closed dup'ed master */
if (s->ptymaster != -1 && close(s->ptymaster) == -1)
error("close(s->ptymaster/%d): %s",
s->ptymaster, strerror(errno));
/* unlink pty from session */
s->ttyfd = -1;
}
#ifdef USE_PAM
void
mm_start_pam(struct ssh *ssh)
{
struct sshbuf *m;
debug3("%s entering", __func__);
if (!options.use_pam)
fatal("UsePAM=no, but ended up in %s anyway", __func__);
if ((m = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_START, m);
sshbuf_free(m);
}
u_int
mm_do_pam_account(void)
{
struct sshbuf *m;
u_int ret;
char *msg;
size_t msglen;
int r;
debug3("%s entering", __func__);
if (!options.use_pam)
fatal("UsePAM=no, but ended up in %s anyway", __func__);
if ((m = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_ACCOUNT, m);
mm_request_receive_expect(pmonitor->m_recvfd,
MONITOR_ANS_PAM_ACCOUNT, m);
if ((r = sshbuf_get_u32(m, &ret)) != 0 ||
(r = sshbuf_get_cstring(m, &msg, &msglen)) != 0 ||
(r = sshbuf_put(loginmsg, msg, msglen)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
free(msg);
sshbuf_free(m);
debug3("%s returning %d", __func__, ret);
return (ret);
}
void *
mm_sshpam_init_ctx(Authctxt *authctxt)
{
struct sshbuf *m;
int r, success;
debug3("%s", __func__);
if ((m = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_INIT_CTX, m);
debug3("%s: waiting for MONITOR_ANS_PAM_INIT_CTX", __func__);
mm_request_receive_expect(pmonitor->m_recvfd,
MONITOR_ANS_PAM_INIT_CTX, m);
if ((r = sshbuf_get_u32(m, &success)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
if (success == 0) {
debug3("%s: pam_init_ctx failed", __func__);
sshbuf_free(m);
return (NULL);
}
sshbuf_free(m);
return (authctxt);
}
int
mm_sshpam_query(void *ctx, char **name, char **info,
u_int *num, char ***prompts, u_int **echo_on)
{
struct sshbuf *m;
u_int i, n;
int r, ret;
debug3("%s", __func__);
if ((m = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_QUERY, m);
debug3("%s: waiting for MONITOR_ANS_PAM_QUERY", __func__);
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_QUERY, m);
if ((r = sshbuf_get_u32(m, &ret)) != 0 ||
(r = sshbuf_get_cstring(m, name, NULL)) != 0 ||
(r = sshbuf_get_cstring(m, info, NULL)) != 0 ||
(r = sshbuf_get_u32(m, &n)) != 0 ||
(r = sshbuf_get_u32(m, num)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
debug3("%s: pam_query returned %d", __func__, ret);
sshpam_set_maxtries_reached(n);
if (*num > PAM_MAX_NUM_MSG)
fatal("%s: received %u PAM messages, expected <= %u",
__func__, *num, PAM_MAX_NUM_MSG);
*prompts = xcalloc((*num + 1), sizeof(char *));
*echo_on = xcalloc((*num + 1), sizeof(u_int));
for (i = 0; i < *num; ++i) {
if ((r = sshbuf_get_cstring(m, &((*prompts)[i]), NULL)) != 0 ||
(r = sshbuf_get_u32(m, &((*echo_on)[i]))) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
}
sshbuf_free(m);
return (ret);
}
int
mm_sshpam_respond(void *ctx, u_int num, char **resp)
{
struct sshbuf *m;
u_int n, i;
int r, ret;
debug3("%s", __func__);
if ((m = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
if ((r = sshbuf_put_u32(m, num)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
for (i = 0; i < num; ++i) {
if ((r = sshbuf_put_cstring(m, resp[i])) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
}
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_RESPOND, m);
debug3("%s: waiting for MONITOR_ANS_PAM_RESPOND", __func__);
mm_request_receive_expect(pmonitor->m_recvfd,
MONITOR_ANS_PAM_RESPOND, m);
if ((r = sshbuf_get_u32(m, &n)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
ret = (int)n; /* XXX */
debug3("%s: pam_respond returned %d", __func__, ret);
sshbuf_free(m);
return (ret);
}
void
mm_sshpam_free_ctx(void *ctxtp)
{
struct sshbuf *m;
debug3("%s", __func__);
if ((m = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_FREE_CTX, m);
debug3("%s: waiting for MONITOR_ANS_PAM_FREE_CTX", __func__);
mm_request_receive_expect(pmonitor->m_recvfd,
MONITOR_ANS_PAM_FREE_CTX, m);
sshbuf_free(m);
}
#endif /* USE_PAM */
/* Request process termination */
void
mm_terminate(void)
{
struct sshbuf *m;
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_TERM, m);
sshbuf_free(m);
}
static void
mm_chall_setup(char **name, char **infotxt, u_int *numprompts,
char ***prompts, u_int **echo_on)
{
*name = xstrdup("");
*infotxt = xstrdup("");
*numprompts = 1;
*prompts = xcalloc(*numprompts, sizeof(char *));
*echo_on = xcalloc(*numprompts, sizeof(u_int));
(*echo_on)[0] = 0;
}
int
mm_bsdauth_query(void *ctx, char **name, char **infotxt,
u_int *numprompts, char ***prompts, u_int **echo_on)
{
struct sshbuf *m;
u_int success;
char *challenge;
int r;
debug3_f("entering");
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_BSDAUTHQUERY, m);
mm_request_receive_expect(pmonitor->m_recvfd,
MONITOR_ANS_BSDAUTHQUERY, m);
if ((r = sshbuf_get_u32(m, &success)) != 0)
fatal_fr(r, "parse success");
if (success == 0) {
debug3_f("no challenge");
sshbuf_free(m);
return (-1);
}
/* Get the challenge, and format the response */
if ((r = sshbuf_get_cstring(m, &challenge, NULL)) != 0)
fatal_fr(r, "parse challenge");
sshbuf_free(m);
mm_chall_setup(name, infotxt, numprompts, prompts, echo_on);
(*prompts)[0] = challenge;
debug3_f("received challenge: %s", challenge);
return (0);
}
int
mm_bsdauth_respond(void *ctx, u_int numresponses, char **responses)
{
struct sshbuf *m;
int r, authok;
debug3_f("entering");
if (numresponses != 1)
return (-1);
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_cstring(m, responses[0])) != 0)
fatal_fr(r, "assemble");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_BSDAUTHRESPOND, m);
mm_request_receive_expect(pmonitor->m_recvfd,
MONITOR_ANS_BSDAUTHRESPOND, m);
if ((r = sshbuf_get_u32(m, &authok)) != 0)
fatal_fr(r, "parse");
sshbuf_free(m);
return ((authok == 0) ? -1 : 0);
}
#ifdef SSH_AUDIT_EVENTS
void
mm_audit_event(struct ssh *ssh, ssh_audit_event_t event)
{
struct sshbuf *m;
int r;
debug3("%s entering", __func__);
if ((m = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
if ((r = sshbuf_put_u32(m, event)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_EVENT, m);
sshbuf_free(m);
}
void
mm_audit_run_command(const char *command)
{
struct sshbuf *m;
int r;
debug3("%s entering command %s", __func__, command);
if ((m = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
if ((r = sshbuf_put_cstring(m, command)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, m);
sshbuf_free(m);
}
#endif /* SSH_AUDIT_EVENTS */
#ifdef GSSAPI
OM_uint32
mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID goid)
{
struct sshbuf *m;
OM_uint32 major;
int r;
/* Client doesn't get to see the context */
*ctx = NULL;
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_string(m, goid->elements, goid->length)) != 0)
fatal_fr(r, "assemble");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSETUP, m);
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSETUP, m);
if ((r = sshbuf_get_u32(m, &major)) != 0)
fatal_fr(r, "parse");
sshbuf_free(m);
return (major);
}
OM_uint32
mm_ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *in,
gss_buffer_desc *out, OM_uint32 *flagsp)
{
struct sshbuf *m;
OM_uint32 major;
u_int flags;
int r;
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_string(m, in->value, in->length)) != 0)
fatal_fr(r, "assemble");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSTEP, m);
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSTEP, m);
if ((r = sshbuf_get_u32(m, &major)) != 0 ||
(r = ssh_gssapi_get_buffer_desc(m, out)) != 0)
fatal_fr(r, "parse");
if (flagsp != NULL) {
if ((r = sshbuf_get_u32(m, &flags)) != 0)
fatal_fr(r, "parse flags");
*flagsp = flags;
}
sshbuf_free(m);
return (major);
}
OM_uint32
mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
{
struct sshbuf *m;
OM_uint32 major;
int r;
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_string(m, gssbuf->value, gssbuf->length)) != 0 ||
(r = sshbuf_put_string(m, gssmic->value, gssmic->length)) != 0)
fatal_fr(r, "assemble");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSCHECKMIC, m);
mm_request_receive_expect(pmonitor->m_recvfd,
MONITOR_ANS_GSSCHECKMIC, m);
if ((r = sshbuf_get_u32(m, &major)) != 0)
fatal_fr(r, "parse");
sshbuf_free(m);
return(major);
}
int
mm_ssh_gssapi_userok(char *user)
{
struct sshbuf *m;
int r, authenticated = 0;
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, m);
mm_request_receive_expect(pmonitor->m_recvfd,
MONITOR_ANS_GSSUSEROK, m);
if ((r = sshbuf_get_u32(m, &authenticated)) != 0)
fatal_fr(r, "parse");
sshbuf_free(m);
debug3_f("user %sauthenticated", authenticated ? "" : "not ");
return (authenticated);
}
#endif /* GSSAPI */
diff --git a/monitor_wrap.h b/monitor_wrap.h
index 8507f1c11ef8..a163b67d2878 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -1,103 +1,102 @@
-/* $OpenBSD: monitor_wrap.h,v 1.46 2020/10/16 13:24:45 djm Exp $ */
+/* $OpenBSD: monitor_wrap.h,v 1.47 2021/04/15 16:24:31 markus Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MM_WRAP_H_
#define _MM_WRAP_H_
extern int use_privsep;
#define PRIVSEP(x) (use_privsep ? mm_##x : x)
enum mm_keytype { MM_NOKEY, MM_HOSTKEY, MM_USERKEY };
struct ssh;
struct monitor;
struct Authctxt;
struct sshkey;
struct sshauthopt;
struct sshkey_sig_details;
-void mm_log_handler(const char *, const char *, int, LogLevel,
- const char *, void *);
+void mm_log_handler(LogLevel, int, const char *, void *);
int mm_is_monitor(void);
#ifdef WITH_OPENSSL
DH *mm_choose_dh(int, int, int);
#endif
int mm_sshkey_sign(struct ssh *, struct sshkey *, u_char **, size_t *,
const u_char *, size_t, const char *, const char *,
const char *, u_int compat);
void mm_inform_authserv(char *, char *);
struct passwd *mm_getpwnamallow(struct ssh *, const char *);
char *mm_auth2_read_banner(void);
int mm_auth_password(struct ssh *, char *);
int mm_key_allowed(enum mm_keytype, const char *, const char *, struct sshkey *,
int, struct sshauthopt **);
int mm_user_key_allowed(struct ssh *, struct passwd *, struct sshkey *, int,
struct sshauthopt **);
int mm_hostbased_key_allowed(struct ssh *, struct passwd *, const char *,
const char *, struct sshkey *);
int mm_sshkey_verify(const struct sshkey *, const u_char *, size_t,
const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **);
#ifdef GSSAPI
OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
int mm_ssh_gssapi_userok(char *user);
OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
#endif
#ifdef USE_PAM
void mm_start_pam(struct ssh *ssh);
u_int mm_do_pam_account(void);
void *mm_sshpam_init_ctx(struct Authctxt *);
int mm_sshpam_query(void *, char **, char **, u_int *, char ***, u_int **);
int mm_sshpam_respond(void *, u_int, char **);
void mm_sshpam_free_ctx(void *);
#endif
#ifdef SSH_AUDIT_EVENTS
#include "audit.h"
void mm_audit_event(struct ssh *, ssh_audit_event_t);
void mm_audit_run_command(const char *);
#endif
struct Session;
void mm_terminate(void);
int mm_pty_allocate(int *, int *, char *, size_t);
void mm_session_pty_cleanup2(struct Session *);
/* Key export functions */
struct newkeys *mm_newkeys_from_blob(u_char *, int);
int mm_newkeys_to_blob(int, u_char **, u_int *);
void mm_send_keystate(struct ssh *, struct monitor*);
/* bsdauth */
int mm_bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **);
int mm_bsdauth_respond(void *, u_int, char **);
#endif /* _MM_WRAP_H_ */
diff --git a/mux.c b/mux.c
index d0f066a77d62..faf4ef1e92a7 100644
--- a/mux.c
+++ b/mux.c
@@ -1,2356 +1,2356 @@
-/* $OpenBSD: mux.c,v 1.86 2020/10/29 02:52:43 djm Exp $ */
+/* $OpenBSD: mux.c,v 1.87 2021/04/03 06:18:40 djm Exp $ */
/*
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* ssh session multiplexing support */
#include "includes.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#else
# ifdef HAVE_SYS_POLL_H
# include <sys/poll.h>
# endif
#endif
#ifdef HAVE_UTIL_H
# include <util.h>
#endif
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "log.h"
#include "ssh.h"
#include "ssh2.h"
#include "pathnames.h"
#include "misc.h"
#include "match.h"
#include "sshbuf.h"
#include "channels.h"
#include "msg.h"
#include "packet.h"
#include "monitor_fdpass.h"
#include "sshpty.h"
#include "sshkey.h"
#include "readconf.h"
#include "clientloop.h"
#include "ssherr.h"
/* from ssh.c */
extern int tty_flag;
extern Options options;
extern int stdin_null_flag;
extern char *host;
extern int subsystem_flag;
extern struct sshbuf *command;
extern volatile sig_atomic_t quit_pending;
/* Context for session open confirmation callback */
struct mux_session_confirm_ctx {
u_int want_tty;
u_int want_subsys;
u_int want_x_fwd;
u_int want_agent_fwd;
struct sshbuf *cmd;
char *term;
struct termios tio;
char **env;
u_int rid;
};
/* Context for stdio fwd open confirmation callback */
struct mux_stdio_confirm_ctx {
u_int rid;
};
/* Context for global channel callback */
struct mux_channel_confirm_ctx {
u_int cid; /* channel id */
u_int rid; /* request id */
int fid; /* forward id */
};
/* fd to control socket */
int muxserver_sock = -1;
/* client request id */
u_int muxclient_request_id = 0;
/* Multiplexing control command */
u_int muxclient_command = 0;
/* Set when signalled. */
static volatile sig_atomic_t muxclient_terminate = 0;
/* PID of multiplex server */
static u_int muxserver_pid = 0;
static Channel *mux_listener_channel = NULL;
struct mux_master_state {
int hello_rcvd;
};
/* mux protocol messages */
#define MUX_MSG_HELLO 0x00000001
#define MUX_C_NEW_SESSION 0x10000002
#define MUX_C_ALIVE_CHECK 0x10000004
#define MUX_C_TERMINATE 0x10000005
#define MUX_C_OPEN_FWD 0x10000006
#define MUX_C_CLOSE_FWD 0x10000007
#define MUX_C_NEW_STDIO_FWD 0x10000008
#define MUX_C_STOP_LISTENING 0x10000009
#define MUX_C_PROXY 0x1000000f
#define MUX_S_OK 0x80000001
#define MUX_S_PERMISSION_DENIED 0x80000002
#define MUX_S_FAILURE 0x80000003
#define MUX_S_EXIT_MESSAGE 0x80000004
#define MUX_S_ALIVE 0x80000005
#define MUX_S_SESSION_OPENED 0x80000006
#define MUX_S_REMOTE_PORT 0x80000007
#define MUX_S_TTY_ALLOC_FAIL 0x80000008
#define MUX_S_PROXY 0x8000000f
/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */
#define MUX_FWD_LOCAL 1
#define MUX_FWD_REMOTE 2
#define MUX_FWD_DYNAMIC 3
static void mux_session_confirm(struct ssh *, int, int, void *);
static void mux_stdio_confirm(struct ssh *, int, int, void *);
static int mux_master_process_hello(struct ssh *, u_int,
Channel *, struct sshbuf *, struct sshbuf *);
static int mux_master_process_new_session(struct ssh *, u_int,
Channel *, struct sshbuf *, struct sshbuf *);
static int mux_master_process_alive_check(struct ssh *, u_int,
Channel *, struct sshbuf *, struct sshbuf *);
static int mux_master_process_terminate(struct ssh *, u_int,
Channel *, struct sshbuf *, struct sshbuf *);
static int mux_master_process_open_fwd(struct ssh *, u_int,
Channel *, struct sshbuf *, struct sshbuf *);
static int mux_master_process_close_fwd(struct ssh *, u_int,
Channel *, struct sshbuf *, struct sshbuf *);
static int mux_master_process_stdio_fwd(struct ssh *, u_int,
Channel *, struct sshbuf *, struct sshbuf *);
static int mux_master_process_stop_listening(struct ssh *, u_int,
Channel *, struct sshbuf *, struct sshbuf *);
static int mux_master_process_proxy(struct ssh *, u_int,
Channel *, struct sshbuf *, struct sshbuf *);
static const struct {
u_int type;
int (*handler)(struct ssh *, u_int, Channel *,
struct sshbuf *, struct sshbuf *);
} mux_master_handlers[] = {
{ MUX_MSG_HELLO, mux_master_process_hello },
{ MUX_C_NEW_SESSION, mux_master_process_new_session },
{ MUX_C_ALIVE_CHECK, mux_master_process_alive_check },
{ MUX_C_TERMINATE, mux_master_process_terminate },
{ MUX_C_OPEN_FWD, mux_master_process_open_fwd },
{ MUX_C_CLOSE_FWD, mux_master_process_close_fwd },
{ MUX_C_NEW_STDIO_FWD, mux_master_process_stdio_fwd },
{ MUX_C_STOP_LISTENING, mux_master_process_stop_listening },
{ MUX_C_PROXY, mux_master_process_proxy },
{ 0, NULL }
};
/* Cleanup callback fired on closure of mux client _session_ channel */
/* ARGSUSED */
static void
mux_master_session_cleanup_cb(struct ssh *ssh, int cid, void *unused)
{
Channel *cc, *c = channel_by_id(ssh, cid);
debug3_f("entering for channel %d", cid);
if (c == NULL)
fatal_f("channel_by_id(%i) == NULL", cid);
if (c->ctl_chan != -1) {
if ((cc = channel_by_id(ssh, c->ctl_chan)) == NULL)
fatal_f("channel %d missing control channel %d",
c->self, c->ctl_chan);
c->ctl_chan = -1;
cc->remote_id = 0;
cc->have_remote_id = 0;
chan_rcvd_oclose(ssh, cc);
}
channel_cancel_cleanup(ssh, c->self);
}
/* Cleanup callback fired on closure of mux client _control_ channel */
/* ARGSUSED */
static void
mux_master_control_cleanup_cb(struct ssh *ssh, int cid, void *unused)
{
Channel *sc, *c = channel_by_id(ssh, cid);
debug3_f("entering for channel %d", cid);
if (c == NULL)
fatal_f("channel_by_id(%i) == NULL", cid);
if (c->have_remote_id) {
if ((sc = channel_by_id(ssh, c->remote_id)) == NULL)
fatal_f("channel %d missing session channel %u",
c->self, c->remote_id);
c->remote_id = 0;
c->have_remote_id = 0;
sc->ctl_chan = -1;
if (sc->type != SSH_CHANNEL_OPEN &&
sc->type != SSH_CHANNEL_OPENING) {
debug2_f("channel %d: not open", sc->self);
chan_mark_dead(ssh, sc);
} else {
if (sc->istate == CHAN_INPUT_OPEN)
chan_read_failed(ssh, sc);
if (sc->ostate == CHAN_OUTPUT_OPEN)
chan_write_failed(ssh, sc);
}
}
channel_cancel_cleanup(ssh, c->self);
}
/* Check mux client environment variables before passing them to mux master. */
static int
env_permitted(char *env)
{
int i, ret;
char name[1024], *cp;
if ((cp = strchr(env, '=')) == NULL || cp == env)
return 0;
ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env);
if (ret <= 0 || (size_t)ret >= sizeof(name)) {
error_f("name '%.100s...' too long", env);
return 0;
}
for (i = 0; i < options.num_send_env; i++)
if (match_pattern(name, options.send_env[i]))
return 1;
return 0;
}
/* Mux master protocol message handlers */
static int
mux_master_process_hello(struct ssh *ssh, u_int rid,
Channel *c, struct sshbuf *m, struct sshbuf *reply)
{
u_int ver;
struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
int r;
if (state == NULL)
fatal_f("channel %d: c->mux_ctx == NULL", c->self);
if (state->hello_rcvd) {
error_f("HELLO received twice");
return -1;
}
if ((r = sshbuf_get_u32(m, &ver)) != 0) {
error_fr(r, "parse");
return -1;
}
if (ver != SSHMUX_VER) {
error_f("unsupported multiplexing protocol version %u "
"(expected %u)", ver, SSHMUX_VER);
return -1;
}
debug2_f("channel %d client version %u", c->self, ver);
/* No extensions are presently defined */
while (sshbuf_len(m) > 0) {
char *name = NULL;
size_t value_len = 0;
if ((r = sshbuf_get_cstring(m, &name, NULL)) != 0 ||
(r = sshbuf_get_string_direct(m, NULL, &value_len)) != 0) {
error_fr(r, "parse extension");
return -1;
}
debug2_f("Unrecognised extension \"%s\" length %zu",
name, value_len);
free(name);
}
state->hello_rcvd = 1;
return 0;
}
/* Enqueue a "ok" response to the reply buffer */
static void
reply_ok(struct sshbuf *reply, u_int rid)
{
int r;
if ((r = sshbuf_put_u32(reply, MUX_S_OK)) != 0 ||
(r = sshbuf_put_u32(reply, rid)) != 0)
fatal_fr(r, "reply");
}
/* Enqueue an error response to the reply buffer */
static void
reply_error(struct sshbuf *reply, u_int type, u_int rid, const char *msg)
{
int r;
if ((r = sshbuf_put_u32(reply, type)) != 0 ||
(r = sshbuf_put_u32(reply, rid)) != 0 ||
(r = sshbuf_put_cstring(reply, msg)) != 0)
fatal_fr(r, "reply");
}
static int
mux_master_process_new_session(struct ssh *ssh, u_int rid,
Channel *c, struct sshbuf *m, struct sshbuf *reply)
{
Channel *nc;
struct mux_session_confirm_ctx *cctx;
char *cmd, *cp;
u_int i, j, env_len, escape_char, window, packetmax;
int r, new_fd[3];
/* Reply for SSHMUX_COMMAND_OPEN */
cctx = xcalloc(1, sizeof(*cctx));
cctx->term = NULL;
cctx->rid = rid;
cmd = NULL;
cctx->env = NULL;
env_len = 0;
if ((r = sshbuf_skip_string(m)) != 0 || /* reserved */
(r = sshbuf_get_u32(m, &cctx->want_tty)) != 0 ||
(r = sshbuf_get_u32(m, &cctx->want_x_fwd)) != 0 ||
(r = sshbuf_get_u32(m, &cctx->want_agent_fwd)) != 0 ||
(r = sshbuf_get_u32(m, &cctx->want_subsys)) != 0 ||
(r = sshbuf_get_u32(m, &escape_char)) != 0 ||
(r = sshbuf_get_cstring(m, &cctx->term, NULL)) != 0 ||
(r = sshbuf_get_cstring(m, &cmd, NULL)) != 0) {
malf:
free(cmd);
for (j = 0; j < env_len; j++)
free(cctx->env[j]);
free(cctx->env);
free(cctx->term);
free(cctx);
error_f("malformed message");
return -1;
}
#define MUX_MAX_ENV_VARS 4096
while (sshbuf_len(m) > 0) {
if ((r = sshbuf_get_cstring(m, &cp, NULL)) != 0)
goto malf;
if (!env_permitted(cp)) {
free(cp);
continue;
}
cctx->env = xreallocarray(cctx->env, env_len + 2,
sizeof(*cctx->env));
cctx->env[env_len++] = cp;
cctx->env[env_len] = NULL;
if (env_len > MUX_MAX_ENV_VARS) {
error_f(">%d environment variables received, "
"ignoring additional", MUX_MAX_ENV_VARS);
break;
}
}
debug2_f("channel %d: request tty %d, X %d, agent %d, subsys %d, "
"term \"%s\", cmd \"%s\", env %u", c->self,
cctx->want_tty, cctx->want_x_fwd, cctx->want_agent_fwd,
cctx->want_subsys, cctx->term, cmd, env_len);
if ((cctx->cmd = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_put(cctx->cmd, cmd, strlen(cmd))) != 0)
fatal_fr(r, "sshbuf_put");
free(cmd);
cmd = NULL;
/* Gather fds from client */
for(i = 0; i < 3; i++) {
if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) {
error_f("failed to receive fd %d from client", i);
for (j = 0; j < i; j++)
close(new_fd[j]);
for (j = 0; j < env_len; j++)
free(cctx->env[j]);
free(cctx->env);
free(cctx->term);
sshbuf_free(cctx->cmd);
free(cctx);
reply_error(reply, MUX_S_FAILURE, rid,
"did not receive file descriptors");
return -1;
}
}
debug3_f("got fds stdin %d, stdout %d, stderr %d",
new_fd[0], new_fd[1], new_fd[2]);
/* XXX support multiple child sessions in future */
if (c->have_remote_id) {
debug2_f("session already open");
reply_error(reply, MUX_S_FAILURE, rid,
"Multiple sessions not supported");
cleanup:
close(new_fd[0]);
close(new_fd[1]);
close(new_fd[2]);
free(cctx->term);
if (env_len != 0) {
for (i = 0; i < env_len; i++)
free(cctx->env[i]);
free(cctx->env);
}
sshbuf_free(cctx->cmd);
free(cctx);
return 0;
}
if (options.control_master == SSHCTL_MASTER_ASK ||
options.control_master == SSHCTL_MASTER_AUTO_ASK) {
if (!ask_permission("Allow shared connection to %s? ", host)) {
debug2_f("session refused by user");
reply_error(reply, MUX_S_PERMISSION_DENIED, rid,
"Permission denied");
goto cleanup;
}
}
/* Try to pick up ttymodes from client before it goes raw */
if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1)
error_f("tcgetattr: %s", strerror(errno));
/* enable nonblocking unless tty */
if (!isatty(new_fd[0]))
set_nonblock(new_fd[0]);
if (!isatty(new_fd[1]))
set_nonblock(new_fd[1]);
if (!isatty(new_fd[2]))
set_nonblock(new_fd[2]);
window = CHAN_SES_WINDOW_DEFAULT;
packetmax = CHAN_SES_PACKET_DEFAULT;
if (cctx->want_tty) {
window >>= 1;
packetmax >>= 1;
}
nc = channel_new(ssh, "session", SSH_CHANNEL_OPENING,
new_fd[0], new_fd[1], new_fd[2], window, packetmax,
CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
nc->ctl_chan = c->self; /* link session -> control channel */
c->remote_id = nc->self; /* link control -> session channel */
c->have_remote_id = 1;
if (cctx->want_tty && escape_char != 0xffffffff) {
channel_register_filter(ssh, nc->self,
client_simple_escape_filter, NULL,
client_filter_cleanup,
client_new_escape_filter_ctx((int)escape_char));
}
debug2_f("channel_new: %d linked to control channel %d",
nc->self, nc->ctl_chan);
channel_send_open(ssh, nc->self);
channel_register_open_confirm(ssh, nc->self, mux_session_confirm, cctx);
c->mux_pause = 1; /* stop handling messages until open_confirm done */
channel_register_cleanup(ssh, nc->self,
mux_master_session_cleanup_cb, 1);
/* reply is deferred, sent by mux_session_confirm */
return 0;
}
static int
mux_master_process_alive_check(struct ssh *ssh, u_int rid,
Channel *c, struct sshbuf *m, struct sshbuf *reply)
{
int r;
debug2_f("channel %d: alive check", c->self);
/* prepare reply */
if ((r = sshbuf_put_u32(reply, MUX_S_ALIVE)) != 0 ||
(r = sshbuf_put_u32(reply, rid)) != 0 ||
(r = sshbuf_put_u32(reply, (u_int)getpid())) != 0)
fatal_fr(r, "reply");
return 0;
}
static int
mux_master_process_terminate(struct ssh *ssh, u_int rid,
Channel *c, struct sshbuf *m, struct sshbuf *reply)
{
debug2_f("channel %d: terminate request", c->self);
if (options.control_master == SSHCTL_MASTER_ASK ||
options.control_master == SSHCTL_MASTER_AUTO_ASK) {
if (!ask_permission("Terminate shared connection to %s? ",
host)) {
debug2_f("termination refused by user");
reply_error(reply, MUX_S_PERMISSION_DENIED, rid,
"Permission denied");
return 0;
}
}
quit_pending = 1;
reply_ok(reply, rid);
/* XXX exit happens too soon - message never makes it to client */
return 0;
}
static char *
format_forward(u_int ftype, struct Forward *fwd)
{
char *ret;
switch (ftype) {
case MUX_FWD_LOCAL:
xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d",
(fwd->listen_path != NULL) ? fwd->listen_path :
(fwd->listen_host == NULL) ?
(options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") :
fwd->listen_host, fwd->listen_port,
(fwd->connect_path != NULL) ? fwd->connect_path :
fwd->connect_host, fwd->connect_port);
break;
case MUX_FWD_DYNAMIC:
xasprintf(&ret, "dynamic forward %.200s:%d -> *",
(fwd->listen_host == NULL) ?
(options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") :
- fwd->listen_host, fwd->listen_port);
+ fwd->listen_host, fwd->listen_port);
break;
case MUX_FWD_REMOTE:
xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d",
(fwd->listen_path != NULL) ? fwd->listen_path :
(fwd->listen_host == NULL) ?
"LOCALHOST" : fwd->listen_host,
fwd->listen_port,
(fwd->connect_path != NULL) ? fwd->connect_path :
fwd->connect_host, fwd->connect_port);
break;
default:
fatal_f("unknown forward type %u", ftype);
}
return ret;
}
static int
compare_host(const char *a, const char *b)
{
if (a == NULL && b == NULL)
return 1;
if (a == NULL || b == NULL)
return 0;
return strcmp(a, b) == 0;
}
static int
compare_forward(struct Forward *a, struct Forward *b)
{
if (!compare_host(a->listen_host, b->listen_host))
return 0;
if (!compare_host(a->listen_path, b->listen_path))
return 0;
if (a->listen_port != b->listen_port)
return 0;
if (!compare_host(a->connect_host, b->connect_host))
return 0;
if (!compare_host(a->connect_path, b->connect_path))
return 0;
if (a->connect_port != b->connect_port)
return 0;
return 1;
}
static void
mux_confirm_remote_forward(struct ssh *ssh, int type, u_int32_t seq, void *ctxt)
{
struct mux_channel_confirm_ctx *fctx = ctxt;
char *failmsg = NULL;
struct Forward *rfwd;
Channel *c;
struct sshbuf *out;
u_int port;
int r;
if ((c = channel_by_id(ssh, fctx->cid)) == NULL) {
/* no channel for reply */
error_f("unknown channel");
return;
}
if ((out = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if (fctx->fid >= options.num_remote_forwards ||
(options.remote_forwards[fctx->fid].connect_path == NULL &&
options.remote_forwards[fctx->fid].connect_host == NULL)) {
xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid);
goto fail;
}
rfwd = &options.remote_forwards[fctx->fid];
debug_f("%s for: listen %d, connect %s:%d",
type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
rfwd->listen_port, rfwd->connect_path ? rfwd->connect_path :
rfwd->connect_host, rfwd->connect_port);
if (type == SSH2_MSG_REQUEST_SUCCESS) {
if (rfwd->listen_port == 0) {
if ((r = sshpkt_get_u32(ssh, &port)) != 0)
fatal_fr(r, "parse port");
if (port > 65535) {
fatal("Invalid allocated port %u for "
"mux remote forward to %s:%d", port,
rfwd->connect_host, rfwd->connect_port);
}
rfwd->allocated_port = (int)port;
debug("Allocated port %u for mux remote forward"
" to %s:%d", rfwd->allocated_port,
rfwd->connect_host, rfwd->connect_port);
if ((r = sshbuf_put_u32(out,
MUX_S_REMOTE_PORT)) != 0 ||
(r = sshbuf_put_u32(out, fctx->rid)) != 0 ||
(r = sshbuf_put_u32(out,
rfwd->allocated_port)) != 0)
fatal_fr(r, "reply");
channel_update_permission(ssh, rfwd->handle,
- rfwd->allocated_port);
+ rfwd->allocated_port);
} else {
reply_ok(out, fctx->rid);
}
goto out;
} else {
if (rfwd->listen_port == 0)
channel_update_permission(ssh, rfwd->handle, -1);
if (rfwd->listen_path != NULL)
xasprintf(&failmsg, "remote port forwarding failed for "
"listen path %s", rfwd->listen_path);
else
xasprintf(&failmsg, "remote port forwarding failed for "
"listen port %d", rfwd->listen_port);
- debug2_f("clearing registered forwarding for listen %d, "
+ debug2_f("clearing registered forwarding for listen %d, "
"connect %s:%d", rfwd->listen_port,
rfwd->connect_path ? rfwd->connect_path :
rfwd->connect_host, rfwd->connect_port);
free(rfwd->listen_host);
free(rfwd->listen_path);
free(rfwd->connect_host);
free(rfwd->connect_path);
memset(rfwd, 0, sizeof(*rfwd));
}
fail:
error_f("%s", failmsg);
reply_error(out, MUX_S_FAILURE, fctx->rid, failmsg);
free(failmsg);
out:
if ((r = sshbuf_put_stringb(c->output, out)) != 0)
fatal_fr(r, "enqueue");
sshbuf_free(out);
if (c->mux_pause <= 0)
fatal_f("mux_pause %d", c->mux_pause);
c->mux_pause = 0; /* start processing messages again */
}
static int
mux_master_process_open_fwd(struct ssh *ssh, u_int rid,
Channel *c, struct sshbuf *m, struct sshbuf *reply)
{
struct Forward fwd;
char *fwd_desc = NULL;
char *listen_addr, *connect_addr;
u_int ftype;
u_int lport, cport;
int r, i, ret = 0, freefwd = 1;
memset(&fwd, 0, sizeof(fwd));
/* XXX - lport/cport check redundant */
if ((r = sshbuf_get_u32(m, &ftype)) != 0 ||
(r = sshbuf_get_cstring(m, &listen_addr, NULL)) != 0 ||
(r = sshbuf_get_u32(m, &lport)) != 0 ||
(r = sshbuf_get_cstring(m, &connect_addr, NULL)) != 0 ||
(r = sshbuf_get_u32(m, &cport)) != 0 ||
(lport != (u_int)PORT_STREAMLOCAL && lport > 65535) ||
(cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) {
error_f("malformed message");
ret = -1;
goto out;
}
if (*listen_addr == '\0') {
free(listen_addr);
listen_addr = NULL;
}
if (*connect_addr == '\0') {
free(connect_addr);
connect_addr = NULL;
}
memset(&fwd, 0, sizeof(fwd));
fwd.listen_port = lport;
if (fwd.listen_port == PORT_STREAMLOCAL)
fwd.listen_path = listen_addr;
else
fwd.listen_host = listen_addr;
fwd.connect_port = cport;
if (fwd.connect_port == PORT_STREAMLOCAL)
fwd.connect_path = connect_addr;
else
fwd.connect_host = connect_addr;
debug2_f("channel %d: request %s", c->self,
(fwd_desc = format_forward(ftype, &fwd)));
if (ftype != MUX_FWD_LOCAL && ftype != MUX_FWD_REMOTE &&
ftype != MUX_FWD_DYNAMIC) {
logit_f("invalid forwarding type %u", ftype);
invalid:
free(listen_addr);
free(connect_addr);
reply_error(reply, MUX_S_FAILURE, rid,
"Invalid forwarding request");
return 0;
}
if (ftype == MUX_FWD_DYNAMIC && fwd.listen_path) {
logit_f("streamlocal and dynamic forwards "
"are mutually exclusive");
goto invalid;
}
if (fwd.listen_port != PORT_STREAMLOCAL && fwd.listen_port >= 65536) {
logit_f("invalid listen port %u", fwd.listen_port);
goto invalid;
}
if ((fwd.connect_port != PORT_STREAMLOCAL &&
fwd.connect_port >= 65536) ||
(ftype != MUX_FWD_DYNAMIC && ftype != MUX_FWD_REMOTE &&
fwd.connect_port == 0)) {
logit_f("invalid connect port %u",
fwd.connect_port);
goto invalid;
}
if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL &&
fwd.connect_path == NULL) {
logit_f("missing connect host");
goto invalid;
}
/* Skip forwards that have already been requested */
switch (ftype) {
case MUX_FWD_LOCAL:
case MUX_FWD_DYNAMIC:
for (i = 0; i < options.num_local_forwards; i++) {
if (compare_forward(&fwd,
options.local_forwards + i)) {
exists:
debug2_f("found existing forwarding");
reply_ok(reply, rid);
goto out;
}
}
break;
case MUX_FWD_REMOTE:
for (i = 0; i < options.num_remote_forwards; i++) {
if (!compare_forward(&fwd, options.remote_forwards + i))
continue;
if (fwd.listen_port != 0)
goto exists;
debug2_f("found allocated port");
if ((r = sshbuf_put_u32(reply,
MUX_S_REMOTE_PORT)) != 0 ||
(r = sshbuf_put_u32(reply, rid)) != 0 ||
(r = sshbuf_put_u32(reply,
options.remote_forwards[i].allocated_port)) != 0)
fatal_fr(r, "reply FWD_REMOTE");
goto out;
}
break;
}
if (options.control_master == SSHCTL_MASTER_ASK ||
options.control_master == SSHCTL_MASTER_AUTO_ASK) {
if (!ask_permission("Open %s on %s?", fwd_desc, host)) {
debug2_f("forwarding refused by user");
reply_error(reply, MUX_S_PERMISSION_DENIED, rid,
"Permission denied");
goto out;
}
}
if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) {
if (!channel_setup_local_fwd_listener(ssh, &fwd,
&options.fwd_opts)) {
fail:
logit_f("requested %s failed", fwd_desc);
reply_error(reply, MUX_S_FAILURE, rid,
"Port forwarding failed");
goto out;
}
add_local_forward(&options, &fwd);
freefwd = 0;
} else {
struct mux_channel_confirm_ctx *fctx;
fwd.handle = channel_request_remote_forwarding(ssh, &fwd);
if (fwd.handle < 0)
goto fail;
add_remote_forward(&options, &fwd);
fctx = xcalloc(1, sizeof(*fctx));
fctx->cid = c->self;
fctx->rid = rid;
fctx->fid = options.num_remote_forwards - 1;
client_register_global_confirm(mux_confirm_remote_forward,
fctx);
freefwd = 0;
c->mux_pause = 1; /* wait for mux_confirm_remote_forward */
/* delayed reply in mux_confirm_remote_forward */
goto out;
}
reply_ok(reply, rid);
out:
free(fwd_desc);
if (freefwd) {
free(fwd.listen_host);
free(fwd.listen_path);
free(fwd.connect_host);
free(fwd.connect_path);
}
return ret;
}
static int
mux_master_process_close_fwd(struct ssh *ssh, u_int rid,
Channel *c, struct sshbuf *m, struct sshbuf *reply)
{
struct Forward fwd, *found_fwd;
char *fwd_desc = NULL;
const char *error_reason = NULL;
char *listen_addr = NULL, *connect_addr = NULL;
u_int ftype;
int r, i, ret = 0;
u_int lport, cport;
memset(&fwd, 0, sizeof(fwd));
if ((r = sshbuf_get_u32(m, &ftype)) != 0 ||
(r = sshbuf_get_cstring(m, &listen_addr, NULL)) != 0 ||
(r = sshbuf_get_u32(m, &lport)) != 0 ||
(r = sshbuf_get_cstring(m, &connect_addr, NULL)) != 0 ||
(r = sshbuf_get_u32(m, &cport)) != 0 ||
(lport != (u_int)PORT_STREAMLOCAL && lport > 65535) ||
(cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) {
error_f("malformed message");
ret = -1;
goto out;
}
if (*listen_addr == '\0') {
free(listen_addr);
listen_addr = NULL;
}
if (*connect_addr == '\0') {
free(connect_addr);
connect_addr = NULL;
}
memset(&fwd, 0, sizeof(fwd));
fwd.listen_port = lport;
if (fwd.listen_port == PORT_STREAMLOCAL)
fwd.listen_path = listen_addr;
else
fwd.listen_host = listen_addr;
fwd.connect_port = cport;
if (fwd.connect_port == PORT_STREAMLOCAL)
fwd.connect_path = connect_addr;
else
fwd.connect_host = connect_addr;
debug2_f("channel %d: request cancel %s", c->self,
(fwd_desc = format_forward(ftype, &fwd)));
/* make sure this has been requested */
found_fwd = NULL;
switch (ftype) {
case MUX_FWD_LOCAL:
case MUX_FWD_DYNAMIC:
for (i = 0; i < options.num_local_forwards; i++) {
if (compare_forward(&fwd,
options.local_forwards + i)) {
found_fwd = options.local_forwards + i;
break;
}
}
break;
case MUX_FWD_REMOTE:
for (i = 0; i < options.num_remote_forwards; i++) {
if (compare_forward(&fwd,
options.remote_forwards + i)) {
found_fwd = options.remote_forwards + i;
break;
}
}
break;
}
if (found_fwd == NULL)
error_reason = "port not forwarded";
else if (ftype == MUX_FWD_REMOTE) {
/*
* This shouldn't fail unless we confused the host/port
* between options.remote_forwards and permitted_opens.
* However, for dynamic allocated listen ports we need
* to use the actual listen port.
*/
if (channel_request_rforward_cancel(ssh, found_fwd) == -1)
error_reason = "port not in permitted opens";
} else { /* local and dynamic forwards */
/* Ditto */
if (channel_cancel_lport_listener(ssh, &fwd, fwd.connect_port,
&options.fwd_opts) == -1)
error_reason = "port not found";
}
if (error_reason != NULL)
reply_error(reply, MUX_S_FAILURE, rid, error_reason);
else {
reply_ok(reply, rid);
free(found_fwd->listen_host);
free(found_fwd->listen_path);
free(found_fwd->connect_host);
free(found_fwd->connect_path);
found_fwd->listen_host = found_fwd->connect_host = NULL;
found_fwd->listen_path = found_fwd->connect_path = NULL;
found_fwd->listen_port = found_fwd->connect_port = 0;
}
out:
free(fwd_desc);
free(listen_addr);
free(connect_addr);
return ret;
}
static int
mux_master_process_stdio_fwd(struct ssh *ssh, u_int rid,
Channel *c, struct sshbuf *m, struct sshbuf *reply)
{
Channel *nc;
char *chost = NULL;
u_int cport, i, j;
int r, new_fd[2];
struct mux_stdio_confirm_ctx *cctx;
if ((r = sshbuf_skip_string(m)) != 0 || /* reserved */
(r = sshbuf_get_cstring(m, &chost, NULL)) != 0 ||
(r = sshbuf_get_u32(m, &cport)) != 0) {
free(chost);
error_f("malformed message");
return -1;
}
debug2_f("channel %d: stdio fwd to %s:%u", c->self, chost, cport);
/* Gather fds from client */
for(i = 0; i < 2; i++) {
if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) {
error_f("failed to receive fd %d from client", i);
for (j = 0; j < i; j++)
close(new_fd[j]);
free(chost);
/* prepare reply */
reply_error(reply, MUX_S_FAILURE, rid,
"did not receive file descriptors");
return -1;
}
}
debug3_f("got fds stdin %d, stdout %d", new_fd[0], new_fd[1]);
/* XXX support multiple child sessions in future */
if (c->have_remote_id) {
debug2_f("session already open");
reply_error(reply, MUX_S_FAILURE, rid,
"Multiple sessions not supported");
cleanup:
close(new_fd[0]);
close(new_fd[1]);
free(chost);
return 0;
}
if (options.control_master == SSHCTL_MASTER_ASK ||
options.control_master == SSHCTL_MASTER_AUTO_ASK) {
if (!ask_permission("Allow forward to %s:%u? ",
chost, cport)) {
debug2_f("stdio fwd refused by user");
reply_error(reply, MUX_S_PERMISSION_DENIED, rid,
"Permission denied");
goto cleanup;
}
}
/* enable nonblocking unless tty */
if (!isatty(new_fd[0]))
set_nonblock(new_fd[0]);
if (!isatty(new_fd[1]))
set_nonblock(new_fd[1]);
nc = channel_connect_stdio_fwd(ssh, chost, cport, new_fd[0], new_fd[1]);
free(chost);
nc->ctl_chan = c->self; /* link session -> control channel */
c->remote_id = nc->self; /* link control -> session channel */
c->have_remote_id = 1;
debug2_f("channel_new: %d control %d", nc->self, nc->ctl_chan);
channel_register_cleanup(ssh, nc->self,
mux_master_session_cleanup_cb, 1);
cctx = xcalloc(1, sizeof(*cctx));
cctx->rid = rid;
channel_register_open_confirm(ssh, nc->self, mux_stdio_confirm, cctx);
c->mux_pause = 1; /* stop handling messages until open_confirm done */
/* reply is deferred, sent by mux_session_confirm */
return 0;
}
/* Callback on open confirmation in mux master for a mux stdio fwd session. */
static void
mux_stdio_confirm(struct ssh *ssh, int id, int success, void *arg)
{
struct mux_stdio_confirm_ctx *cctx = arg;
Channel *c, *cc;
struct sshbuf *reply;
int r;
if (cctx == NULL)
fatal_f("cctx == NULL");
if ((c = channel_by_id(ssh, id)) == NULL)
fatal_f("no channel for id %d", id);
if ((cc = channel_by_id(ssh, c->ctl_chan)) == NULL)
fatal_f("channel %d lacks control channel %d",
id, c->ctl_chan);
if ((reply = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if (!success) {
debug3_f("sending failure reply");
reply_error(reply, MUX_S_FAILURE, cctx->rid,
"Session open refused by peer");
/* prepare reply */
goto done;
}
debug3_f("sending success reply");
/* prepare reply */
if ((r = sshbuf_put_u32(reply, MUX_S_SESSION_OPENED)) != 0 ||
(r = sshbuf_put_u32(reply, cctx->rid)) != 0 ||
(r = sshbuf_put_u32(reply, c->self)) != 0)
fatal_fr(r, "reply");
done:
/* Send reply */
if ((r = sshbuf_put_stringb(cc->output, reply)) != 0)
fatal_fr(r, "enqueue");
sshbuf_free(reply);
if (cc->mux_pause <= 0)
fatal_f("mux_pause %d", cc->mux_pause);
cc->mux_pause = 0; /* start processing messages again */
c->open_confirm_ctx = NULL;
free(cctx);
}
static int
mux_master_process_stop_listening(struct ssh *ssh, u_int rid,
Channel *c, struct sshbuf *m, struct sshbuf *reply)
{
debug_f("channel %d: stop listening", c->self);
if (options.control_master == SSHCTL_MASTER_ASK ||
options.control_master == SSHCTL_MASTER_AUTO_ASK) {
if (!ask_permission("Disable further multiplexing on shared "
"connection to %s? ", host)) {
debug2_f("stop listen refused by user");
reply_error(reply, MUX_S_PERMISSION_DENIED, rid,
"Permission denied");
return 0;
}
}
if (mux_listener_channel != NULL) {
channel_free(ssh, mux_listener_channel);
client_stop_mux();
free(options.control_path);
options.control_path = NULL;
mux_listener_channel = NULL;
muxserver_sock = -1;
}
reply_ok(reply, rid);
return 0;
}
static int
mux_master_process_proxy(struct ssh *ssh, u_int rid,
Channel *c, struct sshbuf *m, struct sshbuf *reply)
{
int r;
debug_f("channel %d: proxy request", c->self);
c->mux_rcb = channel_proxy_downstream;
if ((r = sshbuf_put_u32(reply, MUX_S_PROXY)) != 0 ||
(r = sshbuf_put_u32(reply, rid)) != 0)
fatal_fr(r, "reply");
return 0;
}
/* Channel callbacks fired on read/write from mux client fd */
static int
mux_master_read_cb(struct ssh *ssh, Channel *c)
{
struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
struct sshbuf *in = NULL, *out = NULL;
u_int type, rid, i;
int r, ret = -1;
if ((out = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
/* Setup ctx and */
if (c->mux_ctx == NULL) {
state = xcalloc(1, sizeof(*state));
c->mux_ctx = state;
channel_register_cleanup(ssh, c->self,
mux_master_control_cleanup_cb, 0);
/* Send hello */
if ((r = sshbuf_put_u32(out, MUX_MSG_HELLO)) != 0 ||
(r = sshbuf_put_u32(out, SSHMUX_VER)) != 0)
fatal_fr(r, "reply");
/* no extensions */
if ((r = sshbuf_put_stringb(c->output, out)) != 0)
fatal_fr(r, "enqueue");
debug3_f("channel %d: hello sent", c->self);
ret = 0;
goto out;
}
/* Channel code ensures that we receive whole packets */
if ((r = sshbuf_froms(c->input, &in)) != 0) {
malf:
error_f("malformed message");
goto out;
}
if ((r = sshbuf_get_u32(in, &type)) != 0)
goto malf;
debug3_f("channel %d packet type 0x%08x len %zu", c->self,
type, sshbuf_len(in));
if (type == MUX_MSG_HELLO)
rid = 0;
else {
if (!state->hello_rcvd) {
error_f("expected MUX_MSG_HELLO(0x%08x), "
"received 0x%08x", MUX_MSG_HELLO, type);
goto out;
}
if ((r = sshbuf_get_u32(in, &rid)) != 0)
goto malf;
}
for (i = 0; mux_master_handlers[i].handler != NULL; i++) {
if (type == mux_master_handlers[i].type) {
ret = mux_master_handlers[i].handler(ssh, rid,
c, in, out);
break;
}
}
if (mux_master_handlers[i].handler == NULL) {
error_f("unsupported mux message 0x%08x", type);
reply_error(out, MUX_S_FAILURE, rid, "unsupported request");
ret = 0;
}
/* Enqueue reply packet */
if (sshbuf_len(out) != 0 &&
(r = sshbuf_put_stringb(c->output, out)) != 0)
fatal_fr(r, "enqueue");
out:
sshbuf_free(in);
sshbuf_free(out);
return ret;
}
void
mux_exit_message(struct ssh *ssh, Channel *c, int exitval)
{
struct sshbuf *m;
Channel *mux_chan;
int r;
debug3_f("channel %d: exit message, exitval %d", c->self, exitval);
if ((mux_chan = channel_by_id(ssh, c->ctl_chan)) == NULL)
fatal_f("channel %d missing mux %d", c->self, c->ctl_chan);
/* Append exit message packet to control socket output queue */
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_put_u32(m, MUX_S_EXIT_MESSAGE)) != 0 ||
(r = sshbuf_put_u32(m, c->self)) != 0 ||
(r = sshbuf_put_u32(m, exitval)) != 0 ||
(r = sshbuf_put_stringb(mux_chan->output, m)) != 0)
fatal_fr(r, "reply");
sshbuf_free(m);
}
void
mux_tty_alloc_failed(struct ssh *ssh, Channel *c)
{
struct sshbuf *m;
Channel *mux_chan;
int r;
debug3_f("channel %d: TTY alloc failed", c->self);
if ((mux_chan = channel_by_id(ssh, c->ctl_chan)) == NULL)
fatal_f("channel %d missing mux %d", c->self, c->ctl_chan);
/* Append exit message packet to control socket output queue */
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_put_u32(m, MUX_S_TTY_ALLOC_FAIL)) != 0 ||
(r = sshbuf_put_u32(m, c->self)) != 0 ||
(r = sshbuf_put_stringb(mux_chan->output, m)) != 0)
fatal_fr(r, "reply");
sshbuf_free(m);
}
/* Prepare a mux master to listen on a Unix domain socket. */
void
muxserver_listen(struct ssh *ssh)
{
mode_t old_umask;
char *orig_control_path = options.control_path;
char rbuf[16+1];
u_int i, r;
int oerrno;
if (options.control_path == NULL ||
options.control_master == SSHCTL_MASTER_NO)
return;
debug("setting up multiplex master socket");
/*
* Use a temporary path before listen so we can pseudo-atomically
* establish the listening socket in its final location to avoid
* other processes racing in between bind() and listen() and hitting
* an unready socket.
*/
for (i = 0; i < sizeof(rbuf) - 1; i++) {
r = arc4random_uniform(26+26+10);
rbuf[i] = (r < 26) ? 'a' + r :
(r < 26*2) ? 'A' + r - 26 :
'0' + r - 26 - 26;
}
rbuf[sizeof(rbuf) - 1] = '\0';
options.control_path = NULL;
xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf);
debug3_f("temporary control path %s", options.control_path);
old_umask = umask(0177);
muxserver_sock = unix_listener(options.control_path, 64, 0);
oerrno = errno;
umask(old_umask);
if (muxserver_sock < 0) {
if (oerrno == EINVAL || oerrno == EADDRINUSE) {
error("ControlSocket %s already exists, "
"disabling multiplexing", options.control_path);
disable_mux_master:
if (muxserver_sock != -1) {
close(muxserver_sock);
muxserver_sock = -1;
}
free(orig_control_path);
free(options.control_path);
options.control_path = NULL;
options.control_master = SSHCTL_MASTER_NO;
return;
} else {
/* unix_listener() logs the error */
cleanup_exit(255);
}
}
/* Now atomically "move" the mux socket into position */
if (link(options.control_path, orig_control_path) != 0) {
if (errno != EEXIST) {
fatal_f("link mux listener %s => %s: %s",
options.control_path, orig_control_path,
strerror(errno));
}
error("ControlSocket %s already exists, disabling multiplexing",
orig_control_path);
unlink(options.control_path);
goto disable_mux_master;
}
unlink(options.control_path);
free(options.control_path);
options.control_path = orig_control_path;
set_nonblock(muxserver_sock);
mux_listener_channel = channel_new(ssh, "mux listener",
SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
0, options.control_path, 1);
mux_listener_channel->mux_rcb = mux_master_read_cb;
debug3_f("mux listener channel %d fd %d",
mux_listener_channel->self, mux_listener_channel->sock);
}
/* Callback on open confirmation in mux master for a mux client session. */
static void
mux_session_confirm(struct ssh *ssh, int id, int success, void *arg)
{
struct mux_session_confirm_ctx *cctx = arg;
const char *display;
Channel *c, *cc;
int i, r;
struct sshbuf *reply;
if (cctx == NULL)
fatal_f("cctx == NULL");
if ((c = channel_by_id(ssh, id)) == NULL)
fatal_f("no channel for id %d", id);
if ((cc = channel_by_id(ssh, c->ctl_chan)) == NULL)
fatal_f("channel %d lacks control channel %d",
id, c->ctl_chan);
if ((reply = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if (!success) {
debug3_f("sending failure reply");
reply_error(reply, MUX_S_FAILURE, cctx->rid,
"Session open refused by peer");
goto done;
}
display = getenv("DISPLAY");
if (cctx->want_x_fwd && options.forward_x11 && display != NULL) {
char *proto, *data;
/* Get reasonable local authentication information. */
if (client_x11_get_proto(ssh, display, options.xauth_location,
options.forward_x11_trusted, options.forward_x11_timeout,
&proto, &data) == 0) {
/* Request forwarding with authentication spoofing. */
debug("Requesting X11 forwarding with authentication "
"spoofing.");
x11_request_forwarding_with_spoofing(ssh, id,
display, proto, data, 1);
/* XXX exit_on_forward_failure */
client_expect_confirm(ssh, id, "X11 forwarding",
CONFIRM_WARN);
}
}
if (cctx->want_agent_fwd && options.forward_agent) {
debug("Requesting authentication agent forwarding.");
channel_request_start(ssh, id, "auth-agent-req@openssh.com", 0);
if ((r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send");
}
client_session2_setup(ssh, id, cctx->want_tty, cctx->want_subsys,
cctx->term, &cctx->tio, c->rfd, cctx->cmd, cctx->env);
debug3_f("sending success reply");
/* prepare reply */
if ((r = sshbuf_put_u32(reply, MUX_S_SESSION_OPENED)) != 0 ||
(r = sshbuf_put_u32(reply, cctx->rid)) != 0 ||
(r = sshbuf_put_u32(reply, c->self)) != 0)
fatal_fr(r, "reply");
done:
/* Send reply */
if ((r = sshbuf_put_stringb(cc->output, reply)) != 0)
fatal_fr(r, "enqueue");
sshbuf_free(reply);
if (cc->mux_pause <= 0)
fatal_f("mux_pause %d", cc->mux_pause);
cc->mux_pause = 0; /* start processing messages again */
c->open_confirm_ctx = NULL;
sshbuf_free(cctx->cmd);
free(cctx->term);
if (cctx->env != NULL) {
for (i = 0; cctx->env[i] != NULL; i++)
free(cctx->env[i]);
free(cctx->env);
}
free(cctx);
}
/* ** Multiplexing client support */
/* Exit signal handler */
static void
control_client_sighandler(int signo)
{
muxclient_terminate = signo;
}
/*
* Relay signal handler - used to pass some signals from mux client to
* mux master.
*/
static void
control_client_sigrelay(int signo)
{
int save_errno = errno;
if (muxserver_pid > 1)
kill(muxserver_pid, signo);
errno = save_errno;
}
static int
mux_client_read(int fd, struct sshbuf *b, size_t need)
{
size_t have;
ssize_t len;
u_char *p;
struct pollfd pfd;
int r;
pfd.fd = fd;
pfd.events = POLLIN;
if ((r = sshbuf_reserve(b, need, &p)) != 0)
fatal_fr(r, "reserve");
for (have = 0; have < need; ) {
if (muxclient_terminate) {
errno = EINTR;
return -1;
}
len = read(fd, p + have, need - have);
if (len == -1) {
switch (errno) {
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
case EWOULDBLOCK:
#endif
case EAGAIN:
(void)poll(&pfd, 1, -1);
/* FALLTHROUGH */
case EINTR:
continue;
default:
return -1;
}
}
if (len == 0) {
errno = EPIPE;
return -1;
}
have += (size_t)len;
}
return 0;
}
static int
mux_client_write_packet(int fd, struct sshbuf *m)
{
struct sshbuf *queue;
u_int have, need;
int r, oerrno, len;
const u_char *ptr;
struct pollfd pfd;
pfd.fd = fd;
pfd.events = POLLOUT;
if ((queue = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_put_stringb(queue, m)) != 0)
fatal_fr(r, "enqueue");
need = sshbuf_len(queue);
ptr = sshbuf_ptr(queue);
for (have = 0; have < need; ) {
if (muxclient_terminate) {
sshbuf_free(queue);
errno = EINTR;
return -1;
}
len = write(fd, ptr + have, need - have);
if (len == -1) {
switch (errno) {
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
case EWOULDBLOCK:
#endif
case EAGAIN:
(void)poll(&pfd, 1, -1);
/* FALLTHROUGH */
case EINTR:
continue;
default:
oerrno = errno;
sshbuf_free(queue);
errno = oerrno;
return -1;
}
}
if (len == 0) {
sshbuf_free(queue);
errno = EPIPE;
return -1;
}
have += (u_int)len;
}
sshbuf_free(queue);
return 0;
}
static int
mux_client_read_packet(int fd, struct sshbuf *m)
{
struct sshbuf *queue;
size_t need, have;
const u_char *ptr;
int r, oerrno;
if ((queue = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if (mux_client_read(fd, queue, 4) != 0) {
if ((oerrno = errno) == EPIPE)
debug3_f("read header failed: %s",
strerror(errno));
sshbuf_free(queue);
errno = oerrno;
return -1;
}
need = PEEK_U32(sshbuf_ptr(queue));
if (mux_client_read(fd, queue, need) != 0) {
oerrno = errno;
debug3_f("read body failed: %s", strerror(errno));
sshbuf_free(queue);
errno = oerrno;
return -1;
}
if ((r = sshbuf_get_string_direct(queue, &ptr, &have)) != 0 ||
(r = sshbuf_put(m, ptr, have)) != 0)
fatal_fr(r, "dequeue");
sshbuf_free(queue);
return 0;
}
static int
mux_client_hello_exchange(int fd)
{
struct sshbuf *m;
u_int type, ver;
int r, ret = -1;
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_put_u32(m, MUX_MSG_HELLO)) != 0 ||
(r = sshbuf_put_u32(m, SSHMUX_VER)) != 0)
fatal_fr(r, "assemble hello");
/* no extensions */
if (mux_client_write_packet(fd, m) != 0) {
debug_f("write packet: %s", strerror(errno));
goto out;
}
sshbuf_reset(m);
/* Read their HELLO */
if (mux_client_read_packet(fd, m) != 0) {
debug_f("read packet failed");
goto out;
}
if ((r = sshbuf_get_u32(m, &type)) != 0)
fatal_fr(r, "parse type");
if (type != MUX_MSG_HELLO) {
error_f("expected HELLO (%u) got %u", MUX_MSG_HELLO, type);
goto out;
}
if ((r = sshbuf_get_u32(m, &ver)) != 0)
fatal_fr(r, "parse version");
if (ver != SSHMUX_VER) {
error("Unsupported multiplexing protocol version %d "
"(expected %d)", ver, SSHMUX_VER);
goto out;
}
debug2_f("master version %u", ver);
/* No extensions are presently defined */
while (sshbuf_len(m) > 0) {
char *name = NULL;
if ((r = sshbuf_get_cstring(m, &name, NULL)) != 0 ||
(r = sshbuf_skip_string(m)) != 0) { /* value */
error_fr(r, "parse extension");
goto out;
}
debug2("Unrecognised master extension \"%s\"", name);
free(name);
}
/* success */
ret = 0;
out:
sshbuf_free(m);
return ret;
}
static u_int
mux_client_request_alive(int fd)
{
struct sshbuf *m;
char *e;
u_int pid, type, rid;
int r;
debug3_f("entering");
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_put_u32(m, MUX_C_ALIVE_CHECK)) != 0 ||
(r = sshbuf_put_u32(m, muxclient_request_id)) != 0)
fatal_fr(r, "assemble");
if (mux_client_write_packet(fd, m) != 0)
fatal_f("write packet: %s", strerror(errno));
sshbuf_reset(m);
/* Read their reply */
if (mux_client_read_packet(fd, m) != 0) {
sshbuf_free(m);
return 0;
}
if ((r = sshbuf_get_u32(m, &type)) != 0)
fatal_fr(r, "parse type");
if (type != MUX_S_ALIVE) {
if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
fatal_fr(r, "parse error message");
fatal_f("master returned error: %s", e);
}
if ((r = sshbuf_get_u32(m, &rid)) != 0)
fatal_fr(r, "parse remote ID");
if (rid != muxclient_request_id)
fatal_f("out of sequence reply: my id %u theirs %u",
muxclient_request_id, rid);
if ((r = sshbuf_get_u32(m, &pid)) != 0)
fatal_fr(r, "parse PID");
sshbuf_free(m);
debug3_f("done pid = %u", pid);
muxclient_request_id++;
return pid;
}
static void
mux_client_request_terminate(int fd)
{
struct sshbuf *m;
char *e;
u_int type, rid;
int r;
debug3_f("entering");
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_put_u32(m, MUX_C_TERMINATE)) != 0 ||
(r = sshbuf_put_u32(m, muxclient_request_id)) != 0)
fatal_fr(r, "request");
if (mux_client_write_packet(fd, m) != 0)
fatal_f("write packet: %s", strerror(errno));
sshbuf_reset(m);
/* Read their reply */
if (mux_client_read_packet(fd, m) != 0) {
/* Remote end exited already */
if (errno == EPIPE) {
sshbuf_free(m);
return;
}
fatal_f("read from master failed: %s", strerror(errno));
}
if ((r = sshbuf_get_u32(m, &type)) != 0 ||
(r = sshbuf_get_u32(m, &rid)) != 0)
fatal_fr(r, "parse");
if (rid != muxclient_request_id)
fatal_f("out of sequence reply: my id %u theirs %u",
muxclient_request_id, rid);
switch (type) {
case MUX_S_OK:
break;
case MUX_S_PERMISSION_DENIED:
if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
fatal_fr(r, "parse error message");
fatal("Master refused termination request: %s", e);
case MUX_S_FAILURE:
if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
fatal_fr(r, "parse error message");
fatal_f("termination request failed: %s", e);
default:
fatal_f("unexpected response from master 0x%08x", type);
}
sshbuf_free(m);
muxclient_request_id++;
}
static int
mux_client_forward(int fd, int cancel_flag, u_int ftype, struct Forward *fwd)
{
struct sshbuf *m;
char *e, *fwd_desc;
const char *lhost, *chost;
u_int type, rid;
int r;
fwd_desc = format_forward(ftype, fwd);
debug("Requesting %s %s",
cancel_flag ? "cancellation of" : "forwarding of", fwd_desc);
free(fwd_desc);
type = cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD;
if (fwd->listen_path != NULL)
lhost = fwd->listen_path;
else if (fwd->listen_host == NULL)
lhost = "";
else if (*fwd->listen_host == '\0')
lhost = "*";
else
lhost = fwd->listen_host;
if (fwd->connect_path != NULL)
chost = fwd->connect_path;
else if (fwd->connect_host == NULL)
chost = "";
else
chost = fwd->connect_host;
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_put_u32(m, type)) != 0 ||
(r = sshbuf_put_u32(m, muxclient_request_id)) != 0 ||
(r = sshbuf_put_u32(m, ftype)) != 0 ||
(r = sshbuf_put_cstring(m, lhost)) != 0 ||
(r = sshbuf_put_u32(m, fwd->listen_port)) != 0 ||
(r = sshbuf_put_cstring(m, chost)) != 0 ||
(r = sshbuf_put_u32(m, fwd->connect_port)) != 0)
fatal_fr(r, "request");
if (mux_client_write_packet(fd, m) != 0)
fatal_f("write packet: %s", strerror(errno));
sshbuf_reset(m);
/* Read their reply */
if (mux_client_read_packet(fd, m) != 0) {
sshbuf_free(m);
return -1;
}
if ((r = sshbuf_get_u32(m, &type)) != 0 ||
(r = sshbuf_get_u32(m, &rid)) != 0)
fatal_fr(r, "parse");
if (rid != muxclient_request_id)
fatal_f("out of sequence reply: my id %u theirs %u",
muxclient_request_id, rid);
switch (type) {
case MUX_S_OK:
break;
case MUX_S_REMOTE_PORT:
if (cancel_flag)
fatal_f("got MUX_S_REMOTE_PORT for cancel");
if ((r = sshbuf_get_u32(m, &fwd->allocated_port)) != 0)
fatal_fr(r, "parse port");
verbose("Allocated port %u for remote forward to %s:%d",
fwd->allocated_port,
fwd->connect_host ? fwd->connect_host : "",
fwd->connect_port);
if (muxclient_command == SSHMUX_COMMAND_FORWARD)
fprintf(stdout, "%i\n", fwd->allocated_port);
break;
case MUX_S_PERMISSION_DENIED:
if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
fatal_fr(r, "parse error message");
sshbuf_free(m);
error("Master refused forwarding request: %s", e);
return -1;
case MUX_S_FAILURE:
if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
fatal_fr(r, "parse error message");
sshbuf_free(m);
error_f("forwarding request failed: %s", e);
return -1;
default:
fatal_f("unexpected response from master 0x%08x", type);
}
sshbuf_free(m);
muxclient_request_id++;
return 0;
}
static int
mux_client_forwards(int fd, int cancel_flag)
{
int i, ret = 0;
debug3_f("%s forwardings: %d local, %d remote",
cancel_flag ? "cancel" : "request",
options.num_local_forwards, options.num_remote_forwards);
/* XXX ExitOnForwardingFailure */
for (i = 0; i < options.num_local_forwards; i++) {
if (mux_client_forward(fd, cancel_flag,
options.local_forwards[i].connect_port == 0 ?
MUX_FWD_DYNAMIC : MUX_FWD_LOCAL,
options.local_forwards + i) != 0)
ret = -1;
}
for (i = 0; i < options.num_remote_forwards; i++) {
if (mux_client_forward(fd, cancel_flag, MUX_FWD_REMOTE,
options.remote_forwards + i) != 0)
ret = -1;
}
return ret;
}
static int
mux_client_request_session(int fd)
{
struct sshbuf *m;
char *e;
const char *term;
u_int echar, rid, sid, esid, exitval, type, exitval_seen;
extern char **environ;
int r, i, rawmode;
debug3_f("entering");
if ((muxserver_pid = mux_client_request_alive(fd)) == 0) {
error_f("master alive request failed");
return -1;
}
ssh_signal(SIGPIPE, SIG_IGN);
if (stdin_null_flag && stdfd_devnull(1, 0, 0) == -1)
fatal_f("stdfd_devnull failed");
if ((term = getenv("TERM")) == NULL)
term = "";
echar = 0xffffffff;
if (options.escape_char != SSH_ESCAPECHAR_NONE)
echar = (u_int)options.escape_char;
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_put_u32(m, MUX_C_NEW_SESSION)) != 0 ||
(r = sshbuf_put_u32(m, muxclient_request_id)) != 0 ||
(r = sshbuf_put_string(m, NULL, 0)) != 0 || /* reserved */
(r = sshbuf_put_u32(m, tty_flag)) != 0 ||
(r = sshbuf_put_u32(m, options.forward_x11)) != 0 ||
(r = sshbuf_put_u32(m, options.forward_agent)) != 0 ||
(r = sshbuf_put_u32(m, subsystem_flag)) != 0 ||
(r = sshbuf_put_u32(m, echar)) != 0 ||
(r = sshbuf_put_cstring(m, term)) != 0 ||
(r = sshbuf_put_stringb(m, command)) != 0)
fatal_fr(r, "request");
/* Pass environment */
if (options.num_send_env > 0 && environ != NULL) {
for (i = 0; environ[i] != NULL; i++) {
if (!env_permitted(environ[i]))
continue;
if ((r = sshbuf_put_cstring(m, environ[i])) != 0)
fatal_fr(r, "request sendenv");
}
}
for (i = 0; i < options.num_setenv; i++) {
if ((r = sshbuf_put_cstring(m, options.setenv[i])) != 0)
fatal_fr(r, "request setenv");
}
if (mux_client_write_packet(fd, m) != 0)
fatal_f("write packet: %s", strerror(errno));
/* Send the stdio file descriptors */
if (mm_send_fd(fd, STDIN_FILENO) == -1 ||
mm_send_fd(fd, STDOUT_FILENO) == -1 ||
mm_send_fd(fd, STDERR_FILENO) == -1)
fatal_f("send fds failed");
debug3_f("session request sent");
/* Read their reply */
sshbuf_reset(m);
if (mux_client_read_packet(fd, m) != 0) {
error_f("read from master failed: %s", strerror(errno));
sshbuf_free(m);
return -1;
}
if ((r = sshbuf_get_u32(m, &type)) != 0 ||
(r = sshbuf_get_u32(m, &rid)) != 0)
fatal_fr(r, "parse");
if (rid != muxclient_request_id)
fatal_f("out of sequence reply: my id %u theirs %u",
muxclient_request_id, rid);
switch (type) {
case MUX_S_SESSION_OPENED:
if ((r = sshbuf_get_u32(m, &sid)) != 0)
fatal_fr(r, "parse session ID");
debug_f("master session id: %u", sid);
break;
case MUX_S_PERMISSION_DENIED:
if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
fatal_fr(r, "parse error message");
error("Master refused session request: %s", e);
sshbuf_free(m);
return -1;
case MUX_S_FAILURE:
if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
fatal_fr(r, "parse error message");
error_f("session request failed: %s", e);
sshbuf_free(m);
return -1;
default:
sshbuf_free(m);
error_f("unexpected response from master 0x%08x", type);
return -1;
}
muxclient_request_id++;
if (pledge("stdio proc tty", NULL) == -1)
fatal_f("pledge(): %s", strerror(errno));
platform_pledge_mux();
ssh_signal(SIGHUP, control_client_sighandler);
ssh_signal(SIGINT, control_client_sighandler);
ssh_signal(SIGTERM, control_client_sighandler);
ssh_signal(SIGWINCH, control_client_sigrelay);
rawmode = tty_flag;
if (tty_flag)
enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
/*
* Stick around until the controlee closes the client_fd.
* Before it does, it is expected to write an exit message.
* This process must read the value and wait for the closure of
* the client_fd; if this one closes early, the multiplex master will
* terminate early too (possibly losing data).
*/
for (exitval = 255, exitval_seen = 0;;) {
sshbuf_reset(m);
if (mux_client_read_packet(fd, m) != 0)
break;
if ((r = sshbuf_get_u32(m, &type)) != 0)
fatal_fr(r, "parse type");
switch (type) {
case MUX_S_TTY_ALLOC_FAIL:
if ((r = sshbuf_get_u32(m, &esid)) != 0)
fatal_fr(r, "parse session ID");
if (esid != sid)
fatal_f("tty alloc fail on unknown session: "
"my id %u theirs %u", sid, esid);
leave_raw_mode(options.request_tty ==
REQUEST_TTY_FORCE);
rawmode = 0;
continue;
case MUX_S_EXIT_MESSAGE:
if ((r = sshbuf_get_u32(m, &esid)) != 0)
fatal_fr(r, "parse session ID");
if (esid != sid)
fatal_f("exit on unknown session: "
"my id %u theirs %u", sid, esid);
if (exitval_seen)
fatal_f("exitval sent twice");
if ((r = sshbuf_get_u32(m, &exitval)) != 0)
fatal_fr(r, "parse exitval");
exitval_seen = 1;
continue;
default:
if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
fatal_fr(r, "parse error message");
fatal_f("master returned error: %s", e);
}
}
close(fd);
if (rawmode)
leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
if (muxclient_terminate) {
debug2("Exiting on signal: %s", strsignal(muxclient_terminate));
exitval = 255;
} else if (!exitval_seen) {
debug2("Control master terminated unexpectedly");
exitval = 255;
} else
debug2("Received exit status from master %d", exitval);
if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
fprintf(stderr, "Shared connection to %s closed.\r\n", host);
exit(exitval);
}
static int
mux_client_proxy(int fd)
{
struct sshbuf *m;
char *e;
u_int type, rid;
int r;
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_put_u32(m, MUX_C_PROXY)) != 0 ||
(r = sshbuf_put_u32(m, muxclient_request_id)) != 0)
fatal_fr(r, "request");
if (mux_client_write_packet(fd, m) != 0)
fatal_f("write packet: %s", strerror(errno));
sshbuf_reset(m);
/* Read their reply */
if (mux_client_read_packet(fd, m) != 0) {
sshbuf_free(m);
return 0;
}
if ((r = sshbuf_get_u32(m, &type)) != 0 ||
(r = sshbuf_get_u32(m, &rid)) != 0)
fatal_fr(r, "parse");
if (rid != muxclient_request_id)
fatal_f("out of sequence reply: my id %u theirs %u",
muxclient_request_id, rid);
if (type != MUX_S_PROXY) {
if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
fatal_fr(r, "parse error message");
fatal_f("master returned error: %s", e);
}
sshbuf_free(m);
debug3_f("done");
muxclient_request_id++;
return 0;
}
static int
mux_client_request_stdio_fwd(int fd)
{
struct sshbuf *m;
char *e;
u_int type, rid, sid;
int r;
debug3_f("entering");
if ((muxserver_pid = mux_client_request_alive(fd)) == 0) {
error_f("master alive request failed");
return -1;
}
ssh_signal(SIGPIPE, SIG_IGN);
if (stdin_null_flag && stdfd_devnull(1, 0, 0) == -1)
fatal_f("stdfd_devnull failed");
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_put_u32(m, MUX_C_NEW_STDIO_FWD)) != 0 ||
(r = sshbuf_put_u32(m, muxclient_request_id)) != 0 ||
(r = sshbuf_put_string(m, NULL, 0)) != 0 || /* reserved */
(r = sshbuf_put_cstring(m, options.stdio_forward_host)) != 0 ||
(r = sshbuf_put_u32(m, options.stdio_forward_port)) != 0)
fatal_fr(r, "request");
if (mux_client_write_packet(fd, m) != 0)
fatal_f("write packet: %s", strerror(errno));
/* Send the stdio file descriptors */
if (mm_send_fd(fd, STDIN_FILENO) == -1 ||
mm_send_fd(fd, STDOUT_FILENO) == -1)
fatal_f("send fds failed");
if (pledge("stdio proc tty", NULL) == -1)
fatal_f("pledge(): %s", strerror(errno));
platform_pledge_mux();
debug3_f("stdio forward request sent");
/* Read their reply */
sshbuf_reset(m);
if (mux_client_read_packet(fd, m) != 0) {
error_f("read from master failed: %s", strerror(errno));
sshbuf_free(m);
return -1;
}
if ((r = sshbuf_get_u32(m, &type)) != 0 ||
(r = sshbuf_get_u32(m, &rid)) != 0)
fatal_fr(r, "parse");
if (rid != muxclient_request_id)
fatal_f("out of sequence reply: my id %u theirs %u",
muxclient_request_id, rid);
switch (type) {
case MUX_S_SESSION_OPENED:
if ((r = sshbuf_get_u32(m, &sid)) != 0)
fatal_fr(r, "parse session ID");
debug_f("master session id: %u", sid);
break;
case MUX_S_PERMISSION_DENIED:
if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
fatal_fr(r, "parse error message");
sshbuf_free(m);
fatal("Master refused stdio forwarding request: %s", e);
case MUX_S_FAILURE:
if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
fatal_fr(r, "parse error message");
sshbuf_free(m);
fatal("Stdio forwarding request failed: %s", e);
default:
sshbuf_free(m);
error_f("unexpected response from master 0x%08x", type);
return -1;
}
muxclient_request_id++;
ssh_signal(SIGHUP, control_client_sighandler);
ssh_signal(SIGINT, control_client_sighandler);
ssh_signal(SIGTERM, control_client_sighandler);
ssh_signal(SIGWINCH, control_client_sigrelay);
/*
* Stick around until the controlee closes the client_fd.
*/
sshbuf_reset(m);
if (mux_client_read_packet(fd, m) != 0) {
if (errno == EPIPE ||
(errno == EINTR && muxclient_terminate != 0))
return 0;
fatal_f("mux_client_read_packet: %s", strerror(errno));
}
fatal_f("master returned unexpected message %u", type);
}
static void
mux_client_request_stop_listening(int fd)
{
struct sshbuf *m;
char *e;
u_int type, rid;
int r;
debug3_f("entering");
if ((m = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_put_u32(m, MUX_C_STOP_LISTENING)) != 0 ||
(r = sshbuf_put_u32(m, muxclient_request_id)) != 0)
fatal_fr(r, "request");
if (mux_client_write_packet(fd, m) != 0)
fatal_f("write packet: %s", strerror(errno));
sshbuf_reset(m);
/* Read their reply */
if (mux_client_read_packet(fd, m) != 0)
fatal_f("read from master failed: %s", strerror(errno));
if ((r = sshbuf_get_u32(m, &type)) != 0 ||
(r = sshbuf_get_u32(m, &rid)) != 0)
fatal_fr(r, "parse");
if (rid != muxclient_request_id)
fatal_f("out of sequence reply: my id %u theirs %u",
muxclient_request_id, rid);
switch (type) {
case MUX_S_OK:
break;
case MUX_S_PERMISSION_DENIED:
if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
fatal_fr(r, "parse error message");
fatal("Master refused stop listening request: %s", e);
case MUX_S_FAILURE:
if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
fatal_fr(r, "parse error message");
fatal_f("stop listening request failed: %s", e);
default:
fatal_f("unexpected response from master 0x%08x", type);
}
sshbuf_free(m);
muxclient_request_id++;
}
/* Multiplex client main loop. */
int
muxclient(const char *path)
{
struct sockaddr_un addr;
int sock;
u_int pid;
if (muxclient_command == 0) {
if (options.stdio_forward_host != NULL)
muxclient_command = SSHMUX_COMMAND_STDIO_FWD;
else
muxclient_command = SSHMUX_COMMAND_OPEN;
}
switch (options.control_master) {
case SSHCTL_MASTER_AUTO:
case SSHCTL_MASTER_AUTO_ASK:
debug("auto-mux: Trying existing master");
/* FALLTHROUGH */
case SSHCTL_MASTER_NO:
break;
default:
return -1;
}
memset(&addr, '\0', sizeof(addr));
addr.sun_family = AF_UNIX;
if (strlcpy(addr.sun_path, path,
sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
fatal("ControlPath too long ('%s' >= %u bytes)", path,
- (unsigned int)sizeof(addr.sun_path));
+ (unsigned int)sizeof(addr.sun_path));
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
fatal_f("socket(): %s", strerror(errno));
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
switch (muxclient_command) {
case SSHMUX_COMMAND_OPEN:
case SSHMUX_COMMAND_STDIO_FWD:
break;
default:
fatal("Control socket connect(%.100s): %s", path,
strerror(errno));
}
if (errno == ECONNREFUSED &&
options.control_master != SSHCTL_MASTER_NO) {
debug("Stale control socket %.100s, unlinking", path);
unlink(path);
} else if (errno == ENOENT) {
debug("Control socket \"%.100s\" does not exist", path);
} else {
error("Control socket connect(%.100s): %s", path,
strerror(errno));
}
close(sock);
return -1;
}
set_nonblock(sock);
if (mux_client_hello_exchange(sock) != 0) {
error_f("master hello exchange failed");
close(sock);
return -1;
}
switch (muxclient_command) {
case SSHMUX_COMMAND_ALIVE_CHECK:
if ((pid = mux_client_request_alive(sock)) == 0)
fatal_f("master alive check failed");
fprintf(stderr, "Master running (pid=%u)\r\n", pid);
exit(0);
case SSHMUX_COMMAND_TERMINATE:
mux_client_request_terminate(sock);
if (options.log_level != SYSLOG_LEVEL_QUIET)
fprintf(stderr, "Exit request sent.\r\n");
exit(0);
case SSHMUX_COMMAND_FORWARD:
if (mux_client_forwards(sock, 0) != 0)
fatal_f("master forward request failed");
exit(0);
case SSHMUX_COMMAND_OPEN:
if (mux_client_forwards(sock, 0) != 0) {
error_f("master forward request failed");
return -1;
}
mux_client_request_session(sock);
return -1;
case SSHMUX_COMMAND_STDIO_FWD:
mux_client_request_stdio_fwd(sock);
exit(0);
case SSHMUX_COMMAND_STOP:
mux_client_request_stop_listening(sock);
if (options.log_level != SYSLOG_LEVEL_QUIET)
fprintf(stderr, "Stop listening request sent.\r\n");
exit(0);
case SSHMUX_COMMAND_CANCEL_FWD:
if (mux_client_forwards(sock, 1) != 0)
error_f("master cancel forward request failed");
exit(0);
case SSHMUX_COMMAND_PROXY:
mux_client_proxy(sock);
return (sock);
default:
fatal("unrecognised muxclient_command %d", muxclient_command);
}
}
diff --git a/openbsd-compat/base64.c b/openbsd-compat/base64.c
index 9e7466716425..b7dce095e4c3 100644
--- a/openbsd-compat/base64.c
+++ b/openbsd-compat/base64.c
@@ -1,315 +1,315 @@
/* $OpenBSD: base64.c,v 1.5 2006/10/21 09:55:03 otto Exp $ */
/*
* Copyright (c) 1996 by Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
/*
* Portions Copyright (c) 1995 by International Business Machines, Inc.
*
* International Business Machines, Inc. (hereinafter called IBM) grants
* permission under its copyrights to use, copy, modify, and distribute this
* Software with or without fee, provided that the above copyright notice and
* all paragraphs of this notice appear in all copies, and that the name of IBM
* not be used in connection with the marketing of any product incorporating
* the Software or modifications thereof, without specific, written prior
* permission.
*
* To the extent it has a right to do so, IBM grants an immunity from suit
* under its patents, if any, for the use, sale or manufacture of products to
* the extent that such products are used for performing Domain Name System
* dynamic updates in TCP/IP networks by means of the Software. No immunity is
* granted for any product per se or for any other function of any product.
*
* THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
* DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
* IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
/* OPENBSD ORIGINAL: lib/libc/net/base64.c */
#include "includes.h"
#if (!defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP)) || (!defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON))
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "base64.h"
static const char Base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char Pad64 = '=';
/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
The following encoding technique is taken from RFC 1521 by Borenstein
and Freed. It is reproduced here in a slightly edited form for
convenience.
A 65-character subset of US-ASCII is used, enabling 6 bits to be
represented per printable character. (The extra 65th character, "=",
is used to signify a special processing function.)
The encoding process represents 24-bit groups of input bits as output
strings of 4 encoded characters. Proceeding from left to right, a
24-bit input group is formed by concatenating 3 8-bit input groups.
These 24 bits are then treated as 4 concatenated 6-bit groups, each
of which is translated into a single digit in the base64 alphabet.
Each 6-bit group is used as an index into an array of 64 printable
characters. The character referenced by the index is placed in the
output string.
Table 1: The Base64 Alphabet
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w (pad) =
15 P 32 g 49 x
16 Q 33 h 50 y
Special processing is performed if fewer than 24 bits are available
at the end of the data being encoded. A full encoding quantum is
always completed at the end of a quantity. When fewer than 24 input
bits are available in an input group, zero bits are added (on the
right) to form an integral number of 6-bit groups. Padding at the
end of the data is performed using the '=' character.
Since all base64 input is an integral number of octets, only the
-------------------------------------------------
following cases can arise:
(1) the final quantum of encoding input is an integral
multiple of 24 bits; here, the final unit of encoded
output will be an integral multiple of 4 characters
with no "=" padding,
(2) the final quantum of encoding input is exactly 8 bits;
here, the final unit of encoded output will be two
characters followed by two "=" padding characters, or
(3) the final quantum of encoding input is exactly 16 bits;
here, the final unit of encoded output will be three
characters followed by one "=" padding character.
*/
#if !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP)
int
b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize)
{
size_t datalength = 0;
u_char input[3];
u_char output[4];
u_int i;
while (2 < srclength) {
input[0] = *src++;
input[1] = *src++;
input[2] = *src++;
srclength -= 3;
output[0] = input[0] >> 2;
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
output[3] = input[2] & 0x3f;
if (datalength + 4 > targsize)
return (-1);
target[datalength++] = Base64[output[0]];
target[datalength++] = Base64[output[1]];
target[datalength++] = Base64[output[2]];
target[datalength++] = Base64[output[3]];
}
/* Now we worry about padding. */
if (0 != srclength) {
/* Get what's left. */
input[0] = input[1] = input[2] = '\0';
for (i = 0; i < srclength; i++)
input[i] = *src++;
output[0] = input[0] >> 2;
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
if (datalength + 4 > targsize)
return (-1);
target[datalength++] = Base64[output[0]];
target[datalength++] = Base64[output[1]];
if (srclength == 1)
target[datalength++] = Pad64;
else
target[datalength++] = Base64[output[2]];
target[datalength++] = Pad64;
}
if (datalength >= targsize)
return (-1);
target[datalength] = '\0'; /* Returned value doesn't count \0. */
return (datalength);
}
#endif /* !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) */
#if !defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON)
/* skips all whitespace anywhere.
converts characters, four at a time, starting at (or after)
src from base - 64 numbers into three 8 bit bytes in the target area.
it returns the number of data bytes stored at the target, or -1 on error.
*/
int
b64_pton(char const *src, u_char *target, size_t targsize)
{
u_int tarindex, state;
int ch;
char *pos;
state = 0;
tarindex = 0;
while ((ch = *src++) != '\0') {
if (isspace(ch)) /* Skip whitespace anywhere. */
continue;
if (ch == Pad64)
break;
pos = strchr(Base64, ch);
- if (pos == 0) /* A non-base64 character. */
+ if (pos == 0) /* A non-base64 character. */
return (-1);
switch (state) {
case 0:
if (target) {
if (tarindex >= targsize)
return (-1);
target[tarindex] = (pos - Base64) << 2;
}
state = 1;
break;
case 1:
if (target) {
if (tarindex + 1 >= targsize)
return (-1);
target[tarindex] |= (pos - Base64) >> 4;
target[tarindex+1] = ((pos - Base64) & 0x0f)
<< 4 ;
}
tarindex++;
state = 2;
break;
case 2:
if (target) {
if (tarindex + 1 >= targsize)
return (-1);
target[tarindex] |= (pos - Base64) >> 2;
target[tarindex+1] = ((pos - Base64) & 0x03)
<< 6;
}
tarindex++;
state = 3;
break;
case 3:
if (target) {
if (tarindex >= targsize)
return (-1);
target[tarindex] |= (pos - Base64);
}
tarindex++;
state = 0;
break;
}
}
/*
* We are done decoding Base-64 chars. Let's see if we ended
* on a byte boundary, and/or with erroneous trailing characters.
*/
if (ch == Pad64) { /* We got a pad char. */
ch = *src++; /* Skip it, get next. */
switch (state) {
case 0: /* Invalid = in first position */
case 1: /* Invalid = in second position */
return (-1);
case 2: /* Valid, means one byte of info */
/* Skip any number of spaces. */
for (; ch != '\0'; ch = *src++)
if (!isspace(ch))
break;
/* Make sure there is another trailing = sign. */
if (ch != Pad64)
return (-1);
ch = *src++; /* Skip the = */
/* Fall through to "single trailing =" case. */
/* FALLTHROUGH */
case 3: /* Valid, means two bytes of info */
/*
* We know this char is an =. Is there anything but
* whitespace after it?
*/
for (; ch != '\0'; ch = *src++)
if (!isspace(ch))
return (-1);
/*
* Now make sure for cases 2 and 3 that the "extra"
* bits that slopped past the last full byte were
* zeros. If we don't check them, they become a
* subliminal channel.
*/
if (target && target[tarindex] != 0)
return (-1);
}
} else {
/*
* We ended by seeing the end of the string. Make sure we
* have no partial bytes lying around.
*/
if (state != 0)
return (-1);
}
return (tarindex);
}
#endif /* !defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON) */
#endif
diff --git a/openbsd-compat/bsd-poll.h b/openbsd-compat/bsd-poll.h
index 17945f5b46f5..8420ca1db378 100644
--- a/openbsd-compat/bsd-poll.h
+++ b/openbsd-compat/bsd-poll.h
@@ -1,61 +1,61 @@
/* $OpenBSD: poll.h,v 1.11 2003/12/10 23:10:08 millert Exp $ */
/*
* Copyright (c) 1996 Theo de Raadt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* OPENBSD ORIGINAL: sys/sys/poll.h */
#if !defined(HAVE_POLL) && !defined(HAVE_POLL_H)
#ifndef _COMPAT_POLL_H_
#define _COMPAT_POLL_H_
typedef struct pollfd {
- int fd;
+ int fd;
short events;
short revents;
} pollfd_t;
typedef unsigned int nfds_t;
#define POLLIN 0x0001
#define POLLOUT 0x0004
#define POLLERR 0x0008
#define POLLHUP 0x0010
#define POLLNVAL 0x0020
#if 0
/* the following are currently not implemented */
#define POLLPRI 0x0002
#define POLLRDNORM 0x0040
#define POLLNORM POLLRDNORM
#define POLLWRNORM POLLOUT
#define POLLRDBAND 0x0080
#define POLLWRBAND 0x0100
#endif
#define INFTIM (-1) /* not standard */
int poll(struct pollfd *, nfds_t, int);
#endif /* !_COMPAT_POLL_H_ */
#endif /* !HAVE_POLL_H */
diff --git a/openbsd-compat/bsd-snprintf.c b/openbsd-compat/bsd-snprintf.c
index f041121fd90b..b9eaee14f3c0 100644
--- a/openbsd-compat/bsd-snprintf.c
+++ b/openbsd-compat/bsd-snprintf.c
@@ -1,880 +1,880 @@
/*
* Copyright Patrick Powell 1995
* This code is based on code written by Patrick Powell (papowell@astart.com)
* It may be used for any purpose as long as this notice remains intact
* on all source code distributions
*/
/**************************************************************
* Original:
* Patrick Powell Tue Apr 11 09:48:21 PDT 1995
* A bombproof version of doprnt (dopr) included.
* Sigh. This sort of thing is always nasty do deal with. Note that
* the version here does not include floating point...
*
* snprintf() is used instead of sprintf() as it does limit checks
* for string length. This covers a nasty loophole.
*
* The other functions are there to prevent NULL pointers from
* causing nast effects.
*
* More Recently:
* Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
* This was ugly. It is still ugly. I opted out of floating point
* numbers, but the formatter understands just about everything
* from the normal C string format, at least as far as I can tell from
* the Solaris 2.5 printf(3S) man page.
*
* Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
* Ok, added some minimal floating point support, which means this
* probably requires libm on most operating systems. Don't yet
* support the exponent (e,E) and sigfig (g,G). Also, fmtint()
* was pretty badly broken, it just wasn't being exercised in ways
* which showed it, so that's been fixed. Also, formatted the code
* to mutt conventions, and removed dead code left over from the
* original. Also, there is now a builtin-test, just compile with:
* gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
* and run snprintf for results.
*
* Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
* The PGP code was using unsigned hexadecimal formats.
* Unfortunately, unsigned formats simply didn't work.
*
* Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
* The original code assumed that both snprintf() and vsnprintf() were
* missing. Some systems only have snprintf() but not vsnprintf(), so
* the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
*
* Andrew Tridgell (tridge@samba.org) Oct 1998
* fixed handling of %.0f
* added test for HAVE_LONG_DOUBLE
*
* tridge@samba.org, idra@samba.org, April 2001
* got rid of fcvt code (twas buggy and made testing harder)
* added C99 semantics
*
* date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0
* actually print args for %g and %e
*
* date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0
* Since includes.h isn't included here, VA_COPY has to be defined here. I don't
* see any include file that is guaranteed to be here, so I'm defining it
* locally. Fixes AIX and Solaris builds.
*
* date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13
* put the ifdef for HAVE_VA_COPY in one place rather than in lots of
* functions
*
* date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4
* Fix usage of va_list passed as an arg. Use __va_copy before using it
* when it exists.
*
* date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14
* Fix incorrect zpadlen handling in fmtfp.
* Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
* few mods to make it easier to compile the tests.
* added the "Ollie" test to the floating point ones.
*
* Martin Pool (mbp@samba.org) April 2003
* Remove NO_CONFIG_H so that the test case can be built within a source
* tree with less trouble.
* Remove unnecessary SAFE_FREE() definition.
*
* Martin Pool (mbp@samba.org) May 2003
* Put in a prototype for dummy_snprintf() to quiet compiler warnings.
*
* Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
* if the C library has some snprintf functions already.
*
* Damien Miller (djm@mindrot.org) Jan 2007
* Fix integer overflows in return value.
* Make formatting quite a bit faster by inlining dopr_outch()
*
**************************************************************/
#include "includes.h"
#if defined(BROKEN_SNPRINTF) /* For those with broken snprintf() */
# undef HAVE_SNPRINTF
# undef HAVE_VSNPRINTF
#endif
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#ifdef HAVE_LONG_DOUBLE
# define LDOUBLE long double
#else
# define LDOUBLE double
#endif
#ifdef HAVE_LONG_LONG
# define LLONG long long
#else
# define LLONG long
#endif
/*
* dopr(): poor man's version of doprintf
*/
/* format read states */
#define DP_S_DEFAULT 0
#define DP_S_FLAGS 1
#define DP_S_MIN 2
#define DP_S_DOT 3
#define DP_S_MAX 4
#define DP_S_MOD 5
#define DP_S_CONV 6
#define DP_S_DONE 7
/* format flags - Bits */
-#define DP_F_MINUS (1 << 0)
-#define DP_F_PLUS (1 << 1)
-#define DP_F_SPACE (1 << 2)
-#define DP_F_NUM (1 << 3)
-#define DP_F_ZERO (1 << 4)
-#define DP_F_UP (1 << 5)
-#define DP_F_UNSIGNED (1 << 6)
+#define DP_F_MINUS (1 << 0)
+#define DP_F_PLUS (1 << 1)
+#define DP_F_SPACE (1 << 2)
+#define DP_F_NUM (1 << 3)
+#define DP_F_ZERO (1 << 4)
+#define DP_F_UP (1 << 5)
+#define DP_F_UNSIGNED (1 << 6)
/* Conversion Flags */
#define DP_C_SHORT 1
#define DP_C_LONG 2
#define DP_C_LDOUBLE 3
#define DP_C_LLONG 4
#define DP_C_SIZE 5
#define DP_C_INTMAX 6
#define char_to_int(p) ((p)- '0')
#ifndef MAX
# define MAX(p,q) (((p) >= (q)) ? (p) : (q))
#endif
#define DOPR_OUTCH(buf, pos, buflen, thechar) \
do { \
if (pos + 1 >= INT_MAX) { \
errno = ERANGE; \
return -1; \
} \
if (pos < buflen) \
buf[pos] = thechar; \
(pos)++; \
} while (0)
static int dopr(char *buffer, size_t maxlen, const char *format,
va_list args_in);
static int fmtstr(char *buffer, size_t *currlen, size_t maxlen,
char *value, int flags, int min, int max);
static int fmtint(char *buffer, size_t *currlen, size_t maxlen,
intmax_t value, int base, int min, int max, int flags);
static int fmtfp(char *buffer, size_t *currlen, size_t maxlen,
LDOUBLE fvalue, int min, int max, int flags);
static int
dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
{
char ch;
intmax_t value;
LDOUBLE fvalue;
char *strvalue;
int min;
int max;
int state;
int flags;
int cflags;
size_t currlen;
va_list args;
VA_COPY(args, args_in);
state = DP_S_DEFAULT;
currlen = flags = cflags = min = 0;
max = -1;
ch = *format++;
while (state != DP_S_DONE) {
if (ch == '\0')
state = DP_S_DONE;
switch(state) {
case DP_S_DEFAULT:
if (ch == '%')
state = DP_S_FLAGS;
else
DOPR_OUTCH(buffer, currlen, maxlen, ch);
ch = *format++;
break;
case DP_S_FLAGS:
switch (ch) {
case '-':
flags |= DP_F_MINUS;
ch = *format++;
break;
case '+':
flags |= DP_F_PLUS;
ch = *format++;
break;
case ' ':
flags |= DP_F_SPACE;
ch = *format++;
break;
case '#':
flags |= DP_F_NUM;
ch = *format++;
break;
case '0':
flags |= DP_F_ZERO;
ch = *format++;
break;
default:
state = DP_S_MIN;
break;
}
break;
case DP_S_MIN:
if (isdigit((unsigned char)ch)) {
min = 10*min + char_to_int (ch);
ch = *format++;
} else if (ch == '*') {
min = va_arg (args, int);
ch = *format++;
state = DP_S_DOT;
} else {
state = DP_S_DOT;
}
break;
case DP_S_DOT:
if (ch == '.') {
state = DP_S_MAX;
ch = *format++;
} else {
state = DP_S_MOD;
}
break;
case DP_S_MAX:
if (isdigit((unsigned char)ch)) {
if (max < 0)
max = 0;
max = 10*max + char_to_int (ch);
ch = *format++;
} else if (ch == '*') {
max = va_arg (args, int);
ch = *format++;
state = DP_S_MOD;
} else {
state = DP_S_MOD;
}
break;
case DP_S_MOD:
switch (ch) {
case 'h':
cflags = DP_C_SHORT;
ch = *format++;
break;
case 'j':
cflags = DP_C_INTMAX;
ch = *format++;
break;
case 'l':
cflags = DP_C_LONG;
ch = *format++;
if (ch == 'l') { /* It's a long long */
cflags = DP_C_LLONG;
ch = *format++;
}
break;
case 'L':
cflags = DP_C_LDOUBLE;
ch = *format++;
break;
case 'z':
cflags = DP_C_SIZE;
ch = *format++;
break;
default:
break;
}
state = DP_S_CONV;
break;
case DP_S_CONV:
switch (ch) {
case 'd':
case 'i':
if (cflags == DP_C_SHORT)
value = va_arg (args, int);
else if (cflags == DP_C_LONG)
value = va_arg (args, long int);
else if (cflags == DP_C_LLONG)
value = va_arg (args, LLONG);
else if (cflags == DP_C_SIZE)
value = va_arg (args, ssize_t);
else if (cflags == DP_C_INTMAX)
value = va_arg (args, intmax_t);
else
value = va_arg (args, int);
if (fmtint(buffer, &currlen, maxlen,
value, 10, min, max, flags) == -1)
return -1;
break;
case 'o':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned int);
else if (cflags == DP_C_LONG)
value = (long)va_arg (args, unsigned long int);
else if (cflags == DP_C_LLONG)
value = (long)va_arg (args, unsigned LLONG);
else if (cflags == DP_C_SIZE)
value = va_arg (args, size_t);
#ifdef notyet
else if (cflags == DP_C_INTMAX)
value = va_arg (args, uintmax_t);
#endif
else
value = (long)va_arg (args, unsigned int);
if (fmtint(buffer, &currlen, maxlen, value,
8, min, max, flags) == -1)
return -1;
break;
case 'u':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned int);
else if (cflags == DP_C_LONG)
value = (long)va_arg (args, unsigned long int);
else if (cflags == DP_C_LLONG)
value = (LLONG)va_arg (args, unsigned LLONG);
else if (cflags == DP_C_SIZE)
value = va_arg (args, size_t);
#ifdef notyet
else if (cflags == DP_C_INTMAX)
value = va_arg (args, uintmax_t);
#endif
else
value = (long)va_arg (args, unsigned int);
if (fmtint(buffer, &currlen, maxlen, value,
10, min, max, flags) == -1)
return -1;
break;
case 'X':
flags |= DP_F_UP;
case 'x':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned int);
else if (cflags == DP_C_LONG)
value = (long)va_arg (args, unsigned long int);
else if (cflags == DP_C_LLONG)
value = (LLONG)va_arg (args, unsigned LLONG);
else if (cflags == DP_C_SIZE)
value = va_arg (args, size_t);
#ifdef notyet
else if (cflags == DP_C_INTMAX)
value = va_arg (args, uintmax_t);
#endif
else
value = (long)va_arg (args, unsigned int);
if (fmtint(buffer, &currlen, maxlen, value,
16, min, max, flags) == -1)
return -1;
break;
case 'f':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
if (fmtfp(buffer, &currlen, maxlen, fvalue,
min, max, flags) == -1)
return -1;
break;
case 'E':
flags |= DP_F_UP;
case 'e':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
if (fmtfp(buffer, &currlen, maxlen, fvalue,
min, max, flags) == -1)
return -1;
break;
case 'G':
flags |= DP_F_UP;
case 'g':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
if (fmtfp(buffer, &currlen, maxlen, fvalue,
min, max, flags) == -1)
return -1;
break;
case 'c':
DOPR_OUTCH(buffer, currlen, maxlen,
va_arg (args, int));
break;
case 's':
strvalue = va_arg (args, char *);
if (!strvalue) strvalue = "(NULL)";
if (max == -1) {
max = strlen(strvalue);
}
if (min > 0 && max >= 0 && min > max) max = min;
if (fmtstr(buffer, &currlen, maxlen,
strvalue, flags, min, max) == -1)
return -1;
break;
case 'p':
strvalue = va_arg (args, void *);
if (fmtint(buffer, &currlen, maxlen,
(long) strvalue, 16, min, max, flags) == -1)
return -1;
break;
#if we_dont_want_this_in_openssh
case 'n':
if (cflags == DP_C_SHORT) {
short int *num;
num = va_arg (args, short int *);
*num = currlen;
} else if (cflags == DP_C_LONG) {
long int *num;
num = va_arg (args, long int *);
*num = (long int)currlen;
} else if (cflags == DP_C_LLONG) {
LLONG *num;
num = va_arg (args, LLONG *);
*num = (LLONG)currlen;
} else if (cflags == DP_C_SIZE) {
ssize_t *num;
num = va_arg (args, ssize_t *);
*num = (ssize_t)currlen;
} else if (cflags == DP_C_INTMAX) {
intmax_t *num;
num = va_arg (args, intmax_t *);
*num = (intmax_t)currlen;
} else {
int *num;
num = va_arg (args, int *);
*num = currlen;
}
break;
#endif
case '%':
DOPR_OUTCH(buffer, currlen, maxlen, ch);
break;
case 'w':
/* not supported yet, treat as next char */
ch = *format++;
break;
default:
/* Unknown, skip */
break;
}
ch = *format++;
state = DP_S_DEFAULT;
flags = cflags = min = 0;
max = -1;
break;
case DP_S_DONE:
break;
default:
/* hmm? */
break; /* some picky compilers need this */
}
}
if (maxlen != 0) {
if (currlen < maxlen - 1)
buffer[currlen] = '\0';
else if (maxlen > 0)
buffer[maxlen - 1] = '\0';
}
return currlen < INT_MAX ? (int)currlen : -1;
}
static int
fmtstr(char *buffer, size_t *currlen, size_t maxlen,
char *value, int flags, int min, int max)
{
int padlen, strln; /* amount to pad */
int cnt = 0;
#ifdef DEBUG_SNPRINTF
printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
#endif
if (value == 0) {
value = "<NULL>";
}
for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */
padlen = min - strln;
if (padlen < 0)
padlen = 0;
if (flags & DP_F_MINUS)
padlen = -padlen; /* Left Justify */
while ((padlen > 0) && (cnt < max)) {
DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
--padlen;
++cnt;
}
while (*value && (cnt < max)) {
DOPR_OUTCH(buffer, *currlen, maxlen, *value);
value++;
++cnt;
}
while ((padlen < 0) && (cnt < max)) {
DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
++padlen;
++cnt;
}
return 0;
}
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
static int
fmtint(char *buffer, size_t *currlen, size_t maxlen,
intmax_t value, int base, int min, int max, int flags)
{
int signvalue = 0;
unsigned LLONG uvalue;
char convert[20];
int place = 0;
int spadlen = 0; /* amount to space pad */
int zpadlen = 0; /* amount to zero pad */
int caps = 0;
if (max < 0)
max = 0;
uvalue = value;
if(!(flags & DP_F_UNSIGNED)) {
if( value < 0 ) {
signvalue = '-';
uvalue = -value;
} else {
if (flags & DP_F_PLUS) /* Do a sign (+/i) */
signvalue = '+';
else if (flags & DP_F_SPACE)
signvalue = ' ';
}
}
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
do {
convert[place++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")
[uvalue % (unsigned)base ];
uvalue = (uvalue / (unsigned)base );
} while(uvalue && (place < 20));
if (place == 20) place--;
convert[place] = 0;
zpadlen = max - place;
spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
if (zpadlen < 0) zpadlen = 0;
if (spadlen < 0) spadlen = 0;
if (flags & DP_F_ZERO) {
zpadlen = MAX(zpadlen, spadlen);
spadlen = 0;
}
if (flags & DP_F_MINUS)
spadlen = -spadlen; /* Left Justifty */
#ifdef DEBUG_SNPRINTF
printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
- zpadlen, spadlen, min, max, place);
+ zpadlen, spadlen, min, max, place);
#endif
/* Spaces */
while (spadlen > 0) {
DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
--spadlen;
}
/* Sign */
if (signvalue)
DOPR_OUTCH(buffer, *currlen, maxlen, signvalue);
/* Zeros */
if (zpadlen > 0) {
while (zpadlen > 0) {
DOPR_OUTCH(buffer, *currlen, maxlen, '0');
--zpadlen;
}
}
/* Digits */
while (place > 0) {
--place;
DOPR_OUTCH(buffer, *currlen, maxlen, convert[place]);
}
/* Left Justified spaces */
while (spadlen < 0) {
DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
++spadlen;
}
return 0;
}
static LDOUBLE abs_val(LDOUBLE value)
{
LDOUBLE result = value;
if (value < 0)
result = -value;
return result;
}
static LDOUBLE POW10(int val)
{
LDOUBLE result = 1;
while (val) {
result *= 10;
val--;
}
return result;
}
static LLONG ROUND(LDOUBLE value)
{
LLONG intpart;
intpart = (LLONG)value;
value = value - intpart;
if (value >= 0.5) intpart++;
return intpart;
}
/* a replacement for modf that doesn't need the math library. Should
be portable, but slow */
static double my_modf(double x0, double *iptr)
{
int i;
long l;
double x = x0;
double f = 1.0;
for (i=0;i<100;i++) {
l = (long)x;
if (l <= (x+1) && l >= (x-1)) break;
x *= 0.1;
f *= 10.0;
}
if (i == 100) {
/*
* yikes! the number is beyond what we can handle.
* What do we do?
*/
(*iptr) = 0;
return 0;
}
if (i != 0) {
double i2;
double ret;
ret = my_modf(x0-l*f, &i2);
(*iptr) = l*f + i2;
return ret;
}
(*iptr) = l;
return x - (*iptr);
}
static int
fmtfp (char *buffer, size_t *currlen, size_t maxlen,
LDOUBLE fvalue, int min, int max, int flags)
{
int signvalue = 0;
double ufvalue;
char iconvert[311];
char fconvert[311];
int iplace = 0;
int fplace = 0;
int padlen = 0; /* amount to pad */
int zpadlen = 0;
int caps = 0;
int idx;
double intpart;
double fracpart;
double temp;
/*
* AIX manpage says the default is 0, but Solaris says the default
* is 6, and sprintf on AIX defaults to 6
*/
if (max < 0)
max = 6;
ufvalue = abs_val (fvalue);
if (fvalue < 0) {
signvalue = '-';
} else {
if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
signvalue = '+';
} else {
if (flags & DP_F_SPACE)
signvalue = ' ';
}
}
#if 0
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
#endif
#if 0
if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
#endif
/*
* Sorry, we only support 16 digits past the decimal because of our
* conversion method
*/
if (max > 16)
max = 16;
/* We "cheat" by converting the fractional part to integer by
* multiplying by a factor of 10
*/
temp = ufvalue;
my_modf(temp, &intpart);
fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
if (fracpart >= POW10(max)) {
intpart++;
fracpart -= POW10(max);
}
/* Convert integer part */
do {
temp = intpart*0.1;
my_modf(temp, &intpart);
idx = (int) ((temp -intpart +0.05)* 10.0);
/* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
/* printf ("%llf, %f, %x\n", temp, intpart, idx); */
iconvert[iplace++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
} while (intpart && (iplace < 311));
if (iplace == 311) iplace--;
iconvert[iplace] = 0;
/* Convert fractional part */
if (fracpart)
{
do {
temp = fracpart*0.1;
my_modf(temp, &fracpart);
idx = (int) ((temp -fracpart +0.05)* 10.0);
/* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
/* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
fconvert[fplace++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
} while(fracpart && (fplace < 311));
if (fplace == 311) fplace--;
}
fconvert[fplace] = 0;
/* -1 for decimal point, another -1 if we are printing a sign */
padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
zpadlen = max - fplace;
if (zpadlen < 0) zpadlen = 0;
if (padlen < 0)
padlen = 0;
if (flags & DP_F_MINUS)
padlen = -padlen; /* Left Justifty */
if ((flags & DP_F_ZERO) && (padlen > 0)) {
if (signvalue) {
DOPR_OUTCH(buffer, *currlen, maxlen, signvalue);
--padlen;
signvalue = 0;
}
while (padlen > 0) {
DOPR_OUTCH(buffer, *currlen, maxlen, '0');
--padlen;
}
}
while (padlen > 0) {
DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
--padlen;
}
if (signvalue)
DOPR_OUTCH(buffer, *currlen, maxlen, signvalue);
while (iplace > 0) {
--iplace;
DOPR_OUTCH(buffer, *currlen, maxlen, iconvert[iplace]);
}
#ifdef DEBUG_SNPRINTF
printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
#endif
/*
* Decimal point. This should probably use locale to find the correct
* char to print out.
*/
if (max > 0) {
DOPR_OUTCH(buffer, *currlen, maxlen, '.');
while (zpadlen > 0) {
DOPR_OUTCH(buffer, *currlen, maxlen, '0');
--zpadlen;
}
while (fplace > 0) {
--fplace;
DOPR_OUTCH(buffer, *currlen, maxlen, fconvert[fplace]);
}
}
while (padlen < 0) {
DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
++padlen;
}
return 0;
}
#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
#if !defined(HAVE_VSNPRINTF)
int
vsnprintf (char *str, size_t count, const char *fmt, va_list args)
{
return dopr(str, count, fmt, args);
}
#endif
#if !defined(HAVE_SNPRINTF)
int
snprintf(char *str, size_t count, SNPRINTF_CONST char *fmt, ...)
{
size_t ret;
va_list ap;
va_start(ap, fmt);
ret = vsnprintf(str, count, fmt, ap);
va_end(ap);
return ret;
}
#endif
diff --git a/openbsd-compat/bsd-waitpid.h b/openbsd-compat/bsd-waitpid.h
index b551268ab063..bd61b6909240 100644
--- a/openbsd-compat/bsd-waitpid.h
+++ b/openbsd-compat/bsd-waitpid.h
@@ -1,49 +1,49 @@
/*
* Copyright (c) 2000 Ben Lindstrom. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _BSD_WAITPID_H
#define _BSD_WAITPID_H
#ifndef HAVE_WAITPID
/* Clean out any potential issues */
#undef WIFEXITED
#undef WIFSTOPPED
#undef WIFSIGNALED
/* Define required functions to mimic a POSIX look and feel */
#define _W_INT(w) (*(int*)&(w)) /* convert union wait to int */
#define WIFEXITED(w) (!((_W_INT(w)) & 0377))
#define WIFSTOPPED(w) ((_W_INT(w)) & 0100)
#define WIFSIGNALED(w) (!WIFEXITED(w) && !WIFSTOPPED(w))
#define WEXITSTATUS(w) (int)(WIFEXITED(w) ? ((_W_INT(w) >> 8) & 0377) : -1)
#define WTERMSIG(w) (int)(WIFSIGNALED(w) ? (_W_INT(w) & 0177) : -1)
#define WCOREFLAG 0x80
-#define WCOREDUMP(w) ((_W_INT(w)) & WCOREFLAG)
+#define WCOREDUMP(w) ((_W_INT(w)) & WCOREFLAG)
/* Prototype */
pid_t waitpid(int, int *, int);
#endif /* !HAVE_WAITPID */
#endif /* _BSD_WAITPID_H */
diff --git a/openbsd-compat/getopt_long.c b/openbsd-compat/getopt_long.c
index e28947430578..1a5001f7d98a 100644
--- a/openbsd-compat/getopt_long.c
+++ b/openbsd-compat/getopt_long.c
@@ -1,532 +1,532 @@
/* $OpenBSD: getopt_long.c,v 1.25 2011/03/05 22:10:11 guenther Exp $ */
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
/*
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt_long.c */
#include "includes.h"
#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET)
/*
* Some defines to make it easier to keep the code in sync with upstream.
* getopt opterr optind optopt optreset optarg are all in defines.h which is
* pulled in by includes.h.
*/
#define warnx logit
#if 0
#include <err.h>
#include <getopt.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "log.h"
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define PRINT_ERROR ((opterr) && (*options != ':'))
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
/* return values */
#define BADCH (int)'?'
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
-#define INORDER (int)1
+#define INORDER (int)1
#define EMSG ""
static int getopt_internal(int, char * const *, const char *,
const struct option *, int *, int);
static int parse_long_options(char * const *, const char *,
const struct option *, int *, int);
static int gcd(int, int);
static void permute_args(int, int, int, char * const *);
static char *place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static const char recargchar[] = "option requires an argument -- %c";
static const char recargstring[] = "option requires an argument -- %s";
static const char ambig[] = "ambiguous option -- %.*s";
static const char noarg[] = "option doesn't take an argument -- %.*s";
static const char illoptchar[] = "unknown option -- %c";
static const char illoptstring[] = "unknown option -- %s";
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(int a, int b)
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return (b);
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(int panonopt_start, int panonopt_end, int opt_end,
char * const *nargv)
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
((char **) nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
}
/*
* parse_long_options --
* Parse long options in argc/argv argument vector.
* Returns -1 if short_too is set and the option does not match long_options.
*/
static int
parse_long_options(char * const *nargv, const char *options,
const struct option *long_options, int *idx, int short_too)
{
char *current_argv, *has_equal;
size_t current_argv_len;
int i, match;
current_argv = place;
match = -1;
optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) == current_argv_len) {
/* exact match */
match = i;
break;
}
/*
* If this is a known short option, don't allow
* a partial match of a single character.
*/
if (short_too && current_argv_len == 1)
continue;
if (match == -1) /* partial match */
match = i;
else {
/* ambiguous abbreviation */
if (PRINT_ERROR)
warnx(ambig, (int)current_argv_len,
current_argv);
optopt = 0;
return (BADCH);
}
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
warnx(noarg, (int)current_argv_len,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return (BADARG);
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':' indicates no error
* should be generated.
*/
if (PRINT_ERROR)
warnx(recargstring,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return (BADARG);
}
} else { /* unknown option */
if (short_too) {
--optind;
return (-1);
}
if (PRINT_ERROR)
warnx(illoptstring, current_argv);
optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
return (0);
} else
return (long_options[match].val);
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
*/
static int
getopt_internal(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx, int flags)
{
char *oli; /* option letter list index */
int optchar, short_too;
static int posixly_correct = -1;
if (options == NULL)
return (-1);
/*
* XXX Some GNU programs (like cvs) set optind to 0 instead of
* XXX using optreset. Work around this braindamage.
*/
if (optind == 0)
optind = optreset = 1;
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a '+'.
*/
if (posixly_correct == -1 || optreset)
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
if (*options == '+' || *options == '-')
options++;
optarg = NULL;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[optind]) != '-' ||
(place[1] == '\0' && strchr(options, '-') == NULL)) {
place = EMSG; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
/*
* If no permutation wanted, stop parsing
* at first non-option.
*/
return (-1);
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
/*
* If we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
optind++;
place = EMSG;
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
/*
* Check long options if:
* 1) we were passed some
* 2) the arg is not just "-"
* 3) either the arg starts with -- we are getopt_long_only()
*/
if (long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
if (*place == '-')
place++; /* --foo long option */
else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
optchar = parse_long_options(nargv, options, long_options,
idx, short_too);
if (optchar != -1) {
place = EMSG;
return (optchar);
}
}
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = strchr(options, optchar)) == NULL) {
/*
* If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':').
*/
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++optind;
if (PRINT_ERROR)
warnx(illoptchar, optchar);
optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place) /* no space */
/* NOTHING */;
else if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else /* white space */
place = nargv[optind];
optchar = parse_long_options(nargv, options, long_options,
idx, 0);
place = EMSG;
return (optchar);
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return (optchar);
}
/*
* getopt --
* Parse argc/argv argument vector.
*
* [eventually this will replace the BSD getopt]
*/
int
getopt(int nargc, char * const *nargv, const char *options)
{
/*
* We don't pass FLAG_PERMUTE to getopt_internal() since
* the BSD getopt(3) (unlike GNU) has never done this.
*
* Furthermore, since many privileged programs call getopt()
* before dropping privileges it makes sense to keep things
* as simple (and bug-free) as possible.
*/
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
}
#if 0
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE));
}
/*
* getopt_long_only --
* Parse argc/argv argument vector.
*/
int
getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE|FLAG_LONGONLY));
}
#endif
#endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */
diff --git a/openbsd-compat/libressl-api-compat.c b/openbsd-compat/libressl-api-compat.c
index ae00ff593b7e..801a2e8dd3d9 100644
--- a/openbsd-compat/libressl-api-compat.c
+++ b/openbsd-compat/libressl-api-compat.c
@@ -1,640 +1,640 @@
/* $OpenBSD: dsa_lib.c,v 1.29 2018/04/14 07:09:21 tb Exp $ */
/* $OpenBSD: rsa_lib.c,v 1.37 2018/04/14 07:09:21 tb Exp $ */
/* $OpenBSD: evp_lib.c,v 1.17 2018/09/12 06:35:38 djm Exp $ */
/* $OpenBSD: dh_lib.c,v 1.32 2018/05/02 15:48:38 tb Exp $ */
/* $OpenBSD: p_lib.c,v 1.24 2018/05/30 15:40:50 tb Exp $ */
/* $OpenBSD: digest.c,v 1.30 2018/04/14 07:09:21 tb Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
/* $OpenBSD: dsa_asn1.c,v 1.22 2018/06/14 17:03:19 jsing Exp $ */
/* $OpenBSD: ecs_asn1.c,v 1.9 2018/03/17 15:24:44 tb Exp $ */
/* $OpenBSD: digest.c,v 1.30 2018/04/14 07:09:21 tb Exp $ */
/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project 2000.
*/
/* ====================================================================
* Copyright (c) 2000-2005 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
/* $OpenBSD: rsa_meth.c,v 1.2 2018/09/12 06:35:38 djm Exp $ */
/*
* Copyright (c) 2018 Theo Buehler <tb@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#ifdef WITH_OPENSSL
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/err.h>
#include <openssl/bn.h>
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#ifdef OPENSSL_HAS_ECC
#include <openssl/ecdsa.h>
#endif
#include <openssl/dh.h>
#ifndef HAVE_DSA_GET0_PQG
void
DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
{
if (p != NULL)
*p = d->p;
if (q != NULL)
*q = d->q;
if (g != NULL)
*g = d->g;
}
#endif /* HAVE_DSA_GET0_PQG */
#ifndef HAVE_DSA_SET0_PQG
int
DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{
if ((d->p == NULL && p == NULL) || (d->q == NULL && q == NULL) ||
(d->g == NULL && g == NULL))
return 0;
if (p != NULL) {
BN_free(d->p);
d->p = p;
}
if (q != NULL) {
BN_free(d->q);
d->q = q;
}
if (g != NULL) {
BN_free(d->g);
d->g = g;
}
return 1;
}
#endif /* HAVE_DSA_SET0_PQG */
#ifndef HAVE_DSA_GET0_KEY
void
DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key)
{
if (pub_key != NULL)
*pub_key = d->pub_key;
if (priv_key != NULL)
*priv_key = d->priv_key;
}
#endif /* HAVE_DSA_GET0_KEY */
#ifndef HAVE_DSA_SET0_KEY
int
DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
{
if (d->pub_key == NULL && pub_key == NULL)
return 0;
if (pub_key != NULL) {
BN_free(d->pub_key);
d->pub_key = pub_key;
}
if (priv_key != NULL) {
BN_free(d->priv_key);
d->priv_key = priv_key;
}
return 1;
}
#endif /* HAVE_DSA_SET0_KEY */
#ifndef HAVE_RSA_GET0_KEY
void
RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
{
if (n != NULL)
*n = r->n;
if (e != NULL)
*e = r->e;
if (d != NULL)
*d = r->d;
}
#endif /* HAVE_RSA_GET0_KEY */
#ifndef HAVE_RSA_SET0_KEY
int
RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
{
if ((r->n == NULL && n == NULL) || (r->e == NULL && e == NULL))
return 0;
if (n != NULL) {
BN_free(r->n);
r->n = n;
}
if (e != NULL) {
BN_free(r->e);
r->e = e;
}
if (d != NULL) {
BN_free(r->d);
r->d = d;
}
return 1;
}
#endif /* HAVE_RSA_SET0_KEY */
#ifndef HAVE_RSA_GET0_CRT_PARAMS
void
RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1,
const BIGNUM **iqmp)
{
if (dmp1 != NULL)
*dmp1 = r->dmp1;
if (dmq1 != NULL)
*dmq1 = r->dmq1;
if (iqmp != NULL)
*iqmp = r->iqmp;
}
#endif /* HAVE_RSA_GET0_CRT_PARAMS */
#ifndef HAVE_RSA_SET0_CRT_PARAMS
int
RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
{
if ((r->dmp1 == NULL && dmp1 == NULL) ||
(r->dmq1 == NULL && dmq1 == NULL) ||
(r->iqmp == NULL && iqmp == NULL))
- return 0;
+ return 0;
if (dmp1 != NULL) {
BN_free(r->dmp1);
r->dmp1 = dmp1;
}
if (dmq1 != NULL) {
BN_free(r->dmq1);
r->dmq1 = dmq1;
}
if (iqmp != NULL) {
BN_free(r->iqmp);
r->iqmp = iqmp;
}
return 1;
}
#endif /* HAVE_RSA_SET0_CRT_PARAMS */
#ifndef HAVE_RSA_GET0_FACTORS
void
RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
{
if (p != NULL)
*p = r->p;
if (q != NULL)
*q = r->q;
}
#endif /* HAVE_RSA_GET0_FACTORS */
#ifndef HAVE_RSA_SET0_FACTORS
int
RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
{
if ((r->p == NULL && p == NULL) || (r->q == NULL && q == NULL))
return 0;
if (p != NULL) {
BN_free(r->p);
r->p = p;
}
if (q != NULL) {
BN_free(r->q);
r->q = q;
}
return 1;
}
#endif /* HAVE_RSA_SET0_FACTORS */
#ifndef HAVE_EVP_CIPHER_CTX_GET_IV
int
EVP_CIPHER_CTX_get_iv(const EVP_CIPHER_CTX *ctx, unsigned char *iv, size_t len)
{
if (ctx == NULL)
return 0;
if (EVP_CIPHER_CTX_iv_length(ctx) < 0)
return 0;
if (len != (size_t)EVP_CIPHER_CTX_iv_length(ctx))
return 0;
if (len > EVP_MAX_IV_LENGTH)
return 0; /* sanity check; shouldn't happen */
/*
* Skip the memcpy entirely when the requested IV length is zero,
* since the iv pointer may be NULL or invalid.
*/
if (len != 0) {
if (iv == NULL)
return 0;
# ifdef HAVE_EVP_CIPHER_CTX_IV
memcpy(iv, EVP_CIPHER_CTX_iv(ctx), len);
# else
memcpy(iv, ctx->iv, len);
# endif /* HAVE_EVP_CIPHER_CTX_IV */
}
return 1;
}
#endif /* HAVE_EVP_CIPHER_CTX_GET_IV */
#ifndef HAVE_EVP_CIPHER_CTX_SET_IV
int
EVP_CIPHER_CTX_set_iv(EVP_CIPHER_CTX *ctx, const unsigned char *iv, size_t len)
{
if (ctx == NULL)
return 0;
if (EVP_CIPHER_CTX_iv_length(ctx) < 0)
return 0;
if (len != (size_t)EVP_CIPHER_CTX_iv_length(ctx))
return 0;
if (len > EVP_MAX_IV_LENGTH)
return 0; /* sanity check; shouldn't happen */
/*
* Skip the memcpy entirely when the requested IV length is zero,
* since the iv pointer may be NULL or invalid.
*/
if (len != 0) {
if (iv == NULL)
return 0;
# ifdef HAVE_EVP_CIPHER_CTX_IV_NOCONST
memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), iv, len);
# else
memcpy(ctx->iv, iv, len);
# endif /* HAVE_EVP_CIPHER_CTX_IV_NOCONST */
}
return 1;
}
#endif /* HAVE_EVP_CIPHER_CTX_SET_IV */
#ifndef HAVE_DSA_SIG_GET0
void
DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{
if (pr != NULL)
*pr = sig->r;
if (ps != NULL)
*ps = sig->s;
}
#endif /* HAVE_DSA_SIG_GET0 */
#ifndef HAVE_DSA_SIG_SET0
int
DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
{
if (r == NULL || s == NULL)
return 0;
BN_clear_free(sig->r);
sig->r = r;
BN_clear_free(sig->s);
sig->s = s;
return 1;
}
#endif /* HAVE_DSA_SIG_SET0 */
#ifdef OPENSSL_HAS_ECC
#ifndef HAVE_ECDSA_SIG_GET0
void
ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{
if (pr != NULL)
*pr = sig->r;
if (ps != NULL)
*ps = sig->s;
}
#endif /* HAVE_ECDSA_SIG_GET0 */
#ifndef HAVE_ECDSA_SIG_SET0
int
ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
{
if (r == NULL || s == NULL)
return 0;
BN_clear_free(sig->r);
BN_clear_free(sig->s);
sig->r = r;
sig->s = s;
return 1;
}
#endif /* HAVE_ECDSA_SIG_SET0 */
#endif /* OPENSSL_HAS_ECC */
#ifndef HAVE_DH_GET0_PQG
void
DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
{
if (p != NULL)
*p = dh->p;
if (q != NULL)
*q = dh->q;
if (g != NULL)
*g = dh->g;
}
#endif /* HAVE_DH_GET0_PQG */
#ifndef HAVE_DH_SET0_PQG
int
DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{
if ((dh->p == NULL && p == NULL) || (dh->g == NULL && g == NULL))
return 0;
if (p != NULL) {
BN_free(dh->p);
dh->p = p;
}
if (q != NULL) {
BN_free(dh->q);
dh->q = q;
}
if (g != NULL) {
BN_free(dh->g);
dh->g = g;
}
return 1;
}
#endif /* HAVE_DH_SET0_PQG */
#ifndef HAVE_DH_GET0_KEY
void
DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
{
if (pub_key != NULL)
*pub_key = dh->pub_key;
if (priv_key != NULL)
*priv_key = dh->priv_key;
}
#endif /* HAVE_DH_GET0_KEY */
#ifndef HAVE_DH_SET0_KEY
int
DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
{
if (pub_key != NULL) {
BN_free(dh->pub_key);
dh->pub_key = pub_key;
}
if (priv_key != NULL) {
BN_free(dh->priv_key);
dh->priv_key = priv_key;
}
return 1;
}
#endif /* HAVE_DH_SET0_KEY */
#ifndef HAVE_DH_SET_LENGTH
int
DH_set_length(DH *dh, long length)
{
if (length < 0 || length > INT_MAX)
return 0;
dh->length = length;
return 1;
}
#endif /* HAVE_DH_SET_LENGTH */
#ifndef HAVE_RSA_METH_FREE
void
RSA_meth_free(RSA_METHOD *meth)
{
if (meth != NULL) {
free((char *)meth->name);
free(meth);
}
}
#endif /* HAVE_RSA_METH_FREE */
#ifndef HAVE_RSA_METH_DUP
RSA_METHOD *
RSA_meth_dup(const RSA_METHOD *meth)
{
RSA_METHOD *copy;
if ((copy = calloc(1, sizeof(*copy))) == NULL)
return NULL;
memcpy(copy, meth, sizeof(*copy));
if ((copy->name = strdup(meth->name)) == NULL) {
free(copy);
return NULL;
}
return copy;
}
#endif /* HAVE_RSA_METH_DUP */
#ifndef HAVE_RSA_METH_SET1_NAME
int
RSA_meth_set1_name(RSA_METHOD *meth, const char *name)
{
char *copy;
if ((copy = strdup(name)) == NULL)
return 0;
free((char *)meth->name);
meth->name = copy;
return 1;
}
#endif /* HAVE_RSA_METH_SET1_NAME */
#ifndef HAVE_RSA_METH_GET_FINISH
int
(*RSA_meth_get_finish(const RSA_METHOD *meth))(RSA *rsa)
{
return meth->finish;
}
#endif /* HAVE_RSA_METH_GET_FINISH */
#ifndef HAVE_RSA_METH_SET_PRIV_ENC
int
RSA_meth_set_priv_enc(RSA_METHOD *meth, int (*priv_enc)(int flen,
const unsigned char *from, unsigned char *to, RSA *rsa, int padding))
{
meth->rsa_priv_enc = priv_enc;
return 1;
}
#endif /* HAVE_RSA_METH_SET_PRIV_ENC */
#ifndef HAVE_RSA_METH_SET_PRIV_DEC
int
RSA_meth_set_priv_dec(RSA_METHOD *meth, int (*priv_dec)(int flen,
const unsigned char *from, unsigned char *to, RSA *rsa, int padding))
{
meth->rsa_priv_dec = priv_dec;
return 1;
}
#endif /* HAVE_RSA_METH_SET_PRIV_DEC */
#ifndef HAVE_RSA_METH_SET_FINISH
int
RSA_meth_set_finish(RSA_METHOD *meth, int (*finish)(RSA *rsa))
{
meth->finish = finish;
return 1;
}
#endif /* HAVE_RSA_METH_SET_FINISH */
#ifndef HAVE_EVP_PKEY_GET0_RSA
RSA *
EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
{
if (pkey->type != EVP_PKEY_RSA) {
/* EVPerror(EVP_R_EXPECTING_AN_RSA_KEY); */
return NULL;
}
return pkey->pkey.rsa;
}
#endif /* HAVE_EVP_PKEY_GET0_RSA */
#ifndef HAVE_EVP_MD_CTX_NEW
EVP_MD_CTX *
EVP_MD_CTX_new(void)
{
return calloc(1, sizeof(EVP_MD_CTX));
}
#endif /* HAVE_EVP_MD_CTX_NEW */
#ifndef HAVE_EVP_MD_CTX_FREE
void
EVP_MD_CTX_free(EVP_MD_CTX *ctx)
{
if (ctx == NULL)
return;
EVP_MD_CTX_cleanup(ctx);
free(ctx);
}
#endif /* HAVE_EVP_MD_CTX_FREE */
#endif /* WITH_OPENSSL */
diff --git a/openbsd-compat/memmem.c b/openbsd-compat/memmem.c
index ac1243eb0d17..ad330d1a8879 100644
--- a/openbsd-compat/memmem.c
+++ b/openbsd-compat/memmem.c
@@ -1,191 +1,194 @@
/* $OpenBSD: memmem.c,v 1.5 2020/04/16 12:39:28 claudio Exp $ */
/*
* Copyright (c) 2005-2020 Rich Felker, et al.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "includes.h"
#ifndef HAVE_MEMMEM
#include <string.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
static char *
twobyte_memmem(const unsigned char *h, size_t k, const unsigned char *n)
{
uint16_t nw = n[0]<<8 | n[1], hw = h[0]<<8 | h[1];
for (h+=2, k-=2; k; k--, hw = hw<<8 | *h++)
if (hw == nw) return (char *)h-2;
return hw == nw ? (char *)h-2 : 0;
}
static char *
threebyte_memmem(const unsigned char *h, size_t k, const unsigned char *n)
{
uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8;
uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8;
for (h+=3, k-=3; k; k--, hw = (hw|*h++)<<8)
if (hw == nw) return (char *)h-3;
return hw == nw ? (char *)h-3 : 0;
}
static char *
fourbyte_memmem(const unsigned char *h, size_t k, const unsigned char *n)
{
uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3];
uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3];
for (h+=4, k-=4; k; k--, hw = hw<<8 | *h++)
if (hw == nw) return (char *)h-4;
return hw == nw ? (char *)h-4 : 0;
}
+#if 0
+/* In -portable, defines.h ensures that these are already defined. */
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
#define BITOP(a,b,op) \
((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
/*
* Maxime Crochemore and Dominique Perrin, Two-way string-matching,
* Journal of the ACM, 38(3):651-675, July 1991.
*/
static char *
twoway_memmem(const unsigned char *h, const unsigned char *z,
const unsigned char *n, size_t l)
{
size_t i, ip, jp, k, p, ms, p0, mem, mem0;
size_t byteset[32 / sizeof(size_t)] = { 0 };
size_t shift[256];
/* Computing length of needle and fill shift table */
for (i=0; i<l; i++)
BITOP(byteset, n[i], |=), shift[n[i]] = i+1;
/* Compute maximal suffix */
ip = -1; jp = 0; k = p = 1;
while (jp+k<l) {
if (n[ip+k] == n[jp+k]) {
if (k == p) {
jp += p;
k = 1;
} else k++;
} else if (n[ip+k] > n[jp+k]) {
jp += k;
k = 1;
p = jp - ip;
} else {
ip = jp++;
k = p = 1;
}
}
ms = ip;
p0 = p;
/* And with the opposite comparison */
ip = -1; jp = 0; k = p = 1;
while (jp+k<l) {
if (n[ip+k] == n[jp+k]) {
if (k == p) {
jp += p;
k = 1;
} else k++;
} else if (n[ip+k] < n[jp+k]) {
jp += k;
k = 1;
p = jp - ip;
} else {
ip = jp++;
k = p = 1;
}
}
if (ip+1 > ms+1) ms = ip;
else p = p0;
/* Periodic needle? */
if (memcmp(n, n+p, ms+1)) {
mem0 = 0;
p = MAX(ms, l-ms-1) + 1;
} else mem0 = l-p;
mem = 0;
/* Search loop */
for (;;) {
/* If remainder of haystack is shorter than needle, done */
if (z-h < l) return 0;
/* Check last byte first; advance by shift on mismatch */
if (BITOP(byteset, h[l-1], &)) {
k = l-shift[h[l-1]];
if (k) {
if (k < mem) k = mem;
h += k;
mem = 0;
continue;
}
} else {
h += l;
mem = 0;
continue;
}
/* Compare right half */
for (k=MAX(ms+1,mem); k<l && n[k] == h[k]; k++);
if (k < l) {
h += k-ms;
mem = 0;
continue;
}
/* Compare left half */
for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
if (k <= mem) return (char *)h;
h += p;
mem = mem0;
}
}
void *
memmem(const void *h0, size_t k, const void *n0, size_t l)
{
const unsigned char *h = h0, *n = n0;
/* Return immediately on empty needle */
if (!l) return (void *)h;
/* Return immediately when needle is longer than haystack */
if (k<l) return 0;
/* Use faster algorithms for short needles */
h = memchr(h0, *n, k);
if (!h || l==1) return (void *)h;
k -= h - (const unsigned char *)h0;
if (k<l) return 0;
if (l==2) return twobyte_memmem(h, k, n);
if (l==3) return threebyte_memmem(h, k, n);
if (l==4) return fourbyte_memmem(h, k, n);
return twoway_memmem(h, h+k, n, l);
}
DEF_WEAK(memmem);
#endif /* HAVE_MEMMEM */
diff --git a/openbsd-compat/port-net.c b/openbsd-compat/port-net.c
index da6d446787c9..198e73f0de20 100644
--- a/openbsd-compat/port-net.c
+++ b/openbsd-compat/port-net.c
@@ -1,378 +1,378 @@
/*
* Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "openbsd-compat/sys-queue.h"
#include "log.h"
#include "misc.h"
#include "sshbuf.h"
#include "channels.h"
#include "ssherr.h"
/*
* This file contains various portability code for network support,
* including tun/tap forwarding and routing domains.
*/
#if defined(SYS_RDOMAIN_LINUX) || defined(SSH_TUN_LINUX)
#include <linux/if.h>
#endif
#if defined(SYS_RDOMAIN_LINUX)
char *
sys_get_rdomain(int fd)
{
char dev[IFNAMSIZ + 1];
socklen_t len = sizeof(dev) - 1;
if (getsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, dev, &len) == -1) {
error("%s: cannot determine VRF for fd=%d : %s",
__func__, fd, strerror(errno));
return NULL;
}
dev[len] = '\0';
return strdup(dev);
}
int
sys_set_rdomain(int fd, const char *name)
{
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
name, strlen(name)) == -1) {
error("%s: setsockopt(%d, SO_BINDTODEVICE, %s): %s",
- __func__, fd, name, strerror(errno));
+ __func__, fd, name, strerror(errno));
return -1;
}
return 0;
}
int
sys_valid_rdomain(const char *name)
{
int fd;
/*
* This is a pretty crappy way to test. It would be better to
* check whether "name" represents a VRF device, but apparently
* that requires an rtnetlink transaction.
*/
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return 0;
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
name, strlen(name)) == -1) {
close(fd);
return 0;
}
close(fd);
return 1;
}
#elif defined(SYS_RDOMAIN_XXX)
/* XXX examples */
char *
sys_get_rdomain(int fd)
{
return NULL;
}
int
sys_set_rdomain(int fd, const char *name)
{
return -1;
}
int
valid_rdomain(const char *name)
{
return 0;
}
void
sys_set_process_rdomain(const char *name)
{
fatal("%s: not supported", __func__);
}
#endif /* defined(SYS_RDOMAIN_XXX) */
/*
* This is the portable version of the SSH tunnel forwarding, it
* uses some preprocessor definitions for various platform-specific
* settings.
*
* SSH_TUN_LINUX Use the (newer) Linux tun/tap device
* SSH_TUN_FREEBSD Use the FreeBSD tun/tap device
* SSH_TUN_COMPAT_AF Translate the OpenBSD address family
* SSH_TUN_PREPEND_AF Prepend/remove the address family
*/
/*
* System-specific tunnel open function
*/
#if defined(SSH_TUN_LINUX)
#include <linux/if_tun.h>
#define TUN_CTRL_DEV "/dev/net/tun"
int
sys_tun_open(int tun, int mode, char **ifname)
{
struct ifreq ifr;
int fd = -1;
const char *name = NULL;
if (ifname != NULL)
*ifname = NULL;
if ((fd = open(TUN_CTRL_DEV, O_RDWR)) == -1) {
debug("%s: failed to open tunnel control device \"%s\": %s",
__func__, TUN_CTRL_DEV, strerror(errno));
return (-1);
}
bzero(&ifr, sizeof(ifr));
if (mode == SSH_TUNMODE_ETHERNET) {
ifr.ifr_flags = IFF_TAP;
name = "tap%d";
} else {
ifr.ifr_flags = IFF_TUN;
name = "tun%d";
}
ifr.ifr_flags |= IFF_NO_PI;
if (tun != SSH_TUNID_ANY) {
if (tun > SSH_TUNID_MAX) {
debug("%s: invalid tunnel id %x: %s", __func__,
tun, strerror(errno));
goto failed;
}
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), name, tun);
}
if (ioctl(fd, TUNSETIFF, &ifr) == -1) {
debug("%s: failed to configure tunnel (mode %d): %s", __func__,
mode, strerror(errno));
goto failed;
}
if (tun == SSH_TUNID_ANY)
debug("%s: tunnel mode %d fd %d", __func__, mode, fd);
else
debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd);
if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)) == NULL)
goto failed;
return (fd);
failed:
close(fd);
return (-1);
}
#endif /* SSH_TUN_LINUX */
#ifdef SSH_TUN_FREEBSD
#include <sys/socket.h>
#include <net/if.h>
#ifdef HAVE_NET_IF_TUN_H
#include <net/if_tun.h>
#endif
int
sys_tun_open(int tun, int mode, char **ifname)
{
struct ifreq ifr;
char name[100];
int fd = -1, sock;
const char *tunbase = "tun";
#if defined(TUNSIFHEAD) && !defined(SSH_TUN_PREPEND_AF)
int flag;
#endif
if (ifname != NULL)
*ifname = NULL;
if (mode == SSH_TUNMODE_ETHERNET) {
#ifdef SSH_TUN_NO_L2
debug("%s: no layer 2 tunnelling support", __func__);
return (-1);
#else
tunbase = "tap";
#endif
}
/* Open the tunnel device */
if (tun <= SSH_TUNID_MAX) {
snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun);
fd = open(name, O_RDWR);
} else if (tun == SSH_TUNID_ANY) {
for (tun = 100; tun >= 0; tun--) {
snprintf(name, sizeof(name), "/dev/%s%d",
tunbase, tun);
if ((fd = open(name, O_RDWR)) >= 0)
break;
}
} else {
debug("%s: invalid tunnel %u\n", __func__, tun);
return (-1);
}
if (fd < 0) {
debug("%s: %s open failed: %s", __func__, name,
strerror(errno));
return (-1);
}
/* Turn on tunnel headers */
#if defined(TUNSIFHEAD) && !defined(SSH_TUN_PREPEND_AF)
flag = 1;
if (mode != SSH_TUNMODE_ETHERNET &&
ioctl(fd, TUNSIFHEAD, &flag) == -1) {
debug("%s: ioctl(%d, TUNSIFHEAD, 1): %s", __func__, fd,
strerror(errno));
close(fd);
}
#endif
debug("%s: %s mode %d fd %d", __func__, name, mode, fd);
/* Set the tunnel device operation mode */
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun);
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
goto failed;
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
goto failed;
if ((ifr.ifr_flags & IFF_UP) == 0) {
ifr.ifr_flags |= IFF_UP;
if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
goto failed;
}
if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)) == NULL)
goto failed;
close(sock);
return (fd);
failed:
if (fd >= 0)
close(fd);
if (sock >= 0)
close(sock);
debug("%s: failed to set %s mode %d: %s", __func__, name,
mode, strerror(errno));
return (-1);
}
#endif /* SSH_TUN_FREEBSD */
/*
* System-specific channel filters
*/
#if defined(SSH_TUN_FILTER)
/*
* The tunnel forwarding protocol prepends the address family of forwarded
* IP packets using OpenBSD's numbers.
*/
#define OPENBSD_AF_INET 2
#define OPENBSD_AF_INET6 24
int
sys_tun_infilter(struct ssh *ssh, struct Channel *c, char *buf, int _len)
{
int r;
size_t len;
char *ptr = buf;
#if defined(SSH_TUN_PREPEND_AF)
char rbuf[CHAN_RBUF];
struct ip iph;
#endif
#if defined(SSH_TUN_PREPEND_AF) || defined(SSH_TUN_COMPAT_AF)
u_int32_t af;
#endif
/* XXX update channel input filter API to use unsigned length */
if (_len < 0)
return -1;
len = _len;
#if defined(SSH_TUN_PREPEND_AF)
if (len <= sizeof(iph) || len > sizeof(rbuf) - 4)
return -1;
/* Determine address family from packet IP header. */
memcpy(&iph, buf, sizeof(iph));
af = iph.ip_v == 6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET;
/* Prepend address family to packet using OpenBSD constants */
memcpy(rbuf + 4, buf, len);
len += 4;
POKE_U32(rbuf, af);
ptr = rbuf;
#elif defined(SSH_TUN_COMPAT_AF)
/* Convert existing address family header to OpenBSD value */
if (len <= 4)
return -1;
af = PEEK_U32(buf);
/* Put it back */
POKE_U32(buf, af == AF_INET6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET);
#endif
if ((r = sshbuf_put_string(c->input, ptr, len)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
return (0);
}
u_char *
sys_tun_outfilter(struct ssh *ssh, struct Channel *c,
u_char **data, size_t *dlen)
{
u_char *buf;
u_int32_t af;
int r;
/* XXX new API is incompatible with this signature. */
if ((r = sshbuf_get_string(c->output, data, dlen)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
if (*dlen < sizeof(af))
return (NULL);
buf = *data;
#if defined(SSH_TUN_PREPEND_AF)
/* skip address family */
*dlen -= sizeof(af);
buf = *data + sizeof(af);
#elif defined(SSH_TUN_COMPAT_AF)
/* translate address family */
af = (PEEK_U32(buf) == OPENBSD_AF_INET6) ? AF_INET6 : AF_INET;
POKE_U32(buf, af);
#endif
return (buf);
}
#endif /* SSH_TUN_FILTER */
diff --git a/openbsd-compat/port-solaris.c b/openbsd-compat/port-solaris.c
index 7d5a28cd0b12..b84fbff5e7f5 100644
--- a/openbsd-compat/port-solaris.c
+++ b/openbsd-compat/port-solaris.c
@@ -1,361 +1,361 @@
/*
* Copyright (c) 2006 Chad Mynhier.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "config.h"
#include "includes.h"
-#ifdef USE_SOLARIS_PROCESS_CONTRACTS
-
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <errno.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
+#include "log.h"
+
+#ifdef USE_SOLARIS_PROCESS_CONTRACTS
+
#include <libcontract.h>
#include <sys/contract/process.h>
#include <sys/ctfs.h>
-#include "log.h"
-
#define CT_TEMPLATE CTFS_ROOT "/process/template"
#define CT_LATEST CTFS_ROOT "/process/latest"
static int tmpl_fd = -1;
/* Lookup the latest process contract */
static ctid_t
get_active_process_contract_id(void)
{
int stat_fd;
ctid_t ctid = -1;
ct_stathdl_t stathdl;
if ((stat_fd = open64(CT_LATEST, O_RDONLY)) == -1) {
error("%s: Error opening 'latest' process "
"contract: %s", __func__, strerror(errno));
return -1;
}
if (ct_status_read(stat_fd, CTD_COMMON, &stathdl) != 0) {
error("%s: Error reading process contract "
"status: %s", __func__, strerror(errno));
goto out;
}
if ((ctid = ct_status_get_id(stathdl)) < 0) {
error("%s: Error getting process contract id: %s",
__func__, strerror(errno));
goto out;
}
ct_status_free(stathdl);
out:
close(stat_fd);
return ctid;
}
void
solaris_contract_pre_fork(void)
{
if ((tmpl_fd = open64(CT_TEMPLATE, O_RDWR)) == -1) {
error("%s: open %s: %s", __func__,
CT_TEMPLATE, strerror(errno));
return;
}
debug2("%s: setting up process contract template on fd %d",
__func__, tmpl_fd);
/* First we set the template parameters and event sets. */
if (ct_pr_tmpl_set_param(tmpl_fd, CT_PR_PGRPONLY) != 0) {
error("%s: Error setting process contract parameter set "
"(pgrponly): %s", __func__, strerror(errno));
goto fail;
}
if (ct_pr_tmpl_set_fatal(tmpl_fd, CT_PR_EV_HWERR) != 0) {
error("%s: Error setting process contract template "
"fatal events: %s", __func__, strerror(errno));
goto fail;
}
if (ct_tmpl_set_critical(tmpl_fd, 0) != 0) {
error("%s: Error setting process contract template "
"critical events: %s", __func__, strerror(errno));
goto fail;
}
if (ct_tmpl_set_informative(tmpl_fd, CT_PR_EV_HWERR) != 0) {
error("%s: Error setting process contract template "
"informative events: %s", __func__, strerror(errno));
goto fail;
}
/* Now make this the active template for this process. */
if (ct_tmpl_activate(tmpl_fd) != 0) {
error("%s: Error activating process contract "
"template: %s", __func__, strerror(errno));
goto fail;
}
return;
fail:
if (tmpl_fd != -1) {
close(tmpl_fd);
tmpl_fd = -1;
}
}
void
solaris_contract_post_fork_child()
{
debug2("%s: clearing process contract template on fd %d",
__func__, tmpl_fd);
/* Clear the active template. */
if (ct_tmpl_clear(tmpl_fd) != 0)
error("%s: Error clearing active process contract "
"template: %s", __func__, strerror(errno));
close(tmpl_fd);
tmpl_fd = -1;
}
void
solaris_contract_post_fork_parent(pid_t pid)
{
ctid_t ctid;
char ctl_path[256];
int r, ctl_fd = -1, stat_fd = -1;
debug2("%s: clearing template (fd %d)", __func__, tmpl_fd);
if (tmpl_fd == -1)
return;
/* First clear the active template. */
if ((r = ct_tmpl_clear(tmpl_fd)) != 0)
error("%s: Error clearing active process contract "
"template: %s", __func__, strerror(errno));
close(tmpl_fd);
tmpl_fd = -1;
/*
* If either the fork didn't succeed (pid < 0), or clearing
* th active contract failed (r != 0), then we have nothing
* more do.
*/
if (r != 0 || pid <= 0)
return;
/* Now lookup and abandon the contract we've created. */
ctid = get_active_process_contract_id();
debug2("%s: abandoning contract id %ld", __func__, ctid);
snprintf(ctl_path, sizeof(ctl_path),
CTFS_ROOT "/process/%ld/ctl", ctid);
if ((ctl_fd = open64(ctl_path, O_WRONLY)) < 0) {
error("%s: Error opening process contract "
"ctl file: %s", __func__, strerror(errno));
goto fail;
}
if (ct_ctl_abandon(ctl_fd) < 0) {
error("%s: Error abandoning process contract: %s",
__func__, strerror(errno));
goto fail;
}
close(ctl_fd);
return;
fail:
if (tmpl_fd != -1) {
close(tmpl_fd);
tmpl_fd = -1;
}
if (stat_fd != -1)
close(stat_fd);
if (ctl_fd != -1)
close(ctl_fd);
}
#endif
#ifdef USE_SOLARIS_PROJECTS
#include <sys/task.h>
#include <project.h>
/*
* Get/set solaris default project.
* If we fail, just run along gracefully.
*/
void
solaris_set_default_project(struct passwd *pw)
{
struct project *defaultproject;
struct project tempproject;
char buf[1024];
/* get default project, if we fail just return gracefully */
if ((defaultproject = getdefaultproj(pw->pw_name, &tempproject, &buf,
sizeof(buf))) != NULL) {
/* set default project */
if (setproject(defaultproject->pj_name, pw->pw_name,
TASK_NORMAL) != 0)
debug("setproject(%s): %s", defaultproject->pj_name,
strerror(errno));
} else {
/* debug on getdefaultproj() error */
debug("getdefaultproj(%s): %s", pw->pw_name, strerror(errno));
}
}
#endif /* USE_SOLARIS_PROJECTS */
#ifdef USE_SOLARIS_PRIVS
# ifdef HAVE_PRIV_H
# include <priv.h>
# endif
priv_set_t *
solaris_basic_privset(void)
{
priv_set_t *pset;
#ifdef HAVE_PRIV_BASICSET
if ((pset = priv_allocset()) == NULL) {
error("priv_allocset: %s", strerror(errno));
return NULL;
}
priv_basicset(pset);
#else
if ((pset = priv_str_to_set("basic", ",", NULL)) == NULL) {
error("priv_str_to_set: %s", strerror(errno));
return NULL;
}
#endif
return pset;
}
void
solaris_drop_privs_pinfo_net_fork_exec(void)
{
priv_set_t *pset = NULL, *npset = NULL;
/*
* Note: this variant avoids dropping DAC filesystem rights, in case
* the process calling it is running as root and should have the
* ability to read/write/chown any file on the system.
*
* We start with the basic set, then *add* the DAC rights to it while
* taking away other parts of BASIC we don't need. Then we intersect
* this with our existing PERMITTED set. In this way we keep any
* DAC rights we had before, while otherwise reducing ourselves to
* the minimum set of privileges we need to proceed.
*
* This also means we drop any other parts of "root" that we don't
* need (e.g. the ability to kill any process, create new device nodes
* etc etc).
*/
if ((pset = priv_allocset()) == NULL)
fatal("priv_allocset: %s", strerror(errno));
if ((npset = solaris_basic_privset()) == NULL)
fatal("solaris_basic_privset: %s", strerror(errno));
if (priv_addset(npset, PRIV_FILE_CHOWN) != 0 ||
priv_addset(npset, PRIV_FILE_DAC_READ) != 0 ||
priv_addset(npset, PRIV_FILE_DAC_SEARCH) != 0 ||
priv_addset(npset, PRIV_FILE_DAC_WRITE) != 0 ||
priv_addset(npset, PRIV_FILE_OWNER) != 0)
fatal("priv_addset: %s", strerror(errno));
if (priv_delset(npset, PRIV_PROC_EXEC) != 0 ||
#ifdef PRIV_NET_ACCESS
priv_delset(npset, PRIV_NET_ACCESS) != 0 ||
#endif
priv_delset(npset, PRIV_PROC_FORK) != 0 ||
priv_delset(npset, PRIV_PROC_INFO) != 0 ||
priv_delset(npset, PRIV_PROC_SESSION) != 0)
fatal("priv_delset: %s", strerror(errno));
if (getppriv(PRIV_PERMITTED, pset) != 0)
fatal("getppriv: %s", strerror(errno));
priv_intersect(pset, npset);
if (setppriv(PRIV_SET, PRIV_PERMITTED, npset) != 0 ||
setppriv(PRIV_SET, PRIV_LIMIT, npset) != 0 ||
setppriv(PRIV_SET, PRIV_INHERITABLE, npset) != 0)
fatal("setppriv: %s", strerror(errno));
priv_freeset(pset);
priv_freeset(npset);
}
void
solaris_drop_privs_root_pinfo_net(void)
{
priv_set_t *pset = NULL;
/* Start with "basic" and drop everything we don't need. */
if ((pset = solaris_basic_privset()) == NULL)
fatal("solaris_basic_privset: %s", strerror(errno));
if (priv_delset(pset, PRIV_FILE_LINK_ANY) != 0 ||
#ifdef PRIV_NET_ACCESS
priv_delset(pset, PRIV_NET_ACCESS) != 0 ||
#endif
priv_delset(pset, PRIV_PROC_INFO) != 0 ||
priv_delset(pset, PRIV_PROC_SESSION) != 0)
fatal("priv_delset: %s", strerror(errno));
if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) != 0 ||
setppriv(PRIV_SET, PRIV_LIMIT, pset) != 0 ||
setppriv(PRIV_SET, PRIV_INHERITABLE, pset) != 0)
fatal("setppriv: %s", strerror(errno));
priv_freeset(pset);
}
void
solaris_drop_privs_root_pinfo_net_exec(void)
{
priv_set_t *pset = NULL;
/* Start with "basic" and drop everything we don't need. */
if ((pset = solaris_basic_privset()) == NULL)
fatal("solaris_basic_privset: %s", strerror(errno));
if (priv_delset(pset, PRIV_FILE_LINK_ANY) != 0 ||
#ifdef PRIV_NET_ACCESS
priv_delset(pset, PRIV_NET_ACCESS) != 0 ||
#endif
priv_delset(pset, PRIV_PROC_EXEC) != 0 ||
priv_delset(pset, PRIV_PROC_INFO) != 0)
fatal("priv_delset: %s", strerror(errno));
if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) != 0 ||
setppriv(PRIV_SET, PRIV_LIMIT, pset) != 0 ||
setppriv(PRIV_SET, PRIV_INHERITABLE, pset) != 0)
fatal("setppriv: %s", strerror(errno));
priv_freeset(pset);
}
#endif
diff --git a/openbsd-compat/port-uw.c b/openbsd-compat/port-uw.c
index 132213131e8f..074f80c8d3d5 100644
--- a/openbsd-compat/port-uw.c
+++ b/openbsd-compat/port-uw.c
@@ -1,153 +1,153 @@
/*
* Copyright (c) 2005 The SCO Group. All rights reserved.
* Copyright (c) 2005 Tim Rice. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#if defined(HAVE_LIBIAF) && !defined(HAVE_SECUREWARE)
#include <sys/types.h>
#ifdef HAVE_CRYPT_H
# include <crypt.h>
#endif
#include <pwd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "xmalloc.h"
#include "packet.h"
#include "auth-options.h"
#include "log.h"
#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */
#include "servconf.h"
#include "hostfile.h"
#include "auth.h"
#include "ssh.h"
#include "ssh_api.h"
int nischeck(char *);
int
sys_auth_passwd(struct ssh *ssh, const char *password)
{
Authctxt *authctxt = ssh->authctxt;
struct passwd *pw = authctxt->pw;
char *salt;
int result;
/* Just use the supplied fake password if authctxt is invalid */
char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd;
if (pw_password == NULL)
return 0;
/* Check for users with no password. */
if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0)
return (1);
/* Encrypt the candidate password using the proper salt. */
salt = (pw_password[0] && pw_password[1]) ? pw_password : "xx";
/*
* Authentication is accepted if the encrypted passwords
* are identical.
*/
#ifdef UNIXWARE_LONG_PASSWORDS
if (!nischeck(pw->pw_name)) {
result = ((strcmp(bigcrypt(password, salt), pw_password) == 0)
|| (strcmp(osr5bigcrypt(password, salt), pw_password) == 0));
}
else
#endif /* UNIXWARE_LONG_PASSWORDS */
result = (strcmp(xcrypt(password, salt), pw_password) == 0);
#ifdef USE_LIBIAF
if (authctxt->valid)
free(pw_password);
#endif
return(result);
}
#ifdef UNIXWARE_LONG_PASSWORDS
int
nischeck(char *namep)
{
char password_file[] = "/etc/passwd";
FILE *fd;
struct passwd *ent = NULL;
if ((fd = fopen (password_file, "r")) == NULL) {
/*
* If the passwd file has disappeared we are in a bad state.
* However, returning 0 will send us back through the
* authentication scheme that has checked the ia database for
* passwords earlier.
*/
return(0);
}
/*
* fgetpwent() only reads from password file, so we know for certain
* that the user is local.
*/
while (ent = fgetpwent(fd)) {
if (strcmp (ent->pw_name, namep) == 0) {
/* Local user */
fclose (fd);
return(0);
}
}
fclose (fd);
return (1);
}
#endif /* UNIXWARE_LONG_PASSWORDS */
/*
NOTE: ia_get_logpwd() allocates memory for arg 2
functions that call shadow_pw() will need to free
*/
#ifdef USE_LIBIAF
char *
get_iaf_password(struct passwd *pw)
{
char *pw_password = NULL;
uinfo_t uinfo;
if (!ia_openinfo(pw->pw_name,&uinfo)) {
ia_get_logpwd(uinfo, &pw_password);
if (pw_password == NULL)
fatal("ia_get_logpwd: Unable to get the shadow passwd");
ia_closeinfo(uinfo);
- return pw_password;
+ return pw_password;
}
else
fatal("ia_openinfo: Unable to open the shadow passwd file");
}
#endif /* USE_LIBIAF */
#endif /* HAVE_LIBIAF and not HAVE_SECUREWARE */
diff --git a/openbsd-compat/sha2.c b/openbsd-compat/sha2.c
index ce936e262c89..4f2ad8f2352a 100644
--- a/openbsd-compat/sha2.c
+++ b/openbsd-compat/sha2.c
@@ -1,1010 +1,1010 @@
/* $OpenBSD: sha2.c,v 1.28 2019/07/23 12:35:22 dtucker Exp $ */
/*
* FILE: sha2.c
* AUTHOR: Aaron D. Gifford <me@aarongifford.com>
*
* Copyright (c) 2000-2001, Aaron D. Gifford
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $From: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $
*/
/* OPENBSD ORIGINAL: lib/libc/hash/sha2.c */
#include "includes.h"
#if !defined(HAVE_SHA256UPDATE) || !defined(HAVE_SHA384UPDATE) || \
!defined(HAVE_SHA512UPDATE)
/* no-op out, similar to DEF_WEAK but only needed here */
#define MAKE_CLONE(x, y) void __ssh_compat_make_clone_##x_##y(void)
#include <string.h>
#include "openbsd-compat/sha2.h"
/*
* UNROLLED TRANSFORM LOOP NOTE:
* You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform
* loop version for the hash transform rounds (defined using macros
* later in this file). Either define on the command line, for example:
*
* cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c
*
* or define below:
*
* #define SHA2_UNROLL_TRANSFORM
*
*/
#ifndef SHA2_SMALL
#if defined(__amd64__) || defined(__i386__)
#define SHA2_UNROLL_TRANSFORM
#endif
#endif
/*** SHA-224/256/384/512 Machine Architecture Definitions *****************/
/*
* BYTE_ORDER NOTE:
*
* Please make sure that your system defines BYTE_ORDER. If your
* architecture is little-endian, make sure it also defines
* LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are
* equivalent.
*
* If your system does not define the above, then you can do so by
* hand like this:
*
* #define LITTLE_ENDIAN 1234
* #define BIG_ENDIAN 4321
*
* And for little-endian machines, add:
*
* #define BYTE_ORDER LITTLE_ENDIAN
*
* Or for big-endian machines:
*
* #define BYTE_ORDER BIG_ENDIAN
*
* The FreeBSD machine this was written on defines BYTE_ORDER
* appropriately by including <sys/types.h> (which in turn includes
* <machine/endian.h> where the appropriate definitions are actually
* made).
*/
#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN)
#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN
#endif
/*** SHA-224/256/384/512 Various Length Definitions ***********************/
/* NOTE: Most of these are in sha2.h */
#define SHA224_SHORT_BLOCK_LENGTH (SHA224_BLOCK_LENGTH - 8)
#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8)
#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16)
#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16)
/*** ENDIAN SPECIFIC COPY MACROS **************************************/
#define BE_8_TO_32(dst, cp) do { \
(dst) = (u_int32_t)(cp)[3] | ((u_int32_t)(cp)[2] << 8) | \
((u_int32_t)(cp)[1] << 16) | ((u_int32_t)(cp)[0] << 24); \
} while(0)
#define BE_8_TO_64(dst, cp) do { \
(dst) = (u_int64_t)(cp)[7] | ((u_int64_t)(cp)[6] << 8) | \
((u_int64_t)(cp)[5] << 16) | ((u_int64_t)(cp)[4] << 24) | \
((u_int64_t)(cp)[3] << 32) | ((u_int64_t)(cp)[2] << 40) | \
((u_int64_t)(cp)[1] << 48) | ((u_int64_t)(cp)[0] << 56); \
} while (0)
#define BE_64_TO_8(cp, src) do { \
(cp)[0] = (src) >> 56; \
(cp)[1] = (src) >> 48; \
(cp)[2] = (src) >> 40; \
(cp)[3] = (src) >> 32; \
(cp)[4] = (src) >> 24; \
(cp)[5] = (src) >> 16; \
(cp)[6] = (src) >> 8; \
(cp)[7] = (src); \
} while (0)
#define BE_32_TO_8(cp, src) do { \
(cp)[0] = (src) >> 24; \
(cp)[1] = (src) >> 16; \
(cp)[2] = (src) >> 8; \
(cp)[3] = (src); \
} while (0)
/*
* Macro for incrementally adding the unsigned 64-bit integer n to the
* unsigned 128-bit integer (represented using a two-element array of
* 64-bit words):
*/
#define ADDINC128(w,n) do { \
(w)[0] += (u_int64_t)(n); \
if ((w)[0] < (n)) { \
(w)[1]++; \
} \
} while (0)
/*** THE SIX LOGICAL FUNCTIONS ****************************************/
/*
* Bit shifting and rotation (used by the six SHA-XYZ logical functions:
*
* NOTE: The naming of R and S appears backwards here (R is a SHIFT and
* S is a ROTATION) because the SHA-224/256/384/512 description document
* (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
* same "backwards" definition.
*/
/* Shift-right (used in SHA-224, SHA-256, SHA-384, and SHA-512): */
-#define R(b,x) ((x) >> (b))
+#define R(b,x) ((x) >> (b))
/* 32-bit Rotate-right (used in SHA-224 and SHA-256): */
#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b))))
/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b))))
/* Two of six logical functions used in SHA-224, SHA-256, SHA-384, and SHA-512: */
#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
/* Four of six logical functions used in SHA-224 and SHA-256: */
#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x)))
#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x)))
#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x)))
#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x)))
/* Four of six logical functions used in SHA-384 and SHA-512: */
#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x)))
#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x)))
/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
/* Hash constant words K for SHA-224 and SHA-256: */
static const u_int32_t K256[64] = {
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
};
/* Initial hash value H for SHA-256: */
static const u_int32_t sha256_initial_hash_value[8] = {
0x6a09e667UL,
0xbb67ae85UL,
0x3c6ef372UL,
0xa54ff53aUL,
0x510e527fUL,
0x9b05688cUL,
0x1f83d9abUL,
0x5be0cd19UL
};
/* Hash constant words K for SHA-384 and SHA-512: */
static const u_int64_t K512[80] = {
0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
};
/* Initial hash value H for SHA-512 */
static const u_int64_t sha512_initial_hash_value[8] = {
0x6a09e667f3bcc908ULL,
0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL,
0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL,
0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL,
0x5be0cd19137e2179ULL
};
#if !defined(SHA2_SMALL)
#if 0
/* Initial hash value H for SHA-224: */
static const u_int32_t sha224_initial_hash_value[8] = {
0xc1059ed8UL,
0x367cd507UL,
0x3070dd17UL,
0xf70e5939UL,
0xffc00b31UL,
0x68581511UL,
0x64f98fa7UL,
0xbefa4fa4UL
};
#endif /* 0 */
/* Initial hash value H for SHA-384 */
static const u_int64_t sha384_initial_hash_value[8] = {
0xcbbb9d5dc1059ed8ULL,
0x629a292a367cd507ULL,
0x9159015a3070dd17ULL,
0x152fecd8f70e5939ULL,
0x67332667ffc00b31ULL,
0x8eb44a8768581511ULL,
0xdb0c2e0d64f98fa7ULL,
0x47b5481dbefa4fa4ULL
};
#if 0
/* Initial hash value H for SHA-512-256 */
static const u_int64_t sha512_256_initial_hash_value[8] = {
0x22312194fc2bf72cULL,
0x9f555fa3c84c64c2ULL,
0x2393b86b6f53b151ULL,
0x963877195940eabdULL,
0x96283ee2a88effe3ULL,
0xbe5e1e2553863992ULL,
0x2b0199fc2c85b8aaULL,
0x0eb72ddc81c52ca2ULL
};
/*** SHA-224: *********************************************************/
void
SHA224Init(SHA2_CTX *context)
{
memcpy(context->state.st32, sha224_initial_hash_value,
sizeof(sha224_initial_hash_value));
memset(context->buffer, 0, sizeof(context->buffer));
context->bitcount[0] = 0;
}
DEF_WEAK(SHA224Init);
MAKE_CLONE(SHA224Transform, SHA256Transform);
MAKE_CLONE(SHA224Update, SHA256Update);
MAKE_CLONE(SHA224Pad, SHA256Pad);
DEF_WEAK(SHA224Transform);
DEF_WEAK(SHA224Update);
DEF_WEAK(SHA224Pad);
void
SHA224Final(u_int8_t digest[SHA224_DIGEST_LENGTH], SHA2_CTX *context)
{
SHA224Pad(context);
#if BYTE_ORDER == LITTLE_ENDIAN
int i;
/* Convert TO host byte order */
for (i = 0; i < 7; i++)
BE_32_TO_8(digest + i * 4, context->state.st32[i]);
#else
memcpy(digest, context->state.st32, SHA224_DIGEST_LENGTH);
#endif
explicit_bzero(context, sizeof(*context));
}
DEF_WEAK(SHA224Final);
#endif /* !defined(SHA2_SMALL) */
#endif /* 0 */
/*** SHA-256: *********************************************************/
void
SHA256Init(SHA2_CTX *context)
{
memcpy(context->state.st32, sha256_initial_hash_value,
sizeof(sha256_initial_hash_value));
memset(context->buffer, 0, sizeof(context->buffer));
context->bitcount[0] = 0;
}
DEF_WEAK(SHA256Init);
#ifdef SHA2_UNROLL_TRANSFORM
/* Unrolled SHA-256 round macros: */
#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) do { \
BE_8_TO_32(W256[j], data); \
data += 4; \
T1 = (h) + Sigma1_256((e)) + Ch((e), (f), (g)) + K256[j] + W256[j]; \
(d) += T1; \
(h) = T1 + Sigma0_256((a)) + Maj((a), (b), (c)); \
j++; \
} while(0)
#define ROUND256(a,b,c,d,e,f,g,h) do { \
s0 = W256[(j+1)&0x0f]; \
s0 = sigma0_256(s0); \
s1 = W256[(j+14)&0x0f]; \
s1 = sigma1_256(s1); \
T1 = (h) + Sigma1_256((e)) + Ch((e), (f), (g)) + K256[j] + \
(W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \
(d) += T1; \
(h) = T1 + Sigma0_256((a)) + Maj((a), (b), (c)); \
j++; \
} while(0)
void
SHA256Transform(u_int32_t state[8], const u_int8_t data[SHA256_BLOCK_LENGTH])
{
u_int32_t a, b, c, d, e, f, g, h, s0, s1;
u_int32_t T1, W256[16];
int j;
/* Initialize registers with the prev. intermediate value */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
f = state[5];
g = state[6];
h = state[7];
j = 0;
do {
/* Rounds 0 to 15 (unrolled): */
ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
} while (j < 16);
/* Now for the remaining rounds up to 63: */
do {
ROUND256(a,b,c,d,e,f,g,h);
ROUND256(h,a,b,c,d,e,f,g);
ROUND256(g,h,a,b,c,d,e,f);
ROUND256(f,g,h,a,b,c,d,e);
ROUND256(e,f,g,h,a,b,c,d);
ROUND256(d,e,f,g,h,a,b,c);
ROUND256(c,d,e,f,g,h,a,b);
ROUND256(b,c,d,e,f,g,h,a);
} while (j < 64);
/* Compute the current intermediate hash value */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
state[5] += f;
state[6] += g;
state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = 0;
}
#else /* SHA2_UNROLL_TRANSFORM */
void
SHA256Transform(u_int32_t state[8], const u_int8_t data[SHA256_BLOCK_LENGTH])
{
u_int32_t a, b, c, d, e, f, g, h, s0, s1;
u_int32_t T1, T2, W256[16];
int j;
/* Initialize registers with the prev. intermediate value */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
f = state[5];
g = state[6];
h = state[7];
j = 0;
do {
BE_8_TO_32(W256[j], data);
data += 4;
/* Apply the SHA-256 compression function to update a..h */
T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
T2 = Sigma0_256(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 16);
do {
/* Part of the message block expansion: */
s0 = W256[(j+1)&0x0f];
s0 = sigma0_256(s0);
s1 = W256[(j+14)&0x0f];
s1 = sigma1_256(s1);
/* Apply the SHA-256 compression function to update a..h */
T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] +
(W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
T2 = Sigma0_256(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 64);
/* Compute the current intermediate hash value */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
state[5] += f;
state[6] += g;
state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = T2 = 0;
}
#endif /* SHA2_UNROLL_TRANSFORM */
DEF_WEAK(SHA256Transform);
void
SHA256Update(SHA2_CTX *context, const u_int8_t *data, size_t len)
{
u_int64_t freespace, usedspace;
/* Calling with no data is valid (we do nothing) */
if (len == 0)
return;
usedspace = (context->bitcount[0] >> 3) % SHA256_BLOCK_LENGTH;
if (usedspace > 0) {
/* Calculate how much free space is available in the buffer */
freespace = SHA256_BLOCK_LENGTH - usedspace;
if (len >= freespace) {
/* Fill the buffer completely and process it */
memcpy(&context->buffer[usedspace], data, freespace);
context->bitcount[0] += freespace << 3;
len -= freespace;
data += freespace;
SHA256Transform(context->state.st32, context->buffer);
} else {
/* The buffer is not yet full */
memcpy(&context->buffer[usedspace], data, len);
context->bitcount[0] += (u_int64_t)len << 3;
/* Clean up: */
usedspace = freespace = 0;
return;
}
}
while (len >= SHA256_BLOCK_LENGTH) {
/* Process as many complete blocks as we can */
SHA256Transform(context->state.st32, data);
context->bitcount[0] += SHA256_BLOCK_LENGTH << 3;
len -= SHA256_BLOCK_LENGTH;
data += SHA256_BLOCK_LENGTH;
}
if (len > 0) {
/* There's left-overs, so save 'em */
memcpy(context->buffer, data, len);
context->bitcount[0] += len << 3;
}
/* Clean up: */
usedspace = freespace = 0;
}
DEF_WEAK(SHA256Update);
void
SHA256Pad(SHA2_CTX *context)
{
unsigned int usedspace;
usedspace = (context->bitcount[0] >> 3) % SHA256_BLOCK_LENGTH;
if (usedspace > 0) {
/* Begin padding with a 1 bit: */
context->buffer[usedspace++] = 0x80;
if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) {
/* Set-up for the last transform: */
memset(&context->buffer[usedspace], 0,
SHA256_SHORT_BLOCK_LENGTH - usedspace);
} else {
if (usedspace < SHA256_BLOCK_LENGTH) {
memset(&context->buffer[usedspace], 0,
SHA256_BLOCK_LENGTH - usedspace);
}
/* Do second-to-last transform: */
SHA256Transform(context->state.st32, context->buffer);
/* Prepare for last transform: */
memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH);
}
} else {
/* Set-up for the last transform: */
memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH);
/* Begin padding with a 1 bit: */
*context->buffer = 0x80;
}
/* Store the length of input data (in bits) in big endian format: */
BE_64_TO_8(&context->buffer[SHA256_SHORT_BLOCK_LENGTH],
context->bitcount[0]);
/* Final transform: */
SHA256Transform(context->state.st32, context->buffer);
/* Clean up: */
usedspace = 0;
}
DEF_WEAK(SHA256Pad);
void
SHA256Final(u_int8_t digest[SHA256_DIGEST_LENGTH], SHA2_CTX *context)
{
SHA256Pad(context);
#if BYTE_ORDER == LITTLE_ENDIAN
int i;
/* Convert TO host byte order */
for (i = 0; i < 8; i++)
BE_32_TO_8(digest + i * 4, context->state.st32[i]);
#else
memcpy(digest, context->state.st32, SHA256_DIGEST_LENGTH);
#endif
explicit_bzero(context, sizeof(*context));
}
DEF_WEAK(SHA256Final);
/*** SHA-512: *********************************************************/
void
SHA512Init(SHA2_CTX *context)
{
memcpy(context->state.st64, sha512_initial_hash_value,
sizeof(sha512_initial_hash_value));
memset(context->buffer, 0, sizeof(context->buffer));
context->bitcount[0] = context->bitcount[1] = 0;
}
DEF_WEAK(SHA512Init);
#ifdef SHA2_UNROLL_TRANSFORM
/* Unrolled SHA-512 round macros: */
#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) do { \
BE_8_TO_64(W512[j], data); \
data += 8; \
T1 = (h) + Sigma1_512((e)) + Ch((e), (f), (g)) + K512[j] + W512[j]; \
(d) += T1; \
(h) = T1 + Sigma0_512((a)) + Maj((a), (b), (c)); \
j++; \
} while(0)
#define ROUND512(a,b,c,d,e,f,g,h) do { \
s0 = W512[(j+1)&0x0f]; \
s0 = sigma0_512(s0); \
s1 = W512[(j+14)&0x0f]; \
s1 = sigma1_512(s1); \
T1 = (h) + Sigma1_512((e)) + Ch((e), (f), (g)) + K512[j] + \
(W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \
(d) += T1; \
(h) = T1 + Sigma0_512((a)) + Maj((a), (b), (c)); \
j++; \
} while(0)
void
SHA512Transform(u_int64_t state[8], const u_int8_t data[SHA512_BLOCK_LENGTH])
{
u_int64_t a, b, c, d, e, f, g, h, s0, s1;
u_int64_t T1, W512[16];
int j;
/* Initialize registers with the prev. intermediate value */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
f = state[5];
g = state[6];
h = state[7];
j = 0;
do {
/* Rounds 0 to 15 (unrolled): */
ROUND512_0_TO_15(a,b,c,d,e,f,g,h);
ROUND512_0_TO_15(h,a,b,c,d,e,f,g);
ROUND512_0_TO_15(g,h,a,b,c,d,e,f);
ROUND512_0_TO_15(f,g,h,a,b,c,d,e);
ROUND512_0_TO_15(e,f,g,h,a,b,c,d);
ROUND512_0_TO_15(d,e,f,g,h,a,b,c);
ROUND512_0_TO_15(c,d,e,f,g,h,a,b);
ROUND512_0_TO_15(b,c,d,e,f,g,h,a);
} while (j < 16);
/* Now for the remaining rounds up to 79: */
do {
ROUND512(a,b,c,d,e,f,g,h);
ROUND512(h,a,b,c,d,e,f,g);
ROUND512(g,h,a,b,c,d,e,f);
ROUND512(f,g,h,a,b,c,d,e);
ROUND512(e,f,g,h,a,b,c,d);
ROUND512(d,e,f,g,h,a,b,c);
ROUND512(c,d,e,f,g,h,a,b);
ROUND512(b,c,d,e,f,g,h,a);
} while (j < 80);
/* Compute the current intermediate hash value */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
state[5] += f;
state[6] += g;
state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = 0;
}
#else /* SHA2_UNROLL_TRANSFORM */
void
SHA512Transform(u_int64_t state[8], const u_int8_t data[SHA512_BLOCK_LENGTH])
{
u_int64_t a, b, c, d, e, f, g, h, s0, s1;
u_int64_t T1, T2, W512[16];
int j;
/* Initialize registers with the prev. intermediate value */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
f = state[5];
g = state[6];
h = state[7];
j = 0;
do {
BE_8_TO_64(W512[j], data);
data += 8;
/* Apply the SHA-512 compression function to update a..h */
T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];
T2 = Sigma0_512(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 16);
do {
/* Part of the message block expansion: */
s0 = W512[(j+1)&0x0f];
s0 = sigma0_512(s0);
s1 = W512[(j+14)&0x0f];
s1 = sigma1_512(s1);
/* Apply the SHA-512 compression function to update a..h */
T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] +
(W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
T2 = Sigma0_512(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 80);
/* Compute the current intermediate hash value */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
state[5] += f;
state[6] += g;
state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = T2 = 0;
}
#endif /* SHA2_UNROLL_TRANSFORM */
DEF_WEAK(SHA512Transform);
void
SHA512Update(SHA2_CTX *context, const u_int8_t *data, size_t len)
{
size_t freespace, usedspace;
/* Calling with no data is valid (we do nothing) */
if (len == 0)
return;
usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
if (usedspace > 0) {
/* Calculate how much free space is available in the buffer */
freespace = SHA512_BLOCK_LENGTH - usedspace;
if (len >= freespace) {
/* Fill the buffer completely and process it */
memcpy(&context->buffer[usedspace], data, freespace);
ADDINC128(context->bitcount, freespace << 3);
len -= freespace;
data += freespace;
SHA512Transform(context->state.st64, context->buffer);
} else {
/* The buffer is not yet full */
memcpy(&context->buffer[usedspace], data, len);
ADDINC128(context->bitcount, len << 3);
/* Clean up: */
usedspace = freespace = 0;
return;
}
}
while (len >= SHA512_BLOCK_LENGTH) {
/* Process as many complete blocks as we can */
SHA512Transform(context->state.st64, data);
ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3);
len -= SHA512_BLOCK_LENGTH;
data += SHA512_BLOCK_LENGTH;
}
if (len > 0) {
/* There's left-overs, so save 'em */
memcpy(context->buffer, data, len);
ADDINC128(context->bitcount, len << 3);
}
/* Clean up: */
usedspace = freespace = 0;
}
DEF_WEAK(SHA512Update);
void
SHA512Pad(SHA2_CTX *context)
{
unsigned int usedspace;
usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
if (usedspace > 0) {
/* Begin padding with a 1 bit: */
context->buffer[usedspace++] = 0x80;
if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) {
/* Set-up for the last transform: */
memset(&context->buffer[usedspace], 0, SHA512_SHORT_BLOCK_LENGTH - usedspace);
} else {
if (usedspace < SHA512_BLOCK_LENGTH) {
memset(&context->buffer[usedspace], 0, SHA512_BLOCK_LENGTH - usedspace);
}
/* Do second-to-last transform: */
SHA512Transform(context->state.st64, context->buffer);
/* And set-up for the last transform: */
memset(context->buffer, 0, SHA512_BLOCK_LENGTH - 2);
}
} else {
/* Prepare for final transform: */
memset(context->buffer, 0, SHA512_SHORT_BLOCK_LENGTH);
/* Begin padding with a 1 bit: */
*context->buffer = 0x80;
}
/* Store the length of input data (in bits) in big endian format: */
BE_64_TO_8(&context->buffer[SHA512_SHORT_BLOCK_LENGTH],
context->bitcount[1]);
BE_64_TO_8(&context->buffer[SHA512_SHORT_BLOCK_LENGTH + 8],
context->bitcount[0]);
/* Final transform: */
SHA512Transform(context->state.st64, context->buffer);
/* Clean up: */
usedspace = 0;
}
DEF_WEAK(SHA512Pad);
void
SHA512Final(u_int8_t digest[SHA512_DIGEST_LENGTH], SHA2_CTX *context)
{
SHA512Pad(context);
#if BYTE_ORDER == LITTLE_ENDIAN
int i;
/* Convert TO host byte order */
for (i = 0; i < 8; i++)
BE_64_TO_8(digest + i * 8, context->state.st64[i]);
#else
memcpy(digest, context->state.st64, SHA512_DIGEST_LENGTH);
#endif
explicit_bzero(context, sizeof(*context));
}
DEF_WEAK(SHA512Final);
#if !defined(SHA2_SMALL)
/*** SHA-384: *********************************************************/
void
SHA384Init(SHA2_CTX *context)
{
memcpy(context->state.st64, sha384_initial_hash_value,
sizeof(sha384_initial_hash_value));
memset(context->buffer, 0, sizeof(context->buffer));
context->bitcount[0] = context->bitcount[1] = 0;
}
DEF_WEAK(SHA384Init);
MAKE_CLONE(SHA384Transform, SHA512Transform);
MAKE_CLONE(SHA384Update, SHA512Update);
MAKE_CLONE(SHA384Pad, SHA512Pad);
DEF_WEAK(SHA384Transform);
DEF_WEAK(SHA384Update);
DEF_WEAK(SHA384Pad);
/* Equivalent of MAKE_CLONE (which is a no-op) for SHA384 funcs */
void
SHA384Transform(u_int64_t state[8], const u_int8_t data[SHA512_BLOCK_LENGTH])
{
SHA512Transform(state, data);
}
void
SHA384Update(SHA2_CTX *context, const u_int8_t *data, size_t len)
{
SHA512Update(context, data, len);
}
void
SHA384Pad(SHA2_CTX *context)
{
SHA512Pad(context);
}
void
SHA384Final(u_int8_t digest[SHA384_DIGEST_LENGTH], SHA2_CTX *context)
{
SHA384Pad(context);
#if BYTE_ORDER == LITTLE_ENDIAN
int i;
/* Convert TO host byte order */
for (i = 0; i < 6; i++)
BE_64_TO_8(digest + i * 8, context->state.st64[i]);
#else
memcpy(digest, context->state.st64, SHA384_DIGEST_LENGTH);
#endif
/* Zero out state data */
explicit_bzero(context, sizeof(*context));
}
DEF_WEAK(SHA384Final);
#if 0
/*** SHA-512/256: *********************************************************/
void
SHA512_256Init(SHA2_CTX *context)
{
memcpy(context->state.st64, sha512_256_initial_hash_value,
sizeof(sha512_256_initial_hash_value));
memset(context->buffer, 0, sizeof(context->buffer));
context->bitcount[0] = context->bitcount[1] = 0;
}
DEF_WEAK(SHA512_256Init);
MAKE_CLONE(SHA512_256Transform, SHA512Transform);
MAKE_CLONE(SHA512_256Update, SHA512Update);
MAKE_CLONE(SHA512_256Pad, SHA512Pad);
DEF_WEAK(SHA512_256Transform);
DEF_WEAK(SHA512_256Update);
DEF_WEAK(SHA512_256Pad);
void
SHA512_256Final(u_int8_t digest[SHA512_256_DIGEST_LENGTH], SHA2_CTX *context)
{
SHA512_256Pad(context);
#if BYTE_ORDER == LITTLE_ENDIAN
int i;
/* Convert TO host byte order */
for (i = 0; i < 4; i++)
BE_64_TO_8(digest + i * 8, context->state.st64[i]);
#else
memcpy(digest, context->state.st64, SHA512_256_DIGEST_LENGTH);
#endif
/* Zero out state data */
explicit_bzero(context, sizeof(*context));
}
DEF_WEAK(SHA512_256Final);
#endif /* !defined(SHA2_SMALL) */
#endif /* 0 */
#endif /* HAVE_SHA{256,384,512}UPDATE */
diff --git a/openbsd-compat/strtonum.c b/openbsd-compat/strtonum.c
index 87f2f24b2583..130d89684e90 100644
--- a/openbsd-compat/strtonum.c
+++ b/openbsd-compat/strtonum.c
@@ -1,72 +1,72 @@
/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */
/*
* Copyright (c) 2004 Ted Unangst and Todd Miller
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* OPENBSD ORIGINAL: lib/libc/stdlib/strtonum.c */
#include "includes.h"
#ifndef HAVE_STRTONUM
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
-#define INVALID 1
-#define TOOSMALL 2
-#define TOOLARGE 3
+#define INVALID 1
+#define TOOSMALL 2
+#define TOOLARGE 3
long long
strtonum(const char *numstr, long long minval, long long maxval,
const char **errstrp)
{
long long ll = 0;
char *ep;
int error = 0;
struct errval {
const char *errstr;
int err;
} ev[4] = {
{ NULL, 0 },
{ "invalid", EINVAL },
{ "too small", ERANGE },
{ "too large", ERANGE },
};
ev[0].err = errno;
errno = 0;
if (minval > maxval)
error = INVALID;
else {
ll = strtoll(numstr, &ep, 10);
if (numstr == ep || *ep != '\0')
error = INVALID;
else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
error = TOOSMALL;
else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
error = TOOLARGE;
}
if (errstrp != NULL)
*errstrp = ev[error].errstr;
errno = ev[error].err;
if (error)
ll = 0;
return (ll);
}
#endif /* HAVE_STRTONUM */
diff --git a/packet.c b/packet.c
index 4bd8b4ec9e05..85784ac57702 100644
--- a/packet.c
+++ b/packet.c
@@ -1,2709 +1,2709 @@
-/* $OpenBSD: packet.c,v 1.299 2021/01/27 10:05:28 djm Exp $ */
+/* $OpenBSD: packet.c,v 1.300 2021/04/03 06:18:40 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* This file contains code implementing the packet protocol and communication
* with the other side. This same code is used both on client and server side.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
*
* SSH2 packet format added by Markus Friedl.
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include "openbsd-compat/sys-queue.h"
#include <sys/socket.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#include <signal.h>
#include <time.h>
/*
* Explicitly include OpenSSL before zlib as some versions of OpenSSL have
* "free_func" in their headers, which zlib typedefs.
*/
#ifdef WITH_OPENSSL
# include <openssl/bn.h>
# include <openssl/evp.h>
# ifdef OPENSSL_HAS_ECC
# include <openssl/ec.h>
# endif
#endif
#ifdef WITH_ZLIB
#include <zlib.h>
#endif
#include "xmalloc.h"
#include "compat.h"
#include "ssh2.h"
#include "cipher.h"
#include "sshkey.h"
#include "kex.h"
#include "digest.h"
#include "mac.h"
#include "log.h"
#include "canohost.h"
#include "misc.h"
#include "channels.h"
#include "ssh.h"
#include "packet.h"
#include "ssherr.h"
#include "sshbuf.h"
#ifdef PACKET_DEBUG
#define DBG(x) x
#else
#define DBG(x)
#endif
#define PACKET_MAX_SIZE (256 * 1024)
struct packet_state {
u_int32_t seqnr;
u_int32_t packets;
u_int64_t blocks;
u_int64_t bytes;
};
struct packet {
TAILQ_ENTRY(packet) next;
u_char type;
struct sshbuf *payload;
};
struct session_state {
/*
* This variable contains the file descriptors used for
* communicating with the other side. connection_in is used for
* reading; connection_out for writing. These can be the same
* descriptor, in which case it is assumed to be a socket.
*/
int connection_in;
int connection_out;
/* Protocol flags for the remote side. */
u_int remote_protocol_flags;
/* Encryption context for receiving data. Only used for decryption. */
struct sshcipher_ctx *receive_context;
/* Encryption context for sending data. Only used for encryption. */
struct sshcipher_ctx *send_context;
/* Buffer for raw input data from the socket. */
struct sshbuf *input;
/* Buffer for raw output data going to the socket. */
struct sshbuf *output;
/* Buffer for the partial outgoing packet being constructed. */
struct sshbuf *outgoing_packet;
/* Buffer for the incoming packet currently being processed. */
struct sshbuf *incoming_packet;
/* Scratch buffer for packet compression/decompression. */
struct sshbuf *compression_buffer;
#ifdef WITH_ZLIB
/* Incoming/outgoing compression dictionaries */
z_stream compression_in_stream;
z_stream compression_out_stream;
#endif
int compression_in_started;
int compression_out_started;
int compression_in_failures;
int compression_out_failures;
/* default maximum packet size */
u_int max_packet_size;
/* Flag indicating whether this module has been initialized. */
int initialized;
/* Set to true if the connection is interactive. */
int interactive_mode;
/* Set to true if we are the server side. */
int server_side;
/* Set to true if we are authenticated. */
int after_authentication;
int keep_alive_timeouts;
/* The maximum time that we will wait to send or receive a packet */
int packet_timeout_ms;
/* Session key information for Encryption and MAC */
struct newkeys *newkeys[MODE_MAX];
struct packet_state p_read, p_send;
/* Volume-based rekeying */
u_int64_t max_blocks_in, max_blocks_out, rekey_limit;
/* Time-based rekeying */
u_int32_t rekey_interval; /* how often in seconds */
time_t rekey_time; /* time of last rekeying */
/* roundup current message to extra_pad bytes */
u_char extra_pad;
/* XXX discard incoming data after MAC error */
u_int packet_discard;
size_t packet_discard_mac_already;
struct sshmac *packet_discard_mac;
/* Used in packet_read_poll2() */
u_int packlen;
/* Used in packet_send2 */
int rekeying;
/* Used in ssh_packet_send_mux() */
int mux;
/* Used in packet_set_interactive */
int set_interactive_called;
/* Used in packet_set_maxsize */
int set_maxsize_called;
/* One-off warning about weak ciphers */
int cipher_warning_done;
/* Hook for fuzzing inbound packets */
ssh_packet_hook_fn *hook_in;
void *hook_in_ctx;
TAILQ_HEAD(, packet) outgoing;
};
struct ssh *
ssh_alloc_session_state(void)
{
struct ssh *ssh = NULL;
struct session_state *state = NULL;
if ((ssh = calloc(1, sizeof(*ssh))) == NULL ||
(state = calloc(1, sizeof(*state))) == NULL ||
(ssh->kex = kex_new()) == NULL ||
(state->input = sshbuf_new()) == NULL ||
(state->output = sshbuf_new()) == NULL ||
(state->outgoing_packet = sshbuf_new()) == NULL ||
(state->incoming_packet = sshbuf_new()) == NULL)
goto fail;
TAILQ_INIT(&state->outgoing);
TAILQ_INIT(&ssh->private_keys);
TAILQ_INIT(&ssh->public_keys);
state->connection_in = -1;
state->connection_out = -1;
state->max_packet_size = 32768;
state->packet_timeout_ms = -1;
state->p_send.packets = state->p_read.packets = 0;
state->initialized = 1;
/*
* ssh_packet_send2() needs to queue packets until
* we've done the initial key exchange.
*/
state->rekeying = 1;
ssh->state = state;
return ssh;
fail:
if (ssh) {
kex_free(ssh->kex);
free(ssh);
}
if (state) {
sshbuf_free(state->input);
sshbuf_free(state->output);
sshbuf_free(state->incoming_packet);
sshbuf_free(state->outgoing_packet);
free(state);
}
return NULL;
}
void
ssh_packet_set_input_hook(struct ssh *ssh, ssh_packet_hook_fn *hook, void *ctx)
{
ssh->state->hook_in = hook;
ssh->state->hook_in_ctx = ctx;
}
/* Returns nonzero if rekeying is in progress */
int
ssh_packet_is_rekeying(struct ssh *ssh)
{
return ssh->state->rekeying ||
(ssh->kex != NULL && ssh->kex->done == 0);
}
/*
* Sets the descriptors used for communication.
*/
struct ssh *
ssh_packet_set_connection(struct ssh *ssh, int fd_in, int fd_out)
{
struct session_state *state;
const struct sshcipher *none = cipher_by_name("none");
int r;
if (none == NULL) {
error_f("cannot load cipher 'none'");
return NULL;
}
if (ssh == NULL)
ssh = ssh_alloc_session_state();
if (ssh == NULL) {
error_f("could not allocate state");
return NULL;
}
state = ssh->state;
state->connection_in = fd_in;
state->connection_out = fd_out;
if ((r = cipher_init(&state->send_context, none,
(const u_char *)"", 0, NULL, 0, CIPHER_ENCRYPT)) != 0 ||
(r = cipher_init(&state->receive_context, none,
(const u_char *)"", 0, NULL, 0, CIPHER_DECRYPT)) != 0) {
error_fr(r, "cipher_init failed");
free(ssh); /* XXX need ssh_free_session_state? */
return NULL;
}
state->newkeys[MODE_IN] = state->newkeys[MODE_OUT] = NULL;
/*
* Cache the IP address of the remote connection for use in error
* messages that might be generated after the connection has closed.
*/
(void)ssh_remote_ipaddr(ssh);
return ssh;
}
void
ssh_packet_set_timeout(struct ssh *ssh, int timeout, int count)
{
struct session_state *state = ssh->state;
if (timeout <= 0 || count <= 0) {
state->packet_timeout_ms = -1;
return;
}
if ((INT_MAX / 1000) / count < timeout)
state->packet_timeout_ms = INT_MAX;
else
state->packet_timeout_ms = timeout * count * 1000;
}
void
ssh_packet_set_mux(struct ssh *ssh)
{
ssh->state->mux = 1;
ssh->state->rekeying = 0;
kex_free(ssh->kex);
ssh->kex = NULL;
}
int
ssh_packet_get_mux(struct ssh *ssh)
{
return ssh->state->mux;
}
int
ssh_packet_set_log_preamble(struct ssh *ssh, const char *fmt, ...)
{
va_list args;
int r;
free(ssh->log_preamble);
if (fmt == NULL)
ssh->log_preamble = NULL;
else {
va_start(args, fmt);
r = vasprintf(&ssh->log_preamble, fmt, args);
va_end(args);
if (r < 0 || ssh->log_preamble == NULL)
return SSH_ERR_ALLOC_FAIL;
}
return 0;
}
int
ssh_packet_stop_discard(struct ssh *ssh)
{
struct session_state *state = ssh->state;
int r;
if (state->packet_discard_mac) {
char buf[1024];
size_t dlen = PACKET_MAX_SIZE;
if (dlen > state->packet_discard_mac_already)
dlen -= state->packet_discard_mac_already;
memset(buf, 'a', sizeof(buf));
while (sshbuf_len(state->incoming_packet) < dlen)
if ((r = sshbuf_put(state->incoming_packet, buf,
sizeof(buf))) != 0)
return r;
(void) mac_compute(state->packet_discard_mac,
state->p_read.seqnr,
sshbuf_ptr(state->incoming_packet), dlen,
NULL, 0);
}
logit("Finished discarding for %.200s port %d",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
return SSH_ERR_MAC_INVALID;
}
static int
ssh_packet_start_discard(struct ssh *ssh, struct sshenc *enc,
struct sshmac *mac, size_t mac_already, u_int discard)
{
struct session_state *state = ssh->state;
int r;
if (enc == NULL || !cipher_is_cbc(enc->cipher) || (mac && mac->etm)) {
if ((r = sshpkt_disconnect(ssh, "Packet corrupt")) != 0)
return r;
return SSH_ERR_MAC_INVALID;
}
/*
* Record number of bytes over which the mac has already
* been computed in order to minimize timing attacks.
*/
if (mac && mac->enabled) {
state->packet_discard_mac = mac;
state->packet_discard_mac_already = mac_already;
}
if (sshbuf_len(state->input) >= discard)
return ssh_packet_stop_discard(ssh);
state->packet_discard = discard - sshbuf_len(state->input);
return 0;
}
/* Returns 1 if remote host is connected via socket, 0 if not. */
int
ssh_packet_connection_is_on_socket(struct ssh *ssh)
{
struct session_state *state;
struct sockaddr_storage from, to;
socklen_t fromlen, tolen;
if (ssh == NULL || ssh->state == NULL)
return 0;
state = ssh->state;
if (state->connection_in == -1 || state->connection_out == -1)
return 0;
/* filedescriptors in and out are the same, so it's a socket */
if (state->connection_in == state->connection_out)
return 1;
fromlen = sizeof(from);
memset(&from, 0, sizeof(from));
if (getpeername(state->connection_in, (struct sockaddr *)&from,
&fromlen) == -1)
return 0;
tolen = sizeof(to);
memset(&to, 0, sizeof(to));
if (getpeername(state->connection_out, (struct sockaddr *)&to,
&tolen) == -1)
return 0;
if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0)
return 0;
if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
return 0;
return 1;
}
void
ssh_packet_get_bytes(struct ssh *ssh, u_int64_t *ibytes, u_int64_t *obytes)
{
if (ibytes)
*ibytes = ssh->state->p_read.bytes;
if (obytes)
*obytes = ssh->state->p_send.bytes;
}
int
ssh_packet_connection_af(struct ssh *ssh)
{
return get_sock_af(ssh->state->connection_out);
}
/* Sets the connection into non-blocking mode. */
void
ssh_packet_set_nonblocking(struct ssh *ssh)
{
/* Set the socket into non-blocking mode. */
set_nonblock(ssh->state->connection_in);
if (ssh->state->connection_out != ssh->state->connection_in)
set_nonblock(ssh->state->connection_out);
}
/* Returns the socket used for reading. */
int
ssh_packet_get_connection_in(struct ssh *ssh)
{
return ssh->state->connection_in;
}
/* Returns the descriptor used for writing. */
int
ssh_packet_get_connection_out(struct ssh *ssh)
{
return ssh->state->connection_out;
}
/*
* Returns the IP-address of the remote host as a string. The returned
* string must not be freed.
*/
const char *
ssh_remote_ipaddr(struct ssh *ssh)
{
int sock;
/* Check whether we have cached the ipaddr. */
if (ssh->remote_ipaddr == NULL) {
if (ssh_packet_connection_is_on_socket(ssh)) {
sock = ssh->state->connection_in;
ssh->remote_ipaddr = get_peer_ipaddr(sock);
ssh->remote_port = get_peer_port(sock);
ssh->local_ipaddr = get_local_ipaddr(sock);
ssh->local_port = get_local_port(sock);
} else {
ssh->remote_ipaddr = xstrdup("UNKNOWN");
ssh->remote_port = 65535;
ssh->local_ipaddr = xstrdup("UNKNOWN");
ssh->local_port = 65535;
}
}
return ssh->remote_ipaddr;
}
/* Returns the port number of the remote host. */
int
ssh_remote_port(struct ssh *ssh)
{
(void)ssh_remote_ipaddr(ssh); /* Will lookup and cache. */
return ssh->remote_port;
}
/*
* Returns the IP-address of the local host as a string. The returned
* string must not be freed.
*/
const char *
ssh_local_ipaddr(struct ssh *ssh)
{
(void)ssh_remote_ipaddr(ssh); /* Will lookup and cache. */
return ssh->local_ipaddr;
}
/* Returns the port number of the local host. */
int
ssh_local_port(struct ssh *ssh)
{
(void)ssh_remote_ipaddr(ssh); /* Will lookup and cache. */
return ssh->local_port;
}
/* Returns the routing domain of the input socket, or NULL if unavailable */
const char *
ssh_packet_rdomain_in(struct ssh *ssh)
{
if (ssh->rdomain_in != NULL)
return ssh->rdomain_in;
if (!ssh_packet_connection_is_on_socket(ssh))
return NULL;
ssh->rdomain_in = get_rdomain(ssh->state->connection_in);
return ssh->rdomain_in;
}
/* Closes the connection and clears and frees internal data structures. */
static void
ssh_packet_close_internal(struct ssh *ssh, int do_close)
{
struct session_state *state = ssh->state;
u_int mode;
if (!state->initialized)
return;
state->initialized = 0;
if (do_close) {
if (state->connection_in == state->connection_out) {
close(state->connection_out);
} else {
close(state->connection_in);
close(state->connection_out);
}
}
sshbuf_free(state->input);
sshbuf_free(state->output);
sshbuf_free(state->outgoing_packet);
sshbuf_free(state->incoming_packet);
for (mode = 0; mode < MODE_MAX; mode++) {
kex_free_newkeys(state->newkeys[mode]); /* current keys */
state->newkeys[mode] = NULL;
ssh_clear_newkeys(ssh, mode); /* next keys */
}
#ifdef WITH_ZLIB
/* compression state is in shared mem, so we can only release it once */
if (do_close && state->compression_buffer) {
sshbuf_free(state->compression_buffer);
if (state->compression_out_started) {
z_streamp stream = &state->compression_out_stream;
debug("compress outgoing: "
"raw data %llu, compressed %llu, factor %.2f",
(unsigned long long)stream->total_in,
(unsigned long long)stream->total_out,
stream->total_in == 0 ? 0.0 :
(double) stream->total_out / stream->total_in);
if (state->compression_out_failures == 0)
deflateEnd(stream);
}
if (state->compression_in_started) {
z_streamp stream = &state->compression_in_stream;
debug("compress incoming: "
"raw data %llu, compressed %llu, factor %.2f",
(unsigned long long)stream->total_out,
(unsigned long long)stream->total_in,
stream->total_out == 0 ? 0.0 :
(double) stream->total_in / stream->total_out);
if (state->compression_in_failures == 0)
inflateEnd(stream);
}
}
#endif /* WITH_ZLIB */
cipher_free(state->send_context);
cipher_free(state->receive_context);
state->send_context = state->receive_context = NULL;
if (do_close) {
free(ssh->local_ipaddr);
ssh->local_ipaddr = NULL;
free(ssh->remote_ipaddr);
ssh->remote_ipaddr = NULL;
free(ssh->state);
ssh->state = NULL;
kex_free(ssh->kex);
ssh->kex = NULL;
}
}
void
ssh_packet_close(struct ssh *ssh)
{
ssh_packet_close_internal(ssh, 1);
}
void
ssh_packet_clear_keys(struct ssh *ssh)
{
ssh_packet_close_internal(ssh, 0);
}
/* Sets remote side protocol flags. */
void
ssh_packet_set_protocol_flags(struct ssh *ssh, u_int protocol_flags)
{
ssh->state->remote_protocol_flags = protocol_flags;
}
/* Returns the remote protocol flags set earlier by the above function. */
u_int
ssh_packet_get_protocol_flags(struct ssh *ssh)
{
return ssh->state->remote_protocol_flags;
}
/*
* Starts packet compression from the next packet on in both directions.
* Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
*/
static int
ssh_packet_init_compression(struct ssh *ssh)
{
if (!ssh->state->compression_buffer &&
- ((ssh->state->compression_buffer = sshbuf_new()) == NULL))
+ ((ssh->state->compression_buffer = sshbuf_new()) == NULL))
return SSH_ERR_ALLOC_FAIL;
return 0;
}
#ifdef WITH_ZLIB
static int
start_compression_out(struct ssh *ssh, int level)
{
if (level < 1 || level > 9)
return SSH_ERR_INVALID_ARGUMENT;
debug("Enabling compression at level %d.", level);
if (ssh->state->compression_out_started == 1)
deflateEnd(&ssh->state->compression_out_stream);
switch (deflateInit(&ssh->state->compression_out_stream, level)) {
case Z_OK:
ssh->state->compression_out_started = 1;
break;
case Z_MEM_ERROR:
return SSH_ERR_ALLOC_FAIL;
default:
return SSH_ERR_INTERNAL_ERROR;
}
return 0;
}
static int
start_compression_in(struct ssh *ssh)
{
if (ssh->state->compression_in_started == 1)
inflateEnd(&ssh->state->compression_in_stream);
switch (inflateInit(&ssh->state->compression_in_stream)) {
case Z_OK:
ssh->state->compression_in_started = 1;
break;
case Z_MEM_ERROR:
return SSH_ERR_ALLOC_FAIL;
default:
return SSH_ERR_INTERNAL_ERROR;
}
return 0;
}
/* XXX remove need for separate compression buffer */
static int
compress_buffer(struct ssh *ssh, struct sshbuf *in, struct sshbuf *out)
{
u_char buf[4096];
int r, status;
if (ssh->state->compression_out_started != 1)
return SSH_ERR_INTERNAL_ERROR;
/* This case is not handled below. */
if (sshbuf_len(in) == 0)
return 0;
/* Input is the contents of the input buffer. */
if ((ssh->state->compression_out_stream.next_in =
sshbuf_mutable_ptr(in)) == NULL)
return SSH_ERR_INTERNAL_ERROR;
ssh->state->compression_out_stream.avail_in = sshbuf_len(in);
/* Loop compressing until deflate() returns with avail_out != 0. */
do {
/* Set up fixed-size output buffer. */
ssh->state->compression_out_stream.next_out = buf;
ssh->state->compression_out_stream.avail_out = sizeof(buf);
/* Compress as much data into the buffer as possible. */
status = deflate(&ssh->state->compression_out_stream,
Z_PARTIAL_FLUSH);
switch (status) {
case Z_MEM_ERROR:
return SSH_ERR_ALLOC_FAIL;
case Z_OK:
/* Append compressed data to output_buffer. */
if ((r = sshbuf_put(out, buf, sizeof(buf) -
ssh->state->compression_out_stream.avail_out)) != 0)
return r;
break;
case Z_STREAM_ERROR:
default:
ssh->state->compression_out_failures++;
return SSH_ERR_INVALID_FORMAT;
}
} while (ssh->state->compression_out_stream.avail_out == 0);
return 0;
}
static int
uncompress_buffer(struct ssh *ssh, struct sshbuf *in, struct sshbuf *out)
{
u_char buf[4096];
int r, status;
if (ssh->state->compression_in_started != 1)
return SSH_ERR_INTERNAL_ERROR;
if ((ssh->state->compression_in_stream.next_in =
sshbuf_mutable_ptr(in)) == NULL)
return SSH_ERR_INTERNAL_ERROR;
ssh->state->compression_in_stream.avail_in = sshbuf_len(in);
for (;;) {
/* Set up fixed-size output buffer. */
ssh->state->compression_in_stream.next_out = buf;
ssh->state->compression_in_stream.avail_out = sizeof(buf);
status = inflate(&ssh->state->compression_in_stream,
Z_PARTIAL_FLUSH);
switch (status) {
case Z_OK:
if ((r = sshbuf_put(out, buf, sizeof(buf) -
ssh->state->compression_in_stream.avail_out)) != 0)
return r;
break;
case Z_BUF_ERROR:
/*
* Comments in zlib.h say that we should keep calling
* inflate() until we get an error. This appears to
* be the error that we get.
*/
return 0;
case Z_DATA_ERROR:
return SSH_ERR_INVALID_FORMAT;
case Z_MEM_ERROR:
return SSH_ERR_ALLOC_FAIL;
case Z_STREAM_ERROR:
default:
ssh->state->compression_in_failures++;
return SSH_ERR_INTERNAL_ERROR;
}
}
/* NOTREACHED */
}
#else /* WITH_ZLIB */
static int
start_compression_out(struct ssh *ssh, int level)
{
return SSH_ERR_INTERNAL_ERROR;
}
static int
start_compression_in(struct ssh *ssh)
{
return SSH_ERR_INTERNAL_ERROR;
}
static int
compress_buffer(struct ssh *ssh, struct sshbuf *in, struct sshbuf *out)
{
return SSH_ERR_INTERNAL_ERROR;
}
static int
uncompress_buffer(struct ssh *ssh, struct sshbuf *in, struct sshbuf *out)
{
return SSH_ERR_INTERNAL_ERROR;
}
#endif /* WITH_ZLIB */
void
ssh_clear_newkeys(struct ssh *ssh, int mode)
{
if (ssh->kex && ssh->kex->newkeys[mode]) {
kex_free_newkeys(ssh->kex->newkeys[mode]);
ssh->kex->newkeys[mode] = NULL;
}
}
int
ssh_set_newkeys(struct ssh *ssh, int mode)
{
struct session_state *state = ssh->state;
struct sshenc *enc;
struct sshmac *mac;
struct sshcomp *comp;
struct sshcipher_ctx **ccp;
struct packet_state *ps;
u_int64_t *max_blocks;
const char *wmsg;
int r, crypt_type;
const char *dir = mode == MODE_OUT ? "out" : "in";
debug2("set_newkeys: mode %d", mode);
if (mode == MODE_OUT) {
ccp = &state->send_context;
crypt_type = CIPHER_ENCRYPT;
ps = &state->p_send;
max_blocks = &state->max_blocks_out;
} else {
ccp = &state->receive_context;
crypt_type = CIPHER_DECRYPT;
ps = &state->p_read;
max_blocks = &state->max_blocks_in;
}
if (state->newkeys[mode] != NULL) {
debug_f("rekeying %s, input %llu bytes %llu blocks, "
- "output %llu bytes %llu blocks", dir,
- (unsigned long long)state->p_read.bytes,
- (unsigned long long)state->p_read.blocks,
- (unsigned long long)state->p_send.bytes,
- (unsigned long long)state->p_send.blocks);
+ "output %llu bytes %llu blocks", dir,
+ (unsigned long long)state->p_read.bytes,
+ (unsigned long long)state->p_read.blocks,
+ (unsigned long long)state->p_send.bytes,
+ (unsigned long long)state->p_send.blocks);
kex_free_newkeys(state->newkeys[mode]);
state->newkeys[mode] = NULL;
}
/* note that both bytes and the seqnr are not reset */
ps->packets = ps->blocks = 0;
/* move newkeys from kex to state */
if ((state->newkeys[mode] = ssh->kex->newkeys[mode]) == NULL)
return SSH_ERR_INTERNAL_ERROR;
ssh->kex->newkeys[mode] = NULL;
enc = &state->newkeys[mode]->enc;
mac = &state->newkeys[mode]->mac;
comp = &state->newkeys[mode]->comp;
if (cipher_authlen(enc->cipher) == 0) {
if ((r = mac_init(mac)) != 0)
return r;
}
mac->enabled = 1;
DBG(debug_f("cipher_init_context: %s", dir));
cipher_free(*ccp);
*ccp = NULL;
if ((r = cipher_init(ccp, enc->cipher, enc->key, enc->key_len,
enc->iv, enc->iv_len, crypt_type)) != 0)
return r;
if (!state->cipher_warning_done &&
(wmsg = cipher_warning_message(*ccp)) != NULL) {
error("Warning: %s", wmsg);
state->cipher_warning_done = 1;
}
/* Deleting the keys does not gain extra security */
/* explicit_bzero(enc->iv, enc->block_size);
explicit_bzero(enc->key, enc->key_len);
explicit_bzero(mac->key, mac->key_len); */
if ((comp->type == COMP_ZLIB ||
(comp->type == COMP_DELAYED &&
- state->after_authentication)) && comp->enabled == 0) {
+ state->after_authentication)) && comp->enabled == 0) {
if ((r = ssh_packet_init_compression(ssh)) < 0)
return r;
if (mode == MODE_OUT) {
if ((r = start_compression_out(ssh, 6)) != 0)
return r;
} else {
if ((r = start_compression_in(ssh)) != 0)
return r;
}
comp->enabled = 1;
}
/*
* The 2^(blocksize*2) limit is too expensive for 3DES,
* so enforce a 1GB limit for small blocksizes.
* See RFC4344 section 3.2.
*/
if (enc->block_size >= 16)
*max_blocks = (u_int64_t)1 << (enc->block_size*2);
else
*max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
if (state->rekey_limit)
*max_blocks = MINIMUM(*max_blocks,
state->rekey_limit / enc->block_size);
debug("rekey %s after %llu blocks", dir,
(unsigned long long)*max_blocks);
return 0;
}
#define MAX_PACKETS (1U<<31)
static int
ssh_packet_need_rekeying(struct ssh *ssh, u_int outbound_packet_len)
{
struct session_state *state = ssh->state;
u_int32_t out_blocks;
/* XXX client can't cope with rekeying pre-auth */
if (!state->after_authentication)
return 0;
/* Haven't keyed yet or KEX in progress. */
if (ssh_packet_is_rekeying(ssh))
return 0;
/* Peer can't rekey */
if (ssh->compat & SSH_BUG_NOREKEY)
return 0;
/*
* Permit one packet in or out per rekey - this allows us to
* make progress when rekey limits are very small.
*/
if (state->p_send.packets == 0 && state->p_read.packets == 0)
return 0;
/* Time-based rekeying */
if (state->rekey_interval != 0 &&
(int64_t)state->rekey_time + state->rekey_interval <= monotime())
return 1;
/*
* Always rekey when MAX_PACKETS sent in either direction
* As per RFC4344 section 3.1 we do this after 2^31 packets.
*/
if (state->p_send.packets > MAX_PACKETS ||
state->p_read.packets > MAX_PACKETS)
return 1;
/* Rekey after (cipher-specific) maximum blocks */
out_blocks = ROUNDUP(outbound_packet_len,
state->newkeys[MODE_OUT]->enc.block_size);
return (state->max_blocks_out &&
(state->p_send.blocks + out_blocks > state->max_blocks_out)) ||
(state->max_blocks_in &&
(state->p_read.blocks > state->max_blocks_in));
}
/*
* Delayed compression for SSH2 is enabled after authentication:
* This happens on the server side after a SSH2_MSG_USERAUTH_SUCCESS is sent,
* and on the client side after a SSH2_MSG_USERAUTH_SUCCESS is received.
*/
static int
ssh_packet_enable_delayed_compress(struct ssh *ssh)
{
struct session_state *state = ssh->state;
struct sshcomp *comp = NULL;
int r, mode;
/*
* Remember that we are past the authentication step, so rekeying
* with COMP_DELAYED will turn on compression immediately.
*/
state->after_authentication = 1;
for (mode = 0; mode < MODE_MAX; mode++) {
/* protocol error: USERAUTH_SUCCESS received before NEWKEYS */
if (state->newkeys[mode] == NULL)
continue;
comp = &state->newkeys[mode]->comp;
if (comp && !comp->enabled && comp->type == COMP_DELAYED) {
if ((r = ssh_packet_init_compression(ssh)) != 0)
return r;
if (mode == MODE_OUT) {
if ((r = start_compression_out(ssh, 6)) != 0)
return r;
} else {
if ((r = start_compression_in(ssh)) != 0)
return r;
}
comp->enabled = 1;
}
}
return 0;
}
/* Used to mute debug logging for noisy packet types */
int
ssh_packet_log_type(u_char type)
{
switch (type) {
case SSH2_MSG_CHANNEL_DATA:
case SSH2_MSG_CHANNEL_EXTENDED_DATA:
case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
return 0;
default:
return 1;
}
}
/*
* Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
*/
int
ssh_packet_send2_wrapped(struct ssh *ssh)
{
struct session_state *state = ssh->state;
u_char type, *cp, macbuf[SSH_DIGEST_MAX_LENGTH];
u_char tmp, padlen, pad = 0;
u_int authlen = 0, aadlen = 0;
u_int len;
struct sshenc *enc = NULL;
struct sshmac *mac = NULL;
struct sshcomp *comp = NULL;
int r, block_size;
if (state->newkeys[MODE_OUT] != NULL) {
enc = &state->newkeys[MODE_OUT]->enc;
mac = &state->newkeys[MODE_OUT]->mac;
comp = &state->newkeys[MODE_OUT]->comp;
/* disable mac for authenticated encryption */
if ((authlen = cipher_authlen(enc->cipher)) != 0)
mac = NULL;
}
block_size = enc ? enc->block_size : 8;
aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0;
type = (sshbuf_ptr(state->outgoing_packet))[5];
if (ssh_packet_log_type(type))
debug3("send packet: type %u", type);
#ifdef PACKET_DEBUG
fprintf(stderr, "plain: ");
sshbuf_dump(state->outgoing_packet, stderr);
#endif
if (comp && comp->enabled) {
len = sshbuf_len(state->outgoing_packet);
/* skip header, compress only payload */
if ((r = sshbuf_consume(state->outgoing_packet, 5)) != 0)
goto out;
sshbuf_reset(state->compression_buffer);
if ((r = compress_buffer(ssh, state->outgoing_packet,
state->compression_buffer)) != 0)
goto out;
sshbuf_reset(state->outgoing_packet);
if ((r = sshbuf_put(state->outgoing_packet,
"\0\0\0\0\0", 5)) != 0 ||
(r = sshbuf_putb(state->outgoing_packet,
state->compression_buffer)) != 0)
goto out;
DBG(debug("compression: raw %d compressed %zd", len,
sshbuf_len(state->outgoing_packet)));
}
/* sizeof (packet_len + pad_len + payload) */
len = sshbuf_len(state->outgoing_packet);
/*
* calc size of padding, alloc space, get random data,
* minimum padding is 4 bytes
*/
len -= aadlen; /* packet length is not encrypted for EtM modes */
padlen = block_size - (len % block_size);
if (padlen < 4)
padlen += block_size;
if (state->extra_pad) {
tmp = state->extra_pad;
state->extra_pad =
ROUNDUP(state->extra_pad, block_size);
/* check if roundup overflowed */
if (state->extra_pad < tmp)
return SSH_ERR_INVALID_ARGUMENT;
tmp = (len + padlen) % state->extra_pad;
/* Check whether pad calculation below will underflow */
if (tmp > state->extra_pad)
return SSH_ERR_INVALID_ARGUMENT;
pad = state->extra_pad - tmp;
DBG(debug3_f("adding %d (len %d padlen %d extra_pad %d)",
pad, len, padlen, state->extra_pad));
tmp = padlen;
padlen += pad;
/* Check whether padlen calculation overflowed */
if (padlen < tmp)
return SSH_ERR_INVALID_ARGUMENT; /* overflow */
state->extra_pad = 0;
}
if ((r = sshbuf_reserve(state->outgoing_packet, padlen, &cp)) != 0)
goto out;
if (enc && !cipher_ctx_is_plaintext(state->send_context)) {
/* random padding */
arc4random_buf(cp, padlen);
} else {
/* clear padding */
explicit_bzero(cp, padlen);
}
/* sizeof (packet_len + pad_len + payload + padding) */
len = sshbuf_len(state->outgoing_packet);
cp = sshbuf_mutable_ptr(state->outgoing_packet);
if (cp == NULL) {
r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
/* packet_length includes payload, padding and padding length field */
POKE_U32(cp, len - 4);
cp[4] = padlen;
DBG(debug("send: len %d (includes padlen %d, aadlen %d)",
len, padlen, aadlen));
/* compute MAC over seqnr and packet(length fields, payload, padding) */
if (mac && mac->enabled && !mac->etm) {
if ((r = mac_compute(mac, state->p_send.seqnr,
sshbuf_ptr(state->outgoing_packet), len,
macbuf, sizeof(macbuf))) != 0)
goto out;
DBG(debug("done calc MAC out #%d", state->p_send.seqnr));
}
/* encrypt packet and append to output buffer. */
if ((r = sshbuf_reserve(state->output,
sshbuf_len(state->outgoing_packet) + authlen, &cp)) != 0)
goto out;
if ((r = cipher_crypt(state->send_context, state->p_send.seqnr, cp,
sshbuf_ptr(state->outgoing_packet),
len - aadlen, aadlen, authlen)) != 0)
goto out;
/* append unencrypted MAC */
if (mac && mac->enabled) {
if (mac->etm) {
/* EtM: compute mac over aadlen + cipher text */
if ((r = mac_compute(mac, state->p_send.seqnr,
cp, len, macbuf, sizeof(macbuf))) != 0)
goto out;
DBG(debug("done calc MAC(EtM) out #%d",
state->p_send.seqnr));
}
if ((r = sshbuf_put(state->output, macbuf, mac->mac_len)) != 0)
goto out;
}
#ifdef PACKET_DEBUG
fprintf(stderr, "encrypted: ");
sshbuf_dump(state->output, stderr);
#endif
/* increment sequence number for outgoing packets */
if (++state->p_send.seqnr == 0)
logit("outgoing seqnr wraps around");
if (++state->p_send.packets == 0)
if (!(ssh->compat & SSH_BUG_NOREKEY))
return SSH_ERR_NEED_REKEY;
state->p_send.blocks += len / block_size;
state->p_send.bytes += len;
sshbuf_reset(state->outgoing_packet);
if (type == SSH2_MSG_NEWKEYS)
r = ssh_set_newkeys(ssh, MODE_OUT);
else if (type == SSH2_MSG_USERAUTH_SUCCESS && state->server_side)
r = ssh_packet_enable_delayed_compress(ssh);
else
r = 0;
out:
return r;
}
/* returns non-zero if the specified packet type is usec by KEX */
static int
ssh_packet_type_is_kex(u_char type)
{
return
type >= SSH2_MSG_TRANSPORT_MIN &&
type <= SSH2_MSG_TRANSPORT_MAX &&
type != SSH2_MSG_SERVICE_REQUEST &&
type != SSH2_MSG_SERVICE_ACCEPT &&
type != SSH2_MSG_EXT_INFO;
}
int
ssh_packet_send2(struct ssh *ssh)
{
struct session_state *state = ssh->state;
struct packet *p;
u_char type;
int r, need_rekey;
if (sshbuf_len(state->outgoing_packet) < 6)
return SSH_ERR_INTERNAL_ERROR;
type = sshbuf_ptr(state->outgoing_packet)[5];
need_rekey = !ssh_packet_type_is_kex(type) &&
ssh_packet_need_rekeying(ssh, sshbuf_len(state->outgoing_packet));
/*
* During rekeying we can only send key exchange messages.
* Queue everything else.
*/
if ((need_rekey || state->rekeying) && !ssh_packet_type_is_kex(type)) {
if (need_rekey)
debug3_f("rekex triggered");
debug("enqueue packet: %u", type);
p = calloc(1, sizeof(*p));
if (p == NULL)
return SSH_ERR_ALLOC_FAIL;
p->type = type;
p->payload = state->outgoing_packet;
TAILQ_INSERT_TAIL(&state->outgoing, p, next);
state->outgoing_packet = sshbuf_new();
if (state->outgoing_packet == NULL)
return SSH_ERR_ALLOC_FAIL;
if (need_rekey) {
/*
* This packet triggered a rekey, so send the
* KEXINIT now.
* NB. reenters this function via kex_start_rekex().
*/
return kex_start_rekex(ssh);
}
return 0;
}
/* rekeying starts with sending KEXINIT */
if (type == SSH2_MSG_KEXINIT)
state->rekeying = 1;
if ((r = ssh_packet_send2_wrapped(ssh)) != 0)
return r;
/* after a NEWKEYS message we can send the complete queue */
if (type == SSH2_MSG_NEWKEYS) {
state->rekeying = 0;
state->rekey_time = monotime();
while ((p = TAILQ_FIRST(&state->outgoing))) {
type = p->type;
/*
* If this packet triggers a rekex, then skip the
* remaining packets in the queue for now.
* NB. re-enters this function via kex_start_rekex.
*/
if (ssh_packet_need_rekeying(ssh,
sshbuf_len(p->payload))) {
debug3_f("queued packet triggered rekex");
return kex_start_rekex(ssh);
}
debug("dequeue packet: %u", type);
sshbuf_free(state->outgoing_packet);
state->outgoing_packet = p->payload;
TAILQ_REMOVE(&state->outgoing, p, next);
memset(p, 0, sizeof(*p));
free(p);
if ((r = ssh_packet_send2_wrapped(ssh)) != 0)
return r;
}
}
return 0;
}
/*
* Waits until a packet has been received, and returns its type. Note that
* no other data is processed until this returns, so this function should not
* be used during the interactive session.
*/
int
ssh_packet_read_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
{
struct session_state *state = ssh->state;
int len, r, ms_remain;
fd_set *setp;
char buf[8192];
struct timeval timeout, start, *timeoutp = NULL;
DBG(debug("packet_read()"));
setp = calloc(howmany(state->connection_in + 1,
NFDBITS), sizeof(fd_mask));
if (setp == NULL)
return SSH_ERR_ALLOC_FAIL;
/*
* Since we are blocking, ensure that all written packets have
* been sent.
*/
if ((r = ssh_packet_write_wait(ssh)) != 0)
goto out;
/* Stay in the loop until we have received a complete packet. */
for (;;) {
/* Try to read a packet from the buffer. */
r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p);
if (r != 0)
break;
/* If we got a packet, return it. */
if (*typep != SSH_MSG_NONE)
break;
/*
* Otherwise, wait for some data to arrive, add it to the
* buffer, and try again.
*/
memset(setp, 0, howmany(state->connection_in + 1,
NFDBITS) * sizeof(fd_mask));
FD_SET(state->connection_in, setp);
if (state->packet_timeout_ms > 0) {
ms_remain = state->packet_timeout_ms;
timeoutp = &timeout;
}
/* Wait for some data to arrive. */
for (;;) {
if (state->packet_timeout_ms > 0) {
ms_to_timeval(&timeout, ms_remain);
monotime_tv(&start);
}
if ((r = select(state->connection_in + 1, setp,
NULL, NULL, timeoutp)) >= 0)
break;
if (errno != EAGAIN && errno != EINTR &&
errno != EWOULDBLOCK) {
r = SSH_ERR_SYSTEM_ERROR;
goto out;
}
if (state->packet_timeout_ms <= 0)
continue;
ms_subtract_diff(&start, &ms_remain);
if (ms_remain <= 0) {
r = 0;
break;
}
}
if (r == 0) {
r = SSH_ERR_CONN_TIMEOUT;
goto out;
}
/* Read data from the socket. */
len = read(state->connection_in, buf, sizeof(buf));
if (len == 0) {
r = SSH_ERR_CONN_CLOSED;
goto out;
}
if (len == -1) {
r = SSH_ERR_SYSTEM_ERROR;
goto out;
}
/* Append it to the buffer. */
if ((r = ssh_packet_process_incoming(ssh, buf, len)) != 0)
goto out;
}
out:
free(setp);
return r;
}
int
ssh_packet_read(struct ssh *ssh)
{
u_char type;
int r;
if ((r = ssh_packet_read_seqnr(ssh, &type, NULL)) != 0)
fatal_fr(r, "read");
return type;
}
/*
* Waits until a packet has been received, verifies that its type matches
* that given, and gives a fatal error and exits if there is a mismatch.
*/
int
ssh_packet_read_expect(struct ssh *ssh, u_int expected_type)
{
int r;
u_char type;
if ((r = ssh_packet_read_seqnr(ssh, &type, NULL)) != 0)
return r;
if (type != expected_type) {
if ((r = sshpkt_disconnect(ssh,
"Protocol error: expected packet type %d, got %d",
expected_type, type)) != 0)
return r;
return SSH_ERR_PROTOCOL_ERROR;
}
return 0;
}
static int
ssh_packet_read_poll2_mux(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
{
struct session_state *state = ssh->state;
const u_char *cp;
size_t need;
int r;
if (ssh->kex)
return SSH_ERR_INTERNAL_ERROR;
*typep = SSH_MSG_NONE;
cp = sshbuf_ptr(state->input);
if (state->packlen == 0) {
if (sshbuf_len(state->input) < 4 + 1)
return 0; /* packet is incomplete */
state->packlen = PEEK_U32(cp);
if (state->packlen < 4 + 1 ||
state->packlen > PACKET_MAX_SIZE)
return SSH_ERR_MESSAGE_INCOMPLETE;
}
need = state->packlen + 4;
if (sshbuf_len(state->input) < need)
return 0; /* packet is incomplete */
sshbuf_reset(state->incoming_packet);
if ((r = sshbuf_put(state->incoming_packet, cp + 4,
state->packlen)) != 0 ||
(r = sshbuf_consume(state->input, need)) != 0 ||
(r = sshbuf_get_u8(state->incoming_packet, NULL)) != 0 ||
(r = sshbuf_get_u8(state->incoming_packet, typep)) != 0)
return r;
if (ssh_packet_log_type(*typep))
debug3_f("type %u", *typep);
/* sshbuf_dump(state->incoming_packet, stderr); */
/* reset for next packet */
state->packlen = 0;
return r;
}
int
ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
{
struct session_state *state = ssh->state;
u_int padlen, need;
u_char *cp;
u_int maclen, aadlen = 0, authlen = 0, block_size;
struct sshenc *enc = NULL;
struct sshmac *mac = NULL;
struct sshcomp *comp = NULL;
int r;
if (state->mux)
return ssh_packet_read_poll2_mux(ssh, typep, seqnr_p);
*typep = SSH_MSG_NONE;
if (state->packet_discard)
return 0;
if (state->newkeys[MODE_IN] != NULL) {
enc = &state->newkeys[MODE_IN]->enc;
mac = &state->newkeys[MODE_IN]->mac;
comp = &state->newkeys[MODE_IN]->comp;
/* disable mac for authenticated encryption */
if ((authlen = cipher_authlen(enc->cipher)) != 0)
mac = NULL;
}
maclen = mac && mac->enabled ? mac->mac_len : 0;
block_size = enc ? enc->block_size : 8;
aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0;
if (aadlen && state->packlen == 0) {
if (cipher_get_length(state->receive_context,
&state->packlen, state->p_read.seqnr,
sshbuf_ptr(state->input), sshbuf_len(state->input)) != 0)
return 0;
if (state->packlen < 1 + 4 ||
state->packlen > PACKET_MAX_SIZE) {
#ifdef PACKET_DEBUG
sshbuf_dump(state->input, stderr);
#endif
logit("Bad packet length %u.", state->packlen);
if ((r = sshpkt_disconnect(ssh, "Packet corrupt")) != 0)
return r;
return SSH_ERR_CONN_CORRUPT;
}
sshbuf_reset(state->incoming_packet);
} else if (state->packlen == 0) {
/*
* check if input size is less than the cipher block size,
* decrypt first block and extract length of incoming packet
*/
if (sshbuf_len(state->input) < block_size)
return 0;
sshbuf_reset(state->incoming_packet);
if ((r = sshbuf_reserve(state->incoming_packet, block_size,
&cp)) != 0)
goto out;
if ((r = cipher_crypt(state->receive_context,
state->p_send.seqnr, cp, sshbuf_ptr(state->input),
block_size, 0, 0)) != 0)
goto out;
state->packlen = PEEK_U32(sshbuf_ptr(state->incoming_packet));
if (state->packlen < 1 + 4 ||
state->packlen > PACKET_MAX_SIZE) {
#ifdef PACKET_DEBUG
fprintf(stderr, "input: \n");
sshbuf_dump(state->input, stderr);
fprintf(stderr, "incoming_packet: \n");
sshbuf_dump(state->incoming_packet, stderr);
#endif
logit("Bad packet length %u.", state->packlen);
return ssh_packet_start_discard(ssh, enc, mac, 0,
PACKET_MAX_SIZE);
}
if ((r = sshbuf_consume(state->input, block_size)) != 0)
goto out;
}
DBG(debug("input: packet len %u", state->packlen+4));
if (aadlen) {
/* only the payload is encrypted */
need = state->packlen;
} else {
/*
* the payload size and the payload are encrypted, but we
* have a partial packet of block_size bytes
*/
need = 4 + state->packlen - block_size;
}
DBG(debug("partial packet: block %d, need %d, maclen %d, authlen %d,"
" aadlen %d", block_size, need, maclen, authlen, aadlen));
if (need % block_size != 0) {
logit("padding error: need %d block %d mod %d",
need, block_size, need % block_size);
return ssh_packet_start_discard(ssh, enc, mac, 0,
PACKET_MAX_SIZE - block_size);
}
/*
* check if the entire packet has been received and
* decrypt into incoming_packet:
* 'aadlen' bytes are unencrypted, but authenticated.
* 'need' bytes are encrypted, followed by either
* 'authlen' bytes of authentication tag or
* 'maclen' bytes of message authentication code.
*/
if (sshbuf_len(state->input) < aadlen + need + authlen + maclen)
return 0; /* packet is incomplete */
#ifdef PACKET_DEBUG
fprintf(stderr, "read_poll enc/full: ");
sshbuf_dump(state->input, stderr);
#endif
/* EtM: check mac over encrypted input */
if (mac && mac->enabled && mac->etm) {
if ((r = mac_check(mac, state->p_read.seqnr,
sshbuf_ptr(state->input), aadlen + need,
sshbuf_ptr(state->input) + aadlen + need + authlen,
maclen)) != 0) {
if (r == SSH_ERR_MAC_INVALID)
logit("Corrupted MAC on input.");
goto out;
}
}
if ((r = sshbuf_reserve(state->incoming_packet, aadlen + need,
&cp)) != 0)
goto out;
if ((r = cipher_crypt(state->receive_context, state->p_read.seqnr, cp,
sshbuf_ptr(state->input), need, aadlen, authlen)) != 0)
goto out;
if ((r = sshbuf_consume(state->input, aadlen + need + authlen)) != 0)
goto out;
if (mac && mac->enabled) {
/* Not EtM: check MAC over cleartext */
if (!mac->etm && (r = mac_check(mac, state->p_read.seqnr,
sshbuf_ptr(state->incoming_packet),
sshbuf_len(state->incoming_packet),
sshbuf_ptr(state->input), maclen)) != 0) {
if (r != SSH_ERR_MAC_INVALID)
goto out;
logit("Corrupted MAC on input.");
if (need + block_size > PACKET_MAX_SIZE)
return SSH_ERR_INTERNAL_ERROR;
return ssh_packet_start_discard(ssh, enc, mac,
sshbuf_len(state->incoming_packet),
PACKET_MAX_SIZE - need - block_size);
}
/* Remove MAC from input buffer */
DBG(debug("MAC #%d ok", state->p_read.seqnr));
if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0)
goto out;
}
if (seqnr_p != NULL)
*seqnr_p = state->p_read.seqnr;
if (++state->p_read.seqnr == 0)
logit("incoming seqnr wraps around");
if (++state->p_read.packets == 0)
if (!(ssh->compat & SSH_BUG_NOREKEY))
return SSH_ERR_NEED_REKEY;
state->p_read.blocks += (state->packlen + 4) / block_size;
state->p_read.bytes += state->packlen + 4;
/* get padlen */
padlen = sshbuf_ptr(state->incoming_packet)[4];
DBG(debug("input: padlen %d", padlen));
if (padlen < 4) {
if ((r = sshpkt_disconnect(ssh,
"Corrupted padlen %d on input.", padlen)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
return r;
return SSH_ERR_CONN_CORRUPT;
}
/* skip packet size + padlen, discard padding */
if ((r = sshbuf_consume(state->incoming_packet, 4 + 1)) != 0 ||
((r = sshbuf_consume_end(state->incoming_packet, padlen)) != 0))
goto out;
DBG(debug("input: len before de-compress %zd",
sshbuf_len(state->incoming_packet)));
if (comp && comp->enabled) {
sshbuf_reset(state->compression_buffer);
if ((r = uncompress_buffer(ssh, state->incoming_packet,
state->compression_buffer)) != 0)
goto out;
sshbuf_reset(state->incoming_packet);
if ((r = sshbuf_putb(state->incoming_packet,
state->compression_buffer)) != 0)
goto out;
DBG(debug("input: len after de-compress %zd",
sshbuf_len(state->incoming_packet)));
}
/*
* get packet type, implies consume.
* return length of payload (without type field)
*/
if ((r = sshbuf_get_u8(state->incoming_packet, typep)) != 0)
goto out;
if (ssh_packet_log_type(*typep))
debug3("receive packet: type %u", *typep);
if (*typep < SSH2_MSG_MIN || *typep >= SSH2_MSG_LOCAL_MIN) {
if ((r = sshpkt_disconnect(ssh,
"Invalid ssh2 packet type: %d", *typep)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
return r;
return SSH_ERR_PROTOCOL_ERROR;
}
if (state->hook_in != NULL &&
(r = state->hook_in(ssh, state->incoming_packet, typep,
state->hook_in_ctx)) != 0)
return r;
if (*typep == SSH2_MSG_USERAUTH_SUCCESS && !state->server_side)
r = ssh_packet_enable_delayed_compress(ssh);
else
r = 0;
#ifdef PACKET_DEBUG
fprintf(stderr, "read/plain[%d]:\r\n", *typep);
sshbuf_dump(state->incoming_packet, stderr);
#endif
/* reset for next packet */
state->packlen = 0;
/* do we need to rekey? */
if (ssh_packet_need_rekeying(ssh, 0)) {
debug3_f("rekex triggered");
if ((r = kex_start_rekex(ssh)) != 0)
return r;
}
out:
return r;
}
int
ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
{
struct session_state *state = ssh->state;
u_int reason, seqnr;
int r;
u_char *msg;
for (;;) {
msg = NULL;
r = ssh_packet_read_poll2(ssh, typep, seqnr_p);
if (r != 0)
return r;
if (*typep) {
state->keep_alive_timeouts = 0;
DBG(debug("received packet type %d", *typep));
}
switch (*typep) {
case SSH2_MSG_IGNORE:
debug3("Received SSH2_MSG_IGNORE");
break;
case SSH2_MSG_DEBUG:
if ((r = sshpkt_get_u8(ssh, NULL)) != 0 ||
(r = sshpkt_get_string(ssh, &msg, NULL)) != 0 ||
(r = sshpkt_get_string(ssh, NULL, NULL)) != 0) {
free(msg);
return r;
}
debug("Remote: %.900s", msg);
free(msg);
break;
case SSH2_MSG_DISCONNECT:
if ((r = sshpkt_get_u32(ssh, &reason)) != 0 ||
(r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
return r;
/* Ignore normal client exit notifications */
do_log2(ssh->state->server_side &&
reason == SSH2_DISCONNECT_BY_APPLICATION ?
SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR,
"Received disconnect from %s port %d:"
"%u: %.400s", ssh_remote_ipaddr(ssh),
ssh_remote_port(ssh), reason, msg);
free(msg);
return SSH_ERR_DISCONNECTED;
case SSH2_MSG_UNIMPLEMENTED:
if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0)
return r;
debug("Received SSH2_MSG_UNIMPLEMENTED for %u",
seqnr);
break;
default:
return 0;
}
}
}
/*
* Buffers the given amount of input characters. This is intended to be used
* together with packet_read_poll.
*/
int
ssh_packet_process_incoming(struct ssh *ssh, const char *buf, u_int len)
{
struct session_state *state = ssh->state;
int r;
if (state->packet_discard) {
state->keep_alive_timeouts = 0; /* ?? */
if (len >= state->packet_discard) {
if ((r = ssh_packet_stop_discard(ssh)) != 0)
return r;
}
state->packet_discard -= len;
return 0;
}
if ((r = sshbuf_put(ssh->state->input, buf, len)) != 0)
return r;
return 0;
}
int
ssh_packet_remaining(struct ssh *ssh)
{
return sshbuf_len(ssh->state->incoming_packet);
}
/*
* Sends a diagnostic message from the server to the client. This message
* can be sent at any time (but not while constructing another message). The
* message is printed immediately, but only if the client is being executed
* in verbose mode. These messages are primarily intended to ease debugging
* authentication problems. The length of the formatted message must not
* exceed 1024 bytes. This will automatically call ssh_packet_write_wait.
*/
void
ssh_packet_send_debug(struct ssh *ssh, const char *fmt,...)
{
char buf[1024];
va_list args;
int r;
if ((ssh->compat & SSH_BUG_DEBUG))
return;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
debug3("sending debug message: %s", buf);
if ((r = sshpkt_start(ssh, SSH2_MSG_DEBUG)) != 0 ||
(r = sshpkt_put_u8(ssh, 0)) != 0 || /* always display */
(r = sshpkt_put_cstring(ssh, buf)) != 0 ||
(r = sshpkt_put_cstring(ssh, "")) != 0 ||
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
fatal_fr(r, "send DEBUG");
}
void
sshpkt_fmt_connection_id(struct ssh *ssh, char *s, size_t l)
{
snprintf(s, l, "%.200s%s%s port %d",
ssh->log_preamble ? ssh->log_preamble : "",
ssh->log_preamble ? " " : "",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
}
/*
* Pretty-print connection-terminating errors and exit.
*/
static void
sshpkt_vfatal(struct ssh *ssh, int r, const char *fmt, va_list ap)
{
char *tag = NULL, remote_id[512];
int oerrno = errno;
sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
switch (r) {
case SSH_ERR_CONN_CLOSED:
ssh_packet_clear_keys(ssh);
logdie("Connection closed by %s", remote_id);
case SSH_ERR_CONN_TIMEOUT:
ssh_packet_clear_keys(ssh);
logdie("Connection %s %s timed out",
ssh->state->server_side ? "from" : "to", remote_id);
case SSH_ERR_DISCONNECTED:
ssh_packet_clear_keys(ssh);
logdie("Disconnected from %s", remote_id);
case SSH_ERR_SYSTEM_ERROR:
if (errno == ECONNRESET) {
ssh_packet_clear_keys(ssh);
logdie("Connection reset by %s", remote_id);
}
/* FALLTHROUGH */
case SSH_ERR_NO_CIPHER_ALG_MATCH:
case SSH_ERR_NO_MAC_ALG_MATCH:
case SSH_ERR_NO_COMPRESS_ALG_MATCH:
case SSH_ERR_NO_KEX_ALG_MATCH:
case SSH_ERR_NO_HOSTKEY_ALG_MATCH:
if (ssh && ssh->kex && ssh->kex->failed_choice) {
ssh_packet_clear_keys(ssh);
errno = oerrno;
logdie("Unable to negotiate with %s: %s. "
"Their offer: %s", remote_id, ssh_err(r),
ssh->kex->failed_choice);
}
/* FALLTHROUGH */
default:
if (vasprintf(&tag, fmt, ap) == -1) {
ssh_packet_clear_keys(ssh);
logdie_f("could not allocate failure message");
}
ssh_packet_clear_keys(ssh);
errno = oerrno;
logdie_r(r, "%s%sConnection %s %s",
tag != NULL ? tag : "", tag != NULL ? ": " : "",
ssh->state->server_side ? "from" : "to", remote_id);
}
}
void
sshpkt_fatal(struct ssh *ssh, int r, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
sshpkt_vfatal(ssh, r, fmt, ap);
/* NOTREACHED */
va_end(ap);
logdie_f("should have exited");
}
/*
* Logs the error plus constructs and sends a disconnect packet, closes the
* connection, and exits. This function never returns. The error message
* should not contain a newline. The length of the formatted message must
* not exceed 1024 bytes.
*/
void
ssh_packet_disconnect(struct ssh *ssh, const char *fmt,...)
{
char buf[1024], remote_id[512];
va_list args;
static int disconnecting = 0;
int r;
if (disconnecting) /* Guard against recursive invocations. */
fatal("packet_disconnect called recursively.");
disconnecting = 1;
/*
* Format the message. Note that the caller must make sure the
* message is of limited size.
*/
sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
/* Display the error locally */
logit("Disconnecting %s: %.100s", remote_id, buf);
/*
* Send the disconnect message to the other side, and wait
* for it to get sent.
*/
if ((r = sshpkt_disconnect(ssh, "%s", buf)) != 0)
sshpkt_fatal(ssh, r, "%s", __func__);
if ((r = ssh_packet_write_wait(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s", __func__);
/* Close the connection. */
ssh_packet_close(ssh);
cleanup_exit(255);
}
/*
* Checks if there is any buffered output, and tries to write some of
* the output.
*/
int
ssh_packet_write_poll(struct ssh *ssh)
{
struct session_state *state = ssh->state;
int len = sshbuf_len(state->output);
int r;
if (len > 0) {
len = write(state->connection_out,
sshbuf_ptr(state->output), len);
if (len == -1) {
if (errno == EINTR || errno == EAGAIN ||
errno == EWOULDBLOCK)
return 0;
return SSH_ERR_SYSTEM_ERROR;
}
if (len == 0)
return SSH_ERR_CONN_CLOSED;
if ((r = sshbuf_consume(state->output, len)) != 0)
return r;
}
return 0;
}
/*
* Calls packet_write_poll repeatedly until all pending output data has been
* written.
*/
int
ssh_packet_write_wait(struct ssh *ssh)
{
fd_set *setp;
int ret, r, ms_remain = 0;
struct timeval start, timeout, *timeoutp = NULL;
struct session_state *state = ssh->state;
setp = calloc(howmany(state->connection_out + 1,
NFDBITS), sizeof(fd_mask));
if (setp == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = ssh_packet_write_poll(ssh)) != 0) {
free(setp);
return r;
}
while (ssh_packet_have_data_to_write(ssh)) {
memset(setp, 0, howmany(state->connection_out + 1,
NFDBITS) * sizeof(fd_mask));
FD_SET(state->connection_out, setp);
if (state->packet_timeout_ms > 0) {
ms_remain = state->packet_timeout_ms;
timeoutp = &timeout;
}
for (;;) {
if (state->packet_timeout_ms > 0) {
ms_to_timeval(&timeout, ms_remain);
monotime_tv(&start);
}
if ((ret = select(state->connection_out + 1,
NULL, setp, NULL, timeoutp)) >= 0)
break;
if (errno != EAGAIN && errno != EINTR &&
errno != EWOULDBLOCK)
break;
if (state->packet_timeout_ms <= 0)
continue;
ms_subtract_diff(&start, &ms_remain);
if (ms_remain <= 0) {
ret = 0;
break;
}
}
if (ret == 0) {
free(setp);
return SSH_ERR_CONN_TIMEOUT;
}
if ((r = ssh_packet_write_poll(ssh)) != 0) {
free(setp);
return r;
}
}
free(setp);
return 0;
}
/* Returns true if there is buffered data to write to the connection. */
int
ssh_packet_have_data_to_write(struct ssh *ssh)
{
return sshbuf_len(ssh->state->output) != 0;
}
/* Returns true if there is not too much data to write to the connection. */
int
ssh_packet_not_very_much_data_to_write(struct ssh *ssh)
{
if (ssh->state->interactive_mode)
return sshbuf_len(ssh->state->output) < 16384;
else
return sshbuf_len(ssh->state->output) < 128 * 1024;
}
void
ssh_packet_set_tos(struct ssh *ssh, int tos)
{
if (!ssh_packet_connection_is_on_socket(ssh) || tos == INT_MAX)
return;
set_sock_tos(ssh->state->connection_in, tos);
}
/* Informs that the current session is interactive. Sets IP flags for that. */
void
ssh_packet_set_interactive(struct ssh *ssh, int interactive, int qos_interactive, int qos_bulk)
{
struct session_state *state = ssh->state;
if (state->set_interactive_called)
return;
state->set_interactive_called = 1;
/* Record that we are in interactive mode. */
state->interactive_mode = interactive;
/* Only set socket options if using a socket. */
if (!ssh_packet_connection_is_on_socket(ssh))
return;
set_nodelay(state->connection_in);
ssh_packet_set_tos(ssh, interactive ? qos_interactive : qos_bulk);
}
/* Returns true if the current connection is interactive. */
int
ssh_packet_is_interactive(struct ssh *ssh)
{
return ssh->state->interactive_mode;
}
int
ssh_packet_set_maxsize(struct ssh *ssh, u_int s)
{
struct session_state *state = ssh->state;
if (state->set_maxsize_called) {
logit("packet_set_maxsize: called twice: old %d new %d",
state->max_packet_size, s);
return -1;
}
if (s < 4 * 1024 || s > 1024 * 1024) {
logit("packet_set_maxsize: bad size %d", s);
return -1;
}
state->set_maxsize_called = 1;
debug("packet_set_maxsize: setting to %d", s);
state->max_packet_size = s;
return s;
}
int
ssh_packet_inc_alive_timeouts(struct ssh *ssh)
{
return ++ssh->state->keep_alive_timeouts;
}
void
ssh_packet_set_alive_timeouts(struct ssh *ssh, int ka)
{
ssh->state->keep_alive_timeouts = ka;
}
u_int
ssh_packet_get_maxsize(struct ssh *ssh)
{
return ssh->state->max_packet_size;
}
void
ssh_packet_set_rekey_limits(struct ssh *ssh, u_int64_t bytes, u_int32_t seconds)
{
debug3("rekey after %llu bytes, %u seconds", (unsigned long long)bytes,
(unsigned int)seconds);
ssh->state->rekey_limit = bytes;
ssh->state->rekey_interval = seconds;
}
time_t
ssh_packet_get_rekey_timeout(struct ssh *ssh)
{
time_t seconds;
seconds = ssh->state->rekey_time + ssh->state->rekey_interval -
monotime();
return (seconds <= 0 ? 1 : seconds);
}
void
ssh_packet_set_server(struct ssh *ssh)
{
ssh->state->server_side = 1;
ssh->kex->server = 1; /* XXX unify? */
}
void
ssh_packet_set_authenticated(struct ssh *ssh)
{
ssh->state->after_authentication = 1;
}
void *
ssh_packet_get_input(struct ssh *ssh)
{
return (void *)ssh->state->input;
}
void *
ssh_packet_get_output(struct ssh *ssh)
{
return (void *)ssh->state->output;
}
/* Reset after_authentication and reset compression in post-auth privsep */
static int
ssh_packet_set_postauth(struct ssh *ssh)
{
int r;
debug_f("called");
/* This was set in net child, but is not visible in user child */
ssh->state->after_authentication = 1;
ssh->state->rekeying = 0;
if ((r = ssh_packet_enable_delayed_compress(ssh)) != 0)
return r;
return 0;
}
/* Packet state (de-)serialization for privsep */
/* turn kex into a blob for packet state serialization */
static int
kex_to_blob(struct sshbuf *m, struct kex *kex)
{
int r;
if ((r = sshbuf_put_u32(m, kex->we_need)) != 0 ||
(r = sshbuf_put_cstring(m, kex->hostkey_alg)) != 0 ||
(r = sshbuf_put_u32(m, kex->hostkey_type)) != 0 ||
(r = sshbuf_put_u32(m, kex->hostkey_nid)) != 0 ||
(r = sshbuf_put_u32(m, kex->kex_type)) != 0 ||
(r = sshbuf_put_stringb(m, kex->my)) != 0 ||
(r = sshbuf_put_stringb(m, kex->peer)) != 0 ||
(r = sshbuf_put_stringb(m, kex->client_version)) != 0 ||
(r = sshbuf_put_stringb(m, kex->server_version)) != 0 ||
(r = sshbuf_put_stringb(m, kex->session_id)) != 0 ||
(r = sshbuf_put_u32(m, kex->flags)) != 0)
return r;
return 0;
}
/* turn key exchange results into a blob for packet state serialization */
static int
newkeys_to_blob(struct sshbuf *m, struct ssh *ssh, int mode)
{
struct sshbuf *b;
struct sshcipher_ctx *cc;
struct sshcomp *comp;
struct sshenc *enc;
struct sshmac *mac;
struct newkeys *newkey;
int r;
if ((newkey = ssh->state->newkeys[mode]) == NULL)
return SSH_ERR_INTERNAL_ERROR;
enc = &newkey->enc;
mac = &newkey->mac;
comp = &newkey->comp;
cc = (mode == MODE_OUT) ? ssh->state->send_context :
ssh->state->receive_context;
if ((r = cipher_get_keyiv(cc, enc->iv, enc->iv_len)) != 0)
return r;
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_cstring(b, enc->name)) != 0 ||
(r = sshbuf_put_u32(b, enc->enabled)) != 0 ||
(r = sshbuf_put_u32(b, enc->block_size)) != 0 ||
(r = sshbuf_put_string(b, enc->key, enc->key_len)) != 0 ||
(r = sshbuf_put_string(b, enc->iv, enc->iv_len)) != 0)
goto out;
if (cipher_authlen(enc->cipher) == 0) {
if ((r = sshbuf_put_cstring(b, mac->name)) != 0 ||
(r = sshbuf_put_u32(b, mac->enabled)) != 0 ||
(r = sshbuf_put_string(b, mac->key, mac->key_len)) != 0)
goto out;
}
if ((r = sshbuf_put_u32(b, comp->type)) != 0 ||
(r = sshbuf_put_cstring(b, comp->name)) != 0)
goto out;
r = sshbuf_put_stringb(m, b);
out:
sshbuf_free(b);
return r;
}
/* serialize packet state into a blob */
int
ssh_packet_get_state(struct ssh *ssh, struct sshbuf *m)
{
struct session_state *state = ssh->state;
int r;
if ((r = kex_to_blob(m, ssh->kex)) != 0 ||
(r = newkeys_to_blob(m, ssh, MODE_OUT)) != 0 ||
(r = newkeys_to_blob(m, ssh, MODE_IN)) != 0 ||
(r = sshbuf_put_u64(m, state->rekey_limit)) != 0 ||
(r = sshbuf_put_u32(m, state->rekey_interval)) != 0 ||
(r = sshbuf_put_u32(m, state->p_send.seqnr)) != 0 ||
(r = sshbuf_put_u64(m, state->p_send.blocks)) != 0 ||
(r = sshbuf_put_u32(m, state->p_send.packets)) != 0 ||
(r = sshbuf_put_u64(m, state->p_send.bytes)) != 0 ||
(r = sshbuf_put_u32(m, state->p_read.seqnr)) != 0 ||
(r = sshbuf_put_u64(m, state->p_read.blocks)) != 0 ||
(r = sshbuf_put_u32(m, state->p_read.packets)) != 0 ||
(r = sshbuf_put_u64(m, state->p_read.bytes)) != 0 ||
(r = sshbuf_put_stringb(m, state->input)) != 0 ||
(r = sshbuf_put_stringb(m, state->output)) != 0)
return r;
return 0;
}
/* restore key exchange results from blob for packet state de-serialization */
static int
newkeys_from_blob(struct sshbuf *m, struct ssh *ssh, int mode)
{
struct sshbuf *b = NULL;
struct sshcomp *comp;
struct sshenc *enc;
struct sshmac *mac;
struct newkeys *newkey = NULL;
size_t keylen, ivlen, maclen;
int r;
if ((newkey = calloc(1, sizeof(*newkey))) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_froms(m, &b)) != 0)
goto out;
#ifdef DEBUG_PK
sshbuf_dump(b, stderr);
#endif
enc = &newkey->enc;
mac = &newkey->mac;
comp = &newkey->comp;
if ((r = sshbuf_get_cstring(b, &enc->name, NULL)) != 0 ||
(r = sshbuf_get_u32(b, (u_int *)&enc->enabled)) != 0 ||
(r = sshbuf_get_u32(b, &enc->block_size)) != 0 ||
(r = sshbuf_get_string(b, &enc->key, &keylen)) != 0 ||
(r = sshbuf_get_string(b, &enc->iv, &ivlen)) != 0)
goto out;
if ((enc->cipher = cipher_by_name(enc->name)) == NULL) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (cipher_authlen(enc->cipher) == 0) {
if ((r = sshbuf_get_cstring(b, &mac->name, NULL)) != 0)
goto out;
if ((r = mac_setup(mac, mac->name)) != 0)
goto out;
if ((r = sshbuf_get_u32(b, (u_int *)&mac->enabled)) != 0 ||
(r = sshbuf_get_string(b, &mac->key, &maclen)) != 0)
goto out;
if (maclen > mac->key_len) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
mac->key_len = maclen;
}
if ((r = sshbuf_get_u32(b, &comp->type)) != 0 ||
(r = sshbuf_get_cstring(b, &comp->name, NULL)) != 0)
goto out;
if (sshbuf_len(b) != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
enc->key_len = keylen;
enc->iv_len = ivlen;
ssh->kex->newkeys[mode] = newkey;
newkey = NULL;
r = 0;
out:
free(newkey);
sshbuf_free(b);
return r;
}
/* restore kex from blob for packet state de-serialization */
static int
kex_from_blob(struct sshbuf *m, struct kex **kexp)
{
struct kex *kex;
int r;
if ((kex = kex_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_get_u32(m, &kex->we_need)) != 0 ||
(r = sshbuf_get_cstring(m, &kex->hostkey_alg, NULL)) != 0 ||
(r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_type)) != 0 ||
(r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_nid)) != 0 ||
(r = sshbuf_get_u32(m, &kex->kex_type)) != 0 ||
(r = sshbuf_get_stringb(m, kex->my)) != 0 ||
(r = sshbuf_get_stringb(m, kex->peer)) != 0 ||
(r = sshbuf_get_stringb(m, kex->client_version)) != 0 ||
(r = sshbuf_get_stringb(m, kex->server_version)) != 0 ||
(r = sshbuf_get_stringb(m, kex->session_id)) != 0 ||
(r = sshbuf_get_u32(m, &kex->flags)) != 0)
goto out;
kex->server = 1;
kex->done = 1;
r = 0;
out:
if (r != 0 || kexp == NULL) {
kex_free(kex);
if (kexp != NULL)
*kexp = NULL;
} else {
kex_free(*kexp);
*kexp = kex;
}
return r;
}
/*
* Restore packet state from content of blob 'm' (de-serialization).
* Note that 'm' will be partially consumed on parsing or any other errors.
*/
int
ssh_packet_set_state(struct ssh *ssh, struct sshbuf *m)
{
struct session_state *state = ssh->state;
const u_char *input, *output;
size_t ilen, olen;
int r;
if ((r = kex_from_blob(m, &ssh->kex)) != 0 ||
(r = newkeys_from_blob(m, ssh, MODE_OUT)) != 0 ||
(r = newkeys_from_blob(m, ssh, MODE_IN)) != 0 ||
(r = sshbuf_get_u64(m, &state->rekey_limit)) != 0 ||
(r = sshbuf_get_u32(m, &state->rekey_interval)) != 0 ||
(r = sshbuf_get_u32(m, &state->p_send.seqnr)) != 0 ||
(r = sshbuf_get_u64(m, &state->p_send.blocks)) != 0 ||
(r = sshbuf_get_u32(m, &state->p_send.packets)) != 0 ||
(r = sshbuf_get_u64(m, &state->p_send.bytes)) != 0 ||
(r = sshbuf_get_u32(m, &state->p_read.seqnr)) != 0 ||
(r = sshbuf_get_u64(m, &state->p_read.blocks)) != 0 ||
(r = sshbuf_get_u32(m, &state->p_read.packets)) != 0 ||
(r = sshbuf_get_u64(m, &state->p_read.bytes)) != 0)
return r;
/*
* We set the time here so that in post-auth privsep child we
* count from the completion of the authentication.
*/
state->rekey_time = monotime();
/* XXX ssh_set_newkeys overrides p_read.packets? XXX */
if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0 ||
(r = ssh_set_newkeys(ssh, MODE_OUT)) != 0)
return r;
if ((r = ssh_packet_set_postauth(ssh)) != 0)
return r;
sshbuf_reset(state->input);
sshbuf_reset(state->output);
if ((r = sshbuf_get_string_direct(m, &input, &ilen)) != 0 ||
(r = sshbuf_get_string_direct(m, &output, &olen)) != 0 ||
(r = sshbuf_put(state->input, input, ilen)) != 0 ||
(r = sshbuf_put(state->output, output, olen)) != 0)
return r;
if (sshbuf_len(m))
return SSH_ERR_INVALID_FORMAT;
debug3_f("done");
return 0;
}
/* NEW API */
/* put data to the outgoing packet */
int
sshpkt_put(struct ssh *ssh, const void *v, size_t len)
{
return sshbuf_put(ssh->state->outgoing_packet, v, len);
}
int
sshpkt_putb(struct ssh *ssh, const struct sshbuf *b)
{
return sshbuf_putb(ssh->state->outgoing_packet, b);
}
int
sshpkt_put_u8(struct ssh *ssh, u_char val)
{
return sshbuf_put_u8(ssh->state->outgoing_packet, val);
}
int
sshpkt_put_u32(struct ssh *ssh, u_int32_t val)
{
return sshbuf_put_u32(ssh->state->outgoing_packet, val);
}
int
sshpkt_put_u64(struct ssh *ssh, u_int64_t val)
{
return sshbuf_put_u64(ssh->state->outgoing_packet, val);
}
int
sshpkt_put_string(struct ssh *ssh, const void *v, size_t len)
{
return sshbuf_put_string(ssh->state->outgoing_packet, v, len);
}
int
sshpkt_put_cstring(struct ssh *ssh, const void *v)
{
return sshbuf_put_cstring(ssh->state->outgoing_packet, v);
}
int
sshpkt_put_stringb(struct ssh *ssh, const struct sshbuf *v)
{
return sshbuf_put_stringb(ssh->state->outgoing_packet, v);
}
int
sshpkt_getb_froms(struct ssh *ssh, struct sshbuf **valp)
{
return sshbuf_froms(ssh->state->incoming_packet, valp);
}
#ifdef WITH_OPENSSL
#ifdef OPENSSL_HAS_ECC
int
sshpkt_put_ec(struct ssh *ssh, const EC_POINT *v, const EC_GROUP *g)
{
return sshbuf_put_ec(ssh->state->outgoing_packet, v, g);
}
#endif /* OPENSSL_HAS_ECC */
int
sshpkt_put_bignum2(struct ssh *ssh, const BIGNUM *v)
{
return sshbuf_put_bignum2(ssh->state->outgoing_packet, v);
}
#endif /* WITH_OPENSSL */
/* fetch data from the incoming packet */
int
sshpkt_get(struct ssh *ssh, void *valp, size_t len)
{
return sshbuf_get(ssh->state->incoming_packet, valp, len);
}
int
sshpkt_get_u8(struct ssh *ssh, u_char *valp)
{
return sshbuf_get_u8(ssh->state->incoming_packet, valp);
}
int
sshpkt_get_u32(struct ssh *ssh, u_int32_t *valp)
{
return sshbuf_get_u32(ssh->state->incoming_packet, valp);
}
int
sshpkt_get_u64(struct ssh *ssh, u_int64_t *valp)
{
return sshbuf_get_u64(ssh->state->incoming_packet, valp);
}
int
sshpkt_get_string(struct ssh *ssh, u_char **valp, size_t *lenp)
{
return sshbuf_get_string(ssh->state->incoming_packet, valp, lenp);
}
int
sshpkt_get_string_direct(struct ssh *ssh, const u_char **valp, size_t *lenp)
{
return sshbuf_get_string_direct(ssh->state->incoming_packet, valp, lenp);
}
int
sshpkt_peek_string_direct(struct ssh *ssh, const u_char **valp, size_t *lenp)
{
return sshbuf_peek_string_direct(ssh->state->incoming_packet, valp, lenp);
}
int
sshpkt_get_cstring(struct ssh *ssh, char **valp, size_t *lenp)
{
return sshbuf_get_cstring(ssh->state->incoming_packet, valp, lenp);
}
#ifdef WITH_OPENSSL
#ifdef OPENSSL_HAS_ECC
int
sshpkt_get_ec(struct ssh *ssh, EC_POINT *v, const EC_GROUP *g)
{
return sshbuf_get_ec(ssh->state->incoming_packet, v, g);
}
#endif /* OPENSSL_HAS_ECC */
int
sshpkt_get_bignum2(struct ssh *ssh, BIGNUM **valp)
{
return sshbuf_get_bignum2(ssh->state->incoming_packet, valp);
}
#endif /* WITH_OPENSSL */
int
sshpkt_get_end(struct ssh *ssh)
{
if (sshbuf_len(ssh->state->incoming_packet) > 0)
return SSH_ERR_UNEXPECTED_TRAILING_DATA;
return 0;
}
const u_char *
sshpkt_ptr(struct ssh *ssh, size_t *lenp)
{
if (lenp != NULL)
*lenp = sshbuf_len(ssh->state->incoming_packet);
return sshbuf_ptr(ssh->state->incoming_packet);
}
/* start a new packet */
int
sshpkt_start(struct ssh *ssh, u_char type)
{
u_char buf[6]; /* u32 packet length, u8 pad len, u8 type */
DBG(debug("packet_start[%d]", type));
memset(buf, 0, sizeof(buf));
buf[sizeof(buf) - 1] = type;
sshbuf_reset(ssh->state->outgoing_packet);
return sshbuf_put(ssh->state->outgoing_packet, buf, sizeof(buf));
}
static int
ssh_packet_send_mux(struct ssh *ssh)
{
struct session_state *state = ssh->state;
u_char type, *cp;
size_t len;
int r;
if (ssh->kex)
return SSH_ERR_INTERNAL_ERROR;
len = sshbuf_len(state->outgoing_packet);
if (len < 6)
return SSH_ERR_INTERNAL_ERROR;
cp = sshbuf_mutable_ptr(state->outgoing_packet);
type = cp[5];
if (ssh_packet_log_type(type))
debug3_f("type %u", type);
/* drop everything, but the connection protocol */
if (type >= SSH2_MSG_CONNECTION_MIN &&
type <= SSH2_MSG_CONNECTION_MAX) {
POKE_U32(cp, len - 4);
if ((r = sshbuf_putb(state->output,
state->outgoing_packet)) != 0)
return r;
/* sshbuf_dump(state->output, stderr); */
}
sshbuf_reset(state->outgoing_packet);
return 0;
}
/*
* 9.2. Ignored Data Message
*
* byte SSH_MSG_IGNORE
* string data
*
* All implementations MUST understand (and ignore) this message at any
* time (after receiving the protocol version). No implementation is
* required to send them. This message can be used as an additional
* protection measure against advanced traffic analysis techniques.
*/
int
sshpkt_msg_ignore(struct ssh *ssh, u_int nbytes)
{
u_int32_t rnd = 0;
int r;
u_int i;
if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 ||
(r = sshpkt_put_u32(ssh, nbytes)) != 0)
return r;
for (i = 0; i < nbytes; i++) {
if (i % 4 == 0)
rnd = arc4random();
if ((r = sshpkt_put_u8(ssh, (u_char)rnd & 0xff)) != 0)
return r;
rnd >>= 8;
}
return 0;
}
/* send it */
int
sshpkt_send(struct ssh *ssh)
{
if (ssh->state && ssh->state->mux)
return ssh_packet_send_mux(ssh);
return ssh_packet_send2(ssh);
}
int
sshpkt_disconnect(struct ssh *ssh, const char *fmt,...)
{
char buf[1024];
va_list args;
int r;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 ||
(r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 ||
(r = sshpkt_put_cstring(ssh, buf)) != 0 ||
(r = sshpkt_put_cstring(ssh, "")) != 0 ||
(r = sshpkt_send(ssh)) != 0)
return r;
return 0;
}
/* roundup current message to pad bytes */
int
sshpkt_add_padding(struct ssh *ssh, u_char pad)
{
ssh->state->extra_pad = pad;
return 0;
}
diff --git a/readconf.c b/readconf.c
index 724974b708f9..0f27652b48b8 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,3283 +1,3283 @@
-/* $OpenBSD: readconf.c,v 1.352 2021/02/24 01:18:08 dtucker Exp $ */
+/* $OpenBSD: readconf.c,v 1.353 2021/04/03 06:18:40 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Functions for reading the configuration files.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <netdb.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#ifdef USE_SYSTEM_GLOB
# include <glob.h>
#else
# include "openbsd-compat/glob.h"
#endif
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
# include <vis.h>
#endif
#include "xmalloc.h"
#include "ssh.h"
#include "ssherr.h"
#include "compat.h"
#include "cipher.h"
#include "pathnames.h"
#include "log.h"
#include "sshkey.h"
#include "misc.h"
#include "readconf.h"
#include "match.h"
#include "kex.h"
#include "mac.h"
#include "uidswap.h"
#include "myproposal.h"
#include "digest.h"
/* Format of the configuration file:
# Configuration data is parsed as follows:
# 1. command line options
# 2. user-specific file
# 3. system-wide file
# Any configuration value is only changed the first time it is set.
# Thus, host-specific definitions should be at the beginning of the
# configuration file, and defaults at the end.
# Host-specific declarations. These may override anything above. A single
# host may match multiple declarations; these are processed in the order
# that they are given in.
Host *.ngs.fi ngs.fi
User foo
Host fake.com
Hostname another.host.name.real.org
User blaah
Port 34289
ForwardX11 no
ForwardAgent no
Host books.com
RemoteForward 9999 shadows.cs.hut.fi:9999
Ciphers 3des-cbc
Host fascist.blob.com
Port 23123
User tylonen
PasswordAuthentication no
Host puukko.hut.fi
User t35124p
ProxyCommand ssh-proxy %h %p
Host *.fr
PublicKeyAuthentication no
Host *.su
Ciphers aes128-ctr
PasswordAuthentication no
Host vpn.fake.com
Tunnel yes
TunnelDevice 3
# Defaults for various options
Host *
ForwardAgent no
ForwardX11 no
PasswordAuthentication yes
StrictHostKeyChecking yes
TcpKeepAlive no
IdentityFile ~/.ssh/identity
Port 22
EscapeChar ~
*/
static int read_config_file_depth(const char *filename, struct passwd *pw,
const char *host, const char *original_host, Options *options,
int flags, int *activep, int *want_final_pass, int depth);
static int process_config_line_depth(Options *options, struct passwd *pw,
const char *host, const char *original_host, char *line,
const char *filename, int linenum, int *activep, int flags,
int *want_final_pass, int depth);
/* Keyword tokens. */
typedef enum {
oBadOption,
oHost, oMatch, oInclude,
oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
oGatewayPorts, oExitOnForwardFailure,
oPasswordAuthentication,
oChallengeResponseAuthentication, oXAuthLocation,
oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward,
oPermitRemoteOpen,
oCertificateFile, oAddKeysToAgent, oIdentityAgent,
oUser, oEscapeChar, oProxyCommand,
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
oTCPKeepAlive, oNumberOfPasswordPrompts,
oLogFacility, oLogLevel, oLogVerbose, oCiphers, oMacs,
oPubkeyAuthentication,
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider,
oClearAllForwardings, oNoHostAuthenticationForLocalhost,
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
oAddressFamily, oGssAuthentication, oGssDelegateCreds,
oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
oHashKnownHosts,
oTunnel, oTunnelDevice,
oLocalCommand, oPermitLocalCommand, oRemoteCommand,
oVisualHostKey,
oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
oSecurityKeyProvider, oKnownHostsCommand,
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
} OpCodes;
/* Textual representations of the tokens. */
static struct {
const char *name;
OpCodes opcode;
} keywords[] = {
/* Deprecated options */
{ "protocol", oIgnore }, /* NB. silently ignored */
{ "cipher", oDeprecated },
{ "fallbacktorsh", oDeprecated },
{ "globalknownhostsfile2", oDeprecated },
{ "rhostsauthentication", oDeprecated },
{ "userknownhostsfile2", oDeprecated },
{ "useroaming", oDeprecated },
{ "usersh", oDeprecated },
{ "useprivilegedport", oDeprecated },
/* Unsupported options */
{ "afstokenpassing", oUnsupported },
{ "kerberosauthentication", oUnsupported },
{ "kerberostgtpassing", oUnsupported },
{ "rsaauthentication", oUnsupported },
{ "rhostsrsaauthentication", oUnsupported },
{ "compressionlevel", oUnsupported },
/* Sometimes-unsupported options */
#if defined(GSSAPI)
{ "gssapiauthentication", oGssAuthentication },
{ "gssapidelegatecredentials", oGssDelegateCreds },
# else
{ "gssapiauthentication", oUnsupported },
{ "gssapidelegatecredentials", oUnsupported },
#endif
#ifdef ENABLE_PKCS11
{ "pkcs11provider", oPKCS11Provider },
{ "smartcarddevice", oPKCS11Provider },
# else
{ "smartcarddevice", oUnsupported },
{ "pkcs11provider", oUnsupported },
#endif
{ "forwardagent", oForwardAgent },
{ "forwardx11", oForwardX11 },
{ "forwardx11trusted", oForwardX11Trusted },
{ "forwardx11timeout", oForwardX11Timeout },
{ "exitonforwardfailure", oExitOnForwardFailure },
{ "xauthlocation", oXAuthLocation },
{ "gatewayports", oGatewayPorts },
{ "passwordauthentication", oPasswordAuthentication },
{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
{ "kbdinteractivedevices", oKbdInteractiveDevices },
{ "pubkeyauthentication", oPubkeyAuthentication },
{ "dsaauthentication", oPubkeyAuthentication }, /* alias */
{ "hostbasedauthentication", oHostbasedAuthentication },
{ "challengeresponseauthentication", oChallengeResponseAuthentication },
{ "skeyauthentication", oUnsupported },
{ "tisauthentication", oChallengeResponseAuthentication }, /* alias */
{ "identityfile", oIdentityFile },
{ "identityfile2", oIdentityFile }, /* obsolete */
{ "identitiesonly", oIdentitiesOnly },
{ "certificatefile", oCertificateFile },
{ "addkeystoagent", oAddKeysToAgent },
{ "identityagent", oIdentityAgent },
{ "hostname", oHostname },
{ "hostkeyalias", oHostKeyAlias },
{ "proxycommand", oProxyCommand },
{ "port", oPort },
{ "ciphers", oCiphers },
{ "macs", oMacs },
{ "remoteforward", oRemoteForward },
{ "localforward", oLocalForward },
{ "permitremoteopen", oPermitRemoteOpen },
{ "user", oUser },
{ "host", oHost },
{ "match", oMatch },
{ "escapechar", oEscapeChar },
{ "globalknownhostsfile", oGlobalKnownHostsFile },
{ "userknownhostsfile", oUserKnownHostsFile },
{ "connectionattempts", oConnectionAttempts },
{ "batchmode", oBatchMode },
{ "checkhostip", oCheckHostIP },
{ "stricthostkeychecking", oStrictHostKeyChecking },
{ "compression", oCompression },
{ "tcpkeepalive", oTCPKeepAlive },
{ "keepalive", oTCPKeepAlive }, /* obsolete */
{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
{ "syslogfacility", oLogFacility },
{ "loglevel", oLogLevel },
{ "logverbose", oLogVerbose },
{ "dynamicforward", oDynamicForward },
{ "preferredauthentications", oPreferredAuthentications },
{ "hostkeyalgorithms", oHostKeyAlgorithms },
{ "casignaturealgorithms", oCASignatureAlgorithms },
{ "bindaddress", oBindAddress },
{ "bindinterface", oBindInterface },
{ "clearallforwardings", oClearAllForwardings },
{ "enablesshkeysign", oEnableSSHKeysign },
{ "verifyhostkeydns", oVerifyHostKeyDNS },
{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
{ "rekeylimit", oRekeyLimit },
{ "connecttimeout", oConnectTimeout },
{ "addressfamily", oAddressFamily },
{ "serveraliveinterval", oServerAliveInterval },
{ "serveralivecountmax", oServerAliveCountMax },
{ "sendenv", oSendEnv },
{ "setenv", oSetEnv },
{ "controlpath", oControlPath },
{ "controlmaster", oControlMaster },
{ "controlpersist", oControlPersist },
{ "hashknownhosts", oHashKnownHosts },
{ "include", oInclude },
{ "tunnel", oTunnel },
{ "tunneldevice", oTunnelDevice },
{ "localcommand", oLocalCommand },
{ "permitlocalcommand", oPermitLocalCommand },
{ "remotecommand", oRemoteCommand },
{ "visualhostkey", oVisualHostKey },
{ "kexalgorithms", oKexAlgorithms },
{ "ipqos", oIPQoS },
{ "requesttty", oRequestTTY },
{ "proxyusefdpass", oProxyUseFdpass },
{ "canonicaldomains", oCanonicalDomains },
{ "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
{ "canonicalizehostname", oCanonicalizeHostname },
{ "canonicalizemaxdots", oCanonicalizeMaxDots },
{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
{ "streamlocalbindmask", oStreamLocalBindMask },
{ "streamlocalbindunlink", oStreamLocalBindUnlink },
{ "revokedhostkeys", oRevokedHostKeys },
{ "fingerprinthash", oFingerprintHash },
{ "updatehostkeys", oUpdateHostkeys },
{ "hostbasedalgorithms", oHostbasedAcceptedAlgorithms },
{ "hostbasedkeytypes", oHostbasedAcceptedAlgorithms }, /* obsolete */
{ "pubkeyacceptedalgorithms", oPubkeyAcceptedAlgorithms },
{ "pubkeyacceptedkeytypes", oPubkeyAcceptedAlgorithms }, /* obsolete */
{ "ignoreunknown", oIgnoreUnknown },
{ "proxyjump", oProxyJump },
{ "securitykeyprovider", oSecurityKeyProvider },
{ "knownhostscommand", oKnownHostsCommand },
{ NULL, oBadOption }
};
static const char *lookup_opcode_name(OpCodes code);
const char *
kex_default_pk_alg(void)
{
static char *pkalgs;
if (pkalgs == NULL) {
char *all_key;
all_key = sshkey_alg_list(0, 0, 1, ',');
pkalgs = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
free(all_key);
}
return pkalgs;
}
char *
ssh_connection_hash(const char *thishost, const char *host, const char *portstr,
const char *user)
{
struct ssh_digest_ctx *md;
u_char conn_hash[SSH_DIGEST_MAX_LENGTH];
if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL ||
ssh_digest_update(md, thishost, strlen(thishost)) < 0 ||
ssh_digest_update(md, host, strlen(host)) < 0 ||
ssh_digest_update(md, portstr, strlen(portstr)) < 0 ||
ssh_digest_update(md, user, strlen(user)) < 0 ||
ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0)
fatal_f("mux digest failed");
ssh_digest_free(md);
return tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1));
}
/*
* Adds a local TCP/IP port forward to options. Never returns if there is an
* error.
*/
void
add_local_forward(Options *options, const struct Forward *newfwd)
{
struct Forward *fwd;
int i;
/* Don't add duplicates */
for (i = 0; i < options->num_local_forwards; i++) {
if (forward_equals(newfwd, options->local_forwards + i))
return;
}
options->local_forwards = xreallocarray(options->local_forwards,
options->num_local_forwards + 1,
sizeof(*options->local_forwards));
fwd = &options->local_forwards[options->num_local_forwards++];
fwd->listen_host = newfwd->listen_host;
fwd->listen_port = newfwd->listen_port;
fwd->listen_path = newfwd->listen_path;
fwd->connect_host = newfwd->connect_host;
fwd->connect_port = newfwd->connect_port;
fwd->connect_path = newfwd->connect_path;
}
/*
* Adds a remote TCP/IP port forward to options. Never returns if there is
* an error.
*/
void
add_remote_forward(Options *options, const struct Forward *newfwd)
{
struct Forward *fwd;
int i;
/* Don't add duplicates */
for (i = 0; i < options->num_remote_forwards; i++) {
if (forward_equals(newfwd, options->remote_forwards + i))
return;
}
options->remote_forwards = xreallocarray(options->remote_forwards,
options->num_remote_forwards + 1,
sizeof(*options->remote_forwards));
fwd = &options->remote_forwards[options->num_remote_forwards++];
fwd->listen_host = newfwd->listen_host;
fwd->listen_port = newfwd->listen_port;
fwd->listen_path = newfwd->listen_path;
fwd->connect_host = newfwd->connect_host;
fwd->connect_port = newfwd->connect_port;
fwd->connect_path = newfwd->connect_path;
fwd->handle = newfwd->handle;
fwd->allocated_port = 0;
}
static void
clear_forwardings(Options *options)
{
int i;
for (i = 0; i < options->num_local_forwards; i++) {
free(options->local_forwards[i].listen_host);
free(options->local_forwards[i].listen_path);
free(options->local_forwards[i].connect_host);
free(options->local_forwards[i].connect_path);
}
if (options->num_local_forwards > 0) {
free(options->local_forwards);
options->local_forwards = NULL;
}
options->num_local_forwards = 0;
for (i = 0; i < options->num_remote_forwards; i++) {
free(options->remote_forwards[i].listen_host);
free(options->remote_forwards[i].listen_path);
free(options->remote_forwards[i].connect_host);
free(options->remote_forwards[i].connect_path);
}
if (options->num_remote_forwards > 0) {
free(options->remote_forwards);
options->remote_forwards = NULL;
}
options->num_remote_forwards = 0;
options->tun_open = SSH_TUNMODE_NO;
}
void
add_certificate_file(Options *options, const char *path, int userprovided)
{
int i;
if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
fatal("Too many certificate files specified (max %d)",
SSH_MAX_CERTIFICATE_FILES);
/* Avoid registering duplicates */
for (i = 0; i < options->num_certificate_files; i++) {
if (options->certificate_file_userprovided[i] == userprovided &&
strcmp(options->certificate_files[i], path) == 0) {
debug2_f("ignoring duplicate key %s", path);
return;
}
}
options->certificate_file_userprovided[options->num_certificate_files] =
userprovided;
options->certificate_files[options->num_certificate_files++] =
xstrdup(path);
}
void
add_identity_file(Options *options, const char *dir, const char *filename,
int userprovided)
{
char *path;
int i;
if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
fatal("Too many identity files specified (max %d)",
SSH_MAX_IDENTITY_FILES);
if (dir == NULL) /* no dir, filename is absolute */
path = xstrdup(filename);
else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX)
fatal("Identity file path %s too long", path);
/* Avoid registering duplicates */
for (i = 0; i < options->num_identity_files; i++) {
if (options->identity_file_userprovided[i] == userprovided &&
strcmp(options->identity_files[i], path) == 0) {
debug2_f("ignoring duplicate key %s", path);
free(path);
return;
}
}
options->identity_file_userprovided[options->num_identity_files] =
userprovided;
options->identity_files[options->num_identity_files++] = path;
}
int
default_ssh_port(void)
{
static int port;
struct servent *sp;
if (port == 0) {
sp = getservbyname(SSH_SERVICE_NAME, "tcp");
port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
}
return port;
}
/*
* Execute a command in a shell.
* Return its exit status or -1 on abnormal exit.
*/
static int
execute_in_shell(const char *cmd)
{
char *shell;
pid_t pid;
int status;
if ((shell = getenv("SHELL")) == NULL)
shell = _PATH_BSHELL;
if (access(shell, X_OK) == -1) {
fatal("Shell \"%s\" is not executable: %s",
shell, strerror(errno));
}
debug("Executing command: '%.500s'", cmd);
/* Fork and execute the command. */
if ((pid = fork()) == 0) {
char *argv[4];
if (stdfd_devnull(1, 1, 0) == -1)
fatal_f("stdfd_devnull failed");
closefrom(STDERR_FILENO + 1);
argv[0] = shell;
argv[1] = "-c";
argv[2] = xstrdup(cmd);
argv[3] = NULL;
execv(argv[0], argv);
error("Unable to execute '%.100s': %s", cmd, strerror(errno));
/* Die with signal to make this error apparent to parent. */
ssh_signal(SIGTERM, SIG_DFL);
kill(getpid(), SIGTERM);
_exit(1);
}
/* Parent. */
if (pid == -1)
fatal_f("fork: %.100s", strerror(errno));
while (waitpid(pid, &status, 0) == -1) {
if (errno != EINTR && errno != EAGAIN)
fatal_f("waitpid: %s", strerror(errno));
}
if (!WIFEXITED(status)) {
error("command '%.100s' exited abnormally", cmd);
return -1;
}
debug3("command returned status %d", WEXITSTATUS(status));
return WEXITSTATUS(status);
}
/*
* Parse and execute a Match directive.
*/
static int
match_cfg_line(Options *options, char **condition, struct passwd *pw,
const char *host_arg, const char *original_host, int final_pass,
int *want_final_pass, const char *filename, int linenum)
{
char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
const char *ruser;
int r, port, this_result, result = 1, attributes = 0, negate;
char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
char uidstr[32];
/*
* Configuration is likely to be incomplete at this point so we
* must be prepared to use default values.
*/
port = options->port <= 0 ? default_ssh_port() : options->port;
ruser = options->user == NULL ? pw->pw_name : options->user;
if (final_pass) {
host = xstrdup(options->hostname);
} else if (options->hostname != NULL) {
/* NB. Please keep in sync with ssh.c:main() */
host = percent_expand(options->hostname,
"h", host_arg, (char *)NULL);
} else {
host = xstrdup(host_arg);
}
debug2("checking match for '%s' host %s originally %s",
cp, host, original_host);
while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
criteria = NULL;
this_result = 1;
if ((negate = attrib[0] == '!'))
attrib++;
/* criteria "all" and "canonical" have no argument */
if (strcasecmp(attrib, "all") == 0) {
if (attributes > 1 ||
((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
error("%.200s line %d: '%s' cannot be combined "
"with other Match attributes",
filename, linenum, oattrib);
result = -1;
goto out;
}
if (result)
result = negate ? 0 : 1;
goto out;
}
attributes++;
if (strcasecmp(attrib, "canonical") == 0 ||
strcasecmp(attrib, "final") == 0) {
/*
* If the config requests "Match final" then remember
* this so we can perform a second pass later.
*/
if (strcasecmp(attrib, "final") == 0 &&
want_final_pass != NULL)
*want_final_pass = 1;
r = !!final_pass; /* force bitmask member to boolean */
if (r == (negate ? 1 : 0))
this_result = result = 0;
debug3("%.200s line %d: %smatched '%s'",
filename, linenum,
this_result ? "" : "not ", oattrib);
continue;
}
/* All other criteria require an argument */
if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
error("Missing Match criteria for %s", attrib);
result = -1;
goto out;
}
if (strcasecmp(attrib, "host") == 0) {
criteria = xstrdup(host);
r = match_hostname(host, arg) == 1;
if (r == (negate ? 1 : 0))
this_result = result = 0;
} else if (strcasecmp(attrib, "originalhost") == 0) {
criteria = xstrdup(original_host);
r = match_hostname(original_host, arg) == 1;
if (r == (negate ? 1 : 0))
this_result = result = 0;
} else if (strcasecmp(attrib, "user") == 0) {
criteria = xstrdup(ruser);
r = match_pattern_list(ruser, arg, 0) == 1;
if (r == (negate ? 1 : 0))
this_result = result = 0;
} else if (strcasecmp(attrib, "localuser") == 0) {
criteria = xstrdup(pw->pw_name);
r = match_pattern_list(pw->pw_name, arg, 0) == 1;
if (r == (negate ? 1 : 0))
this_result = result = 0;
} else if (strcasecmp(attrib, "exec") == 0) {
char *conn_hash_hex, *keyalias;
if (gethostname(thishost, sizeof(thishost)) == -1)
fatal("gethostname: %s", strerror(errno));
strlcpy(shorthost, thishost, sizeof(shorthost));
shorthost[strcspn(thishost, ".")] = '\0';
snprintf(portstr, sizeof(portstr), "%d", port);
snprintf(uidstr, sizeof(uidstr), "%llu",
(unsigned long long)pw->pw_uid);
conn_hash_hex = ssh_connection_hash(thishost, host,
- portstr, ruser);
+ portstr, ruser);
keyalias = options->host_key_alias ?
options->host_key_alias : host;
cmd = percent_expand(arg,
"C", conn_hash_hex,
"L", shorthost,
"d", pw->pw_dir,
"h", host,
"k", keyalias,
"l", thishost,
"n", original_host,
"p", portstr,
"r", ruser,
"u", pw->pw_name,
"i", uidstr,
(char *)NULL);
free(conn_hash_hex);
if (result != 1) {
/* skip execution if prior predicate failed */
debug3("%.200s line %d: skipped exec "
"\"%.100s\"", filename, linenum, cmd);
free(cmd);
continue;
}
r = execute_in_shell(cmd);
if (r == -1) {
fatal("%.200s line %d: match exec "
"'%.100s' error", filename,
linenum, cmd);
}
criteria = xstrdup(cmd);
free(cmd);
/* Force exit status to boolean */
r = r == 0;
if (r == (negate ? 1 : 0))
this_result = result = 0;
} else {
error("Unsupported Match attribute %s", attrib);
result = -1;
goto out;
}
debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
filename, linenum, this_result ? "": "not ",
oattrib, criteria);
free(criteria);
}
if (attributes == 0) {
error("One or more attributes required for Match");
result = -1;
goto out;
}
out:
if (result != -1)
debug2("match %sfound", result ? "" : "not ");
*condition = cp;
free(host);
return result;
}
/* Remove environment variable by pattern */
static void
rm_env(Options *options, const char *arg, const char *filename, int linenum)
{
int i, j, onum_send_env = options->num_send_env;
char *cp;
/* Remove an environment variable */
for (i = 0; i < options->num_send_env; ) {
cp = xstrdup(options->send_env[i]);
if (!match_pattern(cp, arg + 1)) {
free(cp);
i++;
continue;
}
debug3("%s line %d: removing environment %s",
filename, linenum, cp);
free(cp);
free(options->send_env[i]);
options->send_env[i] = NULL;
for (j = i; j < options->num_send_env - 1; j++) {
options->send_env[j] = options->send_env[j + 1];
options->send_env[j + 1] = NULL;
}
options->num_send_env--;
/* NB. don't increment i */
}
if (onum_send_env != options->num_send_env) {
options->send_env = xrecallocarray(options->send_env,
onum_send_env, options->num_send_env,
sizeof(*options->send_env));
}
}
/*
* Returns the number of the token pointed to by cp or oBadOption.
*/
static OpCodes
parse_token(const char *cp, const char *filename, int linenum,
const char *ignored_unknown)
{
int i;
for (i = 0; keywords[i].name; i++)
if (strcmp(cp, keywords[i].name) == 0)
return keywords[i].opcode;
if (ignored_unknown != NULL &&
match_pattern_list(cp, ignored_unknown, 1) == 1)
return oIgnoredUnknownOption;
error("%s: line %d: Bad configuration option: %s",
filename, linenum, cp);
return oBadOption;
}
/* Multistate option parsing */
struct multistate {
char *key;
int value;
};
static const struct multistate multistate_flag[] = {
{ "true", 1 },
{ "false", 0 },
{ "yes", 1 },
{ "no", 0 },
{ NULL, -1 }
};
static const struct multistate multistate_yesnoask[] = {
{ "true", 1 },
{ "false", 0 },
{ "yes", 1 },
{ "no", 0 },
{ "ask", 2 },
{ NULL, -1 }
};
static const struct multistate multistate_strict_hostkey[] = {
{ "true", SSH_STRICT_HOSTKEY_YES },
{ "false", SSH_STRICT_HOSTKEY_OFF },
{ "yes", SSH_STRICT_HOSTKEY_YES },
{ "no", SSH_STRICT_HOSTKEY_OFF },
{ "ask", SSH_STRICT_HOSTKEY_ASK },
{ "off", SSH_STRICT_HOSTKEY_OFF },
{ "accept-new", SSH_STRICT_HOSTKEY_NEW },
{ NULL, -1 }
};
static const struct multistate multistate_yesnoaskconfirm[] = {
{ "true", 1 },
{ "false", 0 },
{ "yes", 1 },
{ "no", 0 },
{ "ask", 2 },
{ "confirm", 3 },
{ NULL, -1 }
};
static const struct multistate multistate_addressfamily[] = {
{ "inet", AF_INET },
{ "inet6", AF_INET6 },
{ "any", AF_UNSPEC },
{ NULL, -1 }
};
static const struct multistate multistate_controlmaster[] = {
{ "true", SSHCTL_MASTER_YES },
{ "yes", SSHCTL_MASTER_YES },
{ "false", SSHCTL_MASTER_NO },
{ "no", SSHCTL_MASTER_NO },
{ "auto", SSHCTL_MASTER_AUTO },
{ "ask", SSHCTL_MASTER_ASK },
{ "autoask", SSHCTL_MASTER_AUTO_ASK },
{ NULL, -1 }
};
static const struct multistate multistate_tunnel[] = {
{ "ethernet", SSH_TUNMODE_ETHERNET },
{ "point-to-point", SSH_TUNMODE_POINTOPOINT },
{ "true", SSH_TUNMODE_DEFAULT },
{ "yes", SSH_TUNMODE_DEFAULT },
{ "false", SSH_TUNMODE_NO },
{ "no", SSH_TUNMODE_NO },
{ NULL, -1 }
};
static const struct multistate multistate_requesttty[] = {
{ "true", REQUEST_TTY_YES },
{ "yes", REQUEST_TTY_YES },
{ "false", REQUEST_TTY_NO },
{ "no", REQUEST_TTY_NO },
{ "force", REQUEST_TTY_FORCE },
{ "auto", REQUEST_TTY_AUTO },
{ NULL, -1 }
};
static const struct multistate multistate_canonicalizehostname[] = {
{ "true", SSH_CANONICALISE_YES },
{ "false", SSH_CANONICALISE_NO },
{ "yes", SSH_CANONICALISE_YES },
{ "no", SSH_CANONICALISE_NO },
{ "always", SSH_CANONICALISE_ALWAYS },
{ NULL, -1 }
};
static const struct multistate multistate_compression[] = {
#ifdef WITH_ZLIB
{ "yes", COMP_ZLIB },
#endif
{ "no", COMP_NONE },
{ NULL, -1 }
};
static int
parse_multistate_value(const char *arg, const char *filename, int linenum,
const struct multistate *multistate_ptr)
{
int i;
if (!arg || *arg == '\0') {
error("%s line %d: missing argument.", filename, linenum);
return -1;
}
for (i = 0; multistate_ptr[i].key != NULL; i++) {
if (strcasecmp(arg, multistate_ptr[i].key) == 0)
return multistate_ptr[i].value;
}
return -1;
}
/*
* Processes a single option line as used in the configuration files. This
* only sets those values that have not already been set.
*/
int
process_config_line(Options *options, struct passwd *pw, const char *host,
const char *original_host, char *line, const char *filename,
int linenum, int *activep, int flags)
{
return process_config_line_depth(options, pw, host, original_host,
line, filename, linenum, activep, flags, NULL, 0);
}
#define WHITESPACE " \t\r\n"
static int
process_config_line_depth(Options *options, struct passwd *pw, const char *host,
const char *original_host, char *line, const char *filename,
int linenum, int *activep, int flags, int *want_final_pass, int depth)
{
char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, *p, ch;
char **cpptr, ***cppptr, fwdarg[256];
u_int i, *uintptr, uvalue, max_entries = 0;
int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
int remotefwd, dynamicfwd;
LogLevel *log_level_ptr;
SyslogFacility *log_facility_ptr;
long long val64;
size_t len;
struct Forward fwd;
const struct multistate *multistate_ptr;
struct allowed_cname *cname;
glob_t gl;
const char *errstr;
if (activep == NULL) { /* We are processing a command line directive */
cmdline = 1;
activep = &cmdline;
}
/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
if ((len = strlen(line)) == 0)
return 0;
for (len--; len > 0; len--) {
if (strchr(WHITESPACE "\f", line[len]) == NULL)
break;
line[len] = '\0';
}
s = line;
/* Get the keyword. (Each line is supposed to begin with a keyword). */
if ((keyword = strdelim(&s)) == NULL)
return 0;
/* Ignore leading whitespace. */
if (*keyword == '\0')
keyword = strdelim(&s);
if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
return 0;
/* Match lowercase keyword */
lowercase(keyword);
opcode = parse_token(keyword, filename, linenum,
options->ignored_unknown);
switch (opcode) {
case oBadOption:
/* don't panic, but count bad options */
return -1;
case oIgnore:
return 0;
case oIgnoredUnknownOption:
debug("%s line %d: Ignored unknown option \"%s\"",
filename, linenum, keyword);
return 0;
case oConnectTimeout:
intptr = &options->connection_timeout;
parse_time:
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%s line %d: missing time value.",
filename, linenum);
return -1;
}
if (strcmp(arg, "none") == 0)
value = -1;
else if ((value = convtime(arg)) == -1) {
error("%s line %d: invalid time value.",
filename, linenum);
return -1;
}
if (*activep && *intptr == -1)
*intptr = value;
break;
case oForwardAgent:
intptr = &options->forward_agent;
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%s line %d: missing argument.",
filename, linenum);
return -1;
}
value = -1;
multistate_ptr = multistate_flag;
for (i = 0; multistate_ptr[i].key != NULL; i++) {
if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
value = multistate_ptr[i].value;
break;
}
}
if (value != -1) {
if (*activep && *intptr == -1)
*intptr = value;
break;
}
/* ForwardAgent wasn't 'yes' or 'no', assume a path */
if (*activep && *intptr == -1)
*intptr = 1;
charptr = &options->forward_agent_sock_path;
goto parse_agent_path;
case oForwardX11:
intptr = &options->forward_x11;
parse_flag:
multistate_ptr = multistate_flag;
parse_multistate:
arg = strdelim(&s);
if ((value = parse_multistate_value(arg, filename, linenum,
- multistate_ptr)) == -1) {
+ multistate_ptr)) == -1) {
error("%s line %d: unsupported option \"%s\".",
filename, linenum, arg);
return -1;
}
if (*activep && *intptr == -1)
*intptr = value;
break;
case oForwardX11Trusted:
intptr = &options->forward_x11_trusted;
goto parse_flag;
case oForwardX11Timeout:
intptr = &options->forward_x11_timeout;
goto parse_time;
case oGatewayPorts:
intptr = &options->fwd_opts.gateway_ports;
goto parse_flag;
case oExitOnForwardFailure:
intptr = &options->exit_on_forward_failure;
goto parse_flag;
case oPasswordAuthentication:
intptr = &options->password_authentication;
goto parse_flag;
case oKbdInteractiveAuthentication:
intptr = &options->kbd_interactive_authentication;
goto parse_flag;
case oKbdInteractiveDevices:
charptr = &options->kbd_interactive_devices;
goto parse_string;
case oPubkeyAuthentication:
intptr = &options->pubkey_authentication;
goto parse_flag;
case oHostbasedAuthentication:
intptr = &options->hostbased_authentication;
goto parse_flag;
case oChallengeResponseAuthentication:
intptr = &options->challenge_response_authentication;
goto parse_flag;
case oGssAuthentication:
intptr = &options->gss_authentication;
goto parse_flag;
case oGssDelegateCreds:
intptr = &options->gss_deleg_creds;
goto parse_flag;
case oBatchMode:
intptr = &options->batch_mode;
goto parse_flag;
case oCheckHostIP:
intptr = &options->check_host_ip;
goto parse_flag;
case oVerifyHostKeyDNS:
intptr = &options->verify_host_key_dns;
multistate_ptr = multistate_yesnoask;
goto parse_multistate;
case oStrictHostKeyChecking:
intptr = &options->strict_host_key_checking;
multistate_ptr = multistate_strict_hostkey;
goto parse_multistate;
case oCompression:
intptr = &options->compression;
multistate_ptr = multistate_compression;
goto parse_multistate;
case oTCPKeepAlive:
intptr = &options->tcp_keep_alive;
goto parse_flag;
case oNoHostAuthenticationForLocalhost:
intptr = &options->no_host_authentication_for_localhost;
goto parse_flag;
case oNumberOfPasswordPrompts:
intptr = &options->number_of_password_prompts;
goto parse_int;
case oRekeyLimit:
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.", filename,
linenum);
return -1;
}
if (strcmp(arg, "default") == 0) {
val64 = 0;
} else {
if (scan_scaled(arg, &val64) == -1) {
error("%.200s line %d: Bad number '%s': %s",
filename, linenum, arg, strerror(errno));
return -1;
}
if (val64 != 0 && val64 < 16) {
error("%.200s line %d: RekeyLimit too small",
filename, linenum);
return -1;
}
}
if (*activep && options->rekey_limit == -1)
options->rekey_limit = val64;
if (s != NULL) { /* optional rekey interval present */
if (strcmp(s, "none") == 0) {
(void)strdelim(&s); /* discard */
break;
}
intptr = &options->rekey_interval;
goto parse_time;
}
break;
case oIdentityFile:
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
return -1;
}
if (*activep) {
intptr = &options->num_identity_files;
if (*intptr >= SSH_MAX_IDENTITY_FILES) {
error("%.200s line %d: Too many identity files "
"specified (max %d).", filename, linenum,
SSH_MAX_IDENTITY_FILES);
return -1;
}
add_identity_file(options, NULL,
arg, flags & SSHCONF_USERCONF);
}
break;
case oCertificateFile:
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
return -1;
}
if (*activep) {
intptr = &options->num_certificate_files;
if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
error("%.200s line %d: Too many certificate "
"files specified (max %d).",
filename, linenum,
SSH_MAX_CERTIFICATE_FILES);
return -1;
}
add_certificate_file(options, arg,
flags & SSHCONF_USERCONF);
}
break;
case oXAuthLocation:
charptr=&options->xauth_location;
goto parse_string;
case oUser:
charptr = &options->user;
parse_string:
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
return -1;
}
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
break;
case oGlobalKnownHostsFile:
cpptr = (char **)&options->system_hostfiles;
uintptr = &options->num_system_hostfiles;
max_entries = SSH_MAX_HOSTS_FILES;
parse_char_array:
if (*activep && *uintptr == 0) {
while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
if ((*uintptr) >= max_entries) {
error("%s line %d: too many known "
"hosts files.", filename, linenum);
return -1;
}
cpptr[(*uintptr)++] = xstrdup(arg);
}
}
return 0;
case oUserKnownHostsFile:
cpptr = (char **)&options->user_hostfiles;
uintptr = &options->num_user_hostfiles;
max_entries = SSH_MAX_HOSTS_FILES;
goto parse_char_array;
case oHostname:
charptr = &options->hostname;
goto parse_string;
case oHostKeyAlias:
charptr = &options->host_key_alias;
goto parse_string;
case oPreferredAuthentications:
charptr = &options->preferred_authentications;
goto parse_string;
case oBindAddress:
charptr = &options->bind_address;
goto parse_string;
case oBindInterface:
charptr = &options->bind_interface;
goto parse_string;
case oPKCS11Provider:
charptr = &options->pkcs11_provider;
goto parse_string;
case oSecurityKeyProvider:
charptr = &options->sk_provider;
goto parse_string;
case oKnownHostsCommand:
charptr = &options->known_hosts_command;
goto parse_command;
case oProxyCommand:
charptr = &options->proxy_command;
/* Ignore ProxyCommand if ProxyJump already specified */
if (options->jump_host != NULL)
charptr = &options->jump_host; /* Skip below */
parse_command:
if (s == NULL) {
error("%.200s line %d: Missing argument.",
filename, linenum);
return -1;
}
len = strspn(s, WHITESPACE "=");
if (*activep && *charptr == NULL)
*charptr = xstrdup(s + len);
return 0;
case oProxyJump:
if (s == NULL) {
error("%.200s line %d: Missing argument.",
filename, linenum);
return -1;
}
len = strspn(s, WHITESPACE "=");
if (parse_jump(s + len, options, *activep) == -1) {
error("%.200s line %d: Invalid ProxyJump \"%s\"",
filename, linenum, s + len);
return -1;
}
return 0;
case oPort:
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
return -1;
}
value = a2port(arg);
if (value <= 0) {
error("%.200s line %d: Bad port '%s'.",
filename, linenum, arg);
return -1;
}
if (*activep && options->port == -1)
options->port = value;
break;
case oConnectionAttempts:
intptr = &options->connection_attempts;
parse_int:
arg = strdelim(&s);
if ((errstr = atoi_err(arg, &value)) != NULL) {
error("%s line %d: integer value %s.",
filename, linenum, errstr);
return -1;
}
if (*activep && *intptr == -1)
*intptr = value;
break;
case oCiphers:
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
return -1;
}
if (*arg != '-' &&
!ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)){
error("%.200s line %d: Bad SSH2 cipher spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
return -1;
}
if (*activep && options->ciphers == NULL)
options->ciphers = xstrdup(arg);
break;
case oMacs:
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
return -1;
}
if (*arg != '-' &&
!mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) {
error("%.200s line %d: Bad SSH2 MAC spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
return -1;
}
if (*activep && options->macs == NULL)
options->macs = xstrdup(arg);
break;
case oKexAlgorithms:
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
return -1;
}
if (*arg != '-' &&
!kex_names_valid(*arg == '+' || *arg == '^' ?
arg + 1 : arg)) {
error("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
filename, linenum, arg ? arg : "<NONE>");
return -1;
}
if (*activep && options->kex_algorithms == NULL)
options->kex_algorithms = xstrdup(arg);
break;
case oHostKeyAlgorithms:
charptr = &options->hostkeyalgorithms;
parse_pubkey_algos:
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
return -1;
}
if (*arg != '-' &&
!sshkey_names_valid2(*arg == '+' || *arg == '^' ?
arg + 1 : arg, 1)) {
error("%s line %d: Bad key types '%s'.",
filename, linenum, arg ? arg : "<NONE>");
return -1;
}
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
break;
case oCASignatureAlgorithms:
charptr = &options->ca_sign_algorithms;
goto parse_pubkey_algos;
case oLogLevel:
log_level_ptr = &options->log_level;
arg = strdelim(&s);
value = log_level_number(arg);
if (value == SYSLOG_LEVEL_NOT_SET) {
error("%.200s line %d: unsupported log level '%s'",
filename, linenum, arg ? arg : "<NONE>");
return -1;
}
if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
*log_level_ptr = (LogLevel) value;
break;
case oLogFacility:
log_facility_ptr = &options->log_facility;
arg = strdelim(&s);
value = log_facility_number(arg);
if (value == SYSLOG_FACILITY_NOT_SET) {
error("%.200s line %d: unsupported log facility '%s'",
filename, linenum, arg ? arg : "<NONE>");
return -1;
}
if (*log_facility_ptr == -1)
*log_facility_ptr = (SyslogFacility) value;
break;
case oLogVerbose:
cppptr = &options->log_verbose;
uintptr = &options->num_log_verbose;
if (*activep && *uintptr == 0) {
while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
*cppptr = xrecallocarray(*cppptr, *uintptr,
*uintptr + 1, sizeof(**cppptr));
(*cppptr)[(*uintptr)++] = xstrdup(arg);
}
}
return 0;
case oLocalForward:
case oRemoteForward:
case oDynamicForward:
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
return -1;
}
remotefwd = (opcode == oRemoteForward);
dynamicfwd = (opcode == oDynamicForward);
if (!dynamicfwd) {
arg2 = strdelim(&s);
if (arg2 == NULL || *arg2 == '\0') {
if (remotefwd)
dynamicfwd = 1;
else {
error("%.200s line %d: Missing target "
"argument.", filename, linenum);
return -1;
}
} else {
/* construct a string for parse_forward */
snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg,
arg2);
}
}
if (dynamicfwd)
strlcpy(fwdarg, arg, sizeof(fwdarg));
if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0) {
error("%.200s line %d: Bad forwarding specification.",
filename, linenum);
return -1;
}
if (*activep) {
if (remotefwd) {
add_remote_forward(options, &fwd);
} else {
add_local_forward(options, &fwd);
}
}
break;
case oPermitRemoteOpen:
uintptr = &options->num_permitted_remote_opens;
cppptr = &options->permitted_remote_opens;
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%s line %d: missing %s specification",
filename, linenum, lookup_opcode_name(opcode));
uvalue = *uintptr; /* modified later */
if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) {
if (*activep && uvalue == 0) {
*uintptr = 1;
*cppptr = xcalloc(1, sizeof(**cppptr));
(*cppptr)[0] = xstrdup(arg);
}
break;
}
for (; arg != NULL && *arg != '\0'; arg = strdelim(&s)) {
arg2 = xstrdup(arg);
ch = '\0';
p = hpdelim2(&arg, &ch);
if (p == NULL || ch == '/') {
fatal("%s line %d: missing host in %s",
filename, linenum,
lookup_opcode_name(opcode));
}
p = cleanhostname(p);
/*
* don't want to use permitopen_port to avoid
* dependency on channels.[ch] here.
*/
if (arg == NULL ||
(strcmp(arg, "*") != 0 && a2port(arg) <= 0)) {
fatal("%s line %d: bad port number in %s",
filename, linenum,
lookup_opcode_name(opcode));
}
if (*activep && uvalue == 0) {
opt_array_append(filename, linenum,
lookup_opcode_name(opcode),
cppptr, uintptr, arg2);
}
free(arg2);
}
break;
case oClearAllForwardings:
intptr = &options->clear_forwardings;
goto parse_flag;
case oHost:
if (cmdline) {
error("Host directive not supported as a command-line "
"option");
return -1;
}
*activep = 0;
arg2 = NULL;
while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
if ((flags & SSHCONF_NEVERMATCH) != 0)
break;
negated = *arg == '!';
if (negated)
arg++;
if (match_pattern(host, arg)) {
if (negated) {
debug("%.200s line %d: Skipping Host "
"block because of negated match "
"for %.100s", filename, linenum,
arg);
*activep = 0;
break;
}
if (!*activep)
arg2 = arg; /* logged below */
*activep = 1;
}
}
if (*activep)
debug("%.200s line %d: Applying options for %.100s",
filename, linenum, arg2);
/* Avoid garbage check below, as strdelim is done. */
return 0;
case oMatch:
if (cmdline) {
error("Host directive not supported as a command-line "
"option");
return -1;
}
value = match_cfg_line(options, &s, pw, host, original_host,
flags & SSHCONF_FINAL, want_final_pass,
filename, linenum);
if (value < 0) {
error("%.200s line %d: Bad Match condition", filename,
linenum);
return -1;
}
*activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
break;
case oEscapeChar:
intptr = &options->escape_char;
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
return -1;
}
if (strcmp(arg, "none") == 0)
value = SSH_ESCAPECHAR_NONE;
else if (arg[1] == '\0')
value = (u_char) arg[0];
else if (arg[0] == '^' && arg[2] == 0 &&
(u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
value = (u_char) arg[1] & 31;
else {
error("%.200s line %d: Bad escape character.",
filename, linenum);
return -1;
}
if (*activep && *intptr == -1)
*intptr = value;
break;
case oAddressFamily:
intptr = &options->address_family;
multistate_ptr = multistate_addressfamily;
goto parse_multistate;
case oEnableSSHKeysign:
intptr = &options->enable_ssh_keysign;
goto parse_flag;
case oIdentitiesOnly:
intptr = &options->identities_only;
goto parse_flag;
case oServerAliveInterval:
intptr = &options->server_alive_interval;
goto parse_time;
case oServerAliveCountMax:
intptr = &options->server_alive_count_max;
goto parse_int;
case oSendEnv:
while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
if (strchr(arg, '=') != NULL) {
error("%s line %d: Invalid environment name.",
filename, linenum);
return -1;
}
if (!*activep)
continue;
if (*arg == '-') {
/* Removing an env var */
rm_env(options, arg, filename, linenum);
continue;
} else {
/* Adding an env var */
if (options->num_send_env >= INT_MAX) {
error("%s line %d: too many send env.",
filename, linenum);
return -1;
}
options->send_env = xrecallocarray(
options->send_env, options->num_send_env,
options->num_send_env + 1,
sizeof(*options->send_env));
options->send_env[options->num_send_env++] =
xstrdup(arg);
}
}
break;
case oSetEnv:
value = options->num_setenv;
while ((arg = strdelimw(&s)) != NULL && *arg != '\0') {
if (strchr(arg, '=') == NULL) {
error("%s line %d: Invalid SetEnv.",
filename, linenum);
return -1;
}
if (!*activep || value != 0)
continue;
/* Adding a setenv var */
if (options->num_setenv >= INT_MAX) {
error("%s line %d: too many SetEnv.",
filename, linenum);
return -1;
}
options->setenv = xrecallocarray(
options->setenv, options->num_setenv,
options->num_setenv + 1, sizeof(*options->setenv));
options->setenv[options->num_setenv++] = xstrdup(arg);
}
break;
case oControlPath:
charptr = &options->control_path;
goto parse_string;
case oControlMaster:
intptr = &options->control_master;
multistate_ptr = multistate_controlmaster;
goto parse_multistate;
case oControlPersist:
/* no/false/yes/true, or a time spec */
intptr = &options->control_persist;
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing ControlPersist"
" argument.", filename, linenum);
return -1;
}
value = 0;
value2 = 0; /* timeout */
if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
value = 0;
else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
value = 1;
else if ((value2 = convtime(arg)) >= 0)
value = 1;
else {
error("%.200s line %d: Bad ControlPersist argument.",
filename, linenum);
return -1;
}
if (*activep && *intptr == -1) {
*intptr = value;
options->control_persist_timeout = value2;
}
break;
case oHashKnownHosts:
intptr = &options->hash_known_hosts;
goto parse_flag;
case oTunnel:
intptr = &options->tun_open;
multistate_ptr = multistate_tunnel;
goto parse_multistate;
case oTunnelDevice:
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
return -1;
}
value = a2tun(arg, &value2);
if (value == SSH_TUNID_ERR) {
error("%.200s line %d: Bad tun device.",
filename, linenum);
return -1;
}
if (*activep) {
options->tun_local = value;
options->tun_remote = value2;
}
break;
case oLocalCommand:
charptr = &options->local_command;
goto parse_command;
case oPermitLocalCommand:
intptr = &options->permit_local_command;
goto parse_flag;
case oRemoteCommand:
charptr = &options->remote_command;
goto parse_command;
case oVisualHostKey:
intptr = &options->visual_host_key;
goto parse_flag;
case oInclude:
if (cmdline) {
error("Include directive not supported as a "
"command-line option");
return -1;
}
value = 0;
while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
/*
* Ensure all paths are anchored. User configuration
* files may begin with '~/' but system configurations
* must not. If the path is relative, then treat it
* as living in ~/.ssh for user configurations or
* /etc/ssh for system ones.
*/
if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0) {
error("%.200s line %d: bad include path %s.",
filename, linenum, arg);
return -1;
}
if (!path_absolute(arg) && *arg != '~') {
xasprintf(&arg2, "%s/%s",
(flags & SSHCONF_USERCONF) ?
"~/" _PATH_SSH_USER_DIR : SSHDIR, arg);
} else
arg2 = xstrdup(arg);
memset(&gl, 0, sizeof(gl));
r = glob(arg2, GLOB_TILDE, NULL, &gl);
if (r == GLOB_NOMATCH) {
debug("%.200s line %d: include %s matched no "
"files",filename, linenum, arg2);
free(arg2);
continue;
} else if (r != 0) {
error("%.200s line %d: glob failed for %s.",
filename, linenum, arg2);
return -1;
}
free(arg2);
oactive = *activep;
for (i = 0; i < gl.gl_pathc; i++) {
debug3("%.200s line %d: Including file %s "
"depth %d%s", filename, linenum,
gl.gl_pathv[i], depth,
oactive ? "" : " (parse only)");
r = read_config_file_depth(gl.gl_pathv[i],
pw, host, original_host, options,
flags | SSHCONF_CHECKPERM |
(oactive ? 0 : SSHCONF_NEVERMATCH),
activep, want_final_pass, depth + 1);
if (r != 1 && errno != ENOENT) {
error("Can't open user config file "
"%.100s: %.100s", gl.gl_pathv[i],
strerror(errno));
globfree(&gl);
return -1;
}
/*
* don't let Match in includes clobber the
* containing file's Match state.
*/
*activep = oactive;
if (r != 1)
value = -1;
}
globfree(&gl);
}
if (value != 0)
return value;
break;
case oIPQoS:
arg = strdelim(&s);
if ((value = parse_ipqos(arg)) == -1) {
error("%s line %d: Bad IPQoS value: %s",
filename, linenum, arg);
return -1;
}
arg = strdelim(&s);
if (arg == NULL)
value2 = value;
else if ((value2 = parse_ipqos(arg)) == -1) {
error("%s line %d: Bad IPQoS value: %s",
filename, linenum, arg);
return -1;
}
if (*activep) {
options->ip_qos_interactive = value;
options->ip_qos_bulk = value2;
}
break;
case oRequestTTY:
intptr = &options->request_tty;
multistate_ptr = multistate_requesttty;
goto parse_multistate;
case oIgnoreUnknown:
charptr = &options->ignored_unknown;
goto parse_string;
case oProxyUseFdpass:
intptr = &options->proxy_use_fdpass;
goto parse_flag;
case oCanonicalDomains:
value = options->num_canonical_domains != 0;
while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
if (!valid_domain(arg, 1, &errstr)) {
error("%s line %d: %s", filename, linenum,
errstr);
return -1;
}
if (!*activep || value)
continue;
if (options->num_canonical_domains >=
MAX_CANON_DOMAINS) {
error("%s line %d: too many hostname suffixes.",
filename, linenum);
return -1;
}
options->canonical_domains[
options->num_canonical_domains++] = xstrdup(arg);
}
break;
case oCanonicalizePermittedCNAMEs:
value = options->num_permitted_cnames != 0;
while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
/* Either '*' for everything or 'list:list' */
if (strcmp(arg, "*") == 0)
arg2 = arg;
else {
lowercase(arg);
if ((arg2 = strchr(arg, ':')) == NULL ||
arg2[1] == '\0') {
error("%s line %d: "
"Invalid permitted CNAME \"%s\"",
filename, linenum, arg);
return -1;
}
*arg2 = '\0';
arg2++;
}
if (!*activep || value)
continue;
if (options->num_permitted_cnames >=
MAX_CANON_DOMAINS) {
error("%s line %d: too many permitted CNAMEs.",
filename, linenum);
return -1;
}
cname = options->permitted_cnames +
options->num_permitted_cnames++;
cname->source_list = xstrdup(arg);
cname->target_list = xstrdup(arg2);
}
break;
case oCanonicalizeHostname:
intptr = &options->canonicalize_hostname;
multistate_ptr = multistate_canonicalizehostname;
goto parse_multistate;
case oCanonicalizeMaxDots:
intptr = &options->canonicalize_max_dots;
goto parse_int;
case oCanonicalizeFallbackLocal:
intptr = &options->canonicalize_fallback_local;
goto parse_flag;
case oStreamLocalBindMask:
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing StreamLocalBindMask "
"argument.", filename, linenum);
return -1;
}
/* Parse mode in octal format */
value = strtol(arg, &endofnumber, 8);
if (arg == endofnumber || value < 0 || value > 0777) {
error("%.200s line %d: Bad mask.", filename, linenum);
return -1;
}
options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
break;
case oStreamLocalBindUnlink:
intptr = &options->fwd_opts.streamlocal_bind_unlink;
goto parse_flag;
case oRevokedHostKeys:
charptr = &options->revoked_host_keys;
goto parse_string;
case oFingerprintHash:
intptr = &options->fingerprint_hash;
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
return -1;
}
if ((value = ssh_digest_alg_by_name(arg)) == -1) {
error("%.200s line %d: Invalid hash algorithm \"%s\".",
filename, linenum, arg);
return -1;
}
if (*activep && *intptr == -1)
*intptr = value;
break;
case oUpdateHostkeys:
intptr = &options->update_hostkeys;
multistate_ptr = multistate_yesnoask;
goto parse_multistate;
case oHostbasedAcceptedAlgorithms:
charptr = &options->hostbased_accepted_algos;
goto parse_pubkey_algos;
case oPubkeyAcceptedAlgorithms:
charptr = &options->pubkey_accepted_algos;
goto parse_pubkey_algos;
case oAddKeysToAgent:
arg = strdelim(&s);
arg2 = strdelim(&s);
value = parse_multistate_value(arg, filename, linenum,
- multistate_yesnoaskconfirm);
+ multistate_yesnoaskconfirm);
value2 = 0; /* unlimited lifespan by default */
if (value == 3 && arg2 != NULL) {
/* allow "AddKeysToAgent confirm 5m" */
if ((value2 = convtime(arg2)) == -1 ||
value2 > INT_MAX) {
error("%s line %d: invalid time value.",
filename, linenum);
return -1;
}
} else if (value == -1 && arg2 == NULL) {
if ((value2 = convtime(arg)) == -1 ||
value2 > INT_MAX) {
error("%s line %d: unsupported option",
filename, linenum);
return -1;
}
value = 1; /* yes */
} else if (value == -1 || arg2 != NULL) {
error("%s line %d: unsupported option",
filename, linenum);
return -1;
}
if (*activep && options->add_keys_to_agent == -1) {
options->add_keys_to_agent = value;
options->add_keys_to_agent_lifespan = value2;
}
break;
case oIdentityAgent:
charptr = &options->identity_agent;
arg = strdelim(&s);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
return -1;
}
parse_agent_path:
/* Extra validation if the string represents an env var. */
if ((arg2 = dollar_expand(&r, arg)) == NULL || r) {
error("%.200s line %d: Invalid environment expansion "
"%s.", filename, linenum, arg);
return -1;
}
free(arg2);
/* check for legacy environment format */
if (arg[0] == '$' && arg[1] != '{' &&
!valid_env_name(arg + 1)) {
error("%.200s line %d: Invalid environment name %s.",
filename, linenum, arg);
return -1;
}
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
break;
case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
return 0;
case oUnsupported:
error("%s line %d: Unsupported option \"%s\"",
filename, linenum, keyword);
return 0;
default:
error("%s line %d: Unimplemented opcode %d",
filename, linenum, opcode);
}
/* Check that there is no garbage at end of line. */
if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
error("%.200s line %d: garbage at end of line; \"%.200s\".",
filename, linenum, arg);
return -1;
}
return 0;
}
/*
* Reads the config file and modifies the options accordingly. Options
* should already be initialized before this call. This never returns if
* there is an error. If the file does not exist, this returns 0.
*/
int
read_config_file(const char *filename, struct passwd *pw, const char *host,
const char *original_host, Options *options, int flags,
int *want_final_pass)
{
int active = 1;
return read_config_file_depth(filename, pw, host, original_host,
options, flags, &active, want_final_pass, 0);
}
#define READCONF_MAX_DEPTH 16
static int
read_config_file_depth(const char *filename, struct passwd *pw,
const char *host, const char *original_host, Options *options,
int flags, int *activep, int *want_final_pass, int depth)
{
FILE *f;
char *cp, *line = NULL;
size_t linesize = 0;
int linenum;
int bad_options = 0;
if (depth < 0 || depth > READCONF_MAX_DEPTH)
fatal("Too many recursive configuration includes");
if ((f = fopen(filename, "r")) == NULL)
return 0;
if (flags & SSHCONF_CHECKPERM) {
struct stat sb;
if (fstat(fileno(f), &sb) == -1)
fatal("fstat %s: %s", filename, strerror(errno));
if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
(sb.st_mode & 022) != 0))
fatal("Bad owner or permissions on %s", filename);
}
debug("Reading configuration data %.200s", filename);
/*
* Mark that we are now processing the options. This flag is turned
* on/off by Host specifications.
*/
linenum = 0;
while (getline(&line, &linesize, f) != -1) {
/* Update line number counter. */
linenum++;
/*
* Trim out comments and strip whitespace.
* NB - preserve newlines, they are needed to reproduce
* line numbers later for error messages.
*/
if ((cp = strchr(line, '#')) != NULL)
*cp = '\0';
if (process_config_line_depth(options, pw, host, original_host,
line, filename, linenum, activep, flags, want_final_pass,
depth) != 0)
bad_options++;
}
free(line);
fclose(f);
if (bad_options > 0)
fatal("%s: terminating, %d bad configuration options",
filename, bad_options);
return 1;
}
/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
int
option_clear_or_none(const char *o)
{
return o == NULL || strcasecmp(o, "none") == 0;
}
/*
* Initializes options to special values that indicate that they have not yet
* been set. Read_config_file will only set options with this value. Options
* are processed in the following order: command line, user config file,
* system config file. Last, fill_default_options is called.
*/
void
initialize_options(Options * options)
{
memset(options, 'X', sizeof(*options));
options->forward_agent = -1;
options->forward_agent_sock_path = NULL;
options->forward_x11 = -1;
options->forward_x11_trusted = -1;
options->forward_x11_timeout = -1;
options->stdio_forward_host = NULL;
options->stdio_forward_port = 0;
options->clear_forwardings = -1;
options->exit_on_forward_failure = -1;
options->xauth_location = NULL;
options->fwd_opts.gateway_ports = -1;
options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
options->fwd_opts.streamlocal_bind_unlink = -1;
options->pubkey_authentication = -1;
options->challenge_response_authentication = -1;
options->gss_authentication = -1;
options->gss_deleg_creds = -1;
options->password_authentication = -1;
options->kbd_interactive_authentication = -1;
options->kbd_interactive_devices = NULL;
options->hostbased_authentication = -1;
options->batch_mode = -1;
options->check_host_ip = -1;
options->strict_host_key_checking = -1;
options->compression = -1;
options->tcp_keep_alive = -1;
options->port = -1;
options->address_family = -1;
options->connection_attempts = -1;
options->connection_timeout = -1;
options->number_of_password_prompts = -1;
options->ciphers = NULL;
options->macs = NULL;
options->kex_algorithms = NULL;
options->hostkeyalgorithms = NULL;
options->ca_sign_algorithms = NULL;
options->num_identity_files = 0;
memset(options->identity_keys, 0, sizeof(options->identity_keys));
options->num_certificate_files = 0;
memset(options->certificates, 0, sizeof(options->certificates));
options->hostname = NULL;
options->host_key_alias = NULL;
options->proxy_command = NULL;
options->jump_user = NULL;
options->jump_host = NULL;
options->jump_port = -1;
options->jump_extra = NULL;
options->user = NULL;
options->escape_char = -1;
options->num_system_hostfiles = 0;
options->num_user_hostfiles = 0;
options->local_forwards = NULL;
options->num_local_forwards = 0;
options->remote_forwards = NULL;
options->num_remote_forwards = 0;
options->permitted_remote_opens = NULL;
options->num_permitted_remote_opens = 0;
options->log_facility = SYSLOG_FACILITY_NOT_SET;
options->log_level = SYSLOG_LEVEL_NOT_SET;
options->num_log_verbose = 0;
options->log_verbose = NULL;
options->preferred_authentications = NULL;
options->bind_address = NULL;
options->bind_interface = NULL;
options->pkcs11_provider = NULL;
options->sk_provider = NULL;
options->enable_ssh_keysign = - 1;
options->no_host_authentication_for_localhost = - 1;
options->identities_only = - 1;
options->rekey_limit = - 1;
options->rekey_interval = -1;
options->verify_host_key_dns = -1;
options->server_alive_interval = -1;
options->server_alive_count_max = -1;
options->send_env = NULL;
options->num_send_env = 0;
options->setenv = NULL;
options->num_setenv = 0;
options->control_path = NULL;
options->control_master = -1;
options->control_persist = -1;
options->control_persist_timeout = 0;
options->hash_known_hosts = -1;
options->tun_open = -1;
options->tun_local = -1;
options->tun_remote = -1;
options->local_command = NULL;
options->permit_local_command = -1;
options->remote_command = NULL;
options->add_keys_to_agent = -1;
options->add_keys_to_agent_lifespan = -1;
options->identity_agent = NULL;
options->visual_host_key = -1;
options->ip_qos_interactive = -1;
options->ip_qos_bulk = -1;
options->request_tty = -1;
options->proxy_use_fdpass = -1;
options->ignored_unknown = NULL;
options->num_canonical_domains = 0;
options->num_permitted_cnames = 0;
options->canonicalize_max_dots = -1;
options->canonicalize_fallback_local = -1;
options->canonicalize_hostname = -1;
options->revoked_host_keys = NULL;
options->fingerprint_hash = -1;
options->update_hostkeys = -1;
options->hostbased_accepted_algos = NULL;
options->pubkey_accepted_algos = NULL;
options->known_hosts_command = NULL;
}
/*
* A petite version of fill_default_options() that just fills the options
* needed for hostname canonicalization to proceed.
*/
void
fill_default_options_for_canonicalization(Options *options)
{
if (options->canonicalize_max_dots == -1)
options->canonicalize_max_dots = 1;
if (options->canonicalize_fallback_local == -1)
options->canonicalize_fallback_local = 1;
if (options->canonicalize_hostname == -1)
options->canonicalize_hostname = SSH_CANONICALISE_NO;
}
/*
* Called after processing other sources of option data, this fills those
* options for which no value has been specified with their default values.
*/
int
fill_default_options(Options * options)
{
char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
int ret = 0, r;
if (options->forward_agent == -1)
options->forward_agent = 0;
if (options->forward_x11 == -1)
options->forward_x11 = 0;
if (options->forward_x11_trusted == -1)
options->forward_x11_trusted = 0;
if (options->forward_x11_timeout == -1)
options->forward_x11_timeout = 1200;
/*
* stdio forwarding (-W) changes the default for these but we defer
* setting the values so they can be overridden.
*/
if (options->exit_on_forward_failure == -1)
options->exit_on_forward_failure =
options->stdio_forward_host != NULL ? 1 : 0;
if (options->clear_forwardings == -1)
options->clear_forwardings =
options->stdio_forward_host != NULL ? 1 : 0;
if (options->clear_forwardings == 1)
clear_forwardings(options);
if (options->xauth_location == NULL)
options->xauth_location = xstrdup(_PATH_XAUTH);
if (options->fwd_opts.gateway_ports == -1)
options->fwd_opts.gateway_ports = 0;
if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
options->fwd_opts.streamlocal_bind_mask = 0177;
if (options->fwd_opts.streamlocal_bind_unlink == -1)
options->fwd_opts.streamlocal_bind_unlink = 0;
if (options->pubkey_authentication == -1)
options->pubkey_authentication = 1;
if (options->challenge_response_authentication == -1)
options->challenge_response_authentication = 1;
if (options->gss_authentication == -1)
options->gss_authentication = 0;
if (options->gss_deleg_creds == -1)
options->gss_deleg_creds = 0;
if (options->password_authentication == -1)
options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1)
options->kbd_interactive_authentication = 1;
if (options->hostbased_authentication == -1)
options->hostbased_authentication = 0;
if (options->batch_mode == -1)
options->batch_mode = 0;
if (options->check_host_ip == -1)
options->check_host_ip = 0;
if (options->strict_host_key_checking == -1)
options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
if (options->compression == -1)
options->compression = 0;
if (options->tcp_keep_alive == -1)
options->tcp_keep_alive = 1;
if (options->port == -1)
options->port = 0; /* Filled in ssh_connect. */
if (options->address_family == -1)
options->address_family = AF_UNSPEC;
if (options->connection_attempts == -1)
options->connection_attempts = 1;
if (options->number_of_password_prompts == -1)
options->number_of_password_prompts = 3;
/* options->hostkeyalgorithms, default set in myproposals.h */
if (options->add_keys_to_agent == -1) {
options->add_keys_to_agent = 0;
options->add_keys_to_agent_lifespan = 0;
}
if (options->num_identity_files == 0) {
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0);
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
#ifdef OPENSSL_HAS_ECC
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
add_identity_file(options, "~/",
_PATH_SSH_CLIENT_ID_ECDSA_SK, 0);
#endif
add_identity_file(options, "~/",
_PATH_SSH_CLIENT_ID_ED25519, 0);
add_identity_file(options, "~/",
_PATH_SSH_CLIENT_ID_ED25519_SK, 0);
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0);
}
if (options->escape_char == -1)
options->escape_char = '~';
if (options->num_system_hostfiles == 0) {
options->system_hostfiles[options->num_system_hostfiles++] =
xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
options->system_hostfiles[options->num_system_hostfiles++] =
xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
}
if (options->update_hostkeys == -1) {
if (options->verify_host_key_dns <= 0 &&
(options->num_user_hostfiles == 0 ||
(options->num_user_hostfiles == 1 && strcmp(options->
user_hostfiles[0], _PATH_SSH_USER_HOSTFILE) == 0)))
options->update_hostkeys = SSH_UPDATE_HOSTKEYS_YES;
else
options->update_hostkeys = SSH_UPDATE_HOSTKEYS_NO;
}
if (options->num_user_hostfiles == 0) {
options->user_hostfiles[options->num_user_hostfiles++] =
xstrdup(_PATH_SSH_USER_HOSTFILE);
options->user_hostfiles[options->num_user_hostfiles++] =
xstrdup(_PATH_SSH_USER_HOSTFILE2);
}
if (options->log_level == SYSLOG_LEVEL_NOT_SET)
options->log_level = SYSLOG_LEVEL_INFO;
if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
options->log_facility = SYSLOG_FACILITY_USER;
if (options->no_host_authentication_for_localhost == - 1)
options->no_host_authentication_for_localhost = 0;
if (options->identities_only == -1)
options->identities_only = 0;
if (options->enable_ssh_keysign == -1)
options->enable_ssh_keysign = 0;
if (options->rekey_limit == -1)
options->rekey_limit = 0;
if (options->rekey_interval == -1)
options->rekey_interval = 0;
if (options->verify_host_key_dns == -1)
options->verify_host_key_dns = 0;
if (options->server_alive_interval == -1)
options->server_alive_interval = 0;
if (options->server_alive_count_max == -1)
options->server_alive_count_max = 3;
if (options->control_master == -1)
options->control_master = 0;
if (options->control_persist == -1) {
options->control_persist = 0;
options->control_persist_timeout = 0;
}
if (options->hash_known_hosts == -1)
options->hash_known_hosts = 0;
if (options->tun_open == -1)
options->tun_open = SSH_TUNMODE_NO;
if (options->tun_local == -1)
options->tun_local = SSH_TUNID_ANY;
if (options->tun_remote == -1)
options->tun_remote = SSH_TUNID_ANY;
if (options->permit_local_command == -1)
options->permit_local_command = 0;
if (options->visual_host_key == -1)
options->visual_host_key = 0;
if (options->ip_qos_interactive == -1)
options->ip_qos_interactive = IPTOS_DSCP_AF21;
if (options->ip_qos_bulk == -1)
options->ip_qos_bulk = IPTOS_DSCP_CS1;
if (options->request_tty == -1)
options->request_tty = REQUEST_TTY_AUTO;
if (options->proxy_use_fdpass == -1)
options->proxy_use_fdpass = 0;
if (options->canonicalize_max_dots == -1)
options->canonicalize_max_dots = 1;
if (options->canonicalize_fallback_local == -1)
options->canonicalize_fallback_local = 1;
if (options->canonicalize_hostname == -1)
options->canonicalize_hostname = SSH_CANONICALISE_NO;
if (options->fingerprint_hash == -1)
options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
#ifdef ENABLE_SK_INTERNAL
if (options->sk_provider == NULL)
options->sk_provider = xstrdup("internal");
#else
if (options->sk_provider == NULL)
options->sk_provider = xstrdup("$SSH_SK_PROVIDER");
#endif
/* Expand KEX name lists */
all_cipher = cipher_alg_list(',', 0);
all_mac = mac_alg_list(',');
all_kex = kex_alg_list(',');
all_key = sshkey_alg_list(0, 0, 1, ',');
all_sig = sshkey_alg_list(0, 1, 1, ',');
/* remove unsupported algos from default lists */
def_cipher = match_filter_allowlist(KEX_CLIENT_ENCRYPT, all_cipher);
def_mac = match_filter_allowlist(KEX_CLIENT_MAC, all_mac);
def_kex = match_filter_allowlist(KEX_CLIENT_KEX, all_kex);
def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
#define ASSEMBLE(what, defaults, all) \
do { \
if ((r = kex_assemble_names(&options->what, \
defaults, all)) != 0) { \
error_fr(r, "%s", #what); \
goto fail; \
} \
} while (0)
ASSEMBLE(ciphers, def_cipher, all_cipher);
ASSEMBLE(macs, def_mac, all_mac);
ASSEMBLE(kex_algorithms, def_kex, all_kex);
ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
#undef ASSEMBLE
#define CLEAR_ON_NONE(v) \
do { \
if (option_clear_or_none(v)) { \
free(v); \
v = NULL; \
} \
} while(0)
CLEAR_ON_NONE(options->local_command);
CLEAR_ON_NONE(options->remote_command);
CLEAR_ON_NONE(options->proxy_command);
CLEAR_ON_NONE(options->control_path);
CLEAR_ON_NONE(options->revoked_host_keys);
CLEAR_ON_NONE(options->pkcs11_provider);
CLEAR_ON_NONE(options->sk_provider);
CLEAR_ON_NONE(options->known_hosts_command);
if (options->jump_host != NULL &&
strcmp(options->jump_host, "none") == 0 &&
options->jump_port == 0 && options->jump_user == NULL) {
free(options->jump_host);
options->jump_host = NULL;
}
/* options->identity_agent distinguishes NULL from 'none' */
/* options->user will be set in the main program if appropriate */
/* options->hostname will be set in the main program if appropriate */
/* options->host_key_alias should not be set by default */
/* options->preferred_authentications will be set in ssh */
/* success */
ret = 0;
fail:
free(all_cipher);
free(all_mac);
free(all_kex);
free(all_key);
free(all_sig);
free(def_cipher);
free(def_mac);
free(def_kex);
free(def_key);
free(def_sig);
return ret;
}
void
free_options(Options *o)
{
int i;
if (o == NULL)
return;
#define FREE_ARRAY(type, n, a) \
do { \
type _i; \
for (_i = 0; _i < (n); _i++) \
free((a)[_i]); \
} while (0)
free(o->forward_agent_sock_path);
free(o->xauth_location);
FREE_ARRAY(u_int, o->num_log_verbose, o->log_verbose);
free(o->log_verbose);
free(o->ciphers);
free(o->macs);
free(o->hostkeyalgorithms);
free(o->kex_algorithms);
free(o->ca_sign_algorithms);
free(o->hostname);
free(o->host_key_alias);
free(o->proxy_command);
free(o->user);
FREE_ARRAY(u_int, o->num_system_hostfiles, o->system_hostfiles);
FREE_ARRAY(u_int, o->num_user_hostfiles, o->user_hostfiles);
free(o->preferred_authentications);
free(o->bind_address);
free(o->bind_interface);
free(o->pkcs11_provider);
free(o->sk_provider);
for (i = 0; i < o->num_identity_files; i++) {
free(o->identity_files[i]);
sshkey_free(o->identity_keys[i]);
}
for (i = 0; i < o->num_certificate_files; i++) {
free(o->certificate_files[i]);
sshkey_free(o->certificates[i]);
}
free(o->identity_agent);
for (i = 0; i < o->num_local_forwards; i++) {
free(o->local_forwards[i].listen_host);
free(o->local_forwards[i].listen_path);
free(o->local_forwards[i].connect_host);
free(o->local_forwards[i].connect_path);
}
free(o->local_forwards);
for (i = 0; i < o->num_remote_forwards; i++) {
free(o->remote_forwards[i].listen_host);
free(o->remote_forwards[i].listen_path);
free(o->remote_forwards[i].connect_host);
free(o->remote_forwards[i].connect_path);
}
free(o->remote_forwards);
free(o->stdio_forward_host);
FREE_ARRAY(int, o->num_send_env, o->send_env);
free(o->send_env);
FREE_ARRAY(int, o->num_setenv, o->setenv);
free(o->setenv);
free(o->control_path);
free(o->local_command);
free(o->remote_command);
FREE_ARRAY(int, o->num_canonical_domains, o->canonical_domains);
for (i = 0; i < o->num_permitted_cnames; i++) {
free(o->permitted_cnames[i].source_list);
free(o->permitted_cnames[i].target_list);
}
free(o->revoked_host_keys);
free(o->hostbased_accepted_algos);
free(o->pubkey_accepted_algos);
free(o->jump_user);
free(o->jump_host);
free(o->jump_extra);
free(o->ignored_unknown);
explicit_bzero(o, sizeof(*o));
#undef FREE_ARRAY
}
struct fwdarg {
char *arg;
int ispath;
};
/*
* parse_fwd_field
* parses the next field in a port forwarding specification.
* sets fwd to the parsed field and advances p past the colon
* or sets it to NULL at end of string.
* returns 0 on success, else non-zero.
*/
static int
parse_fwd_field(char **p, struct fwdarg *fwd)
{
char *ep, *cp = *p;
int ispath = 0;
if (*cp == '\0') {
*p = NULL;
return -1; /* end of string */
}
/*
* A field escaped with square brackets is used literally.
* XXX - allow ']' to be escaped via backslash?
*/
if (*cp == '[') {
/* find matching ']' */
for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
if (*ep == '/')
ispath = 1;
}
/* no matching ']' or not at end of field. */
if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
return -1;
/* NUL terminate the field and advance p past the colon */
*ep++ = '\0';
if (*ep != '\0')
*ep++ = '\0';
fwd->arg = cp + 1;
fwd->ispath = ispath;
*p = ep;
return 0;
}
for (cp = *p; *cp != '\0'; cp++) {
switch (*cp) {
case '\\':
memmove(cp, cp + 1, strlen(cp + 1) + 1);
if (*cp == '\0')
return -1;
break;
case '/':
ispath = 1;
break;
case ':':
*cp++ = '\0';
goto done;
}
}
done:
fwd->arg = *p;
fwd->ispath = ispath;
*p = cp;
return 0;
}
/*
* parse_forward
* parses a string containing a port forwarding specification of the form:
* dynamicfwd == 0
* [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
* listenpath:connectpath
* dynamicfwd == 1
* [listenhost:]listenport
* returns number of arguments parsed or zero on error
*/
int
parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
{
struct fwdarg fwdargs[4];
char *p, *cp;
int i, err;
memset(fwd, 0, sizeof(*fwd));
memset(fwdargs, 0, sizeof(fwdargs));
/*
* We expand environment variables before checking if we think they're
* paths so that if ${VAR} expands to a fully qualified path it is
* treated as a path.
*/
cp = p = dollar_expand(&err, fwdspec);
if (p == NULL || err)
return 0;
/* skip leading spaces */
while (isspace((u_char)*cp))
cp++;
for (i = 0; i < 4; ++i) {
if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
break;
}
/* Check for trailing garbage */
if (cp != NULL && *cp != '\0') {
i = 0; /* failure */
}
switch (i) {
case 1:
if (fwdargs[0].ispath) {
fwd->listen_path = xstrdup(fwdargs[0].arg);
fwd->listen_port = PORT_STREAMLOCAL;
} else {
fwd->listen_host = NULL;
fwd->listen_port = a2port(fwdargs[0].arg);
}
fwd->connect_host = xstrdup("socks");
break;
case 2:
if (fwdargs[0].ispath && fwdargs[1].ispath) {
fwd->listen_path = xstrdup(fwdargs[0].arg);
fwd->listen_port = PORT_STREAMLOCAL;
fwd->connect_path = xstrdup(fwdargs[1].arg);
fwd->connect_port = PORT_STREAMLOCAL;
} else if (fwdargs[1].ispath) {
fwd->listen_host = NULL;
fwd->listen_port = a2port(fwdargs[0].arg);
fwd->connect_path = xstrdup(fwdargs[1].arg);
fwd->connect_port = PORT_STREAMLOCAL;
} else {
fwd->listen_host = xstrdup(fwdargs[0].arg);
fwd->listen_port = a2port(fwdargs[1].arg);
fwd->connect_host = xstrdup("socks");
}
break;
case 3:
if (fwdargs[0].ispath) {
fwd->listen_path = xstrdup(fwdargs[0].arg);
fwd->listen_port = PORT_STREAMLOCAL;
fwd->connect_host = xstrdup(fwdargs[1].arg);
fwd->connect_port = a2port(fwdargs[2].arg);
} else if (fwdargs[2].ispath) {
fwd->listen_host = xstrdup(fwdargs[0].arg);
fwd->listen_port = a2port(fwdargs[1].arg);
fwd->connect_path = xstrdup(fwdargs[2].arg);
fwd->connect_port = PORT_STREAMLOCAL;
} else {
fwd->listen_host = NULL;
fwd->listen_port = a2port(fwdargs[0].arg);
fwd->connect_host = xstrdup(fwdargs[1].arg);
fwd->connect_port = a2port(fwdargs[2].arg);
}
break;
case 4:
fwd->listen_host = xstrdup(fwdargs[0].arg);
fwd->listen_port = a2port(fwdargs[1].arg);
fwd->connect_host = xstrdup(fwdargs[2].arg);
fwd->connect_port = a2port(fwdargs[3].arg);
break;
default:
i = 0; /* failure */
}
free(p);
if (dynamicfwd) {
if (!(i == 1 || i == 2))
goto fail_free;
} else {
if (!(i == 3 || i == 4)) {
if (fwd->connect_path == NULL &&
fwd->listen_path == NULL)
goto fail_free;
}
if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
goto fail_free;
}
if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
(!remotefwd && fwd->listen_port == 0))
goto fail_free;
if (fwd->connect_host != NULL &&
strlen(fwd->connect_host) >= NI_MAXHOST)
goto fail_free;
/* XXX - if connecting to a remote socket, max sun len may not match this host */
if (fwd->connect_path != NULL &&
strlen(fwd->connect_path) >= PATH_MAX_SUN)
goto fail_free;
if (fwd->listen_host != NULL &&
strlen(fwd->listen_host) >= NI_MAXHOST)
goto fail_free;
if (fwd->listen_path != NULL &&
strlen(fwd->listen_path) >= PATH_MAX_SUN)
goto fail_free;
return (i);
fail_free:
free(fwd->connect_host);
fwd->connect_host = NULL;
free(fwd->connect_path);
fwd->connect_path = NULL;
free(fwd->listen_host);
fwd->listen_host = NULL;
free(fwd->listen_path);
fwd->listen_path = NULL;
return (0);
}
int
parse_jump(const char *s, Options *o, int active)
{
char *orig, *sdup, *cp;
char *host = NULL, *user = NULL;
int r, ret = -1, port = -1, first;
active &= o->proxy_command == NULL && o->jump_host == NULL;
orig = sdup = xstrdup(s);
first = active;
do {
if (strcasecmp(s, "none") == 0)
break;
if ((cp = strrchr(sdup, ',')) == NULL)
cp = sdup; /* last */
else
*cp++ = '\0';
if (first) {
/* First argument and configuration is active */
r = parse_ssh_uri(cp, &user, &host, &port);
if (r == -1 || (r == 1 &&
parse_user_host_port(cp, &user, &host, &port) != 0))
goto out;
} else {
/* Subsequent argument or inactive configuration */
r = parse_ssh_uri(cp, NULL, NULL, NULL);
if (r == -1 || (r == 1 &&
parse_user_host_port(cp, NULL, NULL, NULL) != 0))
goto out;
}
first = 0; /* only check syntax for subsequent hosts */
} while (cp != sdup);
/* success */
if (active) {
if (strcasecmp(s, "none") == 0) {
o->jump_host = xstrdup("none");
o->jump_port = 0;
} else {
o->jump_user = user;
o->jump_host = host;
o->jump_port = port;
o->proxy_command = xstrdup("none");
user = host = NULL;
if ((cp = strrchr(s, ',')) != NULL && cp != s) {
o->jump_extra = xstrdup(s);
o->jump_extra[cp - s] = '\0';
}
}
}
ret = 0;
out:
free(orig);
free(user);
free(host);
return ret;
}
int
parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
{
char *user = NULL, *host = NULL, *path = NULL;
int r, port;
r = parse_uri("ssh", uri, &user, &host, &port, &path);
if (r == 0 && path != NULL)
r = -1; /* path not allowed */
if (r == 0) {
if (userp != NULL) {
*userp = user;
user = NULL;
}
if (hostp != NULL) {
*hostp = host;
host = NULL;
}
if (portp != NULL)
*portp = port;
}
free(user);
free(host);
free(path);
return r;
}
/* XXX the following is a near-vebatim copy from servconf.c; refactor */
static const char *
fmt_multistate_int(int val, const struct multistate *m)
{
u_int i;
for (i = 0; m[i].key != NULL; i++) {
if (m[i].value == val)
return m[i].key;
}
return "UNKNOWN";
}
static const char *
fmt_intarg(OpCodes code, int val)
{
if (val == -1)
return "unset";
switch (code) {
case oAddressFamily:
return fmt_multistate_int(val, multistate_addressfamily);
case oVerifyHostKeyDNS:
case oUpdateHostkeys:
return fmt_multistate_int(val, multistate_yesnoask);
case oStrictHostKeyChecking:
return fmt_multistate_int(val, multistate_strict_hostkey);
case oControlMaster:
return fmt_multistate_int(val, multistate_controlmaster);
case oTunnel:
return fmt_multistate_int(val, multistate_tunnel);
case oRequestTTY:
return fmt_multistate_int(val, multistate_requesttty);
case oCanonicalizeHostname:
return fmt_multistate_int(val, multistate_canonicalizehostname);
case oAddKeysToAgent:
return fmt_multistate_int(val, multistate_yesnoaskconfirm);
case oFingerprintHash:
return ssh_digest_alg_name(val);
default:
switch (val) {
case 0:
return "no";
case 1:
return "yes";
default:
return "UNKNOWN";
}
}
}
static const char *
lookup_opcode_name(OpCodes code)
{
u_int i;
for (i = 0; keywords[i].name != NULL; i++)
if (keywords[i].opcode == code)
return(keywords[i].name);
return "UNKNOWN";
}
static void
dump_cfg_int(OpCodes code, int val)
{
printf("%s %d\n", lookup_opcode_name(code), val);
}
static void
dump_cfg_fmtint(OpCodes code, int val)
{
printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
}
static void
dump_cfg_string(OpCodes code, const char *val)
{
if (val == NULL)
return;
printf("%s %s\n", lookup_opcode_name(code), val);
}
static void
dump_cfg_strarray(OpCodes code, u_int count, char **vals)
{
u_int i;
for (i = 0; i < count; i++)
printf("%s %s\n", lookup_opcode_name(code), vals[i]);
}
static void
dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
{
u_int i;
printf("%s", lookup_opcode_name(code));
for (i = 0; i < count; i++)
printf(" %s", vals[i]);
printf("\n");
}
static void
dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
{
const struct Forward *fwd;
u_int i;
/* oDynamicForward */
for (i = 0; i < count; i++) {
fwd = &fwds[i];
if (code == oDynamicForward && fwd->connect_host != NULL &&
strcmp(fwd->connect_host, "socks") != 0)
continue;
if (code == oLocalForward && fwd->connect_host != NULL &&
strcmp(fwd->connect_host, "socks") == 0)
continue;
printf("%s", lookup_opcode_name(code));
if (fwd->listen_port == PORT_STREAMLOCAL)
printf(" %s", fwd->listen_path);
else if (fwd->listen_host == NULL)
printf(" %d", fwd->listen_port);
else {
printf(" [%s]:%d",
fwd->listen_host, fwd->listen_port);
}
if (code != oDynamicForward) {
if (fwd->connect_port == PORT_STREAMLOCAL)
printf(" %s", fwd->connect_path);
else if (fwd->connect_host == NULL)
printf(" %d", fwd->connect_port);
else {
printf(" [%s]:%d",
fwd->connect_host, fwd->connect_port);
}
}
printf("\n");
}
}
void
dump_client_config(Options *o, const char *host)
{
int i, r;
char buf[8], *all_key;
/*
* Expand HostKeyAlgorithms name lists. This isn't handled in
* fill_default_options() like the other algorithm lists because
* the host key algorithms are by default dynamically chosen based
* on the host's keys found in known_hosts.
*/
all_key = sshkey_alg_list(0, 0, 1, ',');
if ((r = kex_assemble_names(&o->hostkeyalgorithms, kex_default_pk_alg(),
all_key)) != 0)
fatal_fr(r, "expand HostKeyAlgorithms");
free(all_key);
/* Most interesting options first: user, host, port */
dump_cfg_string(oUser, o->user);
dump_cfg_string(oHostname, host);
dump_cfg_int(oPort, o->port);
/* Flag options */
dump_cfg_fmtint(oAddressFamily, o->address_family);
dump_cfg_fmtint(oBatchMode, o->batch_mode);
dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication);
dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
dump_cfg_fmtint(oCompression, o->compression);
dump_cfg_fmtint(oControlMaster, o->control_master);
dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
dump_cfg_fmtint(oForwardX11, o->forward_x11);
dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
#ifdef GSSAPI
dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
#endif /* GSSAPI */
dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
dump_cfg_fmtint(oRequestTTY, o->request_tty);
dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
dump_cfg_fmtint(oTunnel, o->tun_open);
dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
/* Integer options */
dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
dump_cfg_int(oConnectionAttempts, o->connection_attempts);
dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
/* String options */
dump_cfg_string(oBindAddress, o->bind_address);
dump_cfg_string(oBindInterface, o->bind_interface);
dump_cfg_string(oCiphers, o->ciphers);
dump_cfg_string(oControlPath, o->control_path);
dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
dump_cfg_string(oHostKeyAlias, o->host_key_alias);
dump_cfg_string(oHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
dump_cfg_string(oIdentityAgent, o->identity_agent);
dump_cfg_string(oIgnoreUnknown, o->ignored_unknown);
dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
dump_cfg_string(oKexAlgorithms, o->kex_algorithms);
dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms);
dump_cfg_string(oLocalCommand, o->local_command);
dump_cfg_string(oRemoteCommand, o->remote_command);
dump_cfg_string(oLogLevel, log_level_name(o->log_level));
dump_cfg_string(oMacs, o->macs);
#ifdef ENABLE_PKCS11
dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
#endif
dump_cfg_string(oSecurityKeyProvider, o->sk_provider);
dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
dump_cfg_string(oPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
dump_cfg_string(oXAuthLocation, o->xauth_location);
dump_cfg_string(oKnownHostsCommand, o->known_hosts_command);
/* Forwards */
dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
/* String array options */
dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
dump_cfg_strarray_oneline(oLogVerbose,
o->num_log_verbose, o->log_verbose);
/* Special cases */
/* PermitRemoteOpen */
if (o->num_permitted_remote_opens == 0)
printf("%s any\n", lookup_opcode_name(oPermitRemoteOpen));
else
dump_cfg_strarray_oneline(oPermitRemoteOpen,
o->num_permitted_remote_opens, o->permitted_remote_opens);
/* AddKeysToAgent */
if (o->add_keys_to_agent_lifespan <= 0)
dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);
else {
printf("addkeystoagent%s %d\n",
o->add_keys_to_agent == 3 ? " confirm" : "",
o->add_keys_to_agent_lifespan);
}
/* oForwardAgent */
if (o->forward_agent_sock_path == NULL)
dump_cfg_fmtint(oForwardAgent, o->forward_agent);
else
dump_cfg_string(oForwardAgent, o->forward_agent_sock_path);
/* oConnectTimeout */
if (o->connection_timeout == -1)
printf("connecttimeout none\n");
else
dump_cfg_int(oConnectTimeout, o->connection_timeout);
/* oTunnelDevice */
printf("tunneldevice");
if (o->tun_local == SSH_TUNID_ANY)
printf(" any");
else
printf(" %d", o->tun_local);
if (o->tun_remote == SSH_TUNID_ANY)
printf(":any");
else
printf(":%d", o->tun_remote);
printf("\n");
/* oCanonicalizePermittedCNAMEs */
if ( o->num_permitted_cnames > 0) {
printf("canonicalizePermittedcnames");
for (i = 0; i < o->num_permitted_cnames; i++) {
printf(" %s:%s", o->permitted_cnames[i].source_list,
o->permitted_cnames[i].target_list);
}
printf("\n");
}
/* oControlPersist */
if (o->control_persist == 0 || o->control_persist_timeout == 0)
dump_cfg_fmtint(oControlPersist, o->control_persist);
else
dump_cfg_int(oControlPersist, o->control_persist_timeout);
/* oEscapeChar */
if (o->escape_char == SSH_ESCAPECHAR_NONE)
printf("escapechar none\n");
else {
vis(buf, o->escape_char, VIS_WHITE, 0);
printf("escapechar %s\n", buf);
}
/* oIPQoS */
printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
printf("%s\n", iptos2str(o->ip_qos_bulk));
/* oRekeyLimit */
printf("rekeylimit %llu %d\n",
(unsigned long long)o->rekey_limit, o->rekey_interval);
/* oStreamLocalBindMask */
printf("streamlocalbindmask 0%o\n",
o->fwd_opts.streamlocal_bind_mask);
/* oLogFacility */
printf("syslogfacility %s\n", log_facility_name(o->log_facility));
/* oProxyCommand / oProxyJump */
if (o->jump_host == NULL)
dump_cfg_string(oProxyCommand, o->proxy_command);
else {
/* Check for numeric addresses */
i = strchr(o->jump_host, ':') != NULL ||
strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
snprintf(buf, sizeof(buf), "%d", o->jump_port);
printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
/* optional additional jump spec */
o->jump_extra == NULL ? "" : o->jump_extra,
o->jump_extra == NULL ? "" : ",",
/* optional user */
o->jump_user == NULL ? "" : o->jump_user,
o->jump_user == NULL ? "" : "@",
/* opening [ if hostname is numeric */
i ? "[" : "",
/* mandatory hostname */
o->jump_host,
/* closing ] if hostname is numeric */
i ? "]" : "",
/* optional port number */
o->jump_port <= 0 ? "" : ":",
o->jump_port <= 0 ? "" : buf);
}
}
diff --git a/regress/Makefile b/regress/Makefile
index 43da7c7db940..ced21a11d698 100644
--- a/regress/Makefile
+++ b/regress/Makefile
@@ -1,266 +1,269 @@
# $OpenBSD: Makefile,v 1.110 2020/12/22 06:03:36 djm Exp $
tests: prep file-tests t-exec unit
REGRESS_TARGETS= t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12
# File based tests
file-tests: $(REGRESS_TARGETS)
# Interop tests are not run by default
interop interop-tests: t-exec-interop
prep:
test "x${USE_VALGRIND}" = "x" || mkdir -p $(OBJ)/valgrind-out
clean:
for F in $(CLEANFILES); do rm -f $(OBJ)$$F; done
rm -rf $(OBJ).putty
distclean: clean
LTESTS= connect \
proxy-connect \
connect-privsep \
connect-uri \
proto-version \
proto-mismatch \
exit-status \
envpass \
transfer \
banner \
rekey \
dhgex \
stderr-data \
stderr-after-eof \
broken-pipe \
try-ciphers \
yes-head \
login-timeout \
agent \
agent-getpeereid \
agent-timeout \
agent-ptrace \
agent-subprocess \
keyscan \
keygen-change \
keygen-convert \
keygen-moduli \
key-options \
scp \
scp-uri \
sftp \
sftp-chroot \
sftp-cmds \
sftp-badcmds \
sftp-batch \
sftp-glob \
sftp-perm \
sftp-uri \
reconfigure \
dynamic-forward \
forwarding \
multiplex \
reexec \
brokenkeys \
sshcfgparse \
cfgparse \
cfgmatch \
cfgmatchlisten \
percent \
addrmatch \
localcommand \
forcecommand \
portnum \
keytype \
kextype \
cert-hostkey \
cert-userkey \
host-expand \
keys-command \
forward-control \
integrity \
krl \
multipubkey \
limit-keytype \
hostkey-agent \
keygen-knownhosts \
hostkey-rotate \
principals-command \
cert-file \
cfginclude \
servcfginclude \
allow-deny-users \
authinfo \
sshsig \
keygen-comment \
knownhosts-command
INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers
#INTEROP_TESTS+=ssh-com ssh-com-client ssh-com-keygen ssh-com-sftp
EXTRA_TESTS= agent-pkcs11
#EXTRA_TESTS+= cipher-speed
USERNAME= ${LOGNAME}
CLEANFILES= *.core actual agent-key.* authorized_keys_${USERNAME} \
authorized_keys_${USERNAME}.* \
authorized_principals_${USERNAME} \
banner.in banner.out cert_host_key* cert_user_key* \
copy.1 copy.2 data ed25519-agent ed25519-agent* \
ed25519-agent.pub ed25519 ed25519.pub empty.in \
expect failed-regress.log failed-ssh.log failed-sshd.log \
hkr.* host.ecdsa-sha2-nistp256 host.ecdsa-sha2-nistp384 \
host.ecdsa-sha2-nistp521 host.ssh-dss host.ssh-ed25519 \
host.ssh-rsa host_ca_key* host_krl_* host_revoked_* key.* \
key.dsa-* key.ecdsa-* key.ed25519-512 \
key.ed25519-512.pub key.rsa-* keys-command-args kh.* \
known_hosts known_hosts-cert known_hosts.* krl-* ls.copy \
modpipe netcat no_identity_config \
pidfile putty.rsa2 ready regress.log remote_pid \
revoked-* rsa rsa-agent rsa-agent.pub rsa.pub rsa_ssh2_cr.prv \
rsa_ssh2_crnl.prv scp-ssh-wrapper.exe \
scp-ssh-wrapper.scp setuid-allowed sftp-server.log \
sftp-server.sh sftp.log ssh-log-wrapper.sh ssh.log \
ssh-rsa_oldfmt knownhosts_command \
ssh_config ssh_config.* ssh_proxy ssh_proxy_bak \
ssh_proxy_* sshd.log sshd_config sshd_config.* \
sshd_config.* sshd_proxy sshd_proxy.* sshd_proxy_bak \
sshd_proxy_orig t10.out t10.out.pub t12.out t12.out.pub \
t2.out t3.out t6.out1 t6.out2 t7.out t7.out.pub \
t8.out t8.out.pub t9.out t9.out.pub testdata \
user_*key* user_ca* user_key*
# Enable all malloc(3) randomisations and checks
TEST_ENV= "MALLOC_OPTIONS=CFGJRSUX"
TEST_SSH_SSHKEYGEN?=ssh-keygen
CPPFLAGS=-I..
t1:
${TEST_SSH_SSHKEYGEN} -if ${.CURDIR}/rsa_ssh2.prv | diff - ${.CURDIR}/rsa_openssh.prv
tr '\n' '\r' <${.CURDIR}/rsa_ssh2.prv > ${.OBJDIR}/rsa_ssh2_cr.prv
${TEST_SSH_SSHKEYGEN} -if ${.OBJDIR}/rsa_ssh2_cr.prv | diff - ${.CURDIR}/rsa_openssh.prv
awk '{print $$0 "\r"}' ${.CURDIR}/rsa_ssh2.prv > ${.OBJDIR}/rsa_ssh2_crnl.prv
${TEST_SSH_SSHKEYGEN} -if ${.OBJDIR}/rsa_ssh2_crnl.prv | diff - ${.CURDIR}/rsa_openssh.prv
t2:
cat ${.CURDIR}/rsa_openssh.prv > $(OBJ)/t2.out
chmod 600 $(OBJ)/t2.out
${TEST_SSH_SSHKEYGEN} -yf $(OBJ)/t2.out | diff - ${.CURDIR}/rsa_openssh.pub
t3:
${TEST_SSH_SSHKEYGEN} -ef ${.CURDIR}/rsa_openssh.pub >$(OBJ)/t3.out
${TEST_SSH_SSHKEYGEN} -if $(OBJ)/t3.out | diff - ${.CURDIR}/rsa_openssh.pub
t4:
${TEST_SSH_SSHKEYGEN} -E md5 -lf ${.CURDIR}/rsa_openssh.pub |\
awk '{print $$2}' | diff - ${.CURDIR}/t4.ok
t5:
${TEST_SSH_SSHKEYGEN} -Bf ${.CURDIR}/rsa_openssh.pub |\
awk '{print $$2}' | diff - ${.CURDIR}/t5.ok
t6:
${TEST_SSH_SSHKEYGEN} -if ${.CURDIR}/dsa_ssh2.prv > $(OBJ)/t6.out1
${TEST_SSH_SSHKEYGEN} -if ${.CURDIR}/dsa_ssh2.pub > $(OBJ)/t6.out2
chmod 600 $(OBJ)/t6.out1
${TEST_SSH_SSHKEYGEN} -yf $(OBJ)/t6.out1 | diff - $(OBJ)/t6.out2
$(OBJ)/t7.out:
${TEST_SSH_SSHKEYGEN} -q -t rsa -N '' -f $@
t7: $(OBJ)/t7.out
${TEST_SSH_SSHKEYGEN} -lf $(OBJ)/t7.out > /dev/null
${TEST_SSH_SSHKEYGEN} -Bf $(OBJ)/t7.out > /dev/null
$(OBJ)/t8.out:
${TEST_SSH_SSHKEYGEN} -q -t dsa -N '' -f $@
t8: $(OBJ)/t8.out
${TEST_SSH_SSHKEYGEN} -lf $(OBJ)/t8.out > /dev/null
${TEST_SSH_SSHKEYGEN} -Bf $(OBJ)/t8.out > /dev/null
$(OBJ)/t9.out:
test "${TEST_SSH_ECC}" != yes || \
${TEST_SSH_SSHKEYGEN} -q -t ecdsa -N '' -f $@
t9: $(OBJ)/t9.out
test "${TEST_SSH_ECC}" != yes || \
${TEST_SSH_SSHKEYGEN} -lf $(OBJ)/t9.out > /dev/null
test "${TEST_SSH_ECC}" != yes || \
${TEST_SSH_SSHKEYGEN} -Bf $(OBJ)/t9.out > /dev/null
$(OBJ)/t10.out:
${TEST_SSH_SSHKEYGEN} -q -t ed25519 -N '' -f $@
t10: $(OBJ)/t10.out
${TEST_SSH_SSHKEYGEN} -lf $(OBJ)/t10.out > /dev/null
${TEST_SSH_SSHKEYGEN} -Bf $(OBJ)/t10.out > /dev/null
t11:
${TEST_SSH_SSHKEYGEN} -E sha256 -lf ${.CURDIR}/rsa_openssh.pub |\
awk '{print $$2}' | diff - ${.CURDIR}/t11.ok
$(OBJ)/t12.out:
${TEST_SSH_SSHKEYGEN} -q -t ed25519 -N '' -C 'test-comment-1234' -f $@
t12: $(OBJ)/t12.out
${TEST_SSH_SSHKEYGEN} -lf $(OBJ)/t12.out.pub | grep test-comment-1234 >/dev/null
t-exec: ${LTESTS:=.sh}
@if [ "x$?" = "x" ]; then exit 0; fi; \
for TEST in ""$?; do \
skip=no; \
for t in ""$${SKIP_LTESTS}; do \
if [ "x$${t}.sh" = "x$${TEST}" ]; then skip=yes; fi; \
done; \
if [ "x$${skip}" = "xno" ]; then \
echo "run test $${TEST}" ... 1>&2; \
(env SUDO="${SUDO}" TEST_ENV=${TEST_ENV} ${TEST_SHELL} ${.CURDIR}/test-exec.sh ${.OBJDIR} ${.CURDIR}/$${TEST}) || exit $$?; \
else \
echo skip test $${TEST} 1>&2; \
fi; \
done
t-exec-interop: ${INTEROP_TESTS:=.sh}
@if [ "x$?" = "x" ]; then exit 0; fi; \
for TEST in ""$?; do \
echo "run test $${TEST}" ... 1>&2; \
(env SUDO="${SUDO}" TEST_ENV=${TEST_ENV} ${TEST_SHELL} ${.CURDIR}/test-exec.sh ${.OBJDIR} ${.CURDIR}/$${TEST}) || exit $$?; \
done
t-extra: ${EXTRA_TESTS:=.sh}
@if [ "x$?" = "x" ]; then exit 0; fi; \
for TEST in ""$?; do \
echo "run test $${TEST}" ... 1>&2; \
(env SUDO="${SUDO}" TEST_ENV=${TEST_ENV} ${TEST_SHELL} ${.CURDIR}/test-exec.sh ${.OBJDIR} ${.CURDIR}/$${TEST}) || exit $$?; \
done
# Not run by default
interop: ${INTEROP_TARGETS}
# Unit tests, built by top-level Makefile
unit:
set -e ; if test -z "${SKIP_UNIT}" ; then \
V="" ; \
test "x${USE_VALGRIND}" = "x" || \
V=${.CURDIR}/valgrind-unit.sh ; \
- $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \
- $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \
+ $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \
+ $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \
-d ${.CURDIR}/unittests/sshkey/testdata ; \
$$V ${.OBJDIR}/unittests/sshsig/test_sshsig \
-d ${.CURDIR}/unittests/sshsig/testdata ; \
+ $$V ${.OBJDIR}/unittests/authopt/test_authopt \
+ -d ${.CURDIR}/unittests/authopt/testdata ; \
$$V ${.OBJDIR}/unittests/bitmap/test_bitmap ; \
$$V ${.OBJDIR}/unittests/conversion/test_conversion ; \
$$V ${.OBJDIR}/unittests/kex/test_kex ; \
$$V ${.OBJDIR}/unittests/hostkeys/test_hostkeys \
-d ${.CURDIR}/unittests/hostkeys/testdata ; \
$$V ${.OBJDIR}/unittests/match/test_match ; \
+ $$V ${.OBJDIR}/unittests/misc/test_misc ; \
if test "x${TEST_SSH_UTF8}" = "xyes" ; then \
$$V ${.OBJDIR}/unittests/utf8/test_utf8 ; \
fi \
fi
diff --git a/regress/connect-privsep.sh b/regress/connect-privsep.sh
index 76137b06087e..8970340a29c4 100644
--- a/regress/connect-privsep.sh
+++ b/regress/connect-privsep.sh
@@ -1,35 +1,34 @@
# $OpenBSD: connect-privsep.sh,v 1.9 2017/04/30 23:34:55 djm Exp $
# Placed in the Public Domain.
tid="proxy connect with privsep"
cp $OBJ/sshd_proxy $OBJ/sshd_proxy.orig
echo 'UsePrivilegeSeparation yes' >> $OBJ/sshd_proxy
${SSH} -F $OBJ/ssh_proxy 999.999.999.999 true
if [ $? -ne 0 ]; then
fail "ssh privsep+proxyconnect failed"
fi
cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy
echo 'UsePrivilegeSeparation sandbox' >> $OBJ/sshd_proxy
${SSH} -F $OBJ/ssh_proxy 999.999.999.999 true
if [ $? -ne 0 ]; then
- # XXX replace this with fail once sandbox has stabilised
- warn "ssh privsep/sandbox+proxyconnect failed"
+ fail "ssh privsep/sandbox+proxyconnect failed"
fi
# Because sandbox is sensitive to changes in libc, especially malloc, retest
# with every malloc.conf option (and none).
if [ -z "$TEST_MALLOC_OPTIONS" ]; then
mopts="C F G J R S U X < >"
else
mopts=`echo $TEST_MALLOC_OPTIONS | sed 's/./& /g'`
fi
for m in '' $mopts ; do
env MALLOC_OPTIONS="$m" ${SSH} -F $OBJ/ssh_proxy 999.999.999.999 true
if [ $? -ne 0 ]; then
fail "ssh privsep/sandbox+proxyconnect mopt '$m' failed"
fi
done
diff --git a/regress/sftp-perm.sh b/regress/sftp-perm.sh
index 304ca0ac5877..de96a14da8e8 100644
--- a/regress/sftp-perm.sh
+++ b/regress/sftp-perm.sh
@@ -1,269 +1,271 @@
-# $OpenBSD: sftp-perm.sh,v 1.2 2013/10/17 22:00:18 djm Exp $
+# $OpenBSD: sftp-perm.sh,v 1.3 2021/03/31 21:59:26 djm Exp $
# Placed in the Public Domain.
tid="sftp permissions"
SERVER_LOG=${OBJ}/sftp-server.log
CLIENT_LOG=${OBJ}/sftp.log
TEST_SFTP_SERVER=${OBJ}/sftp-server.sh
prepare_server() {
printf "#!/bin/sh\nexec $SFTPSERVER -el debug3 $* 2>$SERVER_LOG\n" \
> $TEST_SFTP_SERVER
chmod a+x $TEST_SFTP_SERVER
}
run_client() {
echo "$@" | ${SFTP} -D ${TEST_SFTP_SERVER} -vvvb - >$CLIENT_LOG 2>&1
}
prepare_files() {
_prep="$1"
rm -f ${COPY} ${COPY}.1
test -d ${COPY}.dd && { rmdir ${COPY}.dd || fatal "rmdir ${COPY}.dd"; }
test -z "$_prep" && return
sh -c "$_prep" || fail "preparation failed: \"$_prep\""
}
postcondition() {
_title="$1"
_check="$2"
test -z "$_check" && return
${TEST_SHELL} -c "$_check" || fail "postcondition check failed: $_title"
}
ro_test() {
_desc=$1
_cmd="$2"
_prep="$3"
_expect_success_post="$4"
_expect_fail_post="$5"
verbose "$tid: read-only $_desc"
# Plain (no options, mostly to test that _cmd is good)
prepare_files "$_prep"
prepare_server
run_client "$_cmd" || fail "plain $_desc failed"
postcondition "$_desc no-readonly" "$_expect_success_post"
# Read-only enabled
prepare_files "$_prep"
prepare_server -R
run_client "$_cmd" && fail "read-only $_desc succeeded"
postcondition "$_desc readonly" "$_expect_fail_post"
}
perm_test() {
_op=$1
_whitelist_ops=$2
_cmd="$3"
_prep="$4"
_expect_success_post="$5"
_expect_fail_post="$6"
verbose "$tid: explicit $_op"
# Plain (no options, mostly to test that _cmd is good)
prepare_files "$_prep"
prepare_server
run_client "$_cmd" || fail "plain $_op failed"
postcondition "$_op no white/blacklists" "$_expect_success_post"
# Whitelist
prepare_files "$_prep"
prepare_server -p $_op,$_whitelist_ops
run_client "$_cmd" || fail "whitelisted $_op failed"
postcondition "$_op whitelisted" "$_expect_success_post"
# Blacklist
prepare_files "$_prep"
prepare_server -P $_op
run_client "$_cmd" && fail "blacklisted $_op succeeded"
postcondition "$_op blacklisted" "$_expect_fail_post"
# Whitelist with op missing.
prepare_files "$_prep"
prepare_server -p $_whitelist_ops
run_client "$_cmd" && fail "no whitelist $_op succeeded"
postcondition "$_op not in whitelist" "$_expect_fail_post"
}
ro_test \
"upload" \
"put $DATA $COPY" \
"" \
"cmp $DATA $COPY" \
"test ! -f $COPY"
ro_test \
"setstat" \
"chmod 0700 $COPY" \
"touch $COPY; chmod 0400 $COPY" \
"test -x $COPY" \
"test ! -x $COPY"
ro_test \
"rm" \
"rm $COPY" \
"touch $COPY" \
"test ! -f $COPY" \
"test -f $COPY"
ro_test \
"mkdir" \
"mkdir ${COPY}.dd" \
"" \
"test -d ${COPY}.dd" \
"test ! -d ${COPY}.dd"
ro_test \
"rmdir" \
"rmdir ${COPY}.dd" \
"mkdir ${COPY}.dd" \
"test ! -d ${COPY}.dd" \
"test -d ${COPY}.dd"
ro_test \
"posix-rename" \
"rename $COPY ${COPY}.1" \
"touch $COPY" \
"test -f ${COPY}.1 -a ! -f $COPY" \
"test -f $COPY -a ! -f ${COPY}.1"
ro_test \
"oldrename" \
"rename -l $COPY ${COPY}.1" \
"touch $COPY" \
"test -f ${COPY}.1 -a ! -f $COPY" \
"test -f $COPY -a ! -f ${COPY}.1"
ro_test \
"symlink" \
"ln -s $COPY ${COPY}.1" \
"touch $COPY" \
"test -h ${COPY}.1" \
"test ! -h ${COPY}.1"
ro_test \
"hardlink" \
"ln $COPY ${COPY}.1" \
"touch $COPY" \
"test -f ${COPY}.1" \
"test ! -f ${COPY}.1"
# Test explicit permissions
perm_test \
"open" \
"realpath,stat,lstat,read,close" \
"get $DATA $COPY" \
"" \
"cmp $DATA $COPY" \
"! cmp $DATA $COPY 2>/dev/null"
perm_test \
"read" \
"realpath,stat,lstat,open,close" \
"get $DATA $COPY" \
"" \
"cmp $DATA $COPY" \
"! cmp $DATA $COPY 2>/dev/null"
perm_test \
"write" \
"realpath,stat,lstat,open,close" \
"put $DATA $COPY" \
"" \
"cmp $DATA $COPY" \
"! cmp $DATA $COPY 2>/dev/null"
perm_test \
"lstat" \
"realpath,stat,open,read,close" \
"get $DATA $COPY" \
"" \
"cmp $DATA $COPY" \
"! cmp $DATA $COPY 2>/dev/null"
perm_test \
"opendir" \
"realpath,readdir,stat,lstat" \
"ls -ln $OBJ"
perm_test \
"readdir" \
"realpath,opendir,stat,lstat" \
"ls -ln $OBJ"
perm_test \
"setstat" \
"realpath,stat,lstat" \
"chmod 0700 $COPY" \
"touch $COPY; chmod 0400 $COPY" \
"test -x $COPY" \
"test ! -x $COPY"
perm_test \
"remove" \
"realpath,stat,lstat" \
"rm $COPY" \
"touch $COPY" \
"test ! -f $COPY" \
"test -f $COPY"
perm_test \
"mkdir" \
"realpath,stat,lstat" \
"mkdir ${COPY}.dd" \
"" \
"test -d ${COPY}.dd" \
"test ! -d ${COPY}.dd"
perm_test \
"rmdir" \
"realpath,stat,lstat" \
"rmdir ${COPY}.dd" \
"mkdir ${COPY}.dd" \
"test ! -d ${COPY}.dd" \
"test -d ${COPY}.dd"
-perm_test \
- "posix-rename" \
- "realpath,stat,lstat" \
- "rename $COPY ${COPY}.1" \
- "touch $COPY" \
- "test -f ${COPY}.1 -a ! -f $COPY" \
- "test -f $COPY -a ! -f ${COPY}.1"
+# Can't readily test this because the client falls back to traditional rename.
+# XXX maybe there is a behaviorial difference we can test for?
+#perm_test \
+# "posix-rename" \
+# "realpath,stat,lstat" \
+# "rename $COPY ${COPY}.1" \
+# "touch $COPY" \
+# "test -f ${COPY}.1 -a ! -f $COPY" \
+# "test -f $COPY -a ! -f ${COPY}.1"
perm_test \
"rename" \
"realpath,stat,lstat" \
"rename -l $COPY ${COPY}.1" \
"touch $COPY" \
"test -f ${COPY}.1 -a ! -f $COPY" \
"test -f $COPY -a ! -f ${COPY}.1"
perm_test \
"symlink" \
"realpath,stat,lstat" \
"ln -s $COPY ${COPY}.1" \
"touch $COPY" \
"test -h ${COPY}.1" \
"test ! -h ${COPY}.1"
perm_test \
"hardlink" \
"realpath,stat,lstat" \
"ln $COPY ${COPY}.1" \
"touch $COPY" \
"test -f ${COPY}.1" \
"test ! -f ${COPY}.1"
perm_test \
"statvfs" \
"realpath,stat,lstat" \
"df /"
# XXX need good tests for:
# fstat
# fsetstat
# realpath
# stat
# readlink
# fstatvfs
rm -rf ${COPY} ${COPY}.1 ${COPY}.dd
diff --git a/regress/test-exec.sh b/regress/test-exec.sh
index 11475938bed6..bc59ebddf055 100644
--- a/regress/test-exec.sh
+++ b/regress/test-exec.sh
@@ -1,714 +1,722 @@
-# $OpenBSD: test-exec.sh,v 1.77 2021/02/17 03:59:00 dtucker Exp $
+# $OpenBSD: test-exec.sh,v 1.79 2021/04/06 23:57:56 dtucker Exp $
# Placed in the Public Domain.
#SUDO=sudo
# Unbreak GNU head(1)
_POSIX2_VERSION=199209
export _POSIX2_VERSION
case `uname -s 2>/dev/null` in
OSF1*)
BIN_SH=xpg4
export BIN_SH
;;
CYGWIN*)
os=cygwin
;;
esac
-if [ ! -z "$TEST_SSH_PORT" ]; then
- PORT="$TEST_SSH_PORT"
-else
- PORT=4242
-fi
-
# If configure tells us to use a different egrep, create a wrapper function
# to call it. This means we don't need to change all the tests that depend
# on a good implementation.
if test "x${EGREP}" != "x"; then
egrep ()
{
${EGREP} "$@"
}
fi
if [ -x /usr/ucb/whoami ]; then
USER=`/usr/ucb/whoami`
elif whoami >/dev/null 2>&1; then
USER=`whoami`
elif logname >/dev/null 2>&1; then
USER=`logname`
else
USER=`id -un`
fi
if test -z "$LOGNAME"; then
LOGNAME="${USER}"
export LOGNAME
fi
+if [ ! -x "$TEST_SSH_ELAPSED_TIMES" ]; then
+ STARTTIME=`date '+%s'`
+fi
+
+if [ ! -z "$TEST_SSH_PORT" ]; then
+ PORT="$TEST_SSH_PORT"
+else
+ PORT=4242
+fi
+
OBJ=$1
if [ "x$OBJ" = "x" ]; then
echo '$OBJ not defined'
exit 2
fi
if [ ! -d $OBJ ]; then
echo "not a directory: $OBJ"
exit 2
fi
SCRIPT=$2
if [ "x$SCRIPT" = "x" ]; then
echo '$SCRIPT not defined'
exit 2
fi
if [ ! -f $SCRIPT ]; then
echo "not a file: $SCRIPT"
exit 2
fi
if $TEST_SHELL -n $SCRIPT; then
true
else
echo "syntax error in $SCRIPT"
exit 2
fi
unset SSH_AUTH_SOCK
SRC=`dirname ${SCRIPT}`
# defaults
SSH=ssh
SSHD=sshd
SSHAGENT=ssh-agent
SSHADD=ssh-add
SSHKEYGEN=ssh-keygen
SSHKEYSCAN=ssh-keyscan
SFTP=sftp
SFTPSERVER=/usr/libexec/openssh/sftp-server
SCP=scp
# Set by make_tmpdir() on demand (below).
SSH_REGRESS_TMP=
# Interop testing
PLINK=plink
PUTTYGEN=puttygen
CONCH=conch
# Tools used by multiple tests
NC=$OBJ/netcat
if [ "x$TEST_SSH_SSH" != "x" ]; then
SSH="${TEST_SSH_SSH}"
fi
if [ "x$TEST_SSH_SSHD" != "x" ]; then
SSHD="${TEST_SSH_SSHD}"
fi
if [ "x$TEST_SSH_SSHAGENT" != "x" ]; then
SSHAGENT="${TEST_SSH_SSHAGENT}"
fi
if [ "x$TEST_SSH_SSHADD" != "x" ]; then
SSHADD="${TEST_SSH_SSHADD}"
fi
if [ "x$TEST_SSH_SSHKEYGEN" != "x" ]; then
SSHKEYGEN="${TEST_SSH_SSHKEYGEN}"
fi
if [ "x$TEST_SSH_SSHKEYSCAN" != "x" ]; then
SSHKEYSCAN="${TEST_SSH_SSHKEYSCAN}"
fi
if [ "x$TEST_SSH_SFTP" != "x" ]; then
SFTP="${TEST_SSH_SFTP}"
fi
if [ "x$TEST_SSH_SFTPSERVER" != "x" ]; then
SFTPSERVER="${TEST_SSH_SFTPSERVER}"
fi
if [ "x$TEST_SSH_SCP" != "x" ]; then
SCP="${TEST_SSH_SCP}"
fi
if [ "x$TEST_SSH_PLINK" != "x" ]; then
# Find real binary, if it exists
case "${TEST_SSH_PLINK}" in
/*) PLINK="${TEST_SSH_PLINK}" ;;
*) PLINK=`which ${TEST_SSH_PLINK} 2>/dev/null` ;;
esac
fi
if [ "x$TEST_SSH_PUTTYGEN" != "x" ]; then
# Find real binary, if it exists
case "${TEST_SSH_PUTTYGEN}" in
/*) PUTTYGEN="${TEST_SSH_PUTTYGEN}" ;;
*) PUTTYGEN=`which ${TEST_SSH_PUTTYGEN} 2>/dev/null` ;;
esac
fi
if [ "x$TEST_SSH_CONCH" != "x" ]; then
# Find real binary, if it exists
case "${TEST_SSH_CONCH}" in
/*) CONCH="${TEST_SSH_CONCH}" ;;
*) CONCH=`which ${TEST_SSH_CONCH} 2>/dev/null` ;;
esac
fi
if [ "x$TEST_SSH_PKCS11_HELPER" != "x" ]; then
SSH_PKCS11_HELPER="${TEST_SSH_PKCS11_HELPER}"
fi
if [ "x$TEST_SSH_SK_HELPER" != "x" ]; then
SSH_SK_HELPER="${TEST_SSH_SK_HELPER}"
fi
# Path to sshd must be absolute for rexec
case "$SSHD" in
/*) ;;
*) SSHD=`which $SSHD` ;;
esac
case "$SSHAGENT" in
/*) ;;
*) SSHAGENT=`which $SSHAGENT` ;;
esac
# Record the actual binaries used.
SSH_BIN=${SSH}
SSHD_BIN=${SSHD}
SSHAGENT_BIN=${SSHAGENT}
SSHADD_BIN=${SSHADD}
SSHKEYGEN_BIN=${SSHKEYGEN}
SSHKEYSCAN_BIN=${SSHKEYSCAN}
SFTP_BIN=${SFTP}
SFTPSERVER_BIN=${SFTPSERVER}
SCP_BIN=${SCP}
if [ "x$USE_VALGRIND" != "x" ]; then
rm -rf $OBJ/valgrind-out $OBJ/valgrind-vgdb
mkdir -p $OBJ/valgrind-out $OBJ/valgrind-vgdb
# When using sudo ensure low-priv tests can write pipes and logs.
if [ "x$SUDO" != "x" ]; then
chmod 777 $OBJ/valgrind-out $OBJ/valgrind-vgdb
fi
VG_TEST=`basename $SCRIPT .sh`
# Some tests are difficult to fix.
case "$VG_TEST" in
reexec)
VG_SKIP=1 ;;
sftp-chroot)
if [ "x${SUDO}" != "x" ]; then
VG_SKIP=1
fi ;;
esac
if [ x"$VG_SKIP" = "x" ]; then
VG_LEAK="--leak-check=no"
if [ x"$VALGRIND_CHECK_LEAKS" != "x" ]; then
VG_LEAK="--leak-check=full"
fi
VG_IGNORE="/bin/*,/sbin/*,/usr/*,/var/*"
VG_LOG="$OBJ/valgrind-out/${VG_TEST}."
VG_OPTS="--track-origins=yes $VG_LEAK"
VG_OPTS="$VG_OPTS --trace-children=yes"
VG_OPTS="$VG_OPTS --trace-children-skip=${VG_IGNORE}"
VG_OPTS="$VG_OPTS --vgdb-prefix=$OBJ/valgrind-vgdb/"
VG_PATH="valgrind"
if [ "x$VALGRIND_PATH" != "x" ]; then
VG_PATH="$VALGRIND_PATH"
fi
VG="$VG_PATH $VG_OPTS"
SSH="$VG --log-file=${VG_LOG}ssh.%p $SSH"
SSHD="$VG --log-file=${VG_LOG}sshd.%p $SSHD"
SSHAGENT="$VG --log-file=${VG_LOG}ssh-agent.%p $SSHAGENT"
SSHADD="$VG --log-file=${VG_LOG}ssh-add.%p $SSHADD"
SSHKEYGEN="$VG --log-file=${VG_LOG}ssh-keygen.%p $SSHKEYGEN"
SSHKEYSCAN="$VG --log-file=${VG_LOG}ssh-keyscan.%p $SSHKEYSCAN"
SFTP="$VG --log-file=${VG_LOG}sftp.%p ${SFTP}"
SCP="$VG --log-file=${VG_LOG}scp.%p $SCP"
cat > $OBJ/valgrind-sftp-server.sh << EOF
#!/bin/sh
exec $VG --log-file=${VG_LOG}sftp-server.%p $SFTPSERVER "\$@"
EOF
chmod a+rx $OBJ/valgrind-sftp-server.sh
SFTPSERVER="$OBJ/valgrind-sftp-server.sh"
fi
fi
# Logfiles.
# SSH_LOGFILE should be the debug output of ssh(1) only
# SSHD_LOGFILE should be the debug output of sshd(8) only
# REGRESS_LOGFILE is the output of the test itself stdout and stderr
if [ "x$TEST_SSH_LOGFILE" = "x" ]; then
TEST_SSH_LOGFILE=$OBJ/ssh.log
fi
if [ "x$TEST_SSHD_LOGFILE" = "x" ]; then
TEST_SSHD_LOGFILE=$OBJ/sshd.log
fi
if [ "x$TEST_REGRESS_LOGFILE" = "x" ]; then
TEST_REGRESS_LOGFILE=$OBJ/regress.log
fi
# truncate logfiles
>$TEST_SSH_LOGFILE
>$TEST_SSHD_LOGFILE
>$TEST_REGRESS_LOGFILE
# Create wrapper ssh with logging. We can't just specify "SSH=ssh -E..."
# because sftp and scp don't handle spaces in arguments.
SSHLOGWRAP=$OBJ/ssh-log-wrapper.sh
echo "#!/bin/sh" > $SSHLOGWRAP
echo "exec ${SSH} -E${TEST_SSH_LOGFILE} "'"$@"' >>$SSHLOGWRAP
chmod a+rx $OBJ/ssh-log-wrapper.sh
REAL_SSH="$SSH"
REAL_SSHD="$SSHD"
SSH="$SSHLOGWRAP"
# Some test data. We make a copy because some tests will overwrite it.
# The tests may assume that $DATA exists and is writable and $COPY does
# not exist. Tests requiring larger data files can call increase_datafile_size
# [kbytes] to ensure the file is at least that large.
DATANAME=data
DATA=$OBJ/${DATANAME}
cat ${SSHAGENT_BIN} >${DATA}
chmod u+w ${DATA}
COPY=$OBJ/copy
rm -f ${COPY}
increase_datafile_size()
{
while [ `du -k ${DATA} | cut -f1` -lt $1 ]; do
cat ${SSHAGENT_BIN} >>${DATA}
done
}
# these should be used in tests
export SSH SSHD SSHAGENT SSHADD SSHKEYGEN SSHKEYSCAN SFTP SFTPSERVER SCP
export SSH_PKCS11_HELPER SSH_SK_HELPER
#echo $SSH $SSHD $SSHAGENT $SSHADD $SSHKEYGEN $SSHKEYSCAN $SFTP $SFTPSERVER $SCP
# Portable specific functions
have_prog()
{
saved_IFS="$IFS"
IFS=":"
for i in $PATH
do
if [ -x $i/$1 ]; then
IFS="$saved_IFS"
return 0
fi
done
IFS="$saved_IFS"
return 1
}
jot() {
awk "BEGIN { for (i = $2; i < $2 + $1; i++) { printf \"%d\n\", i } exit }"
}
# Check whether preprocessor symbols are defined in config.h.
config_defined ()
{
str=$1
while test "x$2" != "x" ; do
str="$str|$2"
shift
done
egrep "^#define.*($str)" ${BUILDDIR}/config.h >/dev/null 2>&1
}
md5 () {
if have_prog md5sum; then
md5sum
elif have_prog openssl; then
openssl md5
elif have_prog cksum; then
cksum
elif have_prog sum; then
sum
else
wc -c
fi
}
# Some platforms don't have hostname at all, but on others uname -n doesn't
# provide the fully qualified name we need, so in the former case we create
# our own hostname function.
if ! have_prog hostname; then
hostname() {
uname -n
}
fi
+
+make_tmpdir ()
+{
+ SSH_REGRESS_TMP="$($OBJ/mkdtemp openssh-XXXXXXXX)" || \
+ fatal "failed to create temporary directory"
+}
# End of portable specific functions
stop_sshd ()
{
if [ -f $PIDFILE ]; then
pid=`$SUDO cat $PIDFILE`
if [ "X$pid" = "X" ]; then
echo no sshd running
else
if [ $pid -lt 2 ]; then
echo bad pid for sshd: $pid
else
$SUDO kill $pid
trace "wait for sshd to exit"
i=0;
while [ -f $PIDFILE -a $i -lt 5 ]; do
i=`expr $i + 1`
sleep $i
done
if test -f $PIDFILE; then
if $SUDO kill -0 $pid; then
echo "sshd didn't exit " \
"port $PORT pid $pid"
else
echo "sshd died without cleanup"
fi
exit 1
fi
fi
fi
fi
}
-make_tmpdir ()
-{
- SSH_REGRESS_TMP="$($OBJ/mkdtemp openssh-XXXXXXXX)" || \
- fatal "failed to create temporary directory"
-}
-
# helper
cleanup ()
{
if [ "x$SSH_PID" != "x" ]; then
if [ $SSH_PID -lt 2 ]; then
echo bad pid for ssh: $SSH_PID
else
kill $SSH_PID
fi
fi
if [ "x$SSH_REGRESS_TMP" != "x" ]; then
rm -rf "$SSH_REGRESS_TMP"
fi
stop_sshd
+ if [ ! -z "$TEST_SSH_ELAPSED_TIMES" ]; then
+ now=`date '+%s'`
+ elapsed=$(($now - $STARTTIME))
+ echo elapsed $elapsed `basename $SCRIPT .sh`
+ fi
}
start_debug_log ()
{
echo "trace: $@" >$TEST_REGRESS_LOGFILE
echo "trace: $@" >$TEST_SSH_LOGFILE
echo "trace: $@" >$TEST_SSHD_LOGFILE
}
save_debug_log ()
{
echo $@ >>$TEST_REGRESS_LOGFILE
echo $@ >>$TEST_SSH_LOGFILE
echo $@ >>$TEST_SSHD_LOGFILE
(cat $TEST_REGRESS_LOGFILE; echo) >>$OBJ/failed-regress.log
(cat $TEST_SSH_LOGFILE; echo) >>$OBJ/failed-ssh.log
(cat $TEST_SSHD_LOGFILE; echo) >>$OBJ/failed-sshd.log
}
trace ()
{
start_debug_log $@
if [ "X$TEST_SSH_TRACE" = "Xyes" ]; then
echo "$@"
fi
}
verbose ()
{
start_debug_log $@
if [ "X$TEST_SSH_QUIET" != "Xyes" ]; then
echo "$@"
fi
}
-warn ()
-{
- echo "WARNING: $@" >>$TEST_SSH_LOGFILE
- echo "WARNING: $@"
-}
-
fail ()
{
save_debug_log "FAIL: $@"
RESULT=1
echo "$@"
if test "x$TEST_SSH_FAIL_FATAL" != "x" ; then
cleanup
exit $RESULT
fi
}
fatal ()
{
save_debug_log "FATAL: $@"
printf "FATAL: "
fail "$@"
cleanup
exit $RESULT
}
RESULT=0
PIDFILE=$OBJ/pidfile
trap fatal 3 2
# create server config
cat << EOF > $OBJ/sshd_config
StrictModes no
Port $PORT
AddressFamily inet
ListenAddress 127.0.0.1
#ListenAddress ::1
PidFile $PIDFILE
AuthorizedKeysFile $OBJ/authorized_keys_%u
LogLevel DEBUG3
AcceptEnv _XXX_TEST_*
AcceptEnv _XXX_TEST
Subsystem sftp $SFTPSERVER
EOF
# This may be necessary if /usr/src and/or /usr/obj are group-writable,
# but if you aren't careful with permissions then the unit tests could
# be abused to locally escalate privileges.
if [ ! -z "$TEST_SSH_UNSAFE_PERMISSIONS" ]; then
- echo "StrictModes no" >> $OBJ/sshd_config
+ echo " StrictModes no" >> $OBJ/sshd_config
else
# check and warn if excessive permissions are likely to cause failures.
unsafe=""
dir="${OBJ}"
while test ${dir} != "/"; do
if test -d "${dir}" && ! test -h "${dir}"; then
perms=`ls -ld ${dir}`
case "${perms}" in
?????w????*|????????w?*) unsafe="${unsafe} ${dir}" ;;
esac
fi
dir=`dirname ${dir}`
done
if ! test -z "${unsafe}"; then
cat <<EOD
WARNING: Unsafe (group or world writable) directory permissions found:
${unsafe}
These could be abused to locally escalate privileges. If you are
sure that this is not a risk (eg there are no other users), you can
bypass this check by setting TEST_SSH_UNSAFE_PERMISSIONS=1
EOD
fi
fi
+if [ ! -z "$TEST_SSH_MODULI_FILE" ]; then
+ trace "adding modulifile='$TEST_SSH_MODULI_FILE' to sshd_config"
+ echo " ModuliFile '$TEST_SSH_MODULI_FILE'" >> $OBJ/sshd_config
+fi
+
if [ ! -z "$TEST_SSH_SSHD_CONFOPTS" ]; then
trace "adding sshd_config option $TEST_SSH_SSHD_CONFOPTS"
echo "$TEST_SSH_SSHD_CONFOPTS" >> $OBJ/sshd_config
fi
# server config for proxy connects
cp $OBJ/sshd_config $OBJ/sshd_proxy
# allow group-writable directories in proxy-mode
echo 'StrictModes no' >> $OBJ/sshd_proxy
# create client config
cat << EOF > $OBJ/ssh_config
Host *
Hostname 127.0.0.1
HostKeyAlias localhost-with-alias
Port $PORT
User $USER
GlobalKnownHostsFile $OBJ/known_hosts
UserKnownHostsFile $OBJ/known_hosts
PubkeyAuthentication yes
ChallengeResponseAuthentication no
HostbasedAuthentication no
PasswordAuthentication no
BatchMode yes
StrictHostKeyChecking yes
LogLevel DEBUG3
EOF
if [ ! -z "$TEST_SSH_SSH_CONFOPTS" ]; then
trace "adding ssh_config option $TEST_SSH_SSH_CONFOPTS"
echo "$TEST_SSH_SSH_CONFOPTS" >> $OBJ/ssh_config
fi
rm -f $OBJ/known_hosts $OBJ/authorized_keys_$USER
SSH_SK_PROVIDER=
if ! config_defined ENABLE_SK; then
trace skipping sk-dummy
elif [ -f "${SRC}/misc/sk-dummy/obj/sk-dummy.so" ] ; then
SSH_SK_PROVIDER="${SRC}/misc/sk-dummy/obj/sk-dummy.so"
elif [ -f "${SRC}/misc/sk-dummy/sk-dummy.so" ] ; then
SSH_SK_PROVIDER="${SRC}/misc/sk-dummy/sk-dummy.so"
fi
export SSH_SK_PROVIDER
if ! test -z "$SSH_SK_PROVIDER"; then
EXTRA_AGENT_ARGS='-P/*' # XXX want realpath(1)...
echo "SecurityKeyProvider $SSH_SK_PROVIDER" >> $OBJ/ssh_config
echo "SecurityKeyProvider $SSH_SK_PROVIDER" >> $OBJ/sshd_config
echo "SecurityKeyProvider $SSH_SK_PROVIDER" >> $OBJ/sshd_proxy
fi
export EXTRA_AGENT_ARGS
maybe_filter_sk() {
if test -z "$SSH_SK_PROVIDER" ; then
grep -v ^sk
else
cat
fi
}
SSH_KEYTYPES=`$SSH -Q key-plain | maybe_filter_sk`
SSH_HOSTKEY_TYPES=`$SSH -Q key-plain | maybe_filter_sk`
for t in ${SSH_KEYTYPES}; do
# generate user key
if [ ! -f $OBJ/$t ] || [ ${SSHKEYGEN_BIN} -nt $OBJ/$t ]; then
trace "generating key type $t"
rm -f $OBJ/$t
${SSHKEYGEN} -q -N '' -t $t -f $OBJ/$t ||\
fail "ssh-keygen for $t failed"
else
trace "using cached key type $t"
fi
# setup authorized keys
cat $OBJ/$t.pub >> $OBJ/authorized_keys_$USER
echo IdentityFile $OBJ/$t >> $OBJ/ssh_config
done
for t in ${SSH_HOSTKEY_TYPES}; do
# known hosts file for client
(
printf 'localhost-with-alias,127.0.0.1,::1 '
cat $OBJ/$t.pub
) >> $OBJ/known_hosts
# use key as host key, too
$SUDO cp $OBJ/$t $OBJ/host.$t
echo HostKey $OBJ/host.$t >> $OBJ/sshd_config
# don't use SUDO for proxy connect
echo HostKey $OBJ/$t >> $OBJ/sshd_proxy
done
chmod 644 $OBJ/authorized_keys_$USER
# Activate Twisted Conch tests if the binary is present
REGRESS_INTEROP_CONCH=no
if test -x "$CONCH" ; then
REGRESS_INTEROP_CONCH=yes
fi
# If PuTTY is present, new enough and we are running a PuTTY test, prepare
# keys and configuration.
REGRESS_INTEROP_PUTTY=no
if test -x "$PUTTYGEN" -a -x "$PLINK" &&
"$PUTTYGEN" --help 2>&1 | grep -- --new-passphrase >/dev/null; then
REGRESS_INTEROP_PUTTY=yes
fi
case "$SCRIPT" in
*putty*) ;;
*) REGRESS_INTEROP_PUTTY=no ;;
esac
if test "$REGRESS_INTEROP_PUTTY" = "yes" ; then
mkdir -p ${OBJ}/.putty
# Add a PuTTY key to authorized_keys
rm -f ${OBJ}/putty.rsa2
if ! "$PUTTYGEN" -t rsa -o ${OBJ}/putty.rsa2 \
--random-device=/dev/urandom \
--new-passphrase /dev/null < /dev/null > /dev/null; then
echo "Your installed version of PuTTY is too old to support --new-passphrase, skipping test" >&2
exit 1
fi
"$PUTTYGEN" -O public-openssh ${OBJ}/putty.rsa2 \
>> $OBJ/authorized_keys_$USER
# Convert rsa2 host key to PuTTY format
cp $OBJ/ssh-rsa $OBJ/ssh-rsa_oldfmt
${SSHKEYGEN} -p -N '' -m PEM -f $OBJ/ssh-rsa_oldfmt >/dev/null
${SRC}/ssh2putty.sh 127.0.0.1 $PORT $OBJ/ssh-rsa_oldfmt > \
${OBJ}/.putty/sshhostkeys
${SRC}/ssh2putty.sh 127.0.0.1 22 $OBJ/ssh-rsa_oldfmt >> \
${OBJ}/.putty/sshhostkeys
rm -f $OBJ/ssh-rsa_oldfmt
# Setup proxied session
mkdir -p ${OBJ}/.putty/sessions
rm -f ${OBJ}/.putty/sessions/localhost_proxy
echo "Protocol=ssh" >> ${OBJ}/.putty/sessions/localhost_proxy
echo "HostName=127.0.0.1" >> ${OBJ}/.putty/sessions/localhost_proxy
echo "PortNumber=$PORT" >> ${OBJ}/.putty/sessions/localhost_proxy
echo "ProxyMethod=5" >> ${OBJ}/.putty/sessions/localhost_proxy
echo "ProxyTelnetCommand=sh ${SRC}/sshd-log-wrapper.sh ${TEST_SSHD_LOGFILE} ${SSHD} -i -f $OBJ/sshd_proxy" >> ${OBJ}/.putty/sessions/localhost_proxy
echo "ProxyLocalhost=1" >> ${OBJ}/.putty/sessions/localhost_proxy
PUTTYDIR=${OBJ}/.putty
export PUTTYDIR
fi
# create a proxy version of the client config
(
cat $OBJ/ssh_config
echo proxycommand ${SUDO} env SSH_SK_HELPER=\"$SSH_SK_HELPER\" sh ${SRC}/sshd-log-wrapper.sh ${TEST_SSHD_LOGFILE} ${SSHD} -i -f $OBJ/sshd_proxy
) > $OBJ/ssh_proxy
# check proxy config
${SSHD} -t -f $OBJ/sshd_proxy || fatal "sshd_proxy broken"
start_sshd ()
{
# start sshd
$SUDO ${SSHD} -f $OBJ/sshd_config "$@" -t || fatal "sshd_config broken"
$SUDO env SSH_SK_HELPER="$SSH_SK_HELPER" \
${SSHD} -f $OBJ/sshd_config "$@" -E$TEST_SSHD_LOGFILE
trace "wait for sshd"
i=0;
while [ ! -f $PIDFILE -a $i -lt 10 ]; do
i=`expr $i + 1`
sleep $i
done
test -f $PIDFILE || fatal "no sshd running on port $PORT"
}
# source test body
. $SCRIPT
# kill sshd
cleanup
if [ "x$USE_VALGRIND" != "x" ]; then
# wait for any running process to complete
wait; sleep 1
VG_RESULTS=$(find $OBJ/valgrind-out -type f -print)
VG_RESULT_COUNT=0
VG_FAIL_COUNT=0
for i in $VG_RESULTS; do
if grep "ERROR SUMMARY" $i >/dev/null; then
VG_RESULT_COUNT=$(($VG_RESULT_COUNT + 1))
if ! grep "ERROR SUMMARY: 0 errors" $i >/dev/null; then
VG_FAIL_COUNT=$(($VG_FAIL_COUNT + 1))
RESULT=1
verbose valgrind failure $i
cat $i
fi
fi
done
if [ x"$VG_SKIP" != "x" ]; then
verbose valgrind skipped
else
verbose valgrind results $VG_RESULT_COUNT failures $VG_FAIL_COUNT
fi
fi
if [ $RESULT -eq 0 ]; then
verbose ok $tid
else
echo failed $tid
fi
exit $RESULT
diff --git a/regress/unittests/authopt/tests.c b/regress/unittests/authopt/tests.c
index 0e8aacb91699..8c51b3802aa6 100644
--- a/regress/unittests/authopt/tests.c
+++ b/regress/unittests/authopt/tests.c
@@ -1,573 +1,575 @@
/* $OpenBSD: tests.c,v 1.1 2018/03/03 03:16:17 djm Exp $ */
/*
* Regress test for keys options functions.
*
* Placed in the public domain
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include "test_helper.h"
+#include "../test_helper/test_helper.h"
#include "sshkey.h"
#include "authfile.h"
#include "auth-options.h"
#include "misc.h"
#include "log.h"
static struct sshkey *
load_key(const char *name)
{
struct sshkey *ret;
int r;
r = sshkey_load_public(test_data_file(name), &ret, NULL);
ASSERT_INT_EQ(r, 0);
ASSERT_PTR_NE(ret, NULL);
return ret;
}
static struct sshauthopt *
default_authkey_opts(void)
{
struct sshauthopt *ret = sshauthopt_new();
ASSERT_PTR_NE(ret, NULL);
ret->permit_port_forwarding_flag = 1;
ret->permit_agent_forwarding_flag = 1;
ret->permit_x11_forwarding_flag = 1;
ret->permit_pty_flag = 1;
ret->permit_user_rc = 1;
return ret;
}
static struct sshauthopt *
default_authkey_restrict_opts(void)
{
struct sshauthopt *ret = sshauthopt_new();
ASSERT_PTR_NE(ret, NULL);
ret->permit_port_forwarding_flag = 0;
ret->permit_agent_forwarding_flag = 0;
ret->permit_x11_forwarding_flag = 0;
ret->permit_pty_flag = 0;
ret->permit_user_rc = 0;
ret->restricted = 1;
return ret;
}
static char **
commasplit(const char *s, size_t *np)
{
char *ocp, *cp, *cp2, **ret = NULL;
size_t n;
ocp = cp = strdup(s);
ASSERT_PTR_NE(cp, NULL);
for (n = 0; (cp2 = strsep(&cp, ",")) != NULL;) {
ret = recallocarray(ret, n, n + 1, sizeof(*ret));
ASSERT_PTR_NE(ret, NULL);
cp2 = strdup(cp2);
ASSERT_PTR_NE(cp2, NULL);
ret[n++] = cp2;
}
free(ocp);
*np = n;
return ret;
}
static void
compare_opts(const struct sshauthopt *opts,
const struct sshauthopt *expected)
{
size_t i;
ASSERT_PTR_NE(opts, NULL);
ASSERT_PTR_NE(expected, NULL);
ASSERT_PTR_NE(expected, opts); /* bozo :) */
#define FLAG_EQ(x) ASSERT_INT_EQ(opts->x, expected->x)
FLAG_EQ(permit_port_forwarding_flag);
FLAG_EQ(permit_agent_forwarding_flag);
FLAG_EQ(permit_x11_forwarding_flag);
FLAG_EQ(permit_pty_flag);
FLAG_EQ(permit_user_rc);
FLAG_EQ(restricted);
FLAG_EQ(cert_authority);
#undef FLAG_EQ
#define STR_EQ(x) \
do { \
if (expected->x == NULL) \
ASSERT_PTR_EQ(opts->x, expected->x); \
else \
ASSERT_STRING_EQ(opts->x, expected->x); \
} while (0)
STR_EQ(cert_principals);
STR_EQ(force_command);
STR_EQ(required_from_host_cert);
STR_EQ(required_from_host_keys);
#undef STR_EQ
#define ARRAY_EQ(nx, x) \
do { \
ASSERT_SIZE_T_EQ(opts->nx, expected->nx); \
if (expected->nx == 0) \
break; \
for (i = 0; i < expected->nx; i++) \
ASSERT_STRING_EQ(opts->x[i], expected->x[i]); \
} while (0)
ARRAY_EQ(nenv, env);
ARRAY_EQ(npermitopen, permitopen);
#undef ARRAY_EQ
}
static void
test_authkeys_parse(void)
{
struct sshauthopt *opts, *expected;
const char *errstr;
#define FAIL_TEST(label, keywords) \
do { \
TEST_START("sshauthopt_parse invalid " label); \
opts = sshauthopt_parse(keywords, &errstr); \
ASSERT_PTR_EQ(opts, NULL); \
ASSERT_PTR_NE(errstr, NULL); \
TEST_DONE(); \
} while (0)
#define CHECK_SUCCESS_AND_CLEANUP() \
do { \
if (errstr != NULL) \
ASSERT_STRING_EQ(errstr, ""); \
compare_opts(opts, expected); \
sshauthopt_free(expected); \
sshauthopt_free(opts); \
} while (0)
/* Basic tests */
TEST_START("sshauthopt_parse empty");
expected = default_authkey_opts();
opts = sshauthopt_parse("", &errstr);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
TEST_START("sshauthopt_parse trailing whitespace");
expected = default_authkey_opts();
opts = sshauthopt_parse(" ", &errstr);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
TEST_START("sshauthopt_parse restrict");
expected = default_authkey_restrict_opts();
opts = sshauthopt_parse("restrict", &errstr);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
/* Invalid syntax */
FAIL_TEST("trailing comma", "restrict,");
FAIL_TEST("bare comma", ",");
FAIL_TEST("unknown option", "BLAH");
FAIL_TEST("unknown option with trailing comma", "BLAH,");
FAIL_TEST("unknown option with trailing whitespace", "BLAH ");
/* force_tun_device */
TEST_START("sshauthopt_parse tunnel explicit");
expected = default_authkey_opts();
expected->force_tun_device = 1;
opts = sshauthopt_parse("tunnel=\"1\"", &errstr);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
TEST_START("sshauthopt_parse tunnel any");
expected = default_authkey_opts();
expected->force_tun_device = SSH_TUNID_ANY;
opts = sshauthopt_parse("tunnel=\"any\"", &errstr);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
FAIL_TEST("tunnel", "tunnel=\"blah\"");
/* Flag options */
#define FLAG_TEST(keyword, var, val) \
do { \
TEST_START("sshauthopt_parse " keyword); \
expected = default_authkey_opts(); \
expected->var = val; \
opts = sshauthopt_parse(keyword, &errstr); \
CHECK_SUCCESS_AND_CLEANUP(); \
expected = default_authkey_restrict_opts(); \
expected->var = val; \
opts = sshauthopt_parse("restrict,"keyword, &errstr); \
CHECK_SUCCESS_AND_CLEANUP(); \
TEST_DONE(); \
} while (0)
/* Positive flags */
FLAG_TEST("cert-authority", cert_authority, 1);
FLAG_TEST("port-forwarding", permit_port_forwarding_flag, 1);
FLAG_TEST("agent-forwarding", permit_agent_forwarding_flag, 1);
FLAG_TEST("x11-forwarding", permit_x11_forwarding_flag, 1);
FLAG_TEST("pty", permit_pty_flag, 1);
FLAG_TEST("user-rc", permit_user_rc, 1);
/* Negative flags */
FLAG_TEST("no-port-forwarding", permit_port_forwarding_flag, 0);
FLAG_TEST("no-agent-forwarding", permit_agent_forwarding_flag, 0);
FLAG_TEST("no-x11-forwarding", permit_x11_forwarding_flag, 0);
FLAG_TEST("no-pty", permit_pty_flag, 0);
FLAG_TEST("no-user-rc", permit_user_rc, 0);
#undef FLAG_TEST
FAIL_TEST("no-cert-authority", "no-cert-authority");
/* String options */
#define STRING_TEST(keyword, var, val) \
do { \
TEST_START("sshauthopt_parse " keyword); \
expected = default_authkey_opts(); \
expected->var = strdup(val); \
ASSERT_PTR_NE(expected->var, NULL); \
opts = sshauthopt_parse(keyword "=" #val, &errstr); \
CHECK_SUCCESS_AND_CLEANUP(); \
expected = default_authkey_restrict_opts(); \
expected->var = strdup(val); \
ASSERT_PTR_NE(expected->var, NULL); \
opts = sshauthopt_parse( \
"restrict," keyword "=" #val ",restrict", &errstr); \
CHECK_SUCCESS_AND_CLEANUP(); \
TEST_DONE(); \
} while (0)
STRING_TEST("command", force_command, "/bin/true");
STRING_TEST("principals", cert_principals, "gregor,josef,K");
STRING_TEST("from", required_from_host_keys, "127.0.0.0/8");
#undef STRING_TEST
FAIL_TEST("unquoted command", "command=oops");
FAIL_TEST("unquoted principals", "principals=estragon");
FAIL_TEST("unquoted from", "from=127.0.0.1");
/* String array option tests */
#define ARRAY_TEST(label, keywords, var, nvar, val) \
do { \
TEST_START("sshauthopt_parse " label); \
expected = default_authkey_opts(); \
expected->var = commasplit(val, &expected->nvar); \
ASSERT_PTR_NE(expected->var, NULL); \
opts = sshauthopt_parse(keywords, &errstr); \
CHECK_SUCCESS_AND_CLEANUP(); \
expected = default_authkey_restrict_opts(); \
expected->var = commasplit(val, &expected->nvar); \
ASSERT_PTR_NE(expected->var, NULL); \
opts = sshauthopt_parse( \
"restrict," keywords ",restrict", &errstr); \
CHECK_SUCCESS_AND_CLEANUP(); \
TEST_DONE(); \
} while (0)
ARRAY_TEST("environment", "environment=\"foo=1\",environment=\"bar=2\"",
env, nenv, "foo=1,bar=2");
ARRAY_TEST("permitopen", "permitopen=\"foo:123\",permitopen=\"bar:*\"",
permitopen, npermitopen, "foo:123,bar:*");
#undef ARRAY_TEST
FAIL_TEST("environment", "environment=\",=bah\"");
FAIL_TEST("permitopen port", "foo:bar");
FAIL_TEST("permitopen missing port", "foo:");
FAIL_TEST("permitopen missing port specification", "foo");
FAIL_TEST("permitopen invalid host", "[:");
#undef CHECK_SUCCESS_AND_CLEANUP
#undef FAIL_TEST
}
static void
test_cert_parse(void)
{
struct sshkey *cert;
struct sshauthopt *opts, *expected;
#define CHECK_SUCCESS_AND_CLEANUP() \
do { \
compare_opts(opts, expected); \
sshauthopt_free(expected); \
sshauthopt_free(opts); \
sshkey_free(cert); \
} while (0)
#define FLAG_TEST(keybase, var) \
do { \
TEST_START("sshauthopt_from_cert no_" keybase); \
cert = load_key("no_" keybase ".cert"); \
expected = default_authkey_opts(); \
expected->var = 0; \
opts = sshauthopt_from_cert(cert); \
CHECK_SUCCESS_AND_CLEANUP(); \
TEST_DONE(); \
TEST_START("sshauthopt_from_cert only_" keybase); \
cert = load_key("only_" keybase ".cert"); \
expected = sshauthopt_new(); \
ASSERT_PTR_NE(expected, NULL); \
expected->var = 1; \
opts = sshauthopt_from_cert(cert); \
CHECK_SUCCESS_AND_CLEANUP(); \
TEST_DONE(); \
} while (0)
FLAG_TEST("agentfwd", permit_agent_forwarding_flag);
FLAG_TEST("portfwd", permit_port_forwarding_flag);
FLAG_TEST("pty", permit_pty_flag);
FLAG_TEST("user_rc", permit_user_rc);
FLAG_TEST("x11fwd", permit_x11_forwarding_flag);
#undef FLAG_TEST
TEST_START("sshauthopt_from_cert all permitted");
cert = load_key("all_permit.cert");
expected = default_authkey_opts();
opts = sshauthopt_from_cert(cert);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
TEST_START("sshauthopt_from_cert nothing permitted");
cert = load_key("no_permit.cert");
expected = sshauthopt_new();
ASSERT_PTR_NE(expected, NULL);
opts = sshauthopt_from_cert(cert);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
TEST_START("sshauthopt_from_cert force-command");
cert = load_key("force_command.cert");
expected = default_authkey_opts();
expected->force_command = strdup("foo");
ASSERT_PTR_NE(expected->force_command, NULL);
opts = sshauthopt_from_cert(cert);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
TEST_START("sshauthopt_from_cert source-address");
cert = load_key("sourceaddr.cert");
expected = default_authkey_opts();
expected->required_from_host_cert = strdup("127.0.0.1/32,::1/128");
ASSERT_PTR_NE(expected->required_from_host_cert, NULL);
opts = sshauthopt_from_cert(cert);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
#undef CHECK_SUCCESS_AND_CLEANUP
#define FAIL_TEST(keybase) \
do { \
TEST_START("sshauthopt_from_cert " keybase); \
cert = load_key(keybase ".cert"); \
opts = sshauthopt_from_cert(cert); \
ASSERT_PTR_EQ(opts, NULL); \
sshkey_free(cert); \
TEST_DONE(); \
} while (0)
FAIL_TEST("host");
FAIL_TEST("bad_sourceaddr");
FAIL_TEST("unknown_critical");
#undef FAIL_TEST
}
static void
test_merge(void)
{
struct sshkey *cert;
struct sshauthopt *key_opts, *cert_opts, *merge_opts, *expected;
const char *errstr;
/*
* Prepare for a test by making some key and cert options and
* attempting to merge them.
*/
#define PREPARE(label, keyname, keywords) \
do { \
expected = NULL; \
TEST_START("sshauthopt_merge " label); \
cert = load_key(keyname ".cert"); \
cert_opts = sshauthopt_from_cert(cert); \
ASSERT_PTR_NE(cert_opts, NULL); \
key_opts = sshauthopt_parse(keywords, &errstr); \
if (errstr != NULL) \
ASSERT_STRING_EQ(errstr, ""); \
ASSERT_PTR_NE(key_opts, NULL); \
merge_opts = sshauthopt_merge(key_opts, \
cert_opts, &errstr); \
} while (0)
/* Cleanup stuff allocated by PREPARE() */
#define CLEANUP() \
do { \
sshauthopt_free(expected); \
sshauthopt_free(merge_opts); \
sshauthopt_free(key_opts); \
sshauthopt_free(cert_opts); \
sshkey_free(cert); \
} while (0)
/* Check the results of PREPARE() against expectation; calls CLEANUP */
#define CHECK_SUCCESS_AND_CLEANUP() \
do { \
if (errstr != NULL) \
ASSERT_STRING_EQ(errstr, ""); \
compare_opts(merge_opts, expected); \
CLEANUP(); \
} while (0)
/* Check a single case of merging of flag options */
#define FLAG_CASE(keybase, label, keyname, keywords, mostly_off, var, val) \
do { \
PREPARE(keybase " " label, keyname, keywords); \
expected = mostly_off ? \
sshauthopt_new() : default_authkey_opts(); \
expected->var = val; \
ASSERT_PTR_NE(expected, NULL); \
CHECK_SUCCESS_AND_CLEANUP(); \
TEST_DONE(); \
} while (0)
/*
* Fairly exhaustive exercise of a flag option. Tests
* option both set and clear in certificate, set and clear in
* authorized_keys and set and cleared via restrict keyword.
*/
#define FLAG_TEST(keybase, keyword, var) \
do { \
FLAG_CASE(keybase, "keys:default,yes cert:default,no", \
"no_" keybase, keyword, 0, var, 0); \
FLAG_CASE(keybase,"keys:-*,yes cert:default,no", \
"no_" keybase, "restrict," keyword, 1, var, 0); \
FLAG_CASE(keybase, "keys:default,no cert:default,no", \
"no_" keybase, "no-" keyword, 0, var, 0); \
FLAG_CASE(keybase, "keys:-*,no cert:default,no", \
"no_" keybase, "restrict,no-" keyword, 1, var, 0); \
\
FLAG_CASE(keybase, "keys:default,yes cert:-*,yes", \
"only_" keybase, keyword, 1, var, 1); \
FLAG_CASE(keybase,"keys:-*,yes cert:-*,yes", \
"only_" keybase, "restrict," keyword, 1, var, 1); \
FLAG_CASE(keybase, "keys:default,no cert:-*,yes", \
"only_" keybase, "no-" keyword, 1, var, 0); \
FLAG_CASE(keybase, "keys:-*,no cert:-*,yes", \
"only_" keybase, "restrict,no-" keyword, 1, var, 0); \
\
FLAG_CASE(keybase, "keys:default,yes cert:-*", \
"no_permit", keyword, 1, var, 0); \
FLAG_CASE(keybase,"keys:-*,yes cert:-*", \
"no_permit", "restrict," keyword, 1, var, 0); \
FLAG_CASE(keybase, "keys:default,no cert:-*", \
"no_permit", "no-" keyword, 1, var, 0); \
FLAG_CASE(keybase, "keys:-*,no cert:-*", \
"no_permit", "restrict,no-" keyword, 1, var, 0); \
\
FLAG_CASE(keybase, "keys:default,yes cert:*", \
"all_permit", keyword, 0, var, 1); \
FLAG_CASE(keybase,"keys:-*,yes cert:*", \
"all_permit", "restrict," keyword, 1, var, 1); \
FLAG_CASE(keybase, "keys:default,no cert:*", \
"all_permit", "no-" keyword, 0, var, 0); \
FLAG_CASE(keybase, "keys:-*,no cert:*", \
"all_permit", "restrict,no-" keyword, 1, var, 0); \
\
} while (0)
FLAG_TEST("portfwd", "port-forwarding", permit_port_forwarding_flag);
FLAG_TEST("agentfwd", "agent-forwarding", permit_agent_forwarding_flag);
FLAG_TEST("pty", "pty", permit_pty_flag);
FLAG_TEST("user_rc", "user-rc", permit_user_rc);
FLAG_TEST("x11fwd", "x11-forwarding", permit_x11_forwarding_flag);
#undef FLAG_TEST
PREPARE("source-address both", "sourceaddr", "from=\"127.0.0.1\"");
expected = default_authkey_opts();
expected->required_from_host_cert = strdup("127.0.0.1/32,::1/128");
ASSERT_PTR_NE(expected->required_from_host_cert, NULL);
expected->required_from_host_keys = strdup("127.0.0.1");
ASSERT_PTR_NE(expected->required_from_host_keys, NULL);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
PREPARE("source-address none", "all_permit", "");
expected = default_authkey_opts();
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
PREPARE("source-address keys", "all_permit", "from=\"127.0.0.1\"");
expected = default_authkey_opts();
expected->required_from_host_keys = strdup("127.0.0.1");
ASSERT_PTR_NE(expected->required_from_host_keys, NULL);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
PREPARE("source-address cert", "sourceaddr", "");
expected = default_authkey_opts();
expected->required_from_host_cert = strdup("127.0.0.1/32,::1/128");
ASSERT_PTR_NE(expected->required_from_host_cert, NULL);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
PREPARE("force-command both", "force_command", "command=\"foo\"");
expected = default_authkey_opts();
expected->force_command = strdup("foo");
ASSERT_PTR_NE(expected->force_command, NULL);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
PREPARE("force-command none", "all_permit", "");
expected = default_authkey_opts();
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
PREPARE("force-command keys", "all_permit", "command=\"bar\"");
expected = default_authkey_opts();
expected->force_command = strdup("bar");
ASSERT_PTR_NE(expected->force_command, NULL);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
PREPARE("force-command cert", "force_command", "");
expected = default_authkey_opts();
expected->force_command = strdup("foo");
ASSERT_PTR_NE(expected->force_command, NULL);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
PREPARE("force-command mismatch", "force_command", "command=\"bar\"");
ASSERT_PTR_EQ(merge_opts, NULL);
CLEANUP();
TEST_DONE();
PREPARE("tunnel", "all_permit", "tunnel=\"6\"");
expected = default_authkey_opts();
expected->force_tun_device = 6;
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
PREPARE("permitopen", "all_permit",
"permitopen=\"127.0.0.1:*\",permitopen=\"127.0.0.1:123\"");
expected = default_authkey_opts();
expected->permitopen = commasplit("127.0.0.1:*,127.0.0.1:123",
&expected->npermitopen);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
PREPARE("environment", "all_permit",
"environment=\"foo=a\",environment=\"bar=b\"");
expected = default_authkey_opts();
expected->env = commasplit("foo=a,bar=b", &expected->nenv);
CHECK_SUCCESS_AND_CLEANUP();
TEST_DONE();
}
void
tests(void)
{
extern char *__progname;
LogLevel ll = test_is_verbose() ?
SYSLOG_LEVEL_DEBUG3 : SYSLOG_LEVEL_QUIET;
/* test_cert_parse() are a bit spammy to error() by default... */
log_init(__progname, ll, SYSLOG_FACILITY_USER, 1);
test_authkeys_parse();
test_cert_parse();
test_merge();
}
diff --git a/regress/unittests/misc/test_argv.c b/regress/unittests/misc/test_argv.c
new file mode 100644
index 000000000000..7a28f64e5e57
--- /dev/null
+++ b/regress/unittests/misc/test_argv.c
@@ -0,0 +1,141 @@
+/* $OpenBSD: test_argv.c,v 1.1 2021/03/19 04:23:50 djm Exp $ */
+/*
+ * Regress test for misc argv handling functions.
+ *
+ * Placed in the public domain.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "log.h"
+#include "misc.h"
+
+void test_argv(void);
+
+static void
+free_argv(char **av, int ac)
+{
+ int i;
+
+ for (i = 0; i < ac; i++)
+ free(av[i]);
+ free(av);
+}
+
+void
+test_argv(void)
+{
+ char **av = NULL;
+ int ac = 0;
+
+#define RESET_ARGV() \
+ do { \
+ free_argv(av, ac); \
+ av = NULL; \
+ ac = -1; \
+ } while (0)
+
+ TEST_START("empty args");
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("", &ac, &av), 0);
+ ASSERT_INT_EQ(ac, 0);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_PTR_EQ(av[0], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split(" ", &ac, &av), 0);
+ ASSERT_INT_EQ(ac, 0);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_PTR_EQ(av[0], NULL);
+ TEST_DONE();
+
+ TEST_START("trivial args");
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("leamas", &ac, &av), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "leamas");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("smiley leamas", &ac, &av), 0);
+ ASSERT_INT_EQ(ac, 2);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "smiley");
+ ASSERT_STRING_EQ(av[1], "leamas");
+ ASSERT_PTR_EQ(av[2], NULL);
+ TEST_DONE();
+
+ TEST_START("quoted");
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("\"smiley\"", &ac, &av), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "smiley");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("leamas \" smiley \"", &ac, &av), 0);
+ ASSERT_INT_EQ(ac, 2);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "leamas");
+ ASSERT_STRING_EQ(av[1], " smiley ");
+ ASSERT_PTR_EQ(av[2], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("\"smiley leamas\"", &ac, &av), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "smiley leamas");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("smiley\" leamas\" liz", &ac, &av), 0);
+ ASSERT_INT_EQ(ac, 2);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "smiley leamas");
+ ASSERT_STRING_EQ(av[1], "liz");
+ ASSERT_PTR_EQ(av[2], NULL);
+ TEST_DONE();
+
+ TEST_START("escaped");
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("\\\"smiley\\'", &ac, &av), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "\"smiley'");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("'\\'smiley\\\"'", &ac, &av), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "'smiley\"");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("smiley\\'s leamas\\'", &ac, &av), 0);
+ ASSERT_INT_EQ(ac, 2);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "smiley's");
+ ASSERT_STRING_EQ(av[1], "leamas'");
+ ASSERT_PTR_EQ(av[2], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("leamas\\\\smiley", &ac, &av), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "leamas\\smiley");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("leamas\\\\ \\\\smiley", &ac, &av), 0);
+ ASSERT_INT_EQ(ac, 2);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "leamas\\");
+ ASSERT_STRING_EQ(av[1], "\\smiley");
+ ASSERT_PTR_EQ(av[2], NULL);
+ TEST_DONE();
+
+ /* XXX test char *argv_assemble(int argc, char **argv) */
+}
diff --git a/regress/unittests/misc/test_convtime.c b/regress/unittests/misc/test_convtime.c
new file mode 100644
index 000000000000..5be3ee43ad6e
--- /dev/null
+++ b/regress/unittests/misc/test_convtime.c
@@ -0,0 +1,57 @@
+/* $OpenBSD: test_convtime.c,v 1.1 2021/03/19 03:25:01 djm Exp $ */
+/*
+ * Regress test for misc time conversion functions.
+ *
+ * Placed in the public domain.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "log.h"
+#include "misc.h"
+
+void test_convtime(void);
+
+void
+test_convtime(void)
+{
+ char buf[1024];
+
+ TEST_START("misc_convtime");
+ ASSERT_INT_EQ(convtime("0"), 0);
+ ASSERT_INT_EQ(convtime("1"), 1);
+ ASSERT_INT_EQ(convtime("2s"), 2);
+ ASSERT_INT_EQ(convtime("3m"), 180);
+ ASSERT_INT_EQ(convtime("1m30"), 90);
+ ASSERT_INT_EQ(convtime("1m30s"), 90);
+ ASSERT_INT_EQ(convtime("1h1s"), 3601);
+ ASSERT_INT_EQ(convtime("1h30m"), 90 * 60);
+ ASSERT_INT_EQ(convtime("1d"), 24 * 60 * 60);
+ ASSERT_INT_EQ(convtime("1w"), 7 * 24 * 60 * 60);
+ ASSERT_INT_EQ(convtime("1w2d3h4m5"), 788645);
+ ASSERT_INT_EQ(convtime("1w2d3h4m5s"), 788645);
+ /* any negative number or error returns -1 */
+ ASSERT_INT_EQ(convtime("-1"), -1);
+ ASSERT_INT_EQ(convtime(""), -1);
+ ASSERT_INT_EQ(convtime("trout"), -1);
+ ASSERT_INT_EQ(convtime("-77"), -1);
+ /* boundary conditions */
+ snprintf(buf, sizeof buf, "%llu", (long long unsigned)INT_MAX);
+ ASSERT_INT_EQ(convtime(buf), INT_MAX);
+ snprintf(buf, sizeof buf, "%llu", (long long unsigned)INT_MAX + 1);
+ ASSERT_INT_EQ(convtime(buf), -1);
+ ASSERT_INT_EQ(convtime("3550w5d3h14m7s"), 2147483647);
+#if INT_MAX == 2147483647
+ ASSERT_INT_EQ(convtime("3550w5d3h14m8s"), -1);
+#endif
+ TEST_DONE();
+}
diff --git a/regress/unittests/misc/test_expand.c b/regress/unittests/misc/test_expand.c
new file mode 100644
index 000000000000..c336fb0b2d09
--- /dev/null
+++ b/regress/unittests/misc/test_expand.c
@@ -0,0 +1,88 @@
+/* $OpenBSD: test_expand.c,v 1.2 2021/04/06 09:07:33 dtucker Exp $ */
+/*
+ * Regress test for misc string expansion functions.
+ *
+ * Placed in the public domain.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "log.h"
+#include "misc.h"
+
+void test_expand(void);
+
+void
+test_expand(void)
+{
+ int parseerr;
+ char *ret;
+
+ TEST_START("dollar_expand");
+ ASSERT_INT_EQ(setenv("FOO", "bar", 1), 0);
+ ASSERT_INT_EQ(setenv("BAR", "baz", 1), 0);
+ (void)unsetenv("BAZ");
+#define ASSERT_DOLLAR_EQ(x, y) do { \
+ char *str = dollar_expand(NULL, (x)); \
+ ASSERT_STRING_EQ(str, (y)); \
+ free(str); \
+} while(0)
+ ASSERT_DOLLAR_EQ("${FOO}", "bar");
+ ASSERT_DOLLAR_EQ(" ${FOO}", " bar");
+ ASSERT_DOLLAR_EQ("${FOO} ", "bar ");
+ ASSERT_DOLLAR_EQ(" ${FOO} ", " bar ");
+ ASSERT_DOLLAR_EQ("${FOO}${BAR}", "barbaz");
+ ASSERT_DOLLAR_EQ(" ${FOO} ${BAR}", " bar baz");
+ ASSERT_DOLLAR_EQ("${FOO}${BAR} ", "barbaz ");
+ ASSERT_DOLLAR_EQ(" ${FOO} ${BAR} ", " bar baz ");
+ ASSERT_DOLLAR_EQ("$", "$");
+ ASSERT_DOLLAR_EQ(" $", " $");
+ ASSERT_DOLLAR_EQ("$ ", "$ ");
+
+ /* suppress error messages for error handing tests */
+ log_init("test_misc", SYSLOG_LEVEL_QUIET, SYSLOG_FACILITY_AUTH, 1);
+ /* error checking, non existent variable */
+ ret = dollar_expand(&parseerr, "a${BAZ}");
+ ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 0);
+ ret = dollar_expand(&parseerr, "${BAZ}b");
+ ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 0);
+ ret = dollar_expand(&parseerr, "a${BAZ}b");
+ ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 0);
+ /* invalid format */
+ ret = dollar_expand(&parseerr, "${");
+ ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
+ ret = dollar_expand(&parseerr, "${F");
+ ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
+ ret = dollar_expand(&parseerr, "${FO");
+ ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
+ /* empty variable name */
+ ret = dollar_expand(&parseerr, "${}");
+ ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
+ /* restore loglevel to default */
+ log_init("test_misc", SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 1);
+ TEST_DONE();
+
+ TEST_START("percent_expand");
+ ASSERT_STRING_EQ(percent_expand("%%", "%h", "foo", NULL), "%");
+ ASSERT_STRING_EQ(percent_expand("%h", "h", "foo", NULL), "foo");
+ ASSERT_STRING_EQ(percent_expand("%h ", "h", "foo", NULL), "foo ");
+ ASSERT_STRING_EQ(percent_expand(" %h", "h", "foo", NULL), " foo");
+ ASSERT_STRING_EQ(percent_expand(" %h ", "h", "foo", NULL), " foo ");
+ ASSERT_STRING_EQ(percent_expand(" %a%b ", "a", "foo", "b", "bar", NULL),
+ " foobar ");
+ TEST_DONE();
+
+ TEST_START("percent_dollar_expand");
+ ASSERT_STRING_EQ(percent_dollar_expand("%h${FOO}", "h", "foo", NULL),
+ "foobar");
+ TEST_DONE();
+}
diff --git a/regress/unittests/misc/test_parse.c b/regress/unittests/misc/test_parse.c
new file mode 100644
index 000000000000..dd99068d0700
--- /dev/null
+++ b/regress/unittests/misc/test_parse.c
@@ -0,0 +1,84 @@
+/* $OpenBSD: test_parse.c,v 1.1 2021/03/19 03:25:01 djm Exp $ */
+/*
+ * Regress test for misc user/host/URI parsing functions.
+ *
+ * Placed in the public domain.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "log.h"
+#include "misc.h"
+
+void test_parse(void);
+
+void
+test_parse(void)
+{
+ int port;
+ char *user, *host, *path;
+
+ TEST_START("misc_parse_user_host_path");
+ ASSERT_INT_EQ(parse_user_host_path("someuser@some.host:some/path",
+ &user, &host, &path), 0);
+ ASSERT_STRING_EQ(user, "someuser");
+ ASSERT_STRING_EQ(host, "some.host");
+ ASSERT_STRING_EQ(path, "some/path");
+ free(user); free(host); free(path);
+ TEST_DONE();
+
+ TEST_START("misc_parse_user_ipv4_path");
+ ASSERT_INT_EQ(parse_user_host_path("someuser@1.22.33.144:some/path",
+ &user, &host, &path), 0);
+ ASSERT_STRING_EQ(user, "someuser");
+ ASSERT_STRING_EQ(host, "1.22.33.144");
+ ASSERT_STRING_EQ(path, "some/path");
+ free(user); free(host); free(path);
+ TEST_DONE();
+
+ TEST_START("misc_parse_user_[ipv4]_path");
+ ASSERT_INT_EQ(parse_user_host_path("someuser@[1.22.33.144]:some/path",
+ &user, &host, &path), 0);
+ ASSERT_STRING_EQ(user, "someuser");
+ ASSERT_STRING_EQ(host, "1.22.33.144");
+ ASSERT_STRING_EQ(path, "some/path");
+ free(user); free(host); free(path);
+ TEST_DONE();
+
+ TEST_START("misc_parse_user_[ipv4]_nopath");
+ ASSERT_INT_EQ(parse_user_host_path("someuser@[1.22.33.144]:",
+ &user, &host, &path), 0);
+ ASSERT_STRING_EQ(user, "someuser");
+ ASSERT_STRING_EQ(host, "1.22.33.144");
+ ASSERT_STRING_EQ(path, ".");
+ free(user); free(host); free(path);
+ TEST_DONE();
+
+ TEST_START("misc_parse_user_ipv6_path");
+ ASSERT_INT_EQ(parse_user_host_path("someuser@[::1]:some/path",
+ &user, &host, &path), 0);
+ ASSERT_STRING_EQ(user, "someuser");
+ ASSERT_STRING_EQ(host, "::1");
+ ASSERT_STRING_EQ(path, "some/path");
+ free(user); free(host); free(path);
+ TEST_DONE();
+
+ TEST_START("misc_parse_uri");
+ ASSERT_INT_EQ(parse_uri("ssh", "ssh://someuser@some.host:22/some/path",
+ &user, &host, &port, &path), 0);
+ ASSERT_STRING_EQ(user, "someuser");
+ ASSERT_STRING_EQ(host, "some.host");
+ ASSERT_INT_EQ(port, 22);
+ ASSERT_STRING_EQ(path, "some/path");
+ free(user); free(host); free(path);
+ TEST_DONE();
+}
diff --git a/regress/unittests/misc/tests.c b/regress/unittests/misc/tests.c
index d873dc24154e..75013f481cb5 100644
--- a/regress/unittests/misc/tests.c
+++ b/regress/unittests/misc/tests.c
@@ -1,172 +1,34 @@
-/* $OpenBSD: tests.c,v 1.4 2021/01/15 02:58:11 dtucker Exp $ */
+/* $OpenBSD: tests.c,v 1.6 2021/03/19 04:23:50 djm Exp $ */
/*
* Regress test for misc helper functions.
*
* Placed in the public domain.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include "test_helper.h"
+#include "../test_helper/test_helper.h"
#include "log.h"
#include "misc.h"
+void test_parse(void);
+void test_convtime(void);
+void test_expand(void);
+void test_argv(void);
+
void
tests(void)
{
- int port, parseerr;
- char *user, *host, *path, *ret;
- char buf[1024];
-
- TEST_START("misc_parse_user_host_path");
- ASSERT_INT_EQ(parse_user_host_path("someuser@some.host:some/path",
- &user, &host, &path), 0);
- ASSERT_STRING_EQ(user, "someuser");
- ASSERT_STRING_EQ(host, "some.host");
- ASSERT_STRING_EQ(path, "some/path");
- free(user); free(host); free(path);
- TEST_DONE();
-
- TEST_START("misc_parse_user_ipv4_path");
- ASSERT_INT_EQ(parse_user_host_path("someuser@1.22.33.144:some/path",
- &user, &host, &path), 0);
- ASSERT_STRING_EQ(user, "someuser");
- ASSERT_STRING_EQ(host, "1.22.33.144");
- ASSERT_STRING_EQ(path, "some/path");
- free(user); free(host); free(path);
- TEST_DONE();
-
- TEST_START("misc_parse_user_[ipv4]_path");
- ASSERT_INT_EQ(parse_user_host_path("someuser@[1.22.33.144]:some/path",
- &user, &host, &path), 0);
- ASSERT_STRING_EQ(user, "someuser");
- ASSERT_STRING_EQ(host, "1.22.33.144");
- ASSERT_STRING_EQ(path, "some/path");
- free(user); free(host); free(path);
- TEST_DONE();
-
- TEST_START("misc_parse_user_[ipv4]_nopath");
- ASSERT_INT_EQ(parse_user_host_path("someuser@[1.22.33.144]:",
- &user, &host, &path), 0);
- ASSERT_STRING_EQ(user, "someuser");
- ASSERT_STRING_EQ(host, "1.22.33.144");
- ASSERT_STRING_EQ(path, ".");
- free(user); free(host); free(path);
- TEST_DONE();
-
- TEST_START("misc_parse_user_ipv6_path");
- ASSERT_INT_EQ(parse_user_host_path("someuser@[::1]:some/path",
- &user, &host, &path), 0);
- ASSERT_STRING_EQ(user, "someuser");
- ASSERT_STRING_EQ(host, "::1");
- ASSERT_STRING_EQ(path, "some/path");
- free(user); free(host); free(path);
- TEST_DONE();
-
- TEST_START("misc_parse_uri");
- ASSERT_INT_EQ(parse_uri("ssh", "ssh://someuser@some.host:22/some/path",
- &user, &host, &port, &path), 0);
- ASSERT_STRING_EQ(user, "someuser");
- ASSERT_STRING_EQ(host, "some.host");
- ASSERT_INT_EQ(port, 22);
- ASSERT_STRING_EQ(path, "some/path");
- free(user); free(host); free(path);
- TEST_DONE();
-
- TEST_START("misc_convtime");
- ASSERT_INT_EQ(convtime("0"), 0);
- ASSERT_INT_EQ(convtime("1"), 1);
- ASSERT_INT_EQ(convtime("2s"), 2);
- ASSERT_INT_EQ(convtime("3m"), 180);
- ASSERT_INT_EQ(convtime("1m30"), 90);
- ASSERT_INT_EQ(convtime("1m30s"), 90);
- ASSERT_INT_EQ(convtime("1h1s"), 3601);
- ASSERT_INT_EQ(convtime("1h30m"), 90 * 60);
- ASSERT_INT_EQ(convtime("1d"), 24 * 60 * 60);
- ASSERT_INT_EQ(convtime("1w"), 7 * 24 * 60 * 60);
- ASSERT_INT_EQ(convtime("1w2d3h4m5"), 788645);
- ASSERT_INT_EQ(convtime("1w2d3h4m5s"), 788645);
- /* any negative number or error returns -1 */
- ASSERT_INT_EQ(convtime("-1"), -1);
- ASSERT_INT_EQ(convtime(""), -1);
- ASSERT_INT_EQ(convtime("trout"), -1);
- ASSERT_INT_EQ(convtime("-77"), -1);
- /* boundary conditions */
- snprintf(buf, sizeof buf, "%llu", (long long unsigned)INT_MAX);
- ASSERT_INT_EQ(convtime(buf), INT_MAX);
- snprintf(buf, sizeof buf, "%llu", (long long unsigned)INT_MAX + 1);
- ASSERT_INT_EQ(convtime(buf), -1);
- ASSERT_INT_EQ(convtime("3550w5d3h14m7s"), 2147483647);
-#if INT_MAX == 2147483647
- ASSERT_INT_EQ(convtime("3550w5d3h14m8s"), -1);
-#endif
- TEST_DONE();
-
- TEST_START("dollar_expand");
- if (setenv("FOO", "bar", 1) != 0)
- abort();
- if (setenv("BAR", "baz", 1) != 0)
- abort();
- if (unsetenv("BAZ") != 0)
- abort();
-#define ASSERT_DOLLAR_EQ(x, y) do { \
- char *str = dollar_expand(NULL, (x)); \
- ASSERT_STRING_EQ(str, (y)); \
- free(str); \
-} while(0)
- ASSERT_DOLLAR_EQ("${FOO}", "bar");
- ASSERT_DOLLAR_EQ(" ${FOO}", " bar");
- ASSERT_DOLLAR_EQ("${FOO} ", "bar ");
- ASSERT_DOLLAR_EQ(" ${FOO} ", " bar ");
- ASSERT_DOLLAR_EQ("${FOO}${BAR}", "barbaz");
- ASSERT_DOLLAR_EQ(" ${FOO} ${BAR}", " bar baz");
- ASSERT_DOLLAR_EQ("${FOO}${BAR} ", "barbaz ");
- ASSERT_DOLLAR_EQ(" ${FOO} ${BAR} ", " bar baz ");
- ASSERT_DOLLAR_EQ("$", "$");
- ASSERT_DOLLAR_EQ(" $", " $");
- ASSERT_DOLLAR_EQ("$ ", "$ ");
-
- /* suppress error messages for error handing tests */
- log_init("test_misc", SYSLOG_LEVEL_QUIET, SYSLOG_FACILITY_AUTH, 1);
- /* error checking, non existent variable */
- ret = dollar_expand(&parseerr, "a${BAZ}");
- ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 0);
- ret = dollar_expand(&parseerr, "${BAZ}b");
- ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 0);
- ret = dollar_expand(&parseerr, "a${BAZ}b");
- ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 0);
- /* invalid format */
- ret = dollar_expand(&parseerr, "${");
- ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
- ret = dollar_expand(&parseerr, "${F");
- ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
- ret = dollar_expand(&parseerr, "${FO");
- ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
- /* empty variable name */
- ret = dollar_expand(&parseerr, "${}");
- ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
- /* restore loglevel to default */
- log_init("test_misc", SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 1);
- TEST_DONE();
-
- TEST_START("percent_expand");
- ASSERT_STRING_EQ(percent_expand("%%", "%h", "foo", NULL), "%");
- ASSERT_STRING_EQ(percent_expand("%h", "h", "foo", NULL), "foo");
- ASSERT_STRING_EQ(percent_expand("%h ", "h", "foo", NULL), "foo ");
- ASSERT_STRING_EQ(percent_expand(" %h", "h", "foo", NULL), " foo");
- ASSERT_STRING_EQ(percent_expand(" %h ", "h", "foo", NULL), " foo ");
- ASSERT_STRING_EQ(percent_expand(" %a%b ", "a", "foo", "b", "bar", NULL),
- " foobar ");
- TEST_DONE();
-
- TEST_START("percent_dollar_expand");
- ASSERT_STRING_EQ(percent_dollar_expand("%h${FOO}", "h", "foo", NULL),
- "foobar");
- TEST_DONE();
+ test_parse();
+ test_convtime();
+ test_expand();
+ test_argv();
}
diff --git a/regress/valgrind-unit.sh b/regress/valgrind-unit.sh
index 4143ead4b62e..193289e6b78e 100755
--- a/regress/valgrind-unit.sh
+++ b/regress/valgrind-unit.sh
@@ -1,22 +1,24 @@
#!/bin/sh
UNIT_BINARY="$1"
shift
UNIT_ARGS="$@"
test "x$OBJ" = "x" && OBJ=$PWD
# This mostly replicates the logic in test-exec.sh for running the
# regress tests under valgrind, except that we unconditionally enable
# leak checking because the unit tests should be clean.
VG_LEAK="--leak-check=full"
VG_TEST=`basename $UNIT_BINARY`
VG_LOG="$OBJ/valgrind-out/${VG_TEST}.%p"
VG_OPTS="--track-origins=yes $VG_LEAK --log-file=${VG_LOG}"
VG_OPTS="$VG_OPTS --trace-children=yes"
VG_PATH="valgrind"
if [ "x$VALGRIND_PATH" != "x" ]; then
VG_PATH="$VALGRIND_PATH"
fi
+mkdir -p "$OBJ/valgrind-out"
+
exec $VG_PATH $VG_OPTS $UNIT_BINARY $UNIT_ARGS
diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c
index d8dc7120bdd4..798b24bd878f 100644
--- a/sandbox-seccomp-filter.c
+++ b/sandbox-seccomp-filter.c
@@ -1,438 +1,441 @@
/*
* Copyright (c) 2012 Will Drewry <wad@dataspill.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Uncomment the SANDBOX_SECCOMP_FILTER_DEBUG macro below to help diagnose
* filter breakage during development. *Do not* use this in production,
* as it relies on making library calls that are unsafe in signal context.
*
* Instead, live systems the auditctl(8) may be used to monitor failures.
* E.g.
* auditctl -a task,always -F uid=<privsep uid>
*/
/* #define SANDBOX_SECCOMP_FILTER_DEBUG 1 */
/* XXX it should be possible to do logging via the log socket safely */
#ifdef SANDBOX_SECCOMP_FILTER_DEBUG
/* Use the kernel headers in case of an older toolchain. */
# include <asm/siginfo.h>
# define __have_siginfo_t 1
# define __have_sigval_t 1
# define __have_sigevent_t 1
#endif /* SANDBOX_SECCOMP_FILTER_DEBUG */
#include "includes.h"
#ifdef SANDBOX_SECCOMP_FILTER
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/prctl.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <linux/net.h>
#include <linux/audit.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <elf.h>
#include <asm/unistd.h>
#ifdef __s390__
#include <asm/zcrypt.h>
#endif
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h> /* for offsetof */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "log.h"
#include "ssh-sandbox.h"
#include "xmalloc.h"
/* Linux seccomp_filter sandbox */
#define SECCOMP_FILTER_FAIL SECCOMP_RET_KILL
/* Use a signal handler to emit violations when debugging */
#ifdef SANDBOX_SECCOMP_FILTER_DEBUG
# undef SECCOMP_FILTER_FAIL
# define SECCOMP_FILTER_FAIL SECCOMP_RET_TRAP
#endif /* SANDBOX_SECCOMP_FILTER_DEBUG */
#if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARG_LO_OFFSET 0
# define ARG_HI_OFFSET sizeof(uint32_t)
#elif __BYTE_ORDER == __BIG_ENDIAN
# define ARG_LO_OFFSET sizeof(uint32_t)
# define ARG_HI_OFFSET 0
#else
#error "Unknown endianness"
#endif
/* Simple helpers to avoid manual errors (but larger BPF programs). */
#define SC_DENY(_nr, _errno) \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 1), \
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO|(_errno))
#define SC_ALLOW(_nr) \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 1), \
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
#define SC_ALLOW_ARG(_nr, _arg_nr, _arg_val) \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 6), \
/* load and test syscall argument, low word */ \
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_LO_OFFSET), \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, \
((_arg_val) & 0xFFFFFFFF), 0, 3), \
/* load and test syscall argument, high word */ \
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_HI_OFFSET), \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, \
(((uint32_t)((uint64_t)(_arg_val) >> 32)) & 0xFFFFFFFF), 0, 1), \
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), \
/* reload syscall number; all rules expect it in accumulator */ \
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
offsetof(struct seccomp_data, nr))
/* Allow if syscall argument contains only values in mask */
#define SC_ALLOW_ARG_MASK(_nr, _arg_nr, _arg_mask) \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 8), \
/* load, mask and test syscall argument, low word */ \
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_LO_OFFSET), \
BPF_STMT(BPF_ALU+BPF_AND+BPF_K, ~((_arg_mask) & 0xFFFFFFFF)), \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 4), \
/* load, mask and test syscall argument, high word */ \
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_HI_OFFSET), \
BPF_STMT(BPF_ALU+BPF_AND+BPF_K, \
~(((uint32_t)((uint64_t)(_arg_mask) >> 32)) & 0xFFFFFFFF)), \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1), \
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), \
/* reload syscall number; all rules expect it in accumulator */ \
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
offsetof(struct seccomp_data, nr))
/* Syscall filtering set for preauth. */
static const struct sock_filter preauth_insns[] = {
/* Ensure the syscall arch convention is as expected. */
BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
offsetof(struct seccomp_data, arch)),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_AUDIT_ARCH, 1, 0),
BPF_STMT(BPF_RET+BPF_K, SECCOMP_FILTER_FAIL),
/* Load the syscall number for checking. */
BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
offsetof(struct seccomp_data, nr)),
/* Syscalls to non-fatally deny */
#ifdef __NR_lstat
SC_DENY(__NR_lstat, EACCES),
#endif
#ifdef __NR_lstat64
SC_DENY(__NR_lstat64, EACCES),
#endif
#ifdef __NR_fstat
SC_DENY(__NR_fstat, EACCES),
#endif
#ifdef __NR_fstat64
SC_DENY(__NR_fstat64, EACCES),
#endif
+#ifdef __NR_fstatat64
+ SC_DENY(__NR_fstatat64, EACCES),
+#endif
#ifdef __NR_open
SC_DENY(__NR_open, EACCES),
#endif
#ifdef __NR_openat
SC_DENY(__NR_openat, EACCES),
#endif
#ifdef __NR_newfstatat
SC_DENY(__NR_newfstatat, EACCES),
#endif
#ifdef __NR_stat
SC_DENY(__NR_stat, EACCES),
#endif
#ifdef __NR_stat64
SC_DENY(__NR_stat64, EACCES),
#endif
#ifdef __NR_shmget
SC_DENY(__NR_shmget, EACCES),
#endif
#ifdef __NR_shmat
SC_DENY(__NR_shmat, EACCES),
#endif
#ifdef __NR_shmdt
SC_DENY(__NR_shmdt, EACCES),
#endif
#ifdef __NR_ipc
SC_DENY(__NR_ipc, EACCES),
#endif
#ifdef __NR_statx
SC_DENY(__NR_statx, EACCES),
#endif
/* Syscalls to permit */
#ifdef __NR_brk
SC_ALLOW(__NR_brk),
#endif
#ifdef __NR_clock_gettime
SC_ALLOW(__NR_clock_gettime),
#endif
#ifdef __NR_clock_gettime64
SC_ALLOW(__NR_clock_gettime64),
#endif
#ifdef __NR_close
SC_ALLOW(__NR_close),
#endif
#ifdef __NR_exit
SC_ALLOW(__NR_exit),
#endif
#ifdef __NR_exit_group
SC_ALLOW(__NR_exit_group),
#endif
#ifdef __NR_futex
SC_ALLOW(__NR_futex),
#endif
#ifdef __NR_futex_time64
SC_ALLOW(__NR_futex_time64),
#endif
#ifdef __NR_geteuid
SC_ALLOW(__NR_geteuid),
#endif
#ifdef __NR_geteuid32
SC_ALLOW(__NR_geteuid32),
#endif
#ifdef __NR_getpgid
SC_ALLOW(__NR_getpgid),
#endif
#ifdef __NR_getpid
SC_ALLOW(__NR_getpid),
#endif
#ifdef __NR_getrandom
SC_ALLOW(__NR_getrandom),
#endif
#ifdef __NR_gettimeofday
SC_ALLOW(__NR_gettimeofday),
#endif
#ifdef __NR_getuid
SC_ALLOW(__NR_getuid),
#endif
#ifdef __NR_getuid32
SC_ALLOW(__NR_getuid32),
#endif
#ifdef __NR_madvise
SC_ALLOW(__NR_madvise),
#endif
#ifdef __NR_mmap
SC_ALLOW_ARG_MASK(__NR_mmap, 2, PROT_READ|PROT_WRITE|PROT_NONE),
#endif
#ifdef __NR_mmap2
SC_ALLOW_ARG_MASK(__NR_mmap2, 2, PROT_READ|PROT_WRITE|PROT_NONE),
#endif
#ifdef __NR_mprotect
SC_ALLOW_ARG_MASK(__NR_mprotect, 2, PROT_READ|PROT_WRITE|PROT_NONE),
#endif
#ifdef __NR_mremap
SC_ALLOW(__NR_mremap),
#endif
#ifdef __NR_munmap
SC_ALLOW(__NR_munmap),
#endif
#ifdef __NR_nanosleep
SC_ALLOW(__NR_nanosleep),
#endif
#ifdef __NR_clock_nanosleep
SC_ALLOW(__NR_clock_nanosleep),
#endif
#ifdef __NR_clock_nanosleep_time64
SC_ALLOW(__NR_clock_nanosleep_time64),
#endif
#ifdef __NR_clock_gettime64
SC_ALLOW(__NR_clock_gettime64),
#endif
#ifdef __NR__newselect
SC_ALLOW(__NR__newselect),
#endif
#ifdef __NR_poll
SC_ALLOW(__NR_poll),
#endif
#ifdef __NR_pselect6
SC_ALLOW(__NR_pselect6),
#endif
#ifdef __NR_pselect6_time64
SC_ALLOW(__NR_pselect6_time64),
#endif
#ifdef __NR_read
SC_ALLOW(__NR_read),
#endif
#ifdef __NR_rt_sigprocmask
SC_ALLOW(__NR_rt_sigprocmask),
#endif
#ifdef __NR_select
SC_ALLOW(__NR_select),
#endif
#ifdef __NR_shutdown
SC_ALLOW(__NR_shutdown),
#endif
#ifdef __NR_sigprocmask
SC_ALLOW(__NR_sigprocmask),
#endif
#ifdef __NR_time
SC_ALLOW(__NR_time),
#endif
#ifdef __NR_write
SC_ALLOW(__NR_write),
#endif
#ifdef __NR_socketcall
SC_ALLOW_ARG(__NR_socketcall, 0, SYS_SHUTDOWN),
SC_DENY(__NR_socketcall, EACCES),
#endif
#if defined(__NR_ioctl) && defined(__s390__)
/* Allow ioctls for ICA crypto card on s390 */
SC_ALLOW_ARG(__NR_ioctl, 1, Z90STAT_STATUS_MASK),
SC_ALLOW_ARG(__NR_ioctl, 1, ICARSAMODEXPO),
SC_ALLOW_ARG(__NR_ioctl, 1, ICARSACRT),
SC_ALLOW_ARG(__NR_ioctl, 1, ZSECSENDCPRB),
/* Allow ioctls for EP11 crypto card on s390 */
SC_ALLOW_ARG(__NR_ioctl, 1, ZSENDEP11CPRB),
#endif
#if defined(__x86_64__) && defined(__ILP32__) && defined(__X32_SYSCALL_BIT)
/*
* On Linux x32, the clock_gettime VDSO falls back to the
* x86-64 syscall under some circumstances, e.g.
* https://bugs.debian.org/849923
*/
SC_ALLOW(__NR_clock_gettime & ~__X32_SYSCALL_BIT),
#endif
/* Default deny */
BPF_STMT(BPF_RET+BPF_K, SECCOMP_FILTER_FAIL),
};
static const struct sock_fprog preauth_program = {
.len = (unsigned short)(sizeof(preauth_insns)/sizeof(preauth_insns[0])),
.filter = (struct sock_filter *)preauth_insns,
};
struct ssh_sandbox {
pid_t child_pid;
};
struct ssh_sandbox *
ssh_sandbox_init(struct monitor *monitor)
{
struct ssh_sandbox *box;
/*
* Strictly, we don't need to maintain any state here but we need
* to return non-NULL to satisfy the API.
*/
debug3("%s: preparing seccomp filter sandbox", __func__);
box = xcalloc(1, sizeof(*box));
box->child_pid = 0;
return box;
}
#ifdef SANDBOX_SECCOMP_FILTER_DEBUG
extern struct monitor *pmonitor;
void mm_log_handler(LogLevel level, const char *msg, void *ctx);
static void
ssh_sandbox_violation(int signum, siginfo_t *info, void *void_context)
{
char msg[256];
snprintf(msg, sizeof(msg),
"%s: unexpected system call (arch:0x%x,syscall:%d @ %p)",
__func__, info->si_arch, info->si_syscall, info->si_call_addr);
mm_log_handler(SYSLOG_LEVEL_FATAL, msg, pmonitor);
_exit(1);
}
static void
ssh_sandbox_child_debugging(void)
{
struct sigaction act;
sigset_t mask;
debug3("%s: installing SIGSYS handler", __func__);
memset(&act, 0, sizeof(act));
sigemptyset(&mask);
sigaddset(&mask, SIGSYS);
act.sa_sigaction = &ssh_sandbox_violation;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGSYS, &act, NULL) == -1)
fatal("%s: sigaction(SIGSYS): %s", __func__, strerror(errno));
if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
fatal("%s: sigprocmask(SIGSYS): %s",
- __func__, strerror(errno));
+ __func__, strerror(errno));
}
#endif /* SANDBOX_SECCOMP_FILTER_DEBUG */
void
ssh_sandbox_child(struct ssh_sandbox *box)
{
struct rlimit rl_zero;
int nnp_failed = 0;
/* Set rlimits for completeness if possible. */
rl_zero.rlim_cur = rl_zero.rlim_max = 0;
if (setrlimit(RLIMIT_FSIZE, &rl_zero) == -1)
fatal("%s: setrlimit(RLIMIT_FSIZE, { 0, 0 }): %s",
__func__, strerror(errno));
if (setrlimit(RLIMIT_NOFILE, &rl_zero) == -1)
fatal("%s: setrlimit(RLIMIT_NOFILE, { 0, 0 }): %s",
__func__, strerror(errno));
if (setrlimit(RLIMIT_NPROC, &rl_zero) == -1)
fatal("%s: setrlimit(RLIMIT_NPROC, { 0, 0 }): %s",
__func__, strerror(errno));
#ifdef SANDBOX_SECCOMP_FILTER_DEBUG
ssh_sandbox_child_debugging();
#endif /* SANDBOX_SECCOMP_FILTER_DEBUG */
debug3("%s: setting PR_SET_NO_NEW_PRIVS", __func__);
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
debug("%s: prctl(PR_SET_NO_NEW_PRIVS): %s",
- __func__, strerror(errno));
+ __func__, strerror(errno));
nnp_failed = 1;
}
debug3("%s: attaching seccomp filter program", __func__);
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &preauth_program) == -1)
debug("%s: prctl(PR_SET_SECCOMP): %s",
- __func__, strerror(errno));
+ __func__, strerror(errno));
else if (nnp_failed)
fatal("%s: SECCOMP_MODE_FILTER activated but "
"PR_SET_NO_NEW_PRIVS failed", __func__);
}
void
ssh_sandbox_parent_finish(struct ssh_sandbox *box)
{
free(box);
debug3("%s: finished", __func__);
}
void
ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid)
{
box->child_pid = child_pid;
}
#endif /* SANDBOX_SECCOMP_FILTER */
diff --git a/scp.0 b/scp.0
index a5dc9aa364d2..fee6ae89ea60 100644
--- a/scp.0
+++ b/scp.0
@@ -1,191 +1,191 @@
SCP(1) General Commands Manual SCP(1)
NAME
scp M-bM-^@M-^S OpenSSH secure file copy
SYNOPSIS
scp [-346ABCpqrTv] [-c cipher] [-F ssh_config] [-i identity_file]
[-J destination] [-l limit] [-o ssh_option] [-P port] [-S program]
source ... target
DESCRIPTION
scp copies files between hosts on a network.
It uses ssh(1) for data transfer, and uses the same authentication and
provides the same security as a login session. The scp protocol requires
execution of the remote user's shell to perform glob(3) pattern matching.
scp will ask for passwords or passphrases if they are needed for
authentication.
The source and target may be specified as a local pathname, a remote host
with optional path in the form [user@]host:[path], or a URI in the form
scp://[user@]host[:port][/path]. Local file names can be made explicit
using absolute or relative pathnames to avoid scp treating file names
containing M-bM-^@M-^X:M-bM-^@M-^Y as host specifiers.
When copying between two remote hosts, if the URI format is used, a port
may only be specified on the target if the -3 option is used.
The options are as follows:
-3 Copies between two remote hosts are transferred through the local
host. Without this option the data is copied directly between
the two remote hosts. Note that this option disables the
progress meter and selects batch mode for the second host, since
scp cannot ask for passwords or passphrases for both hosts.
-4 Forces scp to use IPv4 addresses only.
-6 Forces scp to use IPv6 addresses only.
-A Allows forwarding of ssh-agent(1) to the remote system. The
default is not to forward an authentication agent.
-B Selects batch mode (prevents asking for passwords or
passphrases).
-C Compression enable. Passes the -C flag to ssh(1) to enable
compression.
-c cipher
Selects the cipher to use for encrypting the data transfer. This
option is directly passed to ssh(1).
-F ssh_config
Specifies an alternative per-user configuration file for ssh.
This option is directly passed to ssh(1).
-i identity_file
Selects the file from which the identity (private key) for public
key authentication is read. This option is directly passed to
ssh(1).
-J destination
Connect to the target host by first making an scp connection to
the jump host described by destination and then establishing a
TCP forwarding to the ultimate destination from there. Multiple
jump hops may be specified separated by comma characters. This
is a shortcut to specify a ProxyJump configuration directive.
This option is directly passed to ssh(1).
-l limit
Limits the used bandwidth, specified in Kbit/s.
-o ssh_option
Can be used to pass options to ssh in the format used in
ssh_config(5). This is useful for specifying options for which
there is no separate scp command-line flag. For full details of
the options listed below, and their possible values, see
ssh_config(5).
AddressFamily
BatchMode
BindAddress
BindInterface
CanonicalDomains
CanonicalizeFallbackLocal
CanonicalizeHostname
CanonicalizeMaxDots
CanonicalizePermittedCNAMEs
CASignatureAlgorithms
CertificateFile
ChallengeResponseAuthentication
CheckHostIP
Ciphers
Compression
ConnectionAttempts
ConnectTimeout
ControlMaster
ControlPath
ControlPersist
GlobalKnownHostsFile
GSSAPIAuthentication
GSSAPIDelegateCredentials
HashKnownHosts
Host
HostbasedAcceptedAlgorithms
HostbasedAuthentication
HostKeyAlgorithms
HostKeyAlias
Hostname
IdentitiesOnly
IdentityAgent
IdentityFile
IPQoS
KbdInteractiveAuthentication
KbdInteractiveDevices
KexAlgorithms
KnownHostsCommand
LogLevel
MACs
NoHostAuthenticationForLocalhost
NumberOfPasswordPrompts
PasswordAuthentication
PKCS11Provider
Port
PreferredAuthentications
ProxyCommand
ProxyJump
PubkeyAcceptedAlgorithms
PubkeyAuthentication
RekeyLimit
SendEnv
ServerAliveInterval
ServerAliveCountMax
SetEnv
StrictHostKeyChecking
TCPKeepAlive
UpdateHostKeys
User
UserKnownHostsFile
VerifyHostKeyDNS
-P port
Specifies the port to connect to on the remote host. Note that
this option is written with a capital M-bM-^@M-^XPM-bM-^@M-^Y, because -p is already
reserved for preserving the times and modes of the file.
-p Preserves modification times, access times, and modes from the
original file.
-q Quiet mode: disables the progress meter as well as warning and
diagnostic messages from ssh(1).
-r Recursively copy entire directories. Note that scp follows
symbolic links encountered in the tree traversal.
-S program
Name of program to use for the encrypted connection. The program
must understand ssh(1) options.
-T Disable strict filename checking. By default when copying files
from a remote host to a local directory scp checks that the
received filenames match those requested on the command-line to
prevent the remote end from sending unexpected or unwanted files.
Because of differences in how various operating systems and
shells interpret filename wildcards, these checks may cause
wanted files to be rejected. This option disables these checks
at the expense of fully trusting that the server will not send
unexpected filenames.
-v Verbose mode. Causes scp and ssh(1) to print debugging messages
about their progress. This is helpful in debugging connection,
authentication, and configuration problems.
EXIT STATUS
The scp utility exitsM-BM- 0 on success, andM-BM- >0 if an error occurs.
SEE ALSO
sftp(1), ssh(1), ssh-add(1), ssh-agent(1), ssh-keygen(1), ssh_config(5),
sshd(8)
HISTORY
scp is based on the rcp program in BSD source code from the Regents of
the University of California.
AUTHORS
Timo Rinne <tri@iki.fi>
Tatu Ylonen <ylo@cs.hut.fi>
-OpenBSD 6.8 January 26, 2021 OpenBSD 6.8
+OpenBSD 6.9 January 26, 2021 OpenBSD 6.9
diff --git a/scp.c b/scp.c
index 59b0a36a1378..d23f34c1755b 100644
--- a/scp.c
+++ b/scp.c
@@ -1,1739 +1,1738 @@
-/* $OpenBSD: scp.c,v 1.213 2020/10/18 11:32:01 djm Exp $ */
+/* $OpenBSD: scp.c,v 1.214 2021/04/03 06:18:40 djm Exp $ */
/*
* scp - secure remote copy. This is basically patched BSD rcp which
* uses ssh to do the data transfer (instead of using rcmd).
*
* NOTE: This version should NOT be suid root. (This uses ssh to
* do the transfer and ssh has the necessary privileges.)
*
* 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi>
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Copyright (c) 1999 Theo de Raadt. All rights reserved.
* Copyright (c) 1999 Aaron Campbell. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Parts from:
*
* Copyright (c) 1983, 1990, 1992, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include "includes.h"
#include <sys/types.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#else
# ifdef HAVE_SYS_POLL_H
# include <sys/poll.h>
# endif
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/wait.h>
#include <sys/uio.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#ifdef HAVE_FNMATCH_H
#include <fnmatch.h>
#endif
#include <limits.h>
#include <locale.h>
#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
#include <vis.h>
#endif
#include "xmalloc.h"
#include "ssh.h"
#include "atomicio.h"
#include "pathnames.h"
#include "log.h"
#include "misc.h"
#include "progressmeter.h"
#include "utf8.h"
extern char *__progname;
#define COPY_BUFLEN 16384
int do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout);
int do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout);
/* Struct for addargs */
arglist args;
arglist remote_remote_args;
/* Bandwidth limit */
long long limit_kbps = 0;
struct bwlimit bwlimit;
/* Name of current file being transferred. */
char *curfile;
/* This is set to non-zero to enable verbose mode. */
int verbose_mode = 0;
/* This is set to zero if the progressmeter is not desired. */
int showprogress = 1;
/*
* This is set to non-zero if remote-remote copy should be piped
* through this process.
*/
int throughlocal = 0;
/* Non-standard port to use for the ssh connection or -1. */
int sshport = -1;
/* This is the program to execute for the secured connection. ("ssh" or -S) */
char *ssh_program = _PATH_SSH_PROGRAM;
/* This is used to store the pid of ssh_program */
pid_t do_cmd_pid = -1;
static void
killchild(int signo)
{
if (do_cmd_pid > 1) {
kill(do_cmd_pid, signo ? signo : SIGTERM);
waitpid(do_cmd_pid, NULL, 0);
}
if (signo)
_exit(1);
exit(1);
}
static void
suspchild(int signo)
{
int status;
if (do_cmd_pid > 1) {
kill(do_cmd_pid, signo);
while (waitpid(do_cmd_pid, &status, WUNTRACED) == -1 &&
errno == EINTR)
;
kill(getpid(), SIGSTOP);
}
}
static int
do_local_cmd(arglist *a)
{
u_int i;
int status;
pid_t pid;
if (a->num == 0)
fatal("do_local_cmd: no arguments");
if (verbose_mode) {
fprintf(stderr, "Executing:");
for (i = 0; i < a->num; i++)
fmprintf(stderr, " %s", a->list[i]);
fprintf(stderr, "\n");
}
if ((pid = fork()) == -1)
fatal("do_local_cmd: fork: %s", strerror(errno));
if (pid == 0) {
execvp(a->list[0], a->list);
perror(a->list[0]);
exit(1);
}
do_cmd_pid = pid;
ssh_signal(SIGTERM, killchild);
ssh_signal(SIGINT, killchild);
ssh_signal(SIGHUP, killchild);
while (waitpid(pid, &status, 0) == -1)
if (errno != EINTR)
fatal("do_local_cmd: waitpid: %s", strerror(errno));
do_cmd_pid = -1;
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
return (-1);
return (0);
}
/*
* This function executes the given command as the specified user on the
* given host. This returns < 0 if execution fails, and >= 0 otherwise. This
* assigns the input and output file descriptors on success.
*/
int
do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)
{
int pin[2], pout[2], reserved[2];
if (verbose_mode)
fmprintf(stderr,
"Executing: program %s host %s, user %s, command %s\n",
ssh_program, host,
remuser ? remuser : "(unspecified)", cmd);
if (port == -1)
port = sshport;
/*
* Reserve two descriptors so that the real pipes won't get
* descriptors 0 and 1 because that will screw up dup2 below.
*/
if (pipe(reserved) == -1)
fatal("pipe: %s", strerror(errno));
/* Create a socket pair for communicating with ssh. */
if (pipe(pin) == -1)
fatal("pipe: %s", strerror(errno));
if (pipe(pout) == -1)
fatal("pipe: %s", strerror(errno));
/* Free the reserved descriptors. */
close(reserved[0]);
close(reserved[1]);
ssh_signal(SIGTSTP, suspchild);
ssh_signal(SIGTTIN, suspchild);
ssh_signal(SIGTTOU, suspchild);
/* Fork a child to execute the command on the remote host using ssh. */
do_cmd_pid = fork();
if (do_cmd_pid == 0) {
/* Child. */
close(pin[1]);
close(pout[0]);
dup2(pin[0], 0);
dup2(pout[1], 1);
close(pin[0]);
close(pout[1]);
replacearg(&args, 0, "%s", ssh_program);
if (port != -1) {
addargs(&args, "-p");
addargs(&args, "%d", port);
}
if (remuser != NULL) {
addargs(&args, "-l");
addargs(&args, "%s", remuser);
}
addargs(&args, "--");
addargs(&args, "%s", host);
addargs(&args, "%s", cmd);
execvp(ssh_program, args.list);
perror(ssh_program);
exit(1);
} else if (do_cmd_pid == -1) {
fatal("fork: %s", strerror(errno));
}
/* Parent. Close the other side, and return the local side. */
close(pin[0]);
*fdout = pin[1];
close(pout[1]);
*fdin = pout[0];
ssh_signal(SIGTERM, killchild);
ssh_signal(SIGINT, killchild);
ssh_signal(SIGHUP, killchild);
return 0;
}
/*
* This function executes a command similar to do_cmd(), but expects the
* input and output descriptors to be setup by a previous call to do_cmd().
* This way the input and output of two commands can be connected.
*/
int
do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout)
{
pid_t pid;
int status;
if (verbose_mode)
fmprintf(stderr,
"Executing: 2nd program %s host %s, user %s, command %s\n",
ssh_program, host,
remuser ? remuser : "(unspecified)", cmd);
if (port == -1)
port = sshport;
/* Fork a child to execute the command on the remote host using ssh. */
pid = fork();
if (pid == 0) {
dup2(fdin, 0);
dup2(fdout, 1);
replacearg(&args, 0, "%s", ssh_program);
if (port != -1) {
addargs(&args, "-p");
addargs(&args, "%d", port);
}
if (remuser != NULL) {
addargs(&args, "-l");
addargs(&args, "%s", remuser);
}
addargs(&args, "-oBatchMode=yes");
addargs(&args, "--");
addargs(&args, "%s", host);
addargs(&args, "%s", cmd);
execvp(ssh_program, args.list);
perror(ssh_program);
exit(1);
} else if (pid == -1) {
fatal("fork: %s", strerror(errno));
}
while (waitpid(pid, &status, 0) == -1)
if (errno != EINTR)
fatal("do_cmd2: waitpid: %s", strerror(errno));
return 0;
}
typedef struct {
size_t cnt;
char *buf;
} BUF;
BUF *allocbuf(BUF *, int, int);
void lostconn(int);
int okname(char *);
void run_err(const char *,...)
__attribute__((__format__ (printf, 1, 2)))
__attribute__((__nonnull__ (1)));
int note_err(const char *,...)
__attribute__((__format__ (printf, 1, 2)));
void verifydir(char *);
struct passwd *pwd;
uid_t userid;
int errs, remin, remout;
int Tflag, pflag, iamremote, iamrecursive, targetshouldbedirectory;
#define CMDNEEDS 64
char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
int response(void);
void rsource(char *, struct stat *);
void sink(int, char *[], const char *);
void source(int, char *[]);
void tolocal(int, char *[]);
void toremote(int, char *[]);
void usage(void);
int
main(int argc, char **argv)
{
int ch, fflag, tflag, status, n;
char **newargv;
const char *errstr;
extern char *optarg;
extern int optind;
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
sanitise_stdfd();
seed_rng();
msetlocale();
/* Copy argv, because we modify it */
newargv = xcalloc(MAXIMUM(argc + 1, 1), sizeof(*newargv));
for (n = 0; n < argc; n++)
newargv[n] = xstrdup(argv[n]);
argv = newargv;
__progname = ssh_get_progname(argv[0]);
memset(&args, '\0', sizeof(args));
memset(&remote_remote_args, '\0', sizeof(remote_remote_args));
args.list = remote_remote_args.list = NULL;
addargs(&args, "%s", ssh_program);
addargs(&args, "-x");
addargs(&args, "-oPermitLocalCommand=no");
addargs(&args, "-oClearAllForwardings=yes");
addargs(&args, "-oRemoteCommand=none");
addargs(&args, "-oRequestTTY=no");
fflag = Tflag = tflag = 0;
while ((ch = getopt(argc, argv,
"12346ABCTdfpqrtvF:J:P:S:c:i:l:o:")) != -1) {
switch (ch) {
/* User-visible flags. */
case '1':
fatal("SSH protocol v.1 is no longer supported");
break;
case '2':
/* Ignored */
break;
case 'A':
case '4':
case '6':
case 'C':
addargs(&args, "-%c", ch);
addargs(&remote_remote_args, "-%c", ch);
break;
case '3':
throughlocal = 1;
break;
case 'o':
case 'c':
case 'i':
case 'F':
case 'J':
addargs(&remote_remote_args, "-%c", ch);
addargs(&remote_remote_args, "%s", optarg);
addargs(&args, "-%c", ch);
addargs(&args, "%s", optarg);
break;
case 'P':
sshport = a2port(optarg);
if (sshport <= 0)
fatal("bad port \"%s\"\n", optarg);
break;
case 'B':
addargs(&remote_remote_args, "-oBatchmode=yes");
addargs(&args, "-oBatchmode=yes");
break;
case 'l':
limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
&errstr);
if (errstr != NULL)
usage();
limit_kbps *= 1024; /* kbps */
bandwidth_limit_init(&bwlimit, limit_kbps, COPY_BUFLEN);
break;
case 'p':
pflag = 1;
break;
case 'r':
iamrecursive = 1;
break;
case 'S':
ssh_program = xstrdup(optarg);
break;
case 'v':
addargs(&args, "-v");
addargs(&remote_remote_args, "-v");
verbose_mode = 1;
break;
case 'q':
addargs(&args, "-q");
addargs(&remote_remote_args, "-q");
showprogress = 0;
break;
/* Server options. */
case 'd':
targetshouldbedirectory = 1;
break;
case 'f': /* "from" */
iamremote = 1;
fflag = 1;
break;
case 't': /* "to" */
iamremote = 1;
tflag = 1;
#ifdef HAVE_CYGWIN
setmode(0, O_BINARY);
#endif
break;
case 'T':
Tflag = 1;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
/* Do this last because we want the user to be able to override it */
addargs(&args, "-oForwardAgent=no");
if ((pwd = getpwuid(userid = getuid())) == NULL)
fatal("unknown user %u", (u_int) userid);
if (!isatty(STDOUT_FILENO))
showprogress = 0;
if (pflag) {
/* Cannot pledge: -p allows setuid/setgid files... */
} else {
if (pledge("stdio rpath wpath cpath fattr tty proc exec",
NULL) == -1) {
perror("pledge");
exit(1);
}
}
remin = STDIN_FILENO;
remout = STDOUT_FILENO;
if (fflag) {
/* Follow "protocol", send data. */
(void) response();
source(argc, argv);
exit(errs != 0);
}
if (tflag) {
/* Receive data. */
sink(argc, argv, NULL);
exit(errs != 0);
}
if (argc < 2)
usage();
if (argc > 2)
targetshouldbedirectory = 1;
remin = remout = -1;
do_cmd_pid = -1;
/* Command to be executed on remote system using "ssh". */
(void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",
verbose_mode ? " -v" : "",
iamrecursive ? " -r" : "", pflag ? " -p" : "",
targetshouldbedirectory ? " -d" : "");
(void) ssh_signal(SIGPIPE, lostconn);
if (colon(argv[argc - 1])) /* Dest is remote host. */
toremote(argc, argv);
else {
if (targetshouldbedirectory)
verifydir(argv[argc - 1]);
tolocal(argc, argv); /* Dest is local host. */
}
/*
* Finally check the exit status of the ssh process, if one was forked
* and no error has occurred yet
*/
if (do_cmd_pid != -1 && errs == 0) {
if (remin != -1)
(void) close(remin);
if (remout != -1)
(void) close(remout);
if (waitpid(do_cmd_pid, &status, 0) == -1)
errs = 1;
else {
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
errs = 1;
}
}
exit(errs != 0);
}
/* Callback from atomicio6 to update progress meter and limit bandwidth */
static int
scpio(void *_cnt, size_t s)
{
off_t *cnt = (off_t *)_cnt;
*cnt += s;
refresh_progress_meter(0);
if (limit_kbps > 0)
bandwidth_limit(&bwlimit, s);
return 0;
}
static int
do_times(int fd, int verb, const struct stat *sb)
{
/* strlen(2^64) == 20; strlen(10^6) == 7 */
char buf[(20 + 7 + 2) * 2 + 2];
(void)snprintf(buf, sizeof(buf), "T%llu 0 %llu 0\n",
(unsigned long long) (sb->st_mtime < 0 ? 0 : sb->st_mtime),
(unsigned long long) (sb->st_atime < 0 ? 0 : sb->st_atime));
if (verb) {
fprintf(stderr, "File mtime %lld atime %lld\n",
(long long)sb->st_mtime, (long long)sb->st_atime);
fprintf(stderr, "Sending file timestamps: %s", buf);
}
(void) atomicio(vwrite, fd, buf, strlen(buf));
return (response());
}
static int
parse_scp_uri(const char *uri, char **userp, char **hostp, int *portp,
- char **pathp)
+ char **pathp)
{
int r;
r = parse_uri("scp", uri, userp, hostp, portp, pathp);
if (r == 0 && *pathp == NULL)
*pathp = xstrdup(".");
return r;
}
/* Appends a string to an array; returns 0 on success, -1 on alloc failure */
static int
append(char *cp, char ***ap, size_t *np)
{
char **tmp;
if ((tmp = reallocarray(*ap, *np + 1, sizeof(*tmp))) == NULL)
return -1;
tmp[(*np)] = cp;
(*np)++;
*ap = tmp;
return 0;
}
/*
* Finds the start and end of the first brace pair in the pattern.
* returns 0 on success or -1 for invalid patterns.
*/
static int
find_brace(const char *pattern, int *startp, int *endp)
{
int i;
int in_bracket, brace_level;
*startp = *endp = -1;
in_bracket = brace_level = 0;
for (i = 0; i < INT_MAX && *endp < 0 && pattern[i] != '\0'; i++) {
switch (pattern[i]) {
case '\\':
/* skip next character */
if (pattern[i + 1] != '\0')
i++;
break;
case '[':
in_bracket = 1;
break;
case ']':
in_bracket = 0;
break;
case '{':
if (in_bracket)
break;
if (pattern[i + 1] == '}') {
/* Protect a single {}, for find(1), like csh */
i++; /* skip */
break;
}
if (*startp == -1)
*startp = i;
brace_level++;
break;
case '}':
if (in_bracket)
break;
if (*startp < 0) {
/* Unbalanced brace */
return -1;
}
if (--brace_level <= 0)
*endp = i;
break;
}
}
/* unbalanced brackets/braces */
if (*endp < 0 && (*startp >= 0 || in_bracket))
return -1;
return 0;
}
/*
* Assembles and records a successfully-expanded pattern, returns -1 on
* alloc failure.
*/
static int
emit_expansion(const char *pattern, int brace_start, int brace_end,
int sel_start, int sel_end, char ***patternsp, size_t *npatternsp)
{
char *cp;
int o = 0, tail_len = strlen(pattern + brace_end + 1);
if ((cp = malloc(brace_start + (sel_end - sel_start) +
tail_len + 1)) == NULL)
return -1;
/* Pattern before initial brace */
if (brace_start > 0) {
memcpy(cp, pattern, brace_start);
o = brace_start;
}
/* Current braced selection */
if (sel_end - sel_start > 0) {
memcpy(cp + o, pattern + sel_start,
sel_end - sel_start);
o += sel_end - sel_start;
}
/* Remainder of pattern after closing brace */
if (tail_len > 0) {
memcpy(cp + o, pattern + brace_end + 1, tail_len);
o += tail_len;
}
cp[o] = '\0';
if (append(cp, patternsp, npatternsp) != 0) {
free(cp);
return -1;
}
return 0;
}
/*
* Expand the first encountered brace in pattern, appending the expanded
* patterns it yielded to the *patternsp array.
*
* Returns 0 on success or -1 on allocation failure.
*
* Signals whether expansion was performed via *expanded and whether
* pattern was invalid via *invalid.
*/
static int
brace_expand_one(const char *pattern, char ***patternsp, size_t *npatternsp,
int *expanded, int *invalid)
{
int i;
int in_bracket, brace_start, brace_end, brace_level;
int sel_start, sel_end;
*invalid = *expanded = 0;
if (find_brace(pattern, &brace_start, &brace_end) != 0) {
*invalid = 1;
return 0;
} else if (brace_start == -1)
return 0;
in_bracket = brace_level = 0;
for (i = sel_start = brace_start + 1; i < brace_end; i++) {
switch (pattern[i]) {
case '{':
if (in_bracket)
break;
brace_level++;
break;
case '}':
if (in_bracket)
break;
brace_level--;
break;
case '[':
in_bracket = 1;
break;
case ']':
in_bracket = 0;
break;
case '\\':
if (i < brace_end - 1)
i++; /* skip */
break;
}
if (pattern[i] == ',' || i == brace_end - 1) {
if (in_bracket || brace_level > 0)
continue;
/* End of a selection, emit an expanded pattern */
/* Adjust end index for last selection */
sel_end = (i == brace_end - 1) ? brace_end : i;
if (emit_expansion(pattern, brace_start, brace_end,
sel_start, sel_end, patternsp, npatternsp) != 0)
return -1;
/* move on to the next selection */
sel_start = i + 1;
continue;
}
}
if (in_bracket || brace_level > 0) {
*invalid = 1;
return 0;
}
/* success */
*expanded = 1;
return 0;
}
/* Expand braces from pattern. Returns 0 on success, -1 on failure */
static int
brace_expand(const char *pattern, char ***patternsp, size_t *npatternsp)
{
char *cp, *cp2, **active = NULL, **done = NULL;
size_t i, nactive = 0, ndone = 0;
int ret = -1, invalid = 0, expanded = 0;
*patternsp = NULL;
*npatternsp = 0;
/* Start the worklist with the original pattern */
if ((cp = strdup(pattern)) == NULL)
return -1;
if (append(cp, &active, &nactive) != 0) {
free(cp);
return -1;
}
while (nactive > 0) {
cp = active[nactive - 1];
nactive--;
if (brace_expand_one(cp, &active, &nactive,
&expanded, &invalid) == -1) {
free(cp);
goto fail;
}
if (invalid)
fatal_f("invalid brace pattern \"%s\"", cp);
if (expanded) {
/*
* Current entry expanded to new entries on the
* active list; discard the progenitor pattern.
*/
free(cp);
continue;
}
/*
* Pattern did not expand; append the finename component to
* the completed list
*/
if ((cp2 = strrchr(cp, '/')) != NULL)
*cp2++ = '\0';
else
cp2 = cp;
if (append(xstrdup(cp2), &done, &ndone) != 0) {
free(cp);
goto fail;
}
free(cp);
}
/* success */
*patternsp = done;
*npatternsp = ndone;
done = NULL;
ndone = 0;
ret = 0;
fail:
for (i = 0; i < nactive; i++)
free(active[i]);
free(active);
for (i = 0; i < ndone; i++)
free(done[i]);
free(done);
return ret;
}
void
toremote(int argc, char **argv)
{
char *suser = NULL, *host = NULL, *src = NULL;
char *bp, *tuser, *thost, *targ;
int sport = -1, tport = -1;
arglist alist;
int i, r;
u_int j;
memset(&alist, '\0', sizeof(alist));
alist.list = NULL;
/* Parse target */
r = parse_scp_uri(argv[argc - 1], &tuser, &thost, &tport, &targ);
if (r == -1) {
fmprintf(stderr, "%s: invalid uri\n", argv[argc - 1]);
++errs;
goto out;
}
if (r != 0) {
if (parse_user_host_path(argv[argc - 1], &tuser, &thost,
&targ) == -1) {
fmprintf(stderr, "%s: invalid target\n", argv[argc - 1]);
++errs;
goto out;
}
}
if (tuser != NULL && !okname(tuser)) {
++errs;
goto out;
}
/* Parse source files */
for (i = 0; i < argc - 1; i++) {
free(suser);
free(host);
free(src);
r = parse_scp_uri(argv[i], &suser, &host, &sport, &src);
if (r == -1) {
fmprintf(stderr, "%s: invalid uri\n", argv[i]);
++errs;
continue;
}
if (r != 0) {
parse_user_host_path(argv[i], &suser, &host, &src);
}
if (suser != NULL && !okname(suser)) {
++errs;
continue;
}
if (host && throughlocal) { /* extended remote to remote */
xasprintf(&bp, "%s -f %s%s", cmd,
*src == '-' ? "-- " : "", src);
if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0)
exit(1);
free(bp);
xasprintf(&bp, "%s -t %s%s", cmd,
*targ == '-' ? "-- " : "", targ);
if (do_cmd2(thost, tuser, tport, bp, remin, remout) < 0)
exit(1);
free(bp);
(void) close(remin);
(void) close(remout);
remin = remout = -1;
} else if (host) { /* standard remote to remote */
if (tport != -1 && tport != SSH_DEFAULT_PORT) {
/* This would require the remote support URIs */
fatal("target port not supported with two "
"remote hosts without the -3 option");
}
freeargs(&alist);
addargs(&alist, "%s", ssh_program);
addargs(&alist, "-x");
addargs(&alist, "-oClearAllForwardings=yes");
addargs(&alist, "-n");
for (j = 0; j < remote_remote_args.num; j++) {
addargs(&alist, "%s",
remote_remote_args.list[j]);
}
if (sport != -1) {
addargs(&alist, "-p");
addargs(&alist, "%d", sport);
}
if (suser) {
addargs(&alist, "-l");
addargs(&alist, "%s", suser);
}
addargs(&alist, "--");
addargs(&alist, "%s", host);
addargs(&alist, "%s", cmd);
addargs(&alist, "%s", src);
addargs(&alist, "%s%s%s:%s",
tuser ? tuser : "", tuser ? "@" : "",
thost, targ);
if (do_local_cmd(&alist) != 0)
errs = 1;
} else { /* local to remote */
if (remin == -1) {
xasprintf(&bp, "%s -t %s%s", cmd,
*targ == '-' ? "-- " : "", targ);
if (do_cmd(thost, tuser, tport, bp, &remin,
&remout) < 0)
exit(1);
if (response() < 0)
exit(1);
free(bp);
}
source(1, argv + i);
}
}
out:
free(tuser);
free(thost);
free(targ);
free(suser);
free(host);
free(src);
}
void
tolocal(int argc, char **argv)
{
char *bp, *host = NULL, *src = NULL, *suser = NULL;
arglist alist;
int i, r, sport = -1;
memset(&alist, '\0', sizeof(alist));
alist.list = NULL;
for (i = 0; i < argc - 1; i++) {
free(suser);
free(host);
free(src);
r = parse_scp_uri(argv[i], &suser, &host, &sport, &src);
if (r == -1) {
fmprintf(stderr, "%s: invalid uri\n", argv[i]);
++errs;
continue;
}
if (r != 0)
parse_user_host_path(argv[i], &suser, &host, &src);
if (suser != NULL && !okname(suser)) {
++errs;
continue;
}
if (!host) { /* Local to local. */
freeargs(&alist);
addargs(&alist, "%s", _PATH_CP);
if (iamrecursive)
addargs(&alist, "-r");
if (pflag)
addargs(&alist, "-p");
addargs(&alist, "--");
addargs(&alist, "%s", argv[i]);
addargs(&alist, "%s", argv[argc-1]);
if (do_local_cmd(&alist))
++errs;
continue;
}
/* Remote to local. */
xasprintf(&bp, "%s -f %s%s",
cmd, *src == '-' ? "-- " : "", src);
if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0) {
free(bp);
++errs;
continue;
}
free(bp);
sink(1, argv + argc - 1, src);
(void) close(remin);
remin = remout = -1;
}
free(suser);
free(host);
free(src);
}
void
source(int argc, char **argv)
{
struct stat stb;
static BUF buffer;
BUF *bp;
off_t i, statbytes;
size_t amt, nr;
int fd = -1, haderr, indx;
char *last, *name, buf[PATH_MAX + 128], encname[PATH_MAX];
int len;
for (indx = 0; indx < argc; ++indx) {
name = argv[indx];
statbytes = 0;
len = strlen(name);
while (len > 1 && name[len-1] == '/')
name[--len] = '\0';
if ((fd = open(name, O_RDONLY|O_NONBLOCK, 0)) == -1)
goto syserr;
if (strchr(name, '\n') != NULL) {
strnvis(encname, name, sizeof(encname), VIS_NL);
name = encname;
}
if (fstat(fd, &stb) == -1) {
syserr: run_err("%s: %s", name, strerror(errno));
goto next;
}
if (stb.st_size < 0) {
run_err("%s: %s", name, "Negative file size");
goto next;
}
unset_nonblock(fd);
switch (stb.st_mode & S_IFMT) {
case S_IFREG:
break;
case S_IFDIR:
if (iamrecursive) {
rsource(name, &stb);
goto next;
}
/* FALLTHROUGH */
default:
run_err("%s: not a regular file", name);
goto next;
}
if ((last = strrchr(name, '/')) == NULL)
last = name;
else
++last;
curfile = last;
if (pflag) {
if (do_times(remout, verbose_mode, &stb) < 0)
goto next;
}
#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
snprintf(buf, sizeof buf, "C%04o %lld %s\n",
(u_int) (stb.st_mode & FILEMODEMASK),
(long long)stb.st_size, last);
if (verbose_mode)
fmprintf(stderr, "Sending file modes: %s", buf);
(void) atomicio(vwrite, remout, buf, strlen(buf));
if (response() < 0)
goto next;
if ((bp = allocbuf(&buffer, fd, COPY_BUFLEN)) == NULL) {
next: if (fd != -1) {
(void) close(fd);
fd = -1;
}
continue;
}
if (showprogress)
start_progress_meter(curfile, stb.st_size, &statbytes);
set_nonblock(remout);
for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
amt = bp->cnt;
if (i + (off_t)amt > stb.st_size)
amt = stb.st_size - i;
if (!haderr) {
if ((nr = atomicio(read, fd,
bp->buf, amt)) != amt) {
haderr = errno;
memset(bp->buf + nr, 0, amt - nr);
}
}
/* Keep writing after error to retain sync */
if (haderr) {
(void)atomicio(vwrite, remout, bp->buf, amt);
memset(bp->buf, 0, amt);
continue;
}
if (atomicio6(vwrite, remout, bp->buf, amt, scpio,
&statbytes) != amt)
haderr = errno;
}
unset_nonblock(remout);
if (fd != -1) {
if (close(fd) == -1 && !haderr)
haderr = errno;
fd = -1;
}
if (!haderr)
(void) atomicio(vwrite, remout, "", 1);
else
run_err("%s: %s", name, strerror(haderr));
(void) response();
if (showprogress)
stop_progress_meter();
}
}
void
rsource(char *name, struct stat *statp)
{
DIR *dirp;
struct dirent *dp;
char *last, *vect[1], path[PATH_MAX];
if (!(dirp = opendir(name))) {
run_err("%s: %s", name, strerror(errno));
return;
}
last = strrchr(name, '/');
if (last == NULL)
last = name;
else
last++;
if (pflag) {
if (do_times(remout, verbose_mode, statp) < 0) {
closedir(dirp);
return;
}
}
(void) snprintf(path, sizeof path, "D%04o %d %.1024s\n",
(u_int) (statp->st_mode & FILEMODEMASK), 0, last);
if (verbose_mode)
fmprintf(stderr, "Entering directory: %s", path);
(void) atomicio(vwrite, remout, path, strlen(path));
if (response() < 0) {
closedir(dirp);
return;
}
while ((dp = readdir(dirp)) != NULL) {
if (dp->d_ino == 0)
continue;
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
continue;
if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) {
run_err("%s/%s: name too long", name, dp->d_name);
continue;
}
(void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name);
vect[0] = path;
source(1, vect);
}
(void) closedir(dirp);
(void) atomicio(vwrite, remout, "E\n", 2);
(void) response();
}
#define TYPE_OVERFLOW(type, val) \
((sizeof(type) == 4 && (val) > INT32_MAX) || \
(sizeof(type) == 8 && (val) > INT64_MAX) || \
(sizeof(type) != 4 && sizeof(type) != 8))
void
sink(int argc, char **argv, const char *src)
{
static BUF buffer;
struct stat stb;
BUF *bp;
off_t i;
size_t j, count;
int amt, exists, first, ofd;
mode_t mode, omode, mask;
off_t size, statbytes;
unsigned long long ull;
int setimes, targisdir, wrerr;
char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048];
char **patterns = NULL;
size_t n, npatterns = 0;
struct timeval tv[2];
#define atime tv[0]
#define mtime tv[1]
#define SCREWUP(str) { why = str; goto screwup; }
if (TYPE_OVERFLOW(time_t, 0) || TYPE_OVERFLOW(off_t, 0))
SCREWUP("Unexpected off_t/time_t size");
setimes = targisdir = 0;
mask = umask(0);
if (!pflag)
(void) umask(mask);
if (argc != 1) {
run_err("ambiguous target");
exit(1);
}
targ = *argv;
if (targetshouldbedirectory)
verifydir(targ);
(void) atomicio(vwrite, remout, "", 1);
if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
targisdir = 1;
if (src != NULL && !iamrecursive && !Tflag) {
/*
* Prepare to try to restrict incoming filenames to match
* the requested destination file glob.
*/
if (brace_expand(src, &patterns, &npatterns) != 0)
fatal_f("could not expand pattern");
}
for (first = 1;; first = 0) {
cp = buf;
if (atomicio(read, remin, cp, 1) != 1)
goto done;
if (*cp++ == '\n')
SCREWUP("unexpected <newline>");
do {
if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
SCREWUP("lost connection");
*cp++ = ch;
} while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
*cp = 0;
if (verbose_mode)
fmprintf(stderr, "Sink: %s", buf);
if (buf[0] == '\01' || buf[0] == '\02') {
if (iamremote == 0) {
(void) snmprintf(visbuf, sizeof(visbuf),
NULL, "%s", buf + 1);
(void) atomicio(vwrite, STDERR_FILENO,
visbuf, strlen(visbuf));
}
if (buf[0] == '\02')
exit(1);
++errs;
continue;
}
if (buf[0] == 'E') {
(void) atomicio(vwrite, remout, "", 1);
goto done;
}
if (ch == '\n')
*--cp = 0;
cp = buf;
if (*cp == 'T') {
setimes++;
cp++;
if (!isdigit((unsigned char)*cp))
SCREWUP("mtime.sec not present");
ull = strtoull(cp, &cp, 10);
if (!cp || *cp++ != ' ')
SCREWUP("mtime.sec not delimited");
if (TYPE_OVERFLOW(time_t, ull))
setimes = 0; /* out of range */
mtime.tv_sec = ull;
mtime.tv_usec = strtol(cp, &cp, 10);
if (!cp || *cp++ != ' ' || mtime.tv_usec < 0 ||
mtime.tv_usec > 999999)
SCREWUP("mtime.usec not delimited");
if (!isdigit((unsigned char)*cp))
SCREWUP("atime.sec not present");
ull = strtoull(cp, &cp, 10);
if (!cp || *cp++ != ' ')
SCREWUP("atime.sec not delimited");
if (TYPE_OVERFLOW(time_t, ull))
setimes = 0; /* out of range */
atime.tv_sec = ull;
atime.tv_usec = strtol(cp, &cp, 10);
if (!cp || *cp++ != '\0' || atime.tv_usec < 0 ||
atime.tv_usec > 999999)
SCREWUP("atime.usec not delimited");
(void) atomicio(vwrite, remout, "", 1);
continue;
}
if (*cp != 'C' && *cp != 'D') {
/*
* Check for the case "rcp remote:foo\* local:bar".
* In this case, the line "No match." can be returned
* by the shell before the rcp command on the remote is
* executed so the ^Aerror_message convention isn't
* followed.
*/
if (first) {
run_err("%s", cp);
exit(1);
}
SCREWUP("expected control record");
}
mode = 0;
for (++cp; cp < buf + 5; cp++) {
if (*cp < '0' || *cp > '7')
SCREWUP("bad mode");
mode = (mode << 3) | (*cp - '0');
}
if (!pflag)
mode &= ~mask;
if (*cp++ != ' ')
SCREWUP("mode not delimited");
if (!isdigit((unsigned char)*cp))
SCREWUP("size not present");
ull = strtoull(cp, &cp, 10);
if (!cp || *cp++ != ' ')
SCREWUP("size not delimited");
if (TYPE_OVERFLOW(off_t, ull))
SCREWUP("size out of range");
size = (off_t)ull;
if (*cp == '\0' || strchr(cp, '/') != NULL ||
strcmp(cp, ".") == 0 || strcmp(cp, "..") == 0) {
run_err("error: unexpected filename: %s", cp);
exit(1);
}
if (npatterns > 0) {
for (n = 0; n < npatterns; n++) {
if (fnmatch(patterns[n], cp, 0) == 0)
break;
}
if (n >= npatterns)
SCREWUP("filename does not match request");
}
if (targisdir) {
static char *namebuf;
static size_t cursize;
size_t need;
need = strlen(targ) + strlen(cp) + 250;
if (need > cursize) {
free(namebuf);
namebuf = xmalloc(need);
cursize = need;
}
(void) snprintf(namebuf, need, "%s%s%s", targ,
strcmp(targ, "/") ? "/" : "", cp);
np = namebuf;
} else
np = targ;
curfile = cp;
exists = stat(np, &stb) == 0;
if (buf[0] == 'D') {
int mod_flag = pflag;
if (!iamrecursive)
SCREWUP("received directory without -r");
if (exists) {
if (!S_ISDIR(stb.st_mode)) {
errno = ENOTDIR;
goto bad;
}
if (pflag)
(void) chmod(np, mode);
} else {
- /* Handle copying from a read-only
- directory */
+ /* Handle copying from a read-only directory */
mod_flag = 1;
if (mkdir(np, mode | S_IRWXU) == -1)
goto bad;
}
vect[0] = xstrdup(np);
sink(1, vect, src);
if (setimes) {
setimes = 0;
(void) utimes(vect[0], tv);
}
if (mod_flag)
(void) chmod(vect[0], mode);
free(vect[0]);
continue;
}
omode = mode;
mode |= S_IWUSR;
if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) == -1) {
bad: run_err("%s: %s", np, strerror(errno));
continue;
}
(void) atomicio(vwrite, remout, "", 1);
if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) {
(void) close(ofd);
continue;
}
cp = bp->buf;
wrerr = 0;
/*
* NB. do not use run_err() unless immediately followed by
* exit() below as it may send a spurious reply that might
* desyncronise us from the peer. Use note_err() instead.
*/
statbytes = 0;
if (showprogress)
start_progress_meter(curfile, size, &statbytes);
set_nonblock(remin);
for (count = i = 0; i < size; i += bp->cnt) {
amt = bp->cnt;
if (i + amt > size)
amt = size - i;
count += amt;
do {
j = atomicio6(read, remin, cp, amt,
scpio, &statbytes);
if (j == 0) {
run_err("%s", j != EPIPE ?
strerror(errno) :
"dropped connection");
exit(1);
}
amt -= j;
cp += j;
} while (amt > 0);
if (count == bp->cnt) {
/* Keep reading so we stay sync'd up. */
if (!wrerr) {
if (atomicio(vwrite, ofd, bp->buf,
count) != count) {
note_err("%s: %s", np,
strerror(errno));
wrerr = 1;
}
}
count = 0;
cp = bp->buf;
}
}
unset_nonblock(remin);
if (count != 0 && !wrerr &&
atomicio(vwrite, ofd, bp->buf, count) != count) {
note_err("%s: %s", np, strerror(errno));
wrerr = 1;
}
if (!wrerr && (!exists || S_ISREG(stb.st_mode)) &&
ftruncate(ofd, size) != 0)
note_err("%s: truncate: %s", np, strerror(errno));
if (pflag) {
if (exists || omode != mode)
#ifdef HAVE_FCHMOD
if (fchmod(ofd, omode)) {
#else /* HAVE_FCHMOD */
if (chmod(np, omode)) {
#endif /* HAVE_FCHMOD */
note_err("%s: set mode: %s",
np, strerror(errno));
}
} else {
if (!exists && omode != mode)
#ifdef HAVE_FCHMOD
if (fchmod(ofd, omode & ~mask)) {
#else /* HAVE_FCHMOD */
if (chmod(np, omode & ~mask)) {
#endif /* HAVE_FCHMOD */
note_err("%s: set mode: %s",
np, strerror(errno));
}
}
if (close(ofd) == -1)
note_err("%s: close: %s", np, strerror(errno));
(void) response();
if (showprogress)
stop_progress_meter();
if (setimes && !wrerr) {
setimes = 0;
if (utimes(np, tv) == -1) {
note_err("%s: set times: %s",
np, strerror(errno));
}
}
/* If no error was noted then signal success for this file */
if (note_err(NULL) == 0)
(void) atomicio(vwrite, remout, "", 1);
}
done:
for (n = 0; n < npatterns; n++)
free(patterns[n]);
free(patterns);
return;
screwup:
for (n = 0; n < npatterns; n++)
free(patterns[n]);
free(patterns);
run_err("protocol error: %s", why);
exit(1);
}
int
response(void)
{
char ch, *cp, resp, rbuf[2048], visbuf[2048];
if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp))
lostconn(0);
cp = rbuf;
switch (resp) {
case 0: /* ok */
return (0);
default:
*cp++ = resp;
/* FALLTHROUGH */
case 1: /* error, followed by error msg */
case 2: /* fatal error, "" */
do {
if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
lostconn(0);
*cp++ = ch;
} while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');
if (!iamremote) {
cp[-1] = '\0';
(void) snmprintf(visbuf, sizeof(visbuf),
NULL, "%s\n", rbuf);
(void) atomicio(vwrite, STDERR_FILENO,
visbuf, strlen(visbuf));
}
++errs;
if (resp == 1)
return (-1);
exit(1);
}
/* NOTREACHED */
}
void
usage(void)
{
(void) fprintf(stderr,
"usage: scp [-346ABCpqrTv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
" [-J destination] [-l limit] [-o ssh_option] [-P port]\n"
" [-S program] source ... target\n");
exit(1);
}
void
run_err(const char *fmt,...)
{
static FILE *fp;
va_list ap;
++errs;
if (fp != NULL || (remout != -1 && (fp = fdopen(remout, "w")))) {
(void) fprintf(fp, "%c", 0x01);
(void) fprintf(fp, "scp: ");
va_start(ap, fmt);
(void) vfprintf(fp, fmt, ap);
va_end(ap);
(void) fprintf(fp, "\n");
(void) fflush(fp);
}
if (!iamremote) {
va_start(ap, fmt);
vfmprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
}
}
/*
* Notes a sink error for sending at the end of a file transfer. Returns 0 if
* no error has been noted or -1 otherwise. Use note_err(NULL) to flush
* any active error at the end of the transfer.
*/
int
note_err(const char *fmt, ...)
{
static char *emsg;
va_list ap;
/* Replay any previously-noted error */
if (fmt == NULL) {
if (emsg == NULL)
return 0;
run_err("%s", emsg);
free(emsg);
emsg = NULL;
return -1;
}
errs++;
/* Prefer first-noted error */
if (emsg != NULL)
return -1;
va_start(ap, fmt);
vasnmprintf(&emsg, INT_MAX, NULL, fmt, ap);
va_end(ap);
return -1;
}
void
verifydir(char *cp)
{
struct stat stb;
if (!stat(cp, &stb)) {
if (S_ISDIR(stb.st_mode))
return;
errno = ENOTDIR;
}
run_err("%s: %s", cp, strerror(errno));
killchild(0);
}
int
okname(char *cp0)
{
int c;
char *cp;
cp = cp0;
do {
c = (int)*cp;
if (c & 0200)
goto bad;
if (!isalpha(c) && !isdigit((unsigned char)c)) {
switch (c) {
case '\'':
case '"':
case '`':
case ' ':
case '#':
goto bad;
default:
break;
}
}
} while (*++cp);
return (1);
bad: fmprintf(stderr, "%s: invalid user name\n", cp0);
return (0);
}
BUF *
allocbuf(BUF *bp, int fd, int blksize)
{
size_t size;
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
struct stat stb;
if (fstat(fd, &stb) == -1) {
run_err("fstat: %s", strerror(errno));
return (0);
}
size = ROUNDUP(stb.st_blksize, blksize);
if (size == 0)
size = blksize;
#else /* HAVE_STRUCT_STAT_ST_BLKSIZE */
size = blksize;
#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
if (bp->cnt >= size)
return (bp);
bp->buf = xrecallocarray(bp->buf, bp->cnt, size, 1);
bp->cnt = size;
return (bp);
}
void
lostconn(int signo)
{
if (!iamremote)
(void)write(STDERR_FILENO, "lost connection\n", 16);
if (signo)
_exit(1);
else
exit(1);
}
diff --git a/servconf.c b/servconf.c
index 9695583a0f85..4d1910feb432 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,2989 +1,2997 @@
-/* $OpenBSD: servconf.c,v 1.377 2021/02/24 01:18:08 dtucker Exp $ */
+/* $OpenBSD: servconf.c,v 1.379 2021/04/03 06:18:40 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#ifdef __OpenBSD__
#include <sys/sysctl.h>
#endif
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#ifdef HAVE_NET_ROUTE_H
#include <net/route.h>
#endif
#include <ctype.h>
#include <netdb.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <limits.h>
#include <stdarg.h>
#include <errno.h>
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
#ifdef USE_SYSTEM_GLOB
# include <glob.h>
#else
# include "openbsd-compat/glob.h"
#endif
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "ssh.h"
#include "log.h"
#include "sshbuf.h"
#include "misc.h"
#include "servconf.h"
#include "compat.h"
#include "pathnames.h"
#include "cipher.h"
#include "sshkey.h"
#include "kex.h"
#include "mac.h"
#include "match.h"
#include "channels.h"
#include "groupaccess.h"
#include "canohost.h"
#include "packet.h"
#include "ssherr.h"
#include "hostfile.h"
#include "auth.h"
#include "myproposal.h"
#include "digest.h"
static void add_listen_addr(ServerOptions *, const char *,
const char *, int);
static void add_one_listen_addr(ServerOptions *, const char *,
const char *, int);
static void parse_server_config_depth(ServerOptions *options,
const char *filename, struct sshbuf *conf, struct include_list *includes,
struct connection_info *connectinfo, int flags, int *activep, int depth);
/* Use of privilege separation or not */
extern int use_privsep;
extern struct sshbuf *cfg;
/* Initializes the server options to their default values. */
void
initialize_server_options(ServerOptions *options)
{
memset(options, 0, sizeof(*options));
/* Portable-specific options */
options->use_pam = -1;
/* Standard Options */
options->num_ports = 0;
options->ports_from_cmdline = 0;
options->queued_listen_addrs = NULL;
options->num_queued_listens = 0;
options->listen_addrs = NULL;
options->num_listen_addrs = 0;
options->address_family = -1;
options->routing_domain = NULL;
options->num_host_key_files = 0;
options->num_host_cert_files = 0;
options->host_key_agent = NULL;
options->pid_file = NULL;
options->login_grace_time = -1;
options->permit_root_login = PERMIT_NOT_SET;
options->ignore_rhosts = -1;
options->ignore_user_known_hosts = -1;
options->print_motd = -1;
options->print_lastlog = -1;
options->x11_forwarding = -1;
options->x11_display_offset = -1;
options->x11_use_localhost = -1;
options->permit_tty = -1;
options->permit_user_rc = -1;
options->xauth_location = NULL;
options->strict_modes = -1;
options->tcp_keep_alive = -1;
options->log_facility = SYSLOG_FACILITY_NOT_SET;
options->log_level = SYSLOG_LEVEL_NOT_SET;
options->num_log_verbose = 0;
options->log_verbose = NULL;
options->hostbased_authentication = -1;
options->hostbased_uses_name_from_packet_only = -1;
options->hostbased_accepted_algos = NULL;
options->hostkeyalgorithms = NULL;
options->pubkey_authentication = -1;
options->pubkey_auth_options = -1;
options->pubkey_accepted_algos = NULL;
options->kerberos_authentication = -1;
options->kerberos_or_local_passwd = -1;
options->kerberos_ticket_cleanup = -1;
options->kerberos_get_afs_token = -1;
options->gss_authentication=-1;
options->gss_cleanup_creds = -1;
options->gss_strict_acceptor = -1;
options->password_authentication = -1;
options->kbd_interactive_authentication = -1;
options->challenge_response_authentication = -1;
options->permit_empty_passwd = -1;
options->permit_user_env = -1;
options->permit_user_env_allowlist = NULL;
options->compression = -1;
options->rekey_limit = -1;
options->rekey_interval = -1;
options->allow_tcp_forwarding = -1;
options->allow_streamlocal_forwarding = -1;
options->allow_agent_forwarding = -1;
options->num_allow_users = 0;
options->num_deny_users = 0;
options->num_allow_groups = 0;
options->num_deny_groups = 0;
options->ciphers = NULL;
options->macs = NULL;
options->kex_algorithms = NULL;
options->ca_sign_algorithms = NULL;
options->fwd_opts.gateway_ports = -1;
options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
options->fwd_opts.streamlocal_bind_unlink = -1;
options->num_subsystems = 0;
options->max_startups_begin = -1;
options->max_startups_rate = -1;
options->max_startups = -1;
options->per_source_max_startups = -1;
options->per_source_masklen_ipv4 = -1;
options->per_source_masklen_ipv6 = -1;
options->max_authtries = -1;
options->max_sessions = -1;
options->banner = NULL;
options->use_dns = -1;
options->client_alive_interval = -1;
options->client_alive_count_max = -1;
options->num_authkeys_files = 0;
options->num_accept_env = 0;
options->num_setenv = 0;
options->permit_tun = -1;
options->permitted_opens = NULL;
options->permitted_listens = NULL;
options->adm_forced_command = NULL;
options->chroot_directory = NULL;
options->authorized_keys_command = NULL;
options->authorized_keys_command_user = NULL;
options->revoked_keys_file = NULL;
options->sk_provider = NULL;
options->trusted_user_ca_keys = NULL;
options->authorized_principals_file = NULL;
options->authorized_principals_command = NULL;
options->authorized_principals_command_user = NULL;
options->ip_qos_interactive = -1;
options->ip_qos_bulk = -1;
options->version_addendum = NULL;
options->fingerprint_hash = -1;
options->disable_forwarding = -1;
options->expose_userauth_info = -1;
}
/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
static int
option_clear_or_none(const char *o)
{
return o == NULL || strcasecmp(o, "none") == 0;
}
static void
assemble_algorithms(ServerOptions *o)
{
char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
int r;
all_cipher = cipher_alg_list(',', 0);
all_mac = mac_alg_list(',');
all_kex = kex_alg_list(',');
all_key = sshkey_alg_list(0, 0, 1, ',');
all_sig = sshkey_alg_list(0, 1, 1, ',');
/* remove unsupported algos from default lists */
def_cipher = match_filter_allowlist(KEX_SERVER_ENCRYPT, all_cipher);
def_mac = match_filter_allowlist(KEX_SERVER_MAC, all_mac);
def_kex = match_filter_allowlist(KEX_SERVER_KEX, all_kex);
def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
#define ASSEMBLE(what, defaults, all) \
do { \
if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \
fatal_fr(r, "%s", #what); \
} while (0)
ASSEMBLE(ciphers, def_cipher, all_cipher);
ASSEMBLE(macs, def_mac, all_mac);
ASSEMBLE(kex_algorithms, def_kex, all_kex);
ASSEMBLE(hostkeyalgorithms, def_key, all_key);
ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
#undef ASSEMBLE
free(all_cipher);
free(all_mac);
free(all_kex);
free(all_key);
free(all_sig);
free(def_cipher);
free(def_mac);
free(def_kex);
free(def_key);
free(def_sig);
}
void
servconf_add_hostkey(const char *file, const int line,
ServerOptions *options, const char *path, int userprovided)
{
char *apath = derelativise_path(path);
opt_array_append2(file, line, "HostKey",
&options->host_key_files, &options->host_key_file_userprovided,
&options->num_host_key_files, apath, userprovided);
free(apath);
}
void
servconf_add_hostcert(const char *file, const int line,
ServerOptions *options, const char *path)
{
char *apath = derelativise_path(path);
opt_array_append(file, line, "HostCertificate",
&options->host_cert_files, &options->num_host_cert_files, apath);
free(apath);
}
void
fill_default_server_options(ServerOptions *options)
{
u_int i;
/* Portable-specific options */
if (options->use_pam == -1)
options->use_pam = 0;
/* Standard Options */
if (options->num_host_key_files == 0) {
/* fill default hostkeys for protocols */
servconf_add_hostkey("[default]", 0, options,
_PATH_HOST_RSA_KEY_FILE, 0);
#ifdef OPENSSL_HAS_ECC
servconf_add_hostkey("[default]", 0, options,
_PATH_HOST_ECDSA_KEY_FILE, 0);
#endif
servconf_add_hostkey("[default]", 0, options,
_PATH_HOST_ED25519_KEY_FILE, 0);
#ifdef WITH_XMSS
servconf_add_hostkey("[default]", 0, options,
_PATH_HOST_XMSS_KEY_FILE, 0);
#endif /* WITH_XMSS */
}
/* No certificates by default */
if (options->num_ports == 0)
options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
if (options->address_family == -1)
options->address_family = AF_UNSPEC;
if (options->listen_addrs == NULL)
add_listen_addr(options, NULL, NULL, 0);
if (options->pid_file == NULL)
options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE);
+ if (options->moduli_file == NULL)
+ options->moduli_file = xstrdup(_PATH_DH_MODULI);
if (options->login_grace_time == -1)
options->login_grace_time = 120;
if (options->permit_root_login == PERMIT_NOT_SET)
options->permit_root_login = PERMIT_NO_PASSWD;
if (options->ignore_rhosts == -1)
options->ignore_rhosts = 1;
if (options->ignore_user_known_hosts == -1)
options->ignore_user_known_hosts = 0;
if (options->print_motd == -1)
options->print_motd = 1;
if (options->print_lastlog == -1)
options->print_lastlog = 1;
if (options->x11_forwarding == -1)
options->x11_forwarding = 0;
if (options->x11_display_offset == -1)
options->x11_display_offset = 10;
if (options->x11_use_localhost == -1)
options->x11_use_localhost = 1;
if (options->xauth_location == NULL)
options->xauth_location = xstrdup(_PATH_XAUTH);
if (options->permit_tty == -1)
options->permit_tty = 1;
if (options->permit_user_rc == -1)
options->permit_user_rc = 1;
if (options->strict_modes == -1)
options->strict_modes = 1;
if (options->tcp_keep_alive == -1)
options->tcp_keep_alive = 1;
if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
options->log_facility = SYSLOG_FACILITY_AUTH;
if (options->log_level == SYSLOG_LEVEL_NOT_SET)
options->log_level = SYSLOG_LEVEL_INFO;
if (options->hostbased_authentication == -1)
options->hostbased_authentication = 0;
if (options->hostbased_uses_name_from_packet_only == -1)
options->hostbased_uses_name_from_packet_only = 0;
if (options->pubkey_authentication == -1)
options->pubkey_authentication = 1;
if (options->pubkey_auth_options == -1)
options->pubkey_auth_options = 0;
if (options->kerberos_authentication == -1)
options->kerberos_authentication = 0;
if (options->kerberos_or_local_passwd == -1)
options->kerberos_or_local_passwd = 1;
if (options->kerberos_ticket_cleanup == -1)
options->kerberos_ticket_cleanup = 1;
if (options->kerberos_get_afs_token == -1)
options->kerberos_get_afs_token = 0;
if (options->gss_authentication == -1)
options->gss_authentication = 0;
if (options->gss_cleanup_creds == -1)
options->gss_cleanup_creds = 1;
if (options->gss_strict_acceptor == -1)
options->gss_strict_acceptor = 1;
if (options->password_authentication == -1)
options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1)
options->kbd_interactive_authentication = 0;
if (options->challenge_response_authentication == -1)
options->challenge_response_authentication = 1;
if (options->permit_empty_passwd == -1)
options->permit_empty_passwd = 0;
if (options->permit_user_env == -1) {
options->permit_user_env = 0;
options->permit_user_env_allowlist = NULL;
}
if (options->compression == -1)
#ifdef WITH_ZLIB
options->compression = COMP_DELAYED;
#else
options->compression = COMP_NONE;
#endif
if (options->rekey_limit == -1)
options->rekey_limit = 0;
if (options->rekey_interval == -1)
options->rekey_interval = 0;
if (options->allow_tcp_forwarding == -1)
options->allow_tcp_forwarding = FORWARD_ALLOW;
if (options->allow_streamlocal_forwarding == -1)
options->allow_streamlocal_forwarding = FORWARD_ALLOW;
if (options->allow_agent_forwarding == -1)
options->allow_agent_forwarding = 1;
if (options->fwd_opts.gateway_ports == -1)
options->fwd_opts.gateway_ports = 0;
if (options->max_startups == -1)
options->max_startups = 100;
if (options->max_startups_rate == -1)
options->max_startups_rate = 30; /* 30% */
if (options->max_startups_begin == -1)
options->max_startups_begin = 10;
if (options->per_source_max_startups == -1)
options->per_source_max_startups = INT_MAX;
if (options->per_source_masklen_ipv4 == -1)
options->per_source_masklen_ipv4 = 32;
if (options->per_source_masklen_ipv6 == -1)
options->per_source_masklen_ipv6 = 128;
if (options->max_authtries == -1)
options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
if (options->max_sessions == -1)
options->max_sessions = DEFAULT_SESSIONS_MAX;
if (options->use_dns == -1)
options->use_dns = 0;
if (options->client_alive_interval == -1)
options->client_alive_interval = 0;
if (options->client_alive_count_max == -1)
options->client_alive_count_max = 3;
if (options->num_authkeys_files == 0) {
opt_array_append("[default]", 0, "AuthorizedKeysFiles",
&options->authorized_keys_files,
&options->num_authkeys_files,
_PATH_SSH_USER_PERMITTED_KEYS);
opt_array_append("[default]", 0, "AuthorizedKeysFiles",
&options->authorized_keys_files,
&options->num_authkeys_files,
_PATH_SSH_USER_PERMITTED_KEYS2);
}
if (options->permit_tun == -1)
options->permit_tun = SSH_TUNMODE_NO;
if (options->ip_qos_interactive == -1)
options->ip_qos_interactive = IPTOS_DSCP_AF21;
if (options->ip_qos_bulk == -1)
options->ip_qos_bulk = IPTOS_DSCP_CS1;
if (options->version_addendum == NULL)
options->version_addendum = xstrdup("");
if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
options->fwd_opts.streamlocal_bind_mask = 0177;
if (options->fwd_opts.streamlocal_bind_unlink == -1)
options->fwd_opts.streamlocal_bind_unlink = 0;
if (options->fingerprint_hash == -1)
options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
if (options->disable_forwarding == -1)
options->disable_forwarding = 0;
if (options->expose_userauth_info == -1)
options->expose_userauth_info = 0;
if (options->sk_provider == NULL)
options->sk_provider = xstrdup("internal");
assemble_algorithms(options);
/* Turn privilege separation and sandboxing on by default */
if (use_privsep == -1)
use_privsep = PRIVSEP_ON;
#define CLEAR_ON_NONE(v) \
do { \
if (option_clear_or_none(v)) { \
free(v); \
v = NULL; \
} \
} while(0)
CLEAR_ON_NONE(options->pid_file);
CLEAR_ON_NONE(options->xauth_location);
CLEAR_ON_NONE(options->banner);
CLEAR_ON_NONE(options->trusted_user_ca_keys);
CLEAR_ON_NONE(options->revoked_keys_file);
CLEAR_ON_NONE(options->sk_provider);
CLEAR_ON_NONE(options->authorized_principals_file);
CLEAR_ON_NONE(options->adm_forced_command);
CLEAR_ON_NONE(options->chroot_directory);
CLEAR_ON_NONE(options->routing_domain);
CLEAR_ON_NONE(options->host_key_agent);
for (i = 0; i < options->num_host_key_files; i++)
CLEAR_ON_NONE(options->host_key_files[i]);
for (i = 0; i < options->num_host_cert_files; i++)
CLEAR_ON_NONE(options->host_cert_files[i]);
#undef CLEAR_ON_NONE
/* Similar handling for AuthenticationMethods=any */
if (options->num_auth_methods == 1 &&
strcmp(options->auth_methods[0], "any") == 0) {
free(options->auth_methods[0]);
options->auth_methods[0] = NULL;
options->num_auth_methods = 0;
}
}
/* Keyword tokens. */
typedef enum {
sBadOption, /* == unknown option */
/* Portable-specific options */
sUsePAM,
/* Standard Options */
sPort, sHostKeyFile, sLoginGraceTime,
sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose,
sRhostsRSAAuthentication, sRSAAuthentication,
sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
sKerberosGetAFSToken, sChallengeResponseAuthentication,
sPasswordAuthentication, sKbdInteractiveAuthentication,
sListenAddress, sAddressFamily,
sPrintMotd, sPrintLastLog, sIgnoreRhosts,
sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive,
sPermitUserEnvironment, sAllowTcpForwarding, sCompression,
sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
- sIgnoreUserKnownHosts, sCiphers, sMacs, sPidFile,
+ sIgnoreUserKnownHosts, sCiphers, sMacs, sPidFile, sModuliFile,
sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedAlgorithms,
sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions,
sBanner, sUseDNS, sHostbasedAuthentication,
sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms,
sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize,
sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
sAcceptEnv, sSetEnv, sPermitTunnel,
sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
sUsePrivilegeSeparation, sAllowAgentForwarding,
sHostCertificate, sInclude,
sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
sKexAlgorithms, sCASignatureAlgorithms, sIPQoS, sVersionAddendum,
sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
sStreamLocalBindMask, sStreamLocalBindUnlink,
sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
sDeprecated, sIgnore, sUnsupported
} ServerOpCodes;
#define SSHCFG_GLOBAL 0x01 /* allowed in main section of config */
#define SSHCFG_MATCH 0x02 /* allowed inside a Match section */
#define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH)
#define SSHCFG_NEVERMATCH 0x04 /* Match never matches; internal only */
#define SSHCFG_MATCH_ONLY 0x08 /* Match only in conditional blocks; internal only */
/* Textual representation of the tokens. */
static struct {
const char *name;
ServerOpCodes opcode;
u_int flags;
} keywords[] = {
/* Portable-specific options */
#ifdef USE_PAM
{ "usepam", sUsePAM, SSHCFG_GLOBAL },
#else
{ "usepam", sUnsupported, SSHCFG_GLOBAL },
#endif
{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
/* Standard Options */
{ "port", sPort, SSHCFG_GLOBAL },
{ "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
{ "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL }, /* alias */
{ "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL },
{ "pidfile", sPidFile, SSHCFG_GLOBAL },
+ { "modulifile", sModuliFile, SSHCFG_GLOBAL },
{ "serverkeybits", sDeprecated, SSHCFG_GLOBAL },
{ "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
{ "keyregenerationinterval", sDeprecated, SSHCFG_GLOBAL },
{ "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
{ "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
{ "loglevel", sLogLevel, SSHCFG_ALL },
{ "logverbose", sLogVerbose, SSHCFG_ALL },
{ "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
{ "rhostsrsaauthentication", sDeprecated, SSHCFG_ALL },
{ "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL },
{ "hostbasedacceptedalgorithms", sHostbasedAcceptedAlgorithms, SSHCFG_ALL },
{ "hostbasedacceptedkeytypes", sHostbasedAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
{ "hostkeyalgorithms", sHostKeyAlgorithms, SSHCFG_GLOBAL },
{ "rsaauthentication", sDeprecated, SSHCFG_ALL },
{ "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
{ "pubkeyacceptedalgorithms", sPubkeyAcceptedAlgorithms, SSHCFG_ALL },
{ "pubkeyacceptedkeytypes", sPubkeyAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
{ "pubkeyauthoptions", sPubkeyAuthOptions, SSHCFG_ALL },
{ "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
#ifdef KRB5
{ "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
{ "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
#ifdef USE_AFS
{ "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
#else
{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
#endif
#else
{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
#endif
{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
#ifdef GSSAPI
{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
#else
{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
#endif
{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
{ "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
{ "skeyauthentication", sDeprecated, SSHCFG_GLOBAL },
{ "checkmail", sDeprecated, SSHCFG_GLOBAL },
{ "listenaddress", sListenAddress, SSHCFG_GLOBAL },
{ "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
{ "printmotd", sPrintMotd, SSHCFG_GLOBAL },
#ifdef DISABLE_LASTLOG
{ "printlastlog", sUnsupported, SSHCFG_GLOBAL },
#else
{ "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
#endif
{ "ignorerhosts", sIgnoreRhosts, SSHCFG_ALL },
{ "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
{ "x11forwarding", sX11Forwarding, SSHCFG_ALL },
{ "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
{ "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
{ "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
{ "strictmodes", sStrictModes, SSHCFG_GLOBAL },
{ "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
{ "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
{ "uselogin", sDeprecated, SSHCFG_GLOBAL },
{ "compression", sCompression, SSHCFG_GLOBAL },
{ "rekeylimit", sRekeyLimit, SSHCFG_ALL },
{ "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
{ "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, /* obsolete alias */
{ "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
{ "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL },
{ "allowusers", sAllowUsers, SSHCFG_ALL },
{ "denyusers", sDenyUsers, SSHCFG_ALL },
{ "allowgroups", sAllowGroups, SSHCFG_ALL },
{ "denygroups", sDenyGroups, SSHCFG_ALL },
{ "ciphers", sCiphers, SSHCFG_GLOBAL },
{ "macs", sMacs, SSHCFG_GLOBAL },
{ "protocol", sIgnore, SSHCFG_GLOBAL },
{ "gatewayports", sGatewayPorts, SSHCFG_ALL },
{ "subsystem", sSubsystem, SSHCFG_GLOBAL },
{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
{ "persourcemaxstartups", sPerSourceMaxStartups, SSHCFG_GLOBAL },
{ "persourcenetblocksize", sPerSourceNetBlockSize, SSHCFG_GLOBAL },
{ "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
{ "maxsessions", sMaxSessions, SSHCFG_ALL },
{ "banner", sBanner, SSHCFG_ALL },
{ "usedns", sUseDNS, SSHCFG_GLOBAL },
{ "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
{ "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
{ "clientaliveinterval", sClientAliveInterval, SSHCFG_ALL },
{ "clientalivecountmax", sClientAliveCountMax, SSHCFG_ALL },
{ "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL },
{ "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
{ "useprivilegeseparation", sDeprecated, SSHCFG_GLOBAL},
{ "acceptenv", sAcceptEnv, SSHCFG_ALL },
{ "setenv", sSetEnv, SSHCFG_ALL },
{ "permittunnel", sPermitTunnel, SSHCFG_ALL },
{ "permittty", sPermitTTY, SSHCFG_ALL },
{ "permituserrc", sPermitUserRC, SSHCFG_ALL },
{ "match", sMatch, SSHCFG_ALL },
{ "permitopen", sPermitOpen, SSHCFG_ALL },
{ "permitlisten", sPermitListen, SSHCFG_ALL },
{ "forcecommand", sForceCommand, SSHCFG_ALL },
{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
{ "include", sInclude, SSHCFG_ALL },
{ "ipqos", sIPQoS, SSHCFG_ALL },
{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
{ "authorizedprincipalscommand", sAuthorizedPrincipalsCommand, SSHCFG_ALL },
{ "authorizedprincipalscommanduser", sAuthorizedPrincipalsCommandUser, SSHCFG_ALL },
{ "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
{ "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
{ "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL },
{ "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL },
{ "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
{ "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
{ "disableforwarding", sDisableForwarding, SSHCFG_ALL },
{ "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
{ "rdomain", sRDomain, SSHCFG_ALL },
{ "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
{ "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
{ NULL, sBadOption, 0 }
};
static struct {
int val;
char *text;
} tunmode_desc[] = {
{ SSH_TUNMODE_NO, "no" },
{ SSH_TUNMODE_POINTOPOINT, "point-to-point" },
{ SSH_TUNMODE_ETHERNET, "ethernet" },
{ SSH_TUNMODE_YES, "yes" },
{ -1, NULL }
};
/* Returns an opcode name from its number */
static const char *
lookup_opcode_name(ServerOpCodes code)
{
u_int i;
for (i = 0; keywords[i].name != NULL; i++)
if (keywords[i].opcode == code)
return(keywords[i].name);
return "UNKNOWN";
}
/*
* Returns the number of the token pointed to by cp or sBadOption.
*/
static ServerOpCodes
parse_token(const char *cp, const char *filename,
int linenum, u_int *flags)
{
u_int i;
for (i = 0; keywords[i].name; i++)
if (strcasecmp(cp, keywords[i].name) == 0) {
*flags = keywords[i].flags;
return keywords[i].opcode;
}
error("%s: line %d: Bad configuration option: %s",
filename, linenum, cp);
return sBadOption;
}
char *
derelativise_path(const char *path)
{
char *expanded, *ret, cwd[PATH_MAX];
if (strcasecmp(path, "none") == 0)
return xstrdup("none");
expanded = tilde_expand_filename(path, getuid());
if (path_absolute(expanded))
return expanded;
if (getcwd(cwd, sizeof(cwd)) == NULL)
fatal_f("getcwd: %s", strerror(errno));
xasprintf(&ret, "%s/%s", cwd, expanded);
free(expanded);
return ret;
}
static void
add_listen_addr(ServerOptions *options, const char *addr,
const char *rdomain, int port)
{
u_int i;
if (port > 0)
add_one_listen_addr(options, addr, rdomain, port);
else {
for (i = 0; i < options->num_ports; i++) {
add_one_listen_addr(options, addr, rdomain,
options->ports[i]);
}
}
}
static void
add_one_listen_addr(ServerOptions *options, const char *addr,
const char *rdomain, int port)
{
struct addrinfo hints, *ai, *aitop;
char strport[NI_MAXSERV];
int gaierr;
u_int i;
/* Find listen_addrs entry for this rdomain */
for (i = 0; i < options->num_listen_addrs; i++) {
if (rdomain == NULL && options->listen_addrs[i].rdomain == NULL)
break;
if (rdomain == NULL || options->listen_addrs[i].rdomain == NULL)
continue;
if (strcmp(rdomain, options->listen_addrs[i].rdomain) == 0)
break;
}
if (i >= options->num_listen_addrs) {
/* No entry for this rdomain; allocate one */
if (i >= INT_MAX)
fatal_f("too many listen addresses");
options->listen_addrs = xrecallocarray(options->listen_addrs,
options->num_listen_addrs, options->num_listen_addrs + 1,
sizeof(*options->listen_addrs));
i = options->num_listen_addrs++;
if (rdomain != NULL)
options->listen_addrs[i].rdomain = xstrdup(rdomain);
}
/* options->listen_addrs[i] points to the addresses for this rdomain */
memset(&hints, 0, sizeof(hints));
hints.ai_family = options->address_family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
snprintf(strport, sizeof strport, "%d", port);
if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
fatal("bad addr or host: %s (%s)",
addr ? addr : "<NULL>",
ssh_gai_strerror(gaierr));
for (ai = aitop; ai->ai_next; ai = ai->ai_next)
;
ai->ai_next = options->listen_addrs[i].addrs;
options->listen_addrs[i].addrs = aitop;
}
/* Returns nonzero if the routing domain name is valid */
static int
valid_rdomain(const char *name)
{
#if defined(HAVE_SYS_VALID_RDOMAIN)
return sys_valid_rdomain(name);
#elif defined(__OpenBSD__)
const char *errstr;
long long num;
struct rt_tableinfo info;
int mib[6];
size_t miblen = sizeof(mib);
if (name == NULL)
return 1;
num = strtonum(name, 0, 255, &errstr);
if (errstr != NULL)
return 0;
/* Check whether the table actually exists */
memset(mib, 0, sizeof(mib));
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[4] = NET_RT_TABLE;
mib[5] = (int)num;
if (sysctl(mib, 6, &info, &miblen, NULL, 0) == -1)
return 0;
return 1;
#else /* defined(__OpenBSD__) */
error("Routing domains are not supported on this platform");
return 0;
#endif
}
/*
* Queue a ListenAddress to be processed once we have all of the Ports
* and AddressFamily options.
*/
static void
queue_listen_addr(ServerOptions *options, const char *addr,
const char *rdomain, int port)
{
struct queued_listenaddr *qla;
options->queued_listen_addrs = xrecallocarray(
options->queued_listen_addrs,
options->num_queued_listens, options->num_queued_listens + 1,
sizeof(*options->queued_listen_addrs));
qla = &options->queued_listen_addrs[options->num_queued_listens++];
qla->addr = xstrdup(addr);
qla->port = port;
qla->rdomain = rdomain == NULL ? NULL : xstrdup(rdomain);
}
/*
* Process queued (text) ListenAddress entries.
*/
static void
process_queued_listen_addrs(ServerOptions *options)
{
u_int i;
struct queued_listenaddr *qla;
if (options->num_ports == 0)
options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
if (options->address_family == -1)
options->address_family = AF_UNSPEC;
for (i = 0; i < options->num_queued_listens; i++) {
qla = &options->queued_listen_addrs[i];
add_listen_addr(options, qla->addr, qla->rdomain, qla->port);
free(qla->addr);
free(qla->rdomain);
}
free(options->queued_listen_addrs);
options->queued_listen_addrs = NULL;
options->num_queued_listens = 0;
}
/*
* Inform channels layer of permitopen options for a single forwarding
* direction (local/remote).
*/
static void
process_permitopen_list(struct ssh *ssh, ServerOpCodes opcode,
char **opens, u_int num_opens)
{
u_int i;
int port;
char *host, *arg, *oarg, ch;
int where = opcode == sPermitOpen ? FORWARD_LOCAL : FORWARD_REMOTE;
const char *what = lookup_opcode_name(opcode);
channel_clear_permission(ssh, FORWARD_ADM, where);
if (num_opens == 0)
return; /* permit any */
/* handle keywords: "any" / "none" */
if (num_opens == 1 && strcmp(opens[0], "any") == 0)
return;
if (num_opens == 1 && strcmp(opens[0], "none") == 0) {
channel_disable_admin(ssh, where);
return;
}
/* Otherwise treat it as a list of permitted host:port */
for (i = 0; i < num_opens; i++) {
oarg = arg = xstrdup(opens[i]);
ch = '\0';
host = hpdelim2(&arg, &ch);
if (host == NULL || ch == '/')
fatal_f("missing host in %s", what);
host = cleanhostname(host);
if (arg == NULL || ((port = permitopen_port(arg)) < 0))
fatal_f("bad port number in %s", what);
/* Send it to channels layer */
channel_add_permission(ssh, FORWARD_ADM,
where, host, port);
free(oarg);
}
}
/*
* Inform channels layer of permitopen options from configuration.
*/
void
process_permitopen(struct ssh *ssh, ServerOptions *options)
{
process_permitopen_list(ssh, sPermitOpen,
options->permitted_opens, options->num_permitted_opens);
process_permitopen_list(ssh, sPermitListen,
options->permitted_listens,
options->num_permitted_listens);
}
struct connection_info *
get_connection_info(struct ssh *ssh, int populate, int use_dns)
{
static struct connection_info ci;
if (ssh == NULL || !populate)
return &ci;
ci.host = auth_get_canonical_hostname(ssh, use_dns);
ci.address = ssh_remote_ipaddr(ssh);
ci.laddress = ssh_local_ipaddr(ssh);
ci.lport = ssh_local_port(ssh);
ci.rdomain = ssh_packet_rdomain_in(ssh);
return &ci;
}
/*
* The strategy for the Match blocks is that the config file is parsed twice.
*
* The first time is at startup. activep is initialized to 1 and the
* directives in the global context are processed and acted on. Hitting a
* Match directive unsets activep and the directives inside the block are
* checked for syntax only.
*
* The second time is after a connection has been established but before
* authentication. activep is initialized to 2 and global config directives
* are ignored since they have already been processed. If the criteria in a
* Match block is met, activep is set and the subsequent directives
* processed and actioned until EOF or another Match block unsets it. Any
* options set are copied into the main server config.
*
* Potential additions/improvements:
* - Add Match support for pre-kex directives, eg. Ciphers.
*
* - Add a Tag directive (idea from David Leonard) ala pf, eg:
* Match Address 192.168.0.*
* Tag trusted
* Match Group wheel
* Tag trusted
* Match Tag trusted
* AllowTcpForwarding yes
* GatewayPorts clientspecified
* [...]
*
* - Add a PermittedChannelRequests directive
* Match Group shell
* PermittedChannelRequests session,forwarded-tcpip
*/
static int
match_cfg_line_group(const char *grps, int line, const char *user)
{
int result = 0;
struct passwd *pw;
if (user == NULL)
goto out;
if ((pw = getpwnam(user)) == NULL) {
debug("Can't match group at line %d because user %.100s does "
"not exist", line, user);
} else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
debug("Can't Match group because user %.100s not in any group "
"at line %d", user, line);
} else if (ga_match_pattern_list(grps) != 1) {
debug("user %.100s does not match group list %.100s at line %d",
user, grps, line);
} else {
debug("user %.100s matched group list %.100s at line %d", user,
grps, line);
result = 1;
}
out:
ga_free();
return result;
}
static void
match_test_missing_fatal(const char *criteria, const char *attrib)
{
fatal("'Match %s' in configuration but '%s' not in connection "
"test specification.", criteria, attrib);
}
/*
* All of the attributes on a single Match line are ANDed together, so we need
* to check every attribute and set the result to zero if any attribute does
* not match.
*/
static int
match_cfg_line(char **condition, int line, struct connection_info *ci)
{
int result = 1, attributes = 0, port;
char *arg, *attrib, *cp = *condition;
if (ci == NULL)
debug3("checking syntax for 'Match %s'", cp);
else
debug3("checking match for '%s' user %s host %s addr %s "
"laddr %s lport %d", cp, ci->user ? ci->user : "(null)",
ci->host ? ci->host : "(null)",
ci->address ? ci->address : "(null)",
ci->laddress ? ci->laddress : "(null)", ci->lport);
while ((attrib = strdelim(&cp)) && *attrib != '\0') {
attributes++;
if (strcasecmp(attrib, "all") == 0) {
if (attributes != 1 ||
((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
error("'all' cannot be combined with other "
"Match attributes");
return -1;
}
*condition = cp;
return 1;
}
if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
error("Missing Match criteria for %s", attrib);
return -1;
}
if (strcasecmp(attrib, "user") == 0) {
if (ci == NULL || (ci->test && ci->user == NULL)) {
result = 0;
continue;
}
if (ci->user == NULL)
match_test_missing_fatal("User", "user");
if (match_usergroup_pattern_list(ci->user, arg) != 1)
result = 0;
else
debug("user %.100s matched 'User %.100s' at "
"line %d", ci->user, arg, line);
} else if (strcasecmp(attrib, "group") == 0) {
if (ci == NULL || (ci->test && ci->user == NULL)) {
result = 0;
continue;
}
if (ci->user == NULL)
match_test_missing_fatal("Group", "user");
switch (match_cfg_line_group(arg, line, ci->user)) {
case -1:
return -1;
case 0:
result = 0;
}
} else if (strcasecmp(attrib, "host") == 0) {
if (ci == NULL || (ci->test && ci->host == NULL)) {
result = 0;
continue;
}
if (ci->host == NULL)
match_test_missing_fatal("Host", "host");
if (match_hostname(ci->host, arg) != 1)
result = 0;
else
debug("connection from %.100s matched 'Host "
"%.100s' at line %d", ci->host, arg, line);
} else if (strcasecmp(attrib, "address") == 0) {
if (ci == NULL || (ci->test && ci->address == NULL)) {
if (addr_match_list(NULL, arg) != 0)
fatal("Invalid Match address argument "
"'%s' at line %d", arg, line);
result = 0;
continue;
}
if (ci->address == NULL)
match_test_missing_fatal("Address", "addr");
switch (addr_match_list(ci->address, arg)) {
case 1:
debug("connection from %.100s matched 'Address "
"%.100s' at line %d", ci->address, arg, line);
break;
case 0:
case -1:
result = 0;
break;
case -2:
return -1;
}
} else if (strcasecmp(attrib, "localaddress") == 0){
if (ci == NULL || (ci->test && ci->laddress == NULL)) {
if (addr_match_list(NULL, arg) != 0)
fatal("Invalid Match localaddress "
"argument '%s' at line %d", arg,
line);
result = 0;
continue;
}
if (ci->laddress == NULL)
match_test_missing_fatal("LocalAddress",
"laddr");
switch (addr_match_list(ci->laddress, arg)) {
case 1:
debug("connection from %.100s matched "
"'LocalAddress %.100s' at line %d",
ci->laddress, arg, line);
break;
case 0:
case -1:
result = 0;
break;
case -2:
return -1;
}
} else if (strcasecmp(attrib, "localport") == 0) {
if ((port = a2port(arg)) == -1) {
error("Invalid LocalPort '%s' on Match line",
arg);
return -1;
}
if (ci == NULL || (ci->test && ci->lport == -1)) {
result = 0;
continue;
}
if (ci->lport == 0)
match_test_missing_fatal("LocalPort", "lport");
/* TODO support port lists */
if (port == ci->lport)
debug("connection from %.100s matched "
"'LocalPort %d' at line %d",
ci->laddress, port, line);
else
result = 0;
} else if (strcasecmp(attrib, "rdomain") == 0) {
if (ci == NULL || (ci->test && ci->rdomain == NULL)) {
result = 0;
continue;
}
if (ci->rdomain == NULL)
match_test_missing_fatal("RDomain", "rdomain");
if (match_pattern_list(ci->rdomain, arg, 0) != 1)
result = 0;
else
debug("user %.100s matched 'RDomain %.100s' at "
"line %d", ci->rdomain, arg, line);
} else {
error("Unsupported Match attribute %s", attrib);
return -1;
}
}
if (attributes == 0) {
error("One or more attributes required for Match");
return -1;
}
if (ci != NULL)
debug3("match %sfound", result ? "" : "not ");
*condition = cp;
return result;
}
#define WHITESPACE " \t\r\n"
/* Multistate option parsing */
struct multistate {
char *key;
int value;
};
static const struct multistate multistate_flag[] = {
{ "yes", 1 },
{ "no", 0 },
{ NULL, -1 }
};
static const struct multistate multistate_ignore_rhosts[] = {
{ "yes", IGNORE_RHOSTS_YES },
{ "no", IGNORE_RHOSTS_NO },
{ "shosts-only", IGNORE_RHOSTS_SHOSTS },
{ NULL, -1 }
};
static const struct multistate multistate_addressfamily[] = {
{ "inet", AF_INET },
{ "inet6", AF_INET6 },
{ "any", AF_UNSPEC },
{ NULL, -1 }
};
static const struct multistate multistate_permitrootlogin[] = {
{ "without-password", PERMIT_NO_PASSWD },
{ "prohibit-password", PERMIT_NO_PASSWD },
{ "forced-commands-only", PERMIT_FORCED_ONLY },
{ "yes", PERMIT_YES },
{ "no", PERMIT_NO },
{ NULL, -1 }
};
static const struct multistate multistate_compression[] = {
#ifdef WITH_ZLIB
{ "yes", COMP_DELAYED },
{ "delayed", COMP_DELAYED },
#endif
{ "no", COMP_NONE },
{ NULL, -1 }
};
static const struct multistate multistate_gatewayports[] = {
{ "clientspecified", 2 },
{ "yes", 1 },
{ "no", 0 },
{ NULL, -1 }
};
static const struct multistate multistate_tcpfwd[] = {
{ "yes", FORWARD_ALLOW },
{ "all", FORWARD_ALLOW },
{ "no", FORWARD_DENY },
{ "remote", FORWARD_REMOTE },
{ "local", FORWARD_LOCAL },
{ NULL, -1 }
};
static int
process_server_config_line_depth(ServerOptions *options, char *line,
const char *filename, int linenum, int *activep,
struct connection_info *connectinfo, int *inc_flags, int depth,
struct include_list *includes)
{
char ch, *cp, ***chararrayptr, **charptr, *arg, *arg2, *p;
int cmdline = 0, *intptr, value, value2, n, port, oactive, r, found;
SyslogFacility *log_facility_ptr;
LogLevel *log_level_ptr;
ServerOpCodes opcode;
u_int i, *uintptr, uvalue, flags = 0;
size_t len;
long long val64;
const struct multistate *multistate_ptr;
const char *errstr;
struct include_item *item;
glob_t gbuf;
/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
if ((len = strlen(line)) == 0)
return 0;
for (len--; len > 0; len--) {
if (strchr(WHITESPACE "\f", line[len]) == NULL)
break;
line[len] = '\0';
}
cp = line;
if ((arg = strdelim(&cp)) == NULL)
return 0;
/* Ignore leading whitespace */
if (*arg == '\0')
arg = strdelim(&cp);
if (!arg || !*arg || *arg == '#')
return 0;
intptr = NULL;
charptr = NULL;
opcode = parse_token(arg, filename, linenum, &flags);
if (activep == NULL) { /* We are processing a command line directive */
cmdline = 1;
activep = &cmdline;
}
if (*activep && opcode != sMatch && opcode != sInclude)
debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
if (connectinfo == NULL) {
fatal("%s line %d: Directive '%s' is not allowed "
"within a Match block", filename, linenum, arg);
} else { /* this is a directive we have already processed */
while (arg)
arg = strdelim(&cp);
return 0;
}
}
switch (opcode) {
/* Portable-specific options */
case sUsePAM:
intptr = &options->use_pam;
goto parse_flag;
/* Standard Options */
case sBadOption:
return -1;
case sPort:
/* ignore ports from configfile if cmdline specifies ports */
if (options->ports_from_cmdline)
return 0;
if (options->num_ports >= MAX_PORTS)
fatal("%s line %d: too many ports.",
filename, linenum);
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing port number.",
filename, linenum);
options->ports[options->num_ports++] = a2port(arg);
if (options->ports[options->num_ports-1] <= 0)
fatal("%s line %d: Badly formatted port number.",
filename, linenum);
break;
case sLoginGraceTime:
intptr = &options->login_grace_time;
parse_time:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing time value.",
filename, linenum);
if ((value = convtime(arg)) == -1)
fatal("%s line %d: invalid time value.",
filename, linenum);
if (*activep && *intptr == -1)
*intptr = value;
break;
case sListenAddress:
arg = strdelim(&cp);
if (arg == NULL || *arg == '\0')
fatal("%s line %d: missing address",
filename, linenum);
/* check for bare IPv6 address: no "[]" and 2 or more ":" */
if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
&& strchr(p+1, ':') != NULL) {
port = 0;
p = arg;
} else {
arg2 = NULL;
ch = '\0';
p = hpdelim2(&arg, &ch);
if (p == NULL || ch == '/')
fatal("%s line %d: bad address:port usage",
filename, linenum);
p = cleanhostname(p);
if (arg == NULL)
port = 0;
else if ((port = a2port(arg)) <= 0)
fatal("%s line %d: bad port number",
filename, linenum);
}
/* Optional routing table */
arg2 = NULL;
if ((arg = strdelim(&cp)) != NULL) {
if (strcmp(arg, "rdomain") != 0 ||
(arg2 = strdelim(&cp)) == NULL)
fatal("%s line %d: bad ListenAddress syntax",
filename, linenum);
if (!valid_rdomain(arg2))
fatal("%s line %d: bad routing domain",
filename, linenum);
}
queue_listen_addr(options, p, arg2, port);
break;
case sAddressFamily:
intptr = &options->address_family;
multistate_ptr = multistate_addressfamily;
parse_multistate:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing argument.",
filename, linenum);
value = -1;
for (i = 0; multistate_ptr[i].key != NULL; i++) {
if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
value = multistate_ptr[i].value;
break;
}
}
if (value == -1)
fatal("%s line %d: unsupported option \"%s\".",
filename, linenum, arg);
if (*activep && *intptr == -1)
*intptr = value;
break;
case sHostKeyFile:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing file name.",
filename, linenum);
if (*activep) {
servconf_add_hostkey(filename, linenum,
options, arg, 1);
}
break;
case sHostKeyAgent:
charptr = &options->host_key_agent;
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing socket name.",
filename, linenum);
if (*activep && *charptr == NULL)
*charptr = !strcmp(arg, SSH_AUTHSOCKET_ENV_NAME) ?
xstrdup(arg) : derelativise_path(arg);
break;
case sHostCertificate:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing file name.",
filename, linenum);
if (*activep)
servconf_add_hostcert(filename, linenum, options, arg);
break;
case sPidFile:
charptr = &options->pid_file;
parse_filename:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing file name.",
filename, linenum);
if (*activep && *charptr == NULL) {
*charptr = derelativise_path(arg);
/* increase optional counter */
if (intptr != NULL)
*intptr = *intptr + 1;
}
break;
+ case sModuliFile:
+ charptr = &options->moduli_file;
+ goto parse_filename;
+
case sPermitRootLogin:
intptr = &options->permit_root_login;
multistate_ptr = multistate_permitrootlogin;
goto parse_multistate;
case sIgnoreRhosts:
intptr = &options->ignore_rhosts;
multistate_ptr = multistate_ignore_rhosts;
goto parse_multistate;
case sIgnoreUserKnownHosts:
intptr = &options->ignore_user_known_hosts;
parse_flag:
multistate_ptr = multistate_flag;
goto parse_multistate;
case sHostbasedAuthentication:
intptr = &options->hostbased_authentication;
goto parse_flag;
case sHostbasedUsesNameFromPacketOnly:
intptr = &options->hostbased_uses_name_from_packet_only;
goto parse_flag;
case sHostbasedAcceptedAlgorithms:
charptr = &options->hostbased_accepted_algos;
parse_pubkey_algos:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: Missing argument.",
filename, linenum);
if (*arg != '-' &&
!sshkey_names_valid2(*arg == '+' || *arg == '^' ?
arg + 1 : arg, 1))
fatal("%s line %d: Bad key types '%s'.",
filename, linenum, arg ? arg : "<NONE>");
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
break;
case sHostKeyAlgorithms:
charptr = &options->hostkeyalgorithms;
goto parse_pubkey_algos;
case sCASignatureAlgorithms:
charptr = &options->ca_sign_algorithms;
goto parse_pubkey_algos;
case sPubkeyAuthentication:
intptr = &options->pubkey_authentication;
goto parse_flag;
case sPubkeyAcceptedAlgorithms:
charptr = &options->pubkey_accepted_algos;
goto parse_pubkey_algos;
case sPubkeyAuthOptions:
intptr = &options->pubkey_auth_options;
value = 0;
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (strcasecmp(arg, "none") == 0)
continue;
if (strcasecmp(arg, "touch-required") == 0)
value |= PUBKEYAUTH_TOUCH_REQUIRED;
else if (strcasecmp(arg, "verify-required") == 0)
value |= PUBKEYAUTH_VERIFY_REQUIRED;
else {
fatal("%s line %d: unsupported "
"PubkeyAuthOptions option %s",
filename, linenum, arg);
}
}
if (*activep && *intptr == -1)
*intptr = value;
break;
case sKerberosAuthentication:
intptr = &options->kerberos_authentication;
goto parse_flag;
case sKerberosOrLocalPasswd:
intptr = &options->kerberos_or_local_passwd;
goto parse_flag;
case sKerberosTicketCleanup:
intptr = &options->kerberos_ticket_cleanup;
goto parse_flag;
case sKerberosGetAFSToken:
intptr = &options->kerberos_get_afs_token;
goto parse_flag;
case sGssAuthentication:
intptr = &options->gss_authentication;
goto parse_flag;
case sGssCleanupCreds:
intptr = &options->gss_cleanup_creds;
goto parse_flag;
case sGssStrictAcceptor:
intptr = &options->gss_strict_acceptor;
goto parse_flag;
case sPasswordAuthentication:
intptr = &options->password_authentication;
goto parse_flag;
case sKbdInteractiveAuthentication:
intptr = &options->kbd_interactive_authentication;
goto parse_flag;
case sChallengeResponseAuthentication:
intptr = &options->challenge_response_authentication;
goto parse_flag;
case sPrintMotd:
intptr = &options->print_motd;
goto parse_flag;
case sPrintLastLog:
intptr = &options->print_lastlog;
goto parse_flag;
case sX11Forwarding:
intptr = &options->x11_forwarding;
goto parse_flag;
case sX11DisplayOffset:
intptr = &options->x11_display_offset;
parse_int:
arg = strdelim(&cp);
if ((errstr = atoi_err(arg, &value)) != NULL)
fatal("%s line %d: integer value %s.",
filename, linenum, errstr);
if (*activep && *intptr == -1)
*intptr = value;
break;
case sX11UseLocalhost:
intptr = &options->x11_use_localhost;
goto parse_flag;
case sXAuthLocation:
charptr = &options->xauth_location;
goto parse_filename;
case sPermitTTY:
intptr = &options->permit_tty;
goto parse_flag;
case sPermitUserRC:
intptr = &options->permit_user_rc;
goto parse_flag;
case sStrictModes:
intptr = &options->strict_modes;
goto parse_flag;
case sTCPKeepAlive:
intptr = &options->tcp_keep_alive;
goto parse_flag;
case sEmptyPasswd:
intptr = &options->permit_empty_passwd;
goto parse_flag;
case sPermitUserEnvironment:
intptr = &options->permit_user_env;
charptr = &options->permit_user_env_allowlist;
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing argument.",
filename, linenum);
value = 0;
p = NULL;
if (strcmp(arg, "yes") == 0)
value = 1;
else if (strcmp(arg, "no") == 0)
value = 0;
else {
/* Pattern-list specified */
value = 1;
p = xstrdup(arg);
}
if (*activep && *intptr == -1) {
*intptr = value;
*charptr = p;
p = NULL;
}
free(p);
break;
case sCompression:
intptr = &options->compression;
multistate_ptr = multistate_compression;
goto parse_multistate;
case sRekeyLimit:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename,
linenum);
if (strcmp(arg, "default") == 0) {
val64 = 0;
} else {
if (scan_scaled(arg, &val64) == -1)
fatal("%.200s line %d: Bad number '%s': %s",
filename, linenum, arg, strerror(errno));
if (val64 != 0 && val64 < 16)
fatal("%.200s line %d: RekeyLimit too small",
filename, linenum);
}
if (*activep && options->rekey_limit == -1)
options->rekey_limit = val64;
if (cp != NULL) { /* optional rekey interval present */
if (strcmp(cp, "none") == 0) {
(void)strdelim(&cp); /* discard */
break;
}
intptr = &options->rekey_interval;
goto parse_time;
}
break;
case sGatewayPorts:
intptr = &options->fwd_opts.gateway_ports;
multistate_ptr = multistate_gatewayports;
goto parse_multistate;
case sUseDNS:
intptr = &options->use_dns;
goto parse_flag;
case sLogFacility:
log_facility_ptr = &options->log_facility;
arg = strdelim(&cp);
value = log_facility_number(arg);
if (value == SYSLOG_FACILITY_NOT_SET)
fatal("%.200s line %d: unsupported log facility '%s'",
filename, linenum, arg ? arg : "<NONE>");
if (*log_facility_ptr == -1)
*log_facility_ptr = (SyslogFacility) value;
break;
case sLogLevel:
log_level_ptr = &options->log_level;
arg = strdelim(&cp);
value = log_level_number(arg);
if (value == SYSLOG_LEVEL_NOT_SET)
fatal("%.200s line %d: unsupported log level '%s'",
filename, linenum, arg ? arg : "<NONE>");
if (*activep && *log_level_ptr == -1)
*log_level_ptr = (LogLevel) value;
break;
case sLogVerbose:
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (!*activep)
continue;
opt_array_append(filename, linenum, "oLogVerbose",
&options->log_verbose, &options->num_log_verbose,
arg);
}
break;
case sAllowTcpForwarding:
intptr = &options->allow_tcp_forwarding;
multistate_ptr = multistate_tcpfwd;
goto parse_multistate;
case sAllowStreamLocalForwarding:
intptr = &options->allow_streamlocal_forwarding;
multistate_ptr = multistate_tcpfwd;
goto parse_multistate;
case sAllowAgentForwarding:
intptr = &options->allow_agent_forwarding;
goto parse_flag;
case sDisableForwarding:
intptr = &options->disable_forwarding;
goto parse_flag;
case sAllowUsers:
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (match_user(NULL, NULL, NULL, arg) == -1)
fatal("%s line %d: invalid AllowUsers pattern: "
"\"%.100s\"", filename, linenum, arg);
if (!*activep)
continue;
opt_array_append(filename, linenum, "AllowUsers",
&options->allow_users, &options->num_allow_users,
arg);
}
break;
case sDenyUsers:
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (match_user(NULL, NULL, NULL, arg) == -1)
fatal("%s line %d: invalid DenyUsers pattern: "
"\"%.100s\"", filename, linenum, arg);
if (!*activep)
continue;
opt_array_append(filename, linenum, "DenyUsers",
&options->deny_users, &options->num_deny_users,
arg);
}
break;
case sAllowGroups:
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (!*activep)
continue;
opt_array_append(filename, linenum, "AllowGroups",
&options->allow_groups, &options->num_allow_groups,
arg);
}
break;
case sDenyGroups:
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (!*activep)
continue;
opt_array_append(filename, linenum, "DenyGroups",
&options->deny_groups, &options->num_deny_groups,
arg);
}
break;
case sCiphers:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: Missing argument.", filename, linenum);
if (*arg != '-' &&
!ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
if (options->ciphers == NULL)
options->ciphers = xstrdup(arg);
break;
case sMacs:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: Missing argument.", filename, linenum);
if (*arg != '-' &&
!mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
fatal("%s line %d: Bad SSH2 mac spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
if (options->macs == NULL)
options->macs = xstrdup(arg);
break;
case sKexAlgorithms:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: Missing argument.",
filename, linenum);
if (*arg != '-' &&
!kex_names_valid(*arg == '+' || *arg == '^' ?
arg + 1 : arg))
fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.",
filename, linenum, arg ? arg : "<NONE>");
if (options->kex_algorithms == NULL)
options->kex_algorithms = xstrdup(arg);
break;
case sSubsystem:
if (options->num_subsystems >= MAX_SUBSYSTEMS) {
fatal("%s line %d: too many subsystems defined.",
filename, linenum);
}
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: Missing subsystem name.",
filename, linenum);
if (!*activep) {
arg = strdelim(&cp);
break;
}
for (i = 0; i < options->num_subsystems; i++)
if (strcmp(arg, options->subsystem_name[i]) == 0)
fatal("%s line %d: Subsystem '%s' already defined.",
filename, linenum, arg);
options->subsystem_name[options->num_subsystems] = xstrdup(arg);
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: Missing subsystem command.",
filename, linenum);
options->subsystem_command[options->num_subsystems] = xstrdup(arg);
/* Collect arguments (separate to executable) */
p = xstrdup(arg);
len = strlen(p) + 1;
while ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
len += 1 + strlen(arg);
p = xreallocarray(p, 1, len);
strlcat(p, " ", len);
strlcat(p, arg, len);
}
options->subsystem_args[options->num_subsystems] = p;
options->num_subsystems++;
break;
case sMaxStartups:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: Missing MaxStartups spec.",
filename, linenum);
if ((n = sscanf(arg, "%d:%d:%d",
&options->max_startups_begin,
&options->max_startups_rate,
&options->max_startups)) == 3) {
if (options->max_startups_begin >
options->max_startups ||
options->max_startups_rate > 100 ||
options->max_startups_rate < 1)
fatal("%s line %d: Illegal MaxStartups spec.",
filename, linenum);
} else if (n != 1)
fatal("%s line %d: Illegal MaxStartups spec.",
filename, linenum);
else
options->max_startups = options->max_startups_begin;
break;
case sPerSourceNetBlockSize:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: Missing PerSourceNetBlockSize spec.",
filename, linenum);
switch (n = sscanf(arg, "%d:%d", &value, &value2)) {
case 2:
if (value2 < 0 || value2 > 128)
n = -1;
/* FALLTHROUGH */
case 1:
if (value < 0 || value > 32)
n = -1;
}
if (n != 1 && n != 2)
fatal("%s line %d: Invalid PerSourceNetBlockSize"
" spec.", filename, linenum);
if (*activep) {
options->per_source_masklen_ipv4 = value;
options->per_source_masklen_ipv6 = value2;
}
break;
case sPerSourceMaxStartups:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: Missing PerSourceMaxStartups spec.",
filename, linenum);
if (strcmp(arg, "none") == 0) { /* no limit */
value = INT_MAX;
} else {
if ((errstr = atoi_err(arg, &value)) != NULL)
fatal("%s line %d: integer value %s.",
filename, linenum, errstr);
}
if (*activep)
options->per_source_max_startups = value;
break;
case sMaxAuthTries:
intptr = &options->max_authtries;
goto parse_int;
case sMaxSessions:
intptr = &options->max_sessions;
goto parse_int;
case sBanner:
charptr = &options->banner;
goto parse_filename;
/*
* These options can contain %X options expanded at
* connect time, so that you can specify paths like:
*
* AuthorizedKeysFile /etc/ssh_keys/%u
*/
case sAuthorizedKeysFile:
if (*activep && options->num_authkeys_files == 0) {
while ((arg = strdelim(&cp)) && *arg != '\0') {
arg = tilde_expand_filename(arg, getuid());
opt_array_append(filename, linenum,
"AuthorizedKeysFile",
&options->authorized_keys_files,
&options->num_authkeys_files, arg);
free(arg);
}
}
return 0;
case sAuthorizedPrincipalsFile:
charptr = &options->authorized_principals_file;
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing file name.",
filename, linenum);
if (*activep && *charptr == NULL) {
*charptr = tilde_expand_filename(arg, getuid());
/* increase optional counter */
if (intptr != NULL)
*intptr = *intptr + 1;
}
break;
case sClientAliveInterval:
intptr = &options->client_alive_interval;
goto parse_time;
case sClientAliveCountMax:
intptr = &options->client_alive_count_max;
goto parse_int;
case sAcceptEnv:
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (strchr(arg, '=') != NULL)
fatal("%s line %d: Invalid environment name.",
filename, linenum);
if (!*activep)
continue;
opt_array_append(filename, linenum, "AcceptEnv",
&options->accept_env, &options->num_accept_env,
arg);
}
break;
case sSetEnv:
uvalue = options->num_setenv;
while ((arg = strdelimw(&cp)) && *arg != '\0') {
if (strchr(arg, '=') == NULL)
fatal("%s line %d: Invalid environment.",
filename, linenum);
if (!*activep || uvalue != 0)
continue;
opt_array_append(filename, linenum, "SetEnv",
&options->setenv, &options->num_setenv, arg);
}
break;
case sPermitTunnel:
intptr = &options->permit_tun;
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: Missing yes/point-to-point/"
"ethernet/no argument.", filename, linenum);
value = -1;
for (i = 0; tunmode_desc[i].val != -1; i++)
if (strcmp(tunmode_desc[i].text, arg) == 0) {
value = tunmode_desc[i].val;
break;
}
if (value == -1)
fatal("%s line %d: Bad yes/point-to-point/ethernet/"
"no argument: %s", filename, linenum, arg);
if (*activep && *intptr == -1)
*intptr = value;
break;
case sInclude:
if (cmdline) {
fatal("Include directive not supported as a "
"command-line option");
}
value = 0;
while ((arg2 = strdelim(&cp)) != NULL && *arg2 != '\0') {
value++;
found = 0;
if (*arg2 != '/' && *arg2 != '~') {
xasprintf(&arg, "%s/%s", SSHDIR, arg2);
} else
arg = xstrdup(arg2);
/*
* Don't let included files clobber the containing
* file's Match state.
*/
oactive = *activep;
/* consult cache of include files */
TAILQ_FOREACH(item, includes, entry) {
if (strcmp(item->selector, arg) != 0)
continue;
if (item->filename != NULL) {
parse_server_config_depth(options,
item->filename, item->contents,
includes, connectinfo,
(*inc_flags & SSHCFG_MATCH_ONLY
? SSHCFG_MATCH_ONLY : (oactive
? 0 : SSHCFG_NEVERMATCH)),
activep, depth + 1);
}
found = 1;
*activep = oactive;
}
if (found != 0) {
free(arg);
continue;
}
/* requested glob was not in cache */
debug2("%s line %d: new include %s",
filename, linenum, arg);
if ((r = glob(arg, 0, NULL, &gbuf)) != 0) {
if (r != GLOB_NOMATCH) {
fatal("%s line %d: include \"%s\" "
"glob failed", filename,
linenum, arg);
}
/*
* If no entry matched then record a
* placeholder to skip later glob calls.
*/
debug2("%s line %d: no match for %s",
filename, linenum, arg);
item = xcalloc(1, sizeof(*item));
item->selector = strdup(arg);
TAILQ_INSERT_TAIL(includes,
item, entry);
}
if (gbuf.gl_pathc > INT_MAX)
fatal_f("too many glob results");
for (n = 0; n < (int)gbuf.gl_pathc; n++) {
debug2("%s line %d: including %s",
filename, linenum, gbuf.gl_pathv[n]);
item = xcalloc(1, sizeof(*item));
item->selector = strdup(arg);
item->filename = strdup(gbuf.gl_pathv[n]);
if ((item->contents = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
load_server_config(item->filename,
item->contents);
parse_server_config_depth(options,
item->filename, item->contents,
includes, connectinfo,
(*inc_flags & SSHCFG_MATCH_ONLY
? SSHCFG_MATCH_ONLY : (oactive
? 0 : SSHCFG_NEVERMATCH)),
activep, depth + 1);
*activep = oactive;
TAILQ_INSERT_TAIL(includes, item, entry);
}
globfree(&gbuf);
free(arg);
}
if (value == 0) {
fatal("%s line %d: Include missing filename argument",
filename, linenum);
}
break;
case sMatch:
if (cmdline)
fatal("Match directive not supported as a command-line "
- "option");
+ "option");
value = match_cfg_line(&cp, linenum,
(*inc_flags & SSHCFG_NEVERMATCH ? NULL : connectinfo));
if (value < 0)
fatal("%s line %d: Bad Match condition", filename,
linenum);
*activep = (*inc_flags & SSHCFG_NEVERMATCH) ? 0 : value;
/* The MATCH_ONLY is applicable only until the first match block */
*inc_flags &= ~SSHCFG_MATCH_ONLY;
break;
case sPermitListen:
case sPermitOpen:
if (opcode == sPermitListen) {
uintptr = &options->num_permitted_listens;
chararrayptr = &options->permitted_listens;
} else {
uintptr = &options->num_permitted_opens;
chararrayptr = &options->permitted_opens;
}
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing %s specification",
filename, linenum, lookup_opcode_name(opcode));
uvalue = *uintptr; /* modified later */
if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) {
if (*activep && uvalue == 0) {
*uintptr = 1;
*chararrayptr = xcalloc(1,
sizeof(**chararrayptr));
(*chararrayptr)[0] = xstrdup(arg);
}
break;
}
for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) {
if (opcode == sPermitListen &&
strchr(arg, ':') == NULL) {
/*
* Allow bare port number for PermitListen
* to indicate a wildcard listen host.
*/
xasprintf(&arg2, "*:%s", arg);
} else {
arg2 = xstrdup(arg);
ch = '\0';
p = hpdelim2(&arg, &ch);
if (p == NULL || ch == '/') {
fatal("%s line %d: missing host in %s",
filename, linenum,
lookup_opcode_name(opcode));
}
p = cleanhostname(p);
}
if (arg == NULL ||
((port = permitopen_port(arg)) < 0)) {
fatal("%s line %d: bad port number in %s",
filename, linenum,
lookup_opcode_name(opcode));
}
if (*activep && uvalue == 0) {
opt_array_append(filename, linenum,
lookup_opcode_name(opcode),
chararrayptr, uintptr, arg2);
}
free(arg2);
}
break;
case sForceCommand:
if (cp == NULL || *cp == '\0')
fatal("%.200s line %d: Missing argument.", filename,
linenum);
len = strspn(cp, WHITESPACE);
if (*activep && options->adm_forced_command == NULL)
options->adm_forced_command = xstrdup(cp + len);
return 0;
case sChrootDirectory:
charptr = &options->chroot_directory;
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing file name.",
filename, linenum);
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
break;
case sTrustedUserCAKeys:
charptr = &options->trusted_user_ca_keys;
goto parse_filename;
case sRevokedKeys:
charptr = &options->revoked_keys_file;
goto parse_filename;
case sSecurityKeyProvider:
charptr = &options->sk_provider;
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing file name.",
filename, linenum);
if (*activep && *charptr == NULL) {
*charptr = strcasecmp(arg, "internal") == 0 ?
xstrdup(arg) : derelativise_path(arg);
/* increase optional counter */
if (intptr != NULL)
*intptr = *intptr + 1;
}
break;
case sIPQoS:
arg = strdelim(&cp);
if ((value = parse_ipqos(arg)) == -1)
fatal("%s line %d: Bad IPQoS value: %s",
filename, linenum, arg);
arg = strdelim(&cp);
if (arg == NULL)
value2 = value;
else if ((value2 = parse_ipqos(arg)) == -1)
fatal("%s line %d: Bad IPQoS value: %s",
filename, linenum, arg);
if (*activep) {
options->ip_qos_interactive = value;
options->ip_qos_bulk = value2;
}
break;
case sVersionAddendum:
if (cp == NULL || *cp == '\0')
fatal("%.200s line %d: Missing argument.", filename,
linenum);
len = strspn(cp, WHITESPACE);
if (*activep && options->version_addendum == NULL) {
if (strcasecmp(cp + len, "none") == 0)
options->version_addendum = xstrdup("");
else if (strchr(cp + len, '\r') != NULL)
fatal("%.200s line %d: Invalid argument",
filename, linenum);
else
options->version_addendum = xstrdup(cp + len);
}
return 0;
case sAuthorizedKeysCommand:
if (cp == NULL)
fatal("%.200s line %d: Missing argument.", filename,
linenum);
len = strspn(cp, WHITESPACE);
if (*activep && options->authorized_keys_command == NULL) {
if (cp[len] != '/' && strcasecmp(cp + len, "none") != 0)
fatal("%.200s line %d: AuthorizedKeysCommand "
"must be an absolute path",
filename, linenum);
options->authorized_keys_command = xstrdup(cp + len);
}
return 0;
case sAuthorizedKeysCommandUser:
charptr = &options->authorized_keys_command_user;
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing AuthorizedKeysCommandUser "
"argument.", filename, linenum);
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
break;
case sAuthorizedPrincipalsCommand:
if (cp == NULL)
fatal("%.200s line %d: Missing argument.", filename,
linenum);
len = strspn(cp, WHITESPACE);
if (*activep &&
options->authorized_principals_command == NULL) {
if (cp[len] != '/' && strcasecmp(cp + len, "none") != 0)
fatal("%.200s line %d: "
"AuthorizedPrincipalsCommand must be "
"an absolute path", filename, linenum);
options->authorized_principals_command =
xstrdup(cp + len);
}
return 0;
case sAuthorizedPrincipalsCommandUser:
charptr = &options->authorized_principals_command_user;
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing "
"AuthorizedPrincipalsCommandUser argument.",
filename, linenum);
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
break;
case sAuthenticationMethods:
if (options->num_auth_methods == 0) {
value = 0; /* seen "any" pseudo-method */
value2 = 0; /* successfully parsed any method */
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (strcmp(arg, "any") == 0) {
if (options->num_auth_methods > 0) {
fatal("%s line %d: \"any\" "
"must appear alone in "
"AuthenticationMethods",
filename, linenum);
}
value = 1;
} else if (value) {
fatal("%s line %d: \"any\" must appear "
"alone in AuthenticationMethods",
filename, linenum);
} else if (auth2_methods_valid(arg, 0) != 0) {
fatal("%s line %d: invalid "
"authentication method list.",
filename, linenum);
}
value2 = 1;
if (!*activep)
continue;
opt_array_append(filename, linenum,
"AuthenticationMethods",
&options->auth_methods,
&options->num_auth_methods, arg);
}
if (value2 == 0) {
fatal("%s line %d: no AuthenticationMethods "
"specified", filename, linenum);
}
}
return 0;
case sStreamLocalBindMask:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing StreamLocalBindMask "
"argument.", filename, linenum);
/* Parse mode in octal format */
value = strtol(arg, &p, 8);
if (arg == p || value < 0 || value > 0777)
fatal("%s line %d: Bad mask.", filename, linenum);
if (*activep)
options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
break;
case sStreamLocalBindUnlink:
intptr = &options->fwd_opts.streamlocal_bind_unlink;
goto parse_flag;
case sFingerprintHash:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.",
filename, linenum);
if ((value = ssh_digest_alg_by_name(arg)) == -1)
fatal("%.200s line %d: Invalid hash algorithm \"%s\".",
filename, linenum, arg);
if (*activep)
options->fingerprint_hash = value;
break;
case sExposeAuthInfo:
intptr = &options->expose_userauth_info;
goto parse_flag;
case sRDomain:
#if !defined(__OpenBSD__) && !defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
fatal("%s line %d: setting RDomain not supported on this "
"platform.", filename, linenum);
#endif
charptr = &options->routing_domain;
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.",
filename, linenum);
if (strcasecmp(arg, "none") != 0 && strcmp(arg, "%D") != 0 &&
!valid_rdomain(arg))
fatal("%s line %d: bad routing domain",
filename, linenum);
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
break;
case sDeprecated:
case sIgnore:
case sUnsupported:
do_log2(opcode == sIgnore ?
SYSLOG_LEVEL_DEBUG2 : SYSLOG_LEVEL_INFO,
"%s line %d: %s option %s", filename, linenum,
opcode == sUnsupported ? "Unsupported" : "Deprecated", arg);
while (arg)
arg = strdelim(&cp);
break;
default:
fatal("%s line %d: Missing handler for opcode %s (%d)",
filename, linenum, arg, opcode);
}
if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
fatal("%s line %d: garbage at end of line; \"%.200s\".",
filename, linenum, arg);
return 0;
}
int
process_server_config_line(ServerOptions *options, char *line,
const char *filename, int linenum, int *activep,
struct connection_info *connectinfo, struct include_list *includes)
{
int inc_flags = 0;
return process_server_config_line_depth(options, line, filename,
linenum, activep, connectinfo, &inc_flags, 0, includes);
}
/* Reads the server configuration file. */
void
load_server_config(const char *filename, struct sshbuf *conf)
{
struct stat st;
char *line = NULL, *cp;
size_t linesize = 0;
FILE *f;
int r, lineno = 0;
debug2_f("filename %s", filename);
if ((f = fopen(filename, "r")) == NULL) {
perror(filename);
exit(1);
}
sshbuf_reset(conf);
/* grow buffer, so realloc is avoided for large config files */
if (fstat(fileno(f), &st) == 0 && st.st_size > 0 &&
- (r = sshbuf_allocate(conf, st.st_size)) != 0)
+ (r = sshbuf_allocate(conf, st.st_size)) != 0)
fatal_fr(r, "allocate");
while (getline(&line, &linesize, f) != -1) {
lineno++;
/*
* Trim out comments and strip whitespace
* NB - preserve newlines, they are needed to reproduce
* line numbers later for error messages
*/
if ((cp = strchr(line, '#')) != NULL)
memcpy(cp, "\n", 2);
cp = line + strspn(line, " \t\r");
if ((r = sshbuf_put(conf, cp, strlen(cp))) != 0)
fatal_fr(r, "sshbuf_put");
}
free(line);
if ((r = sshbuf_put_u8(conf, 0)) != 0)
fatal_fr(r, "sshbuf_put_u8");
fclose(f);
debug2_f("done config len = %zu", sshbuf_len(conf));
}
void
parse_server_match_config(ServerOptions *options,
struct include_list *includes, struct connection_info *connectinfo)
{
ServerOptions mo;
initialize_server_options(&mo);
parse_server_config(&mo, "reprocess config", cfg, includes,
connectinfo);
copy_set_server_options(options, &mo, 0);
}
int parse_server_match_testspec(struct connection_info *ci, char *spec)
{
char *p;
while ((p = strsep(&spec, ",")) && *p != '\0') {
if (strncmp(p, "addr=", 5) == 0) {
ci->address = xstrdup(p + 5);
} else if (strncmp(p, "host=", 5) == 0) {
ci->host = xstrdup(p + 5);
} else if (strncmp(p, "user=", 5) == 0) {
ci->user = xstrdup(p + 5);
} else if (strncmp(p, "laddr=", 6) == 0) {
ci->laddress = xstrdup(p + 6);
} else if (strncmp(p, "rdomain=", 8) == 0) {
ci->rdomain = xstrdup(p + 8);
} else if (strncmp(p, "lport=", 6) == 0) {
ci->lport = a2port(p + 6);
if (ci->lport == -1) {
fprintf(stderr, "Invalid port '%s' in test mode"
- " specification %s\n", p+6, p);
+ " specification %s\n", p+6, p);
return -1;
}
} else {
fprintf(stderr, "Invalid test mode specification %s\n",
- p);
+ p);
return -1;
}
}
return 0;
}
/*
* Copy any supported values that are set.
*
* If the preauth flag is set, we do not bother copying the string or
* array values that are not used pre-authentication, because any that we
* do use must be explicitly sent in mm_getpwnamallow().
*/
void
copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
{
#define M_CP_INTOPT(n) do {\
if (src->n != -1) \
dst->n = src->n; \
} while (0)
M_CP_INTOPT(password_authentication);
M_CP_INTOPT(gss_authentication);
M_CP_INTOPT(pubkey_authentication);
M_CP_INTOPT(pubkey_auth_options);
M_CP_INTOPT(kerberos_authentication);
M_CP_INTOPT(hostbased_authentication);
M_CP_INTOPT(hostbased_uses_name_from_packet_only);
M_CP_INTOPT(kbd_interactive_authentication);
M_CP_INTOPT(permit_root_login);
M_CP_INTOPT(permit_empty_passwd);
M_CP_INTOPT(ignore_rhosts);
M_CP_INTOPT(allow_tcp_forwarding);
M_CP_INTOPT(allow_streamlocal_forwarding);
M_CP_INTOPT(allow_agent_forwarding);
M_CP_INTOPT(disable_forwarding);
M_CP_INTOPT(expose_userauth_info);
M_CP_INTOPT(permit_tun);
M_CP_INTOPT(fwd_opts.gateway_ports);
M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
M_CP_INTOPT(x11_display_offset);
M_CP_INTOPT(x11_forwarding);
M_CP_INTOPT(x11_use_localhost);
M_CP_INTOPT(permit_tty);
M_CP_INTOPT(permit_user_rc);
M_CP_INTOPT(max_sessions);
M_CP_INTOPT(max_authtries);
M_CP_INTOPT(client_alive_count_max);
M_CP_INTOPT(client_alive_interval);
M_CP_INTOPT(ip_qos_interactive);
M_CP_INTOPT(ip_qos_bulk);
M_CP_INTOPT(rekey_limit);
M_CP_INTOPT(rekey_interval);
M_CP_INTOPT(log_level);
/*
* The bind_mask is a mode_t that may be unsigned, so we can't use
* M_CP_INTOPT - it does a signed comparison that causes compiler
* warnings.
*/
if (src->fwd_opts.streamlocal_bind_mask != (mode_t)-1) {
dst->fwd_opts.streamlocal_bind_mask =
src->fwd_opts.streamlocal_bind_mask;
}
/* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */
#define M_CP_STROPT(n) do {\
if (src->n != NULL && dst->n != src->n) { \
free(dst->n); \
dst->n = src->n; \
} \
} while(0)
#define M_CP_STRARRAYOPT(s, num_s) do {\
u_int i; \
if (src->num_s != 0) { \
for (i = 0; i < dst->num_s; i++) \
free(dst->s[i]); \
free(dst->s); \
dst->s = xcalloc(src->num_s, sizeof(*dst->s)); \
for (i = 0; i < src->num_s; i++) \
dst->s[i] = xstrdup(src->s[i]); \
dst->num_s = src->num_s; \
} \
} while(0)
/* See comment in servconf.h */
COPY_MATCH_STRING_OPTS();
/* Arguments that accept '+...' need to be expanded */
assemble_algorithms(dst);
/*
* The only things that should be below this point are string options
* which are only used after authentication.
*/
if (preauth)
return;
/* These options may be "none" to clear a global setting */
M_CP_STROPT(adm_forced_command);
if (option_clear_or_none(dst->adm_forced_command)) {
free(dst->adm_forced_command);
dst->adm_forced_command = NULL;
}
M_CP_STROPT(chroot_directory);
if (option_clear_or_none(dst->chroot_directory)) {
free(dst->chroot_directory);
dst->chroot_directory = NULL;
}
}
#undef M_CP_INTOPT
#undef M_CP_STROPT
#undef M_CP_STRARRAYOPT
#define SERVCONF_MAX_DEPTH 16
static void
parse_server_config_depth(ServerOptions *options, const char *filename,
struct sshbuf *conf, struct include_list *includes,
struct connection_info *connectinfo, int flags, int *activep, int depth)
{
int linenum, bad_options = 0;
char *cp, *obuf, *cbuf;
if (depth < 0 || depth > SERVCONF_MAX_DEPTH)
fatal("Too many recursive configuration includes");
debug2_f("config %s len %zu%s", filename, sshbuf_len(conf),
(flags & SSHCFG_NEVERMATCH ? " [checking syntax only]" : ""));
if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL)
fatal_f("sshbuf_dup_string failed");
linenum = 1;
while ((cp = strsep(&cbuf, "\n")) != NULL) {
if (process_server_config_line_depth(options, cp,
filename, linenum++, activep, connectinfo, &flags,
depth, includes) != 0)
bad_options++;
}
free(obuf);
if (bad_options > 0)
fatal("%s: terminating, %d bad configuration options",
filename, bad_options);
}
void
parse_server_config(ServerOptions *options, const char *filename,
struct sshbuf *conf, struct include_list *includes,
struct connection_info *connectinfo)
{
int active = connectinfo ? 0 : 1;
parse_server_config_depth(options, filename, conf, includes,
connectinfo, (connectinfo ? SSHCFG_MATCH_ONLY : 0), &active, 0);
process_queued_listen_addrs(options);
}
static const char *
fmt_multistate_int(int val, const struct multistate *m)
{
u_int i;
for (i = 0; m[i].key != NULL; i++) {
if (m[i].value == val)
return m[i].key;
}
return "UNKNOWN";
}
static const char *
fmt_intarg(ServerOpCodes code, int val)
{
if (val == -1)
return "unset";
switch (code) {
case sAddressFamily:
return fmt_multistate_int(val, multistate_addressfamily);
case sPermitRootLogin:
return fmt_multistate_int(val, multistate_permitrootlogin);
case sGatewayPorts:
return fmt_multistate_int(val, multistate_gatewayports);
case sCompression:
return fmt_multistate_int(val, multistate_compression);
case sAllowTcpForwarding:
return fmt_multistate_int(val, multistate_tcpfwd);
case sAllowStreamLocalForwarding:
return fmt_multistate_int(val, multistate_tcpfwd);
case sIgnoreRhosts:
return fmt_multistate_int(val, multistate_ignore_rhosts);
case sFingerprintHash:
return ssh_digest_alg_name(val);
default:
switch (val) {
case 0:
return "no";
case 1:
return "yes";
default:
return "UNKNOWN";
}
}
}
static void
dump_cfg_int(ServerOpCodes code, int val)
{
printf("%s %d\n", lookup_opcode_name(code), val);
}
static void
dump_cfg_oct(ServerOpCodes code, int val)
{
printf("%s 0%o\n", lookup_opcode_name(code), val);
}
static void
dump_cfg_fmtint(ServerOpCodes code, int val)
{
printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
}
static void
dump_cfg_string(ServerOpCodes code, const char *val)
{
printf("%s %s\n", lookup_opcode_name(code),
val == NULL ? "none" : val);
}
static void
dump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
{
u_int i;
for (i = 0; i < count; i++)
printf("%s %s\n", lookup_opcode_name(code), vals[i]);
}
static void
dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
{
u_int i;
if (count <= 0 && code != sAuthenticationMethods)
return;
printf("%s", lookup_opcode_name(code));
for (i = 0; i < count; i++)
printf(" %s", vals[i]);
if (code == sAuthenticationMethods && count == 0)
printf(" any");
printf("\n");
}
static char *
format_listen_addrs(struct listenaddr *la)
{
int r;
struct addrinfo *ai;
char addr[NI_MAXHOST], port[NI_MAXSERV];
char *laddr1 = xstrdup(""), *laddr2 = NULL;
/*
* ListenAddress must be after Port. add_one_listen_addr pushes
* addresses onto a stack, so to maintain ordering we need to
* print these in reverse order.
*/
for (ai = la->addrs; ai; ai = ai->ai_next) {
if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
sizeof(addr), port, sizeof(port),
NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
error("getnameinfo: %.100s", ssh_gai_strerror(r));
continue;
}
laddr2 = laddr1;
if (ai->ai_family == AF_INET6) {
xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s",
addr, port,
la->rdomain == NULL ? "" : " rdomain ",
la->rdomain == NULL ? "" : la->rdomain,
laddr2);
} else {
xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s",
addr, port,
la->rdomain == NULL ? "" : " rdomain ",
la->rdomain == NULL ? "" : la->rdomain,
laddr2);
}
free(laddr2);
}
return laddr1;
}
void
dump_config(ServerOptions *o)
{
char *s;
u_int i;
/* these are usually at the top of the config */
for (i = 0; i < o->num_ports; i++)
printf("port %d\n", o->ports[i]);
dump_cfg_fmtint(sAddressFamily, o->address_family);
for (i = 0; i < o->num_listen_addrs; i++) {
s = format_listen_addrs(&o->listen_addrs[i]);
printf("%s", s);
free(s);
}
/* integer arguments */
#ifdef USE_PAM
dump_cfg_fmtint(sUsePAM, o->use_pam);
#endif
dump_cfg_int(sLoginGraceTime, o->login_grace_time);
dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
dump_cfg_int(sMaxAuthTries, o->max_authtries);
dump_cfg_int(sMaxSessions, o->max_sessions);
dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
/* formatted integer arguments */
dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
o->hostbased_uses_name_from_packet_only);
dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
#ifdef KRB5
dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
# ifdef USE_AFS
dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
# endif
#endif
#ifdef GSSAPI
dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
#endif
dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
dump_cfg_fmtint(sKbdInteractiveAuthentication,
o->kbd_interactive_authentication);
dump_cfg_fmtint(sChallengeResponseAuthentication,
o->challenge_response_authentication);
dump_cfg_fmtint(sPrintMotd, o->print_motd);
#ifndef DISABLE_LASTLOG
dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
#endif
dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
dump_cfg_fmtint(sPermitTTY, o->permit_tty);
dump_cfg_fmtint(sPermitUserRC, o->permit_user_rc);
dump_cfg_fmtint(sStrictModes, o->strict_modes);
dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
dump_cfg_fmtint(sCompression, o->compression);
dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports);
dump_cfg_fmtint(sUseDNS, o->use_dns);
dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding);
dump_cfg_fmtint(sDisableForwarding, o->disable_forwarding);
dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info);
/* string arguments */
dump_cfg_string(sPidFile, o->pid_file);
+ dump_cfg_string(sModuliFile, o->moduli_file);
dump_cfg_string(sXAuthLocation, o->xauth_location);
dump_cfg_string(sCiphers, o->ciphers);
dump_cfg_string(sMacs, o->macs);
dump_cfg_string(sBanner, o->banner);
dump_cfg_string(sForceCommand, o->adm_forced_command);
dump_cfg_string(sChrootDirectory, o->chroot_directory);
dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
dump_cfg_string(sSecurityKeyProvider, o->sk_provider);
dump_cfg_string(sAuthorizedPrincipalsFile,
o->authorized_principals_file);
dump_cfg_string(sVersionAddendum, *o->version_addendum == '\0'
? "none" : o->version_addendum);
dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
dump_cfg_string(sAuthorizedPrincipalsCommand, o->authorized_principals_command);
dump_cfg_string(sAuthorizedPrincipalsCommandUser, o->authorized_principals_command_user);
dump_cfg_string(sHostKeyAgent, o->host_key_agent);
dump_cfg_string(sKexAlgorithms, o->kex_algorithms);
dump_cfg_string(sCASignatureAlgorithms, o->ca_sign_algorithms);
dump_cfg_string(sHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
dump_cfg_string(sHostKeyAlgorithms, o->hostkeyalgorithms);
dump_cfg_string(sPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
#if defined(__OpenBSD__) || defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
dump_cfg_string(sRDomain, o->routing_domain);
#endif
/* string arguments requiring a lookup */
dump_cfg_string(sLogLevel, log_level_name(o->log_level));
dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
/* string array arguments */
dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files,
o->authorized_keys_files);
dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
- o->host_key_files);
+ o->host_key_files);
dump_cfg_strarray(sHostCertificate, o->num_host_cert_files,
- o->host_cert_files);
+ o->host_cert_files);
dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
dump_cfg_strarray(sSetEnv, o->num_setenv, o->setenv);
dump_cfg_strarray_oneline(sAuthenticationMethods,
o->num_auth_methods, o->auth_methods);
dump_cfg_strarray_oneline(sLogVerbose,
o->num_log_verbose, o->log_verbose);
/* other arguments */
for (i = 0; i < o->num_subsystems; i++)
printf("subsystem %s %s\n", o->subsystem_name[i],
o->subsystem_args[i]);
printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
o->max_startups_rate, o->max_startups);
printf("persourcemaxstartups ");
if (o->per_source_max_startups == INT_MAX)
printf("none\n");
else
printf("%d\n", o->per_source_max_startups);
printf("persourcenetblocksize %d:%d\n", o->per_source_masklen_ipv4,
o->per_source_masklen_ipv6);
s = NULL;
for (i = 0; tunmode_desc[i].val != -1; i++) {
if (tunmode_desc[i].val == o->permit_tun) {
s = tunmode_desc[i].text;
break;
}
}
dump_cfg_string(sPermitTunnel, s);
printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
printf("%s\n", iptos2str(o->ip_qos_bulk));
printf("rekeylimit %llu %d\n", (unsigned long long)o->rekey_limit,
o->rekey_interval);
printf("permitopen");
if (o->num_permitted_opens == 0)
printf(" any");
else {
for (i = 0; i < o->num_permitted_opens; i++)
printf(" %s", o->permitted_opens[i]);
}
printf("\n");
printf("permitlisten");
if (o->num_permitted_listens == 0)
printf(" any");
else {
for (i = 0; i < o->num_permitted_listens; i++)
printf(" %s", o->permitted_listens[i]);
}
printf("\n");
if (o->permit_user_env_allowlist == NULL) {
dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
} else {
printf("permituserenvironment %s\n",
o->permit_user_env_allowlist);
}
printf("pubkeyauthoptions");
if (o->pubkey_auth_options == 0)
printf(" none");
if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED)
printf(" touch-required");
if (o->pubkey_auth_options & PUBKEYAUTH_VERIFY_REQUIRED)
printf(" verify-required");
printf("\n");
}
diff --git a/servconf.h b/servconf.h
index 4f4fd9ba4686..f7cdac22a54b 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,313 +1,314 @@
-/* $OpenBSD: servconf.h,v 1.151 2021/01/26 05:32:21 dtucker Exp $ */
+/* $OpenBSD: servconf.h,v 1.154 2021/04/03 06:18:40 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Definitions for server configuration data and for the functions reading it.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#ifndef SERVCONF_H
#define SERVCONF_H
#include <openbsd-compat/sys-queue.h>
#define MAX_PORTS 256 /* Max # ports. */
#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */
/* permit_root_login */
#define PERMIT_NOT_SET -1
#define PERMIT_NO 0
#define PERMIT_FORCED_ONLY 1
#define PERMIT_NO_PASSWD 2
#define PERMIT_YES 3
/* use_privsep */
#define PRIVSEP_OFF 0
#define PRIVSEP_ON 1
#define PRIVSEP_NOSANDBOX 2
/* PermitOpen */
#define PERMITOPEN_ANY 0
#define PERMITOPEN_NONE -2
/* IgnoreRhosts */
#define IGNORE_RHOSTS_NO 0
#define IGNORE_RHOSTS_YES 1
#define IGNORE_RHOSTS_SHOSTS 2
#define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */
#define DEFAULT_SESSIONS_MAX 10 /* Default for MaxSessions */
/* Magic name for internal sftp-server */
#define INTERNAL_SFTP_NAME "internal-sftp"
/* PubkeyAuthOptions flags */
#define PUBKEYAUTH_TOUCH_REQUIRED (1)
#define PUBKEYAUTH_VERIFY_REQUIRED (1<<1)
struct ssh;
struct fwd_perm_list;
/*
* Used to store addresses from ListenAddr directives. These may be
* incomplete, as they may specify addresses that need to be merged
* with any ports requested by ListenPort.
*/
struct queued_listenaddr {
char *addr;
int port; /* <=0 if unspecified */
char *rdomain;
};
/* Resolved listen addresses, grouped by optional routing domain */
struct listenaddr {
char *rdomain;
struct addrinfo *addrs;
};
typedef struct {
u_int num_ports;
u_int ports_from_cmdline;
int ports[MAX_PORTS]; /* Port number to listen on. */
struct queued_listenaddr *queued_listen_addrs;
u_int num_queued_listens;
struct listenaddr *listen_addrs;
u_int num_listen_addrs;
int address_family; /* Address family used by the server. */
char *routing_domain; /* Bind session to routing domain */
char **host_key_files; /* Files containing host keys. */
int *host_key_file_userprovided; /* Key was specified by user. */
u_int num_host_key_files; /* Number of files for host keys. */
char **host_cert_files; /* Files containing host certs. */
u_int num_host_cert_files; /* Number of files for host certs. */
char *host_key_agent; /* ssh-agent socket for host keys. */
char *pid_file; /* Where to put our pid */
+ char *moduli_file; /* moduli file for DH-GEX */
int login_grace_time; /* Disconnect if no auth in this time
* (sec). */
int permit_root_login; /* PERMIT_*, see above */
int ignore_rhosts; /* Ignore .rhosts and .shosts. */
int ignore_user_known_hosts; /* Ignore ~/.ssh/known_hosts
* for RhostsRsaAuth */
int print_motd; /* If true, print /etc/motd. */
int print_lastlog; /* If true, print lastlog */
int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */
int x11_display_offset; /* What DISPLAY number to start
* searching at */
int x11_use_localhost; /* If true, use localhost for fake X11 server. */
char *xauth_location; /* Location of xauth program */
int permit_tty; /* If false, deny pty allocation */
int permit_user_rc; /* If false, deny ~/.ssh/rc execution */
int strict_modes; /* If true, require string home dir modes. */
int tcp_keep_alive; /* If true, set SO_KEEPALIVE. */
int ip_qos_interactive; /* IP ToS/DSCP/class for interactive */
int ip_qos_bulk; /* IP ToS/DSCP/class for bulk traffic */
char *ciphers; /* Supported SSH2 ciphers. */
char *macs; /* Supported SSH2 macs. */
char *kex_algorithms; /* SSH2 kex methods in order of preference. */
struct ForwardOptions fwd_opts; /* forwarding options */
SyslogFacility log_facility; /* Facility for system logging. */
LogLevel log_level; /* Level for system logging. */
u_int num_log_verbose; /* Verbose log overrides */
char **log_verbose;
int hostbased_authentication; /* If true, permit ssh2 hostbased auth */
int hostbased_uses_name_from_packet_only; /* experimental */
char *hostbased_accepted_algos; /* Algos allowed for hostbased */
char *hostkeyalgorithms; /* SSH2 server key types */
char *ca_sign_algorithms; /* Allowed CA signature algorithms */
int pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */
char *pubkey_accepted_algos; /* Signature algos allowed for pubkey */
int pubkey_auth_options; /* -1 or mask of PUBKEYAUTH_* flags */
int kerberos_authentication; /* If true, permit Kerberos
* authentication. */
int kerberos_or_local_passwd; /* If true, permit kerberos
* and any other password
* authentication mechanism,
* such as SecurID or
* /etc/passwd */
int kerberos_ticket_cleanup; /* If true, destroy ticket
* file on logout. */
int kerberos_get_afs_token; /* If true, try to get AFS token if
* authenticated with Kerberos. */
int gss_authentication; /* If true, permit GSSAPI authentication */
int gss_cleanup_creds; /* If true, destroy cred cache on logout */
int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */
int password_authentication; /* If true, permit password
* authentication. */
int kbd_interactive_authentication; /* If true, permit */
int challenge_response_authentication;
int permit_empty_passwd; /* If false, do not permit empty
* passwords. */
int permit_user_env; /* If true, read ~/.ssh/environment */
char *permit_user_env_allowlist; /* pattern-list of allowed env names */
int compression; /* If true, compression is allowed */
int allow_tcp_forwarding; /* One of FORWARD_* */
int allow_streamlocal_forwarding; /* One of FORWARD_* */
int allow_agent_forwarding;
int disable_forwarding;
u_int num_allow_users;
char **allow_users;
u_int num_deny_users;
char **deny_users;
u_int num_allow_groups;
char **allow_groups;
u_int num_deny_groups;
char **deny_groups;
u_int num_subsystems;
char *subsystem_name[MAX_SUBSYSTEMS];
char *subsystem_command[MAX_SUBSYSTEMS];
char *subsystem_args[MAX_SUBSYSTEMS];
u_int num_accept_env;
char **accept_env;
u_int num_setenv;
char **setenv;
int max_startups_begin;
int max_startups_rate;
int max_startups;
int per_source_max_startups;
int per_source_masklen_ipv4;
int per_source_masklen_ipv6;
int max_authtries;
int max_sessions;
char *banner; /* SSH-2 banner message */
int use_dns;
int client_alive_interval; /*
* poke the client this often to
* see if it's still there
*/
int client_alive_count_max; /*
* If the client is unresponsive
* for this many intervals above,
* disconnect the session
*/
u_int num_authkeys_files; /* Files containing public keys */
char **authorized_keys_files;
char *adm_forced_command;
int use_pam; /* Enable auth via PAM */
int permit_tun;
char **permitted_opens; /* May also be one of PERMITOPEN_* */
u_int num_permitted_opens;
char **permitted_listens; /* May also be one of PERMITOPEN_* */
u_int num_permitted_listens;
char *chroot_directory;
char *revoked_keys_file;
char *trusted_user_ca_keys;
char *authorized_keys_command;
char *authorized_keys_command_user;
char *authorized_principals_file;
char *authorized_principals_command;
char *authorized_principals_command_user;
int64_t rekey_limit;
int rekey_interval;
char *version_addendum; /* Appended to SSH banner */
u_int num_auth_methods;
char **auth_methods;
int fingerprint_hash;
int expose_userauth_info;
u_int64_t timing_secret;
char *sk_provider;
} ServerOptions;
/* Information about the incoming connection as used by Match */
struct connection_info {
const char *user;
const char *host; /* possibly resolved hostname */
- const char *address; /* remote address */
+ const char *address; /* remote address */
const char *laddress; /* local address */
int lport; /* local port */
const char *rdomain; /* routing domain if available */
int test; /* test mode, allow some attributes to be
* unspecified */
};
/* List of included files for re-exec from the parsed configuration */
struct include_item {
char *selector;
char *filename;
struct sshbuf *contents;
TAILQ_ENTRY(include_item) entry;
};
TAILQ_HEAD(include_list, include_item);
/*
* These are string config options that must be copied between the
* Match sub-config and the main config, and must be sent from the
* privsep child to the privsep master. We use a macro to ensure all
* the options are copied and the copies are done in the correct order.
*
* NB. an option must appear in servconf.c:copy_set_server_options() or
* COPY_MATCH_STRING_OPTS here but never both.
*/
#define COPY_MATCH_STRING_OPTS() do { \
M_CP_STROPT(banner); \
M_CP_STROPT(trusted_user_ca_keys); \
M_CP_STROPT(revoked_keys_file); \
M_CP_STROPT(authorized_keys_command); \
M_CP_STROPT(authorized_keys_command_user); \
M_CP_STROPT(authorized_principals_file); \
M_CP_STROPT(authorized_principals_command); \
M_CP_STROPT(authorized_principals_command_user); \
M_CP_STROPT(hostbased_accepted_algos); \
M_CP_STROPT(pubkey_accepted_algos); \
M_CP_STROPT(ca_sign_algorithms); \
M_CP_STROPT(routing_domain); \
M_CP_STROPT(permit_user_env_allowlist); \
M_CP_STRARRAYOPT(authorized_keys_files, num_authkeys_files); \
M_CP_STRARRAYOPT(allow_users, num_allow_users); \
M_CP_STRARRAYOPT(deny_users, num_deny_users); \
M_CP_STRARRAYOPT(allow_groups, num_allow_groups); \
M_CP_STRARRAYOPT(deny_groups, num_deny_groups); \
M_CP_STRARRAYOPT(accept_env, num_accept_env); \
M_CP_STRARRAYOPT(setenv, num_setenv); \
M_CP_STRARRAYOPT(auth_methods, num_auth_methods); \
M_CP_STRARRAYOPT(permitted_opens, num_permitted_opens); \
M_CP_STRARRAYOPT(permitted_listens, num_permitted_listens); \
M_CP_STRARRAYOPT(log_verbose, num_log_verbose); \
} while (0)
struct connection_info *get_connection_info(struct ssh *, int, int);
void initialize_server_options(ServerOptions *);
void fill_default_server_options(ServerOptions *);
int process_server_config_line(ServerOptions *, char *, const char *, int,
- int *, struct connection_info *, struct include_list *includes);
+ int *, struct connection_info *, struct include_list *includes);
void process_permitopen(struct ssh *ssh, ServerOptions *options);
void load_server_config(const char *, struct sshbuf *);
void parse_server_config(ServerOptions *, const char *, struct sshbuf *,
- struct include_list *includes, struct connection_info *);
+ struct include_list *includes, struct connection_info *);
void parse_server_match_config(ServerOptions *,
- struct include_list *includes, struct connection_info *);
+ struct include_list *includes, struct connection_info *);
int parse_server_match_testspec(struct connection_info *, char *);
int server_match_spec_complete(struct connection_info *);
void copy_set_server_options(ServerOptions *, ServerOptions *, int);
void dump_config(ServerOptions *);
char *derelativise_path(const char *);
void servconf_add_hostkey(const char *, const int,
ServerOptions *, const char *path, int);
void servconf_add_hostcert(const char *, const int,
ServerOptions *, const char *path);
#endif /* SERVCONF_H */
diff --git a/serverloop.c b/serverloop.c
index 306658cbcc21..70a20ab496fc 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -1,976 +1,976 @@
-/* $OpenBSD: serverloop.c,v 1.225 2021/01/27 10:05:28 djm Exp $ */
+/* $OpenBSD: serverloop.c,v 1.226 2021/04/03 06:18:41 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Server main loop for handling the interactive session.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
* SSH2 support by Markus Friedl.
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <netinet/in.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <limits.h>
#include <signal.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <stdarg.h>
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "packet.h"
#include "sshbuf.h"
#include "log.h"
#include "misc.h"
#include "servconf.h"
#include "canohost.h"
#include "sshpty.h"
#include "channels.h"
#include "compat.h"
#include "ssh2.h"
#include "sshkey.h"
#include "cipher.h"
#include "kex.h"
#include "hostfile.h"
#include "auth.h"
#include "session.h"
#include "dispatch.h"
#include "auth-options.h"
#include "serverloop.h"
#include "ssherr.h"
extern ServerOptions options;
/* XXX */
extern Authctxt *the_authctxt;
extern struct sshauthopt *auth_opts;
extern int use_privsep;
static int no_more_sessions = 0; /* Disallow further sessions. */
/*
* This SIGCHLD kludge is used to detect when the child exits. The server
* will exit after that, as soon as forwarded connections have terminated.
*/
static volatile sig_atomic_t child_terminated = 0; /* The child has terminated. */
/* Cleanup on signals (!use_privsep case only) */
static volatile sig_atomic_t received_sigterm = 0;
/* prototypes */
static void server_init_dispatch(struct ssh *);
/* requested tunnel forwarding interface(s), shared with session.c */
char *tun_fwd_ifnames = NULL;
/* returns 1 if bind to specified port by specified user is permitted */
static int
bind_permitted(int port, uid_t uid)
{
if (use_privsep)
return 1; /* allow system to decide */
if (port < IPPORT_RESERVED && uid != 0)
return 0;
return 1;
}
/*
* we write to this pipe if a SIGCHLD is caught in order to avoid
* the race between select() and child_terminated
*/
static int notify_pipe[2];
static void
notify_setup(void)
{
if (pipe(notify_pipe) == -1) {
error("pipe(notify_pipe) failed %s", strerror(errno));
} else if ((fcntl(notify_pipe[0], F_SETFD, FD_CLOEXEC) == -1) ||
(fcntl(notify_pipe[1], F_SETFD, FD_CLOEXEC) == -1)) {
error("fcntl(notify_pipe, F_SETFD) failed %s", strerror(errno));
close(notify_pipe[0]);
close(notify_pipe[1]);
} else {
set_nonblock(notify_pipe[0]);
set_nonblock(notify_pipe[1]);
return;
}
notify_pipe[0] = -1; /* read end */
notify_pipe[1] = -1; /* write end */
}
static void
notify_parent(void)
{
if (notify_pipe[1] != -1)
(void)write(notify_pipe[1], "", 1);
}
static void
notify_prepare(fd_set *readset)
{
if (notify_pipe[0] != -1)
FD_SET(notify_pipe[0], readset);
}
static void
notify_done(fd_set *readset)
{
char c;
if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset))
while (read(notify_pipe[0], &c, 1) != -1)
debug2_f("reading");
}
/*ARGSUSED*/
static void
sigchld_handler(int sig)
{
int save_errno = errno;
child_terminated = 1;
notify_parent();
errno = save_errno;
}
/*ARGSUSED*/
static void
sigterm_handler(int sig)
{
received_sigterm = sig;
}
static void
client_alive_check(struct ssh *ssh)
{
char remote_id[512];
int r, channel_id;
/* timeout, check to see how many we have had */
if (options.client_alive_count_max > 0 &&
ssh_packet_inc_alive_timeouts(ssh) >
options.client_alive_count_max) {
sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
logit("Timeout, client not responding from %s", remote_id);
cleanup_exit(255);
}
/*
* send a bogus global/channel request with "wantreply",
* we should get back a failure
*/
if ((channel_id = channel_find_open(ssh)) == -1) {
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, "keepalive@openssh.com"))
!= 0 ||
(r = sshpkt_put_u8(ssh, 1)) != 0) /* boolean: want reply */
fatal_fr(r, "compose");
} else {
channel_request_start(ssh, channel_id,
"keepalive@openssh.com", 1);
}
if ((r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send");
}
/*
* Sleep in select() until we can do something. This will initialize the
* select masks. Upon return, the masks will indicate which descriptors
* have data or can accept data. Optionally, a maximum time can be specified
* for the duration of the wait (0 = infinite).
*/
static void
wait_until_can_do_something(struct ssh *ssh,
int connection_in, int connection_out,
fd_set **readsetp, fd_set **writesetp, int *maxfdp,
u_int *nallocp, u_int64_t max_time_ms)
{
struct timeval tv, *tvp;
int ret;
time_t minwait_secs = 0;
int client_alive_scheduled = 0;
/* time we last heard from the client OR sent a keepalive */
static time_t last_client_time;
/* Allocate and update select() masks for channel descriptors. */
channel_prepare_select(ssh, readsetp, writesetp, maxfdp,
nallocp, &minwait_secs);
/* XXX need proper deadline system for rekey/client alive */
if (minwait_secs != 0)
max_time_ms = MINIMUM(max_time_ms, (u_int)minwait_secs * 1000);
/*
* if using client_alive, set the max timeout accordingly,
* and indicate that this particular timeout was for client
* alive by setting the client_alive_scheduled flag.
*
* this could be randomized somewhat to make traffic
* analysis more difficult, but we're not doing it yet.
*/
if (options.client_alive_interval) {
uint64_t keepalive_ms =
(uint64_t)options.client_alive_interval * 1000;
if (max_time_ms == 0 || max_time_ms > keepalive_ms) {
max_time_ms = keepalive_ms;
client_alive_scheduled = 1;
}
if (last_client_time == 0)
last_client_time = monotime();
}
#if 0
/* wrong: bad condition XXX */
if (channel_not_very_much_buffered_data())
#endif
FD_SET(connection_in, *readsetp);
notify_prepare(*readsetp);
/*
* If we have buffered packet data going to the client, mark that
* descriptor.
*/
if (ssh_packet_have_data_to_write(ssh))
FD_SET(connection_out, *writesetp);
/*
* If child has terminated and there is enough buffer space to read
* from it, then read as much as is available and exit.
*/
if (child_terminated && ssh_packet_not_very_much_data_to_write(ssh))
if (max_time_ms == 0 || client_alive_scheduled)
max_time_ms = 100;
if (max_time_ms == 0)
tvp = NULL;
else {
tv.tv_sec = max_time_ms / 1000;
tv.tv_usec = 1000 * (max_time_ms % 1000);
tvp = &tv;
}
/* Wait for something to happen, or the timeout to expire. */
ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
if (ret == -1) {
memset(*readsetp, 0, *nallocp);
memset(*writesetp, 0, *nallocp);
if (errno != EINTR)
error("select: %.100s", strerror(errno));
} else if (client_alive_scheduled) {
time_t now = monotime();
/*
* If the select timed out, or returned for some other reason
* but we haven't heard from the client in time, send keepalive.
*/
if (ret == 0 || (last_client_time != 0 && last_client_time +
options.client_alive_interval <= now)) {
client_alive_check(ssh);
last_client_time = now;
} else if (FD_ISSET(connection_in, *readsetp)) {
last_client_time = now;
}
}
notify_done(*readsetp);
}
/*
* Processes input from the client and the program. Input data is stored
* in buffers and processed later.
*/
static int
process_input(struct ssh *ssh, fd_set *readset, int connection_in)
{
int r, len;
char buf[16384];
/* Read and buffer any input data from the client. */
if (FD_ISSET(connection_in, readset)) {
len = read(connection_in, buf, sizeof(buf));
if (len == 0) {
verbose("Connection closed by %.100s port %d",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
return -1;
} else if (len == -1) {
if (errno == EINTR || errno == EAGAIN ||
- errno != EWOULDBLOCK)
+ errno == EWOULDBLOCK)
return 0;
verbose("Read error from remote host %s port %d: %s",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
strerror(errno));
cleanup_exit(255);
}
/* Buffer any received data. */
if ((r = ssh_packet_process_incoming(ssh, buf, len)) != 0)
fatal_fr(r, "ssh_packet_process_incoming");
}
return 0;
}
/*
* Sends data from internal buffers to client program stdin.
*/
static void
process_output(struct ssh *ssh, fd_set *writeset, int connection_out)
{
int r;
/* Send any buffered packet data to the client. */
if (FD_ISSET(connection_out, writeset)) {
if ((r = ssh_packet_write_poll(ssh)) != 0) {
sshpkt_fatal(ssh, r, "%s: ssh_packet_write_poll",
__func__);
}
}
}
static void
process_buffered_input_packets(struct ssh *ssh)
{
ssh_dispatch_run_fatal(ssh, DISPATCH_NONBLOCK, NULL);
}
static void
collect_children(struct ssh *ssh)
{
pid_t pid;
sigset_t oset, nset;
int status;
/* block SIGCHLD while we check for dead children */
sigemptyset(&nset);
sigaddset(&nset, SIGCHLD);
sigprocmask(SIG_BLOCK, &nset, &oset);
if (child_terminated) {
debug("Received SIGCHLD.");
while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
(pid == -1 && errno == EINTR))
if (pid > 0)
session_close_by_pid(ssh, pid, status);
child_terminated = 0;
}
sigprocmask(SIG_SETMASK, &oset, NULL);
}
void
server_loop2(struct ssh *ssh, Authctxt *authctxt)
{
fd_set *readset = NULL, *writeset = NULL;
int max_fd;
u_int nalloc = 0, connection_in, connection_out;
u_int64_t rekey_timeout_ms = 0;
debug("Entering interactive session for SSH2.");
ssh_signal(SIGCHLD, sigchld_handler);
child_terminated = 0;
connection_in = ssh_packet_get_connection_in(ssh);
connection_out = ssh_packet_get_connection_out(ssh);
if (!use_privsep) {
ssh_signal(SIGTERM, sigterm_handler);
ssh_signal(SIGINT, sigterm_handler);
ssh_signal(SIGQUIT, sigterm_handler);
}
notify_setup();
max_fd = MAXIMUM(connection_in, connection_out);
max_fd = MAXIMUM(max_fd, notify_pipe[0]);
server_init_dispatch(ssh);
for (;;) {
process_buffered_input_packets(ssh);
if (!ssh_packet_is_rekeying(ssh) &&
ssh_packet_not_very_much_data_to_write(ssh))
channel_output_poll(ssh);
if (options.rekey_interval > 0 &&
!ssh_packet_is_rekeying(ssh)) {
rekey_timeout_ms = ssh_packet_get_rekey_timeout(ssh) *
1000;
} else {
rekey_timeout_ms = 0;
}
wait_until_can_do_something(ssh, connection_in, connection_out,
&readset, &writeset, &max_fd, &nalloc, rekey_timeout_ms);
if (received_sigterm) {
logit("Exiting on signal %d", (int)received_sigterm);
/* Clean up sessions, utmp, etc. */
cleanup_exit(255);
}
collect_children(ssh);
if (!ssh_packet_is_rekeying(ssh))
channel_after_select(ssh, readset, writeset);
if (process_input(ssh, readset, connection_in) < 0)
break;
process_output(ssh, writeset, connection_out);
}
collect_children(ssh);
free(readset);
free(writeset);
/* free all channels, no more reads and writes */
channel_free_all(ssh);
/* free remaining sessions, e.g. remove wtmp entries */
session_destroy_all(ssh, NULL);
}
static int
server_input_keep_alive(int type, u_int32_t seq, struct ssh *ssh)
{
debug("Got %d/%u for keepalive", type, seq);
/*
* reset timeout, since we got a sane answer from the client.
* even if this was generated by something other than
* the bogus CHANNEL_REQUEST we send for keepalives.
*/
ssh_packet_set_alive_timeouts(ssh, 0);
return 0;
}
static Channel *
server_request_direct_tcpip(struct ssh *ssh, int *reason, const char **errmsg)
{
Channel *c = NULL;
char *target = NULL, *originator = NULL;
u_int target_port = 0, originator_port = 0;
int r;
if ((r = sshpkt_get_cstring(ssh, &target, NULL)) != 0 ||
(r = sshpkt_get_u32(ssh, &target_port)) != 0 ||
(r = sshpkt_get_cstring(ssh, &originator, NULL)) != 0 ||
(r = sshpkt_get_u32(ssh, &originator_port)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
if (target_port > 0xFFFF) {
error_f("invalid target port");
*reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED;
goto out;
}
if (originator_port > 0xFFFF) {
error_f("invalid originator port");
*reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED;
goto out;
}
debug_f("originator %s port %u, target %s port %u",
originator, originator_port, target, target_port);
/* XXX fine grained permissions */
if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 &&
auth_opts->permit_port_forwarding_flag &&
!options.disable_forwarding) {
c = channel_connect_to_port(ssh, target, target_port,
"direct-tcpip", "direct-tcpip", reason, errmsg);
} else {
logit("refused local port forward: "
"originator %s port %d, target %s port %d",
originator, originator_port, target, target_port);
if (reason != NULL)
*reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED;
}
out:
free(originator);
free(target);
return c;
}
static Channel *
server_request_direct_streamlocal(struct ssh *ssh)
{
Channel *c = NULL;
char *target = NULL, *originator = NULL;
u_int originator_port = 0;
struct passwd *pw = the_authctxt->pw;
int r;
if (pw == NULL || !the_authctxt->valid)
fatal_f("no/invalid user");
if ((r = sshpkt_get_cstring(ssh, &target, NULL)) != 0 ||
(r = sshpkt_get_cstring(ssh, &originator, NULL)) != 0 ||
(r = sshpkt_get_u32(ssh, &originator_port)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
if (originator_port > 0xFFFF) {
error_f("invalid originator port");
goto out;
}
debug_f("originator %s port %d, target %s",
originator, originator_port, target);
/* XXX fine grained permissions */
if ((options.allow_streamlocal_forwarding & FORWARD_LOCAL) != 0 &&
auth_opts->permit_port_forwarding_flag &&
!options.disable_forwarding && (pw->pw_uid == 0 || use_privsep)) {
c = channel_connect_to_path(ssh, target,
"direct-streamlocal@openssh.com", "direct-streamlocal");
} else {
logit("refused streamlocal port forward: "
"originator %s port %d, target %s",
originator, originator_port, target);
}
out:
free(originator);
free(target);
return c;
}
static Channel *
server_request_tun(struct ssh *ssh)
{
Channel *c = NULL;
u_int mode, tun;
int r, sock;
char *tmp, *ifname = NULL;
if ((r = sshpkt_get_u32(ssh, &mode)) != 0)
sshpkt_fatal(ssh, r, "%s: parse mode", __func__);
switch (mode) {
case SSH_TUNMODE_POINTOPOINT:
case SSH_TUNMODE_ETHERNET:
break;
default:
ssh_packet_send_debug(ssh, "Unsupported tunnel device mode.");
return NULL;
}
if ((options.permit_tun & mode) == 0) {
ssh_packet_send_debug(ssh, "Server has rejected tunnel device "
"forwarding");
return NULL;
}
if ((r = sshpkt_get_u32(ssh, &tun)) != 0)
sshpkt_fatal(ssh, r, "%s: parse device", __func__);
if (tun > INT_MAX) {
debug_f("invalid tun");
goto done;
}
if (auth_opts->force_tun_device != -1) {
if (tun != SSH_TUNID_ANY &&
auth_opts->force_tun_device != (int)tun)
goto done;
tun = auth_opts->force_tun_device;
}
sock = tun_open(tun, mode, &ifname);
if (sock < 0)
goto done;
debug("Tunnel forwarding using interface %s", ifname);
c = channel_new(ssh, "tun", SSH_CHANNEL_OPEN, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
c->datagram = 1;
#if defined(SSH_TUN_FILTER)
if (mode == SSH_TUNMODE_POINTOPOINT)
channel_register_filter(ssh, c->self, sys_tun_infilter,
sys_tun_outfilter, NULL, NULL);
#endif
/*
* Update the list of names exposed to the session
* XXX remove these if the tunnels are closed (won't matter
* much if they are already in the environment though)
*/
tmp = tun_fwd_ifnames;
xasprintf(&tun_fwd_ifnames, "%s%s%s",
tun_fwd_ifnames == NULL ? "" : tun_fwd_ifnames,
tun_fwd_ifnames == NULL ? "" : ",",
ifname);
free(tmp);
free(ifname);
done:
if (c == NULL)
ssh_packet_send_debug(ssh, "Failed to open the tunnel device.");
return c;
}
static Channel *
server_request_session(struct ssh *ssh)
{
Channel *c;
int r;
debug("input_session_request");
if ((r = sshpkt_get_end(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
if (no_more_sessions) {
ssh_packet_disconnect(ssh, "Possible attack: attempt to open a "
"session after additional sessions disabled");
}
/*
* A server session has no fd to read or write until a
* CHANNEL_REQUEST for a shell is made, so we set the type to
* SSH_CHANNEL_LARVAL. Additionally, a callback for handling all
* CHANNEL_REQUEST messages is registered.
*/
c = channel_new(ssh, "session", SSH_CHANNEL_LARVAL,
-1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT,
0, "server-session", 1);
if (session_open(the_authctxt, c->self) != 1) {
debug("session open failed, free channel %d", c->self);
channel_free(ssh, c);
return NULL;
}
channel_register_cleanup(ssh, c->self, session_close_by_channel, 0);
return c;
}
static int
server_input_channel_open(int type, u_int32_t seq, struct ssh *ssh)
{
Channel *c = NULL;
char *ctype = NULL;
const char *errmsg = NULL;
int r, reason = SSH2_OPEN_CONNECT_FAILED;
u_int rchan = 0, rmaxpack = 0, rwindow = 0;
if ((r = sshpkt_get_cstring(ssh, &ctype, NULL)) != 0 ||
(r = sshpkt_get_u32(ssh, &rchan)) != 0 ||
(r = sshpkt_get_u32(ssh, &rwindow)) != 0 ||
(r = sshpkt_get_u32(ssh, &rmaxpack)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
debug_f("ctype %s rchan %u win %u max %u",
ctype, rchan, rwindow, rmaxpack);
if (strcmp(ctype, "session") == 0) {
c = server_request_session(ssh);
} else if (strcmp(ctype, "direct-tcpip") == 0) {
c = server_request_direct_tcpip(ssh, &reason, &errmsg);
} else if (strcmp(ctype, "direct-streamlocal@openssh.com") == 0) {
c = server_request_direct_streamlocal(ssh);
} else if (strcmp(ctype, "tun@openssh.com") == 0) {
c = server_request_tun(ssh);
}
if (c != NULL) {
debug_f("confirm %s", ctype);
c->remote_id = rchan;
c->have_remote_id = 1;
c->remote_window = rwindow;
c->remote_maxpacket = rmaxpack;
if (c->type != SSH_CHANNEL_CONNECTING) {
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 ||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
(r = sshpkt_put_u32(ssh, c->self)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0 ||
(r = sshpkt_send(ssh)) != 0) {
sshpkt_fatal(ssh, r,
"%s: send open confirm", __func__);
}
}
} else {
debug_f("failure %s", ctype);
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN_FAILURE)) != 0 ||
(r = sshpkt_put_u32(ssh, rchan)) != 0 ||
(r = sshpkt_put_u32(ssh, reason)) != 0 ||
(r = sshpkt_put_cstring(ssh, errmsg ? errmsg : "open failed")) != 0 ||
(r = sshpkt_put_cstring(ssh, "")) != 0 ||
(r = sshpkt_send(ssh)) != 0) {
sshpkt_fatal(ssh, r,
"%s: send open failure", __func__);
}
}
free(ctype);
return 0;
}
static int
server_input_hostkeys_prove(struct ssh *ssh, struct sshbuf **respp)
{
struct sshbuf *resp = NULL;
struct sshbuf *sigbuf = NULL;
struct sshkey *key = NULL, *key_pub = NULL, *key_prv = NULL;
int r, ndx, kexsigtype, use_kexsigtype, success = 0;
const u_char *blob;
u_char *sig = 0;
size_t blen, slen;
if ((resp = sshbuf_new()) == NULL || (sigbuf = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
kexsigtype = sshkey_type_plain(
sshkey_type_from_name(ssh->kex->hostkey_alg));
while (ssh_packet_remaining(ssh) > 0) {
sshkey_free(key);
key = NULL;
if ((r = sshpkt_get_string_direct(ssh, &blob, &blen)) != 0 ||
(r = sshkey_from_blob(blob, blen, &key)) != 0) {
error_fr(r, "parse key");
goto out;
}
/*
* Better check that this is actually one of our hostkeys
* before attempting to sign anything with it.
*/
if ((ndx = ssh->kex->host_key_index(key, 1, ssh)) == -1) {
error_f("unknown host %s key", sshkey_type(key));
goto out;
}
/*
* XXX refactor: make kex->sign just use an index rather
* than passing in public and private keys
*/
if ((key_prv = get_hostkey_by_index(ndx)) == NULL &&
(key_pub = get_hostkey_public_by_index(ndx, ssh)) == NULL) {
error_f("can't retrieve hostkey %d", ndx);
goto out;
}
sshbuf_reset(sigbuf);
free(sig);
sig = NULL;
/*
* For RSA keys, prefer to use the signature type negotiated
* during KEX to the default (SHA1).
*/
use_kexsigtype = kexsigtype == KEY_RSA &&
sshkey_type_plain(key->type) == KEY_RSA;
if ((r = sshbuf_put_cstring(sigbuf,
"hostkeys-prove-00@openssh.com")) != 0 ||
(r = sshbuf_put_stringb(sigbuf,
ssh->kex->session_id)) != 0 ||
(r = sshkey_puts(key, sigbuf)) != 0 ||
(r = ssh->kex->sign(ssh, key_prv, key_pub, &sig, &slen,
sshbuf_ptr(sigbuf), sshbuf_len(sigbuf),
use_kexsigtype ? ssh->kex->hostkey_alg : NULL)) != 0 ||
(r = sshbuf_put_string(resp, sig, slen)) != 0) {
error_fr(r, "assemble signature");
goto out;
}
}
/* Success */
*respp = resp;
resp = NULL; /* don't free it */
success = 1;
out:
free(sig);
sshbuf_free(resp);
sshbuf_free(sigbuf);
sshkey_free(key);
return success;
}
static int
server_input_global_request(int type, u_int32_t seq, struct ssh *ssh)
{
char *rtype = NULL;
u_char want_reply = 0;
int r, success = 0, allocated_listen_port = 0;
u_int port = 0;
struct sshbuf *resp = NULL;
struct passwd *pw = the_authctxt->pw;
struct Forward fwd;
memset(&fwd, 0, sizeof(fwd));
if (pw == NULL || !the_authctxt->valid)
fatal_f("no/invalid user");
if ((r = sshpkt_get_cstring(ssh, &rtype, NULL)) != 0 ||
(r = sshpkt_get_u8(ssh, &want_reply)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
debug_f("rtype %s want_reply %d", rtype, want_reply);
/* -R style forwarding */
if (strcmp(rtype, "tcpip-forward") == 0) {
if ((r = sshpkt_get_cstring(ssh, &fwd.listen_host, NULL)) != 0 ||
(r = sshpkt_get_u32(ssh, &port)) != 0)
sshpkt_fatal(ssh, r, "%s: parse tcpip-forward", __func__);
debug_f("tcpip-forward listen %s port %u",
fwd.listen_host, port);
if (port <= INT_MAX)
fwd.listen_port = (int)port;
/* check permissions */
if (port > INT_MAX ||
(options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 ||
!auth_opts->permit_port_forwarding_flag ||
options.disable_forwarding ||
(!want_reply && fwd.listen_port == 0) ||
(fwd.listen_port != 0 &&
- !bind_permitted(fwd.listen_port, pw->pw_uid))) {
+ !bind_permitted(fwd.listen_port, pw->pw_uid))) {
success = 0;
ssh_packet_send_debug(ssh, "Server has disabled port forwarding.");
} else {
/* Start listening on the port */
success = channel_setup_remote_fwd_listener(ssh, &fwd,
&allocated_listen_port, &options.fwd_opts);
}
if ((resp = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if (allocated_listen_port != 0 &&
(r = sshbuf_put_u32(resp, allocated_listen_port)) != 0)
fatal_fr(r, "sshbuf_put_u32");
} else if (strcmp(rtype, "cancel-tcpip-forward") == 0) {
if ((r = sshpkt_get_cstring(ssh, &fwd.listen_host, NULL)) != 0 ||
(r = sshpkt_get_u32(ssh, &port)) != 0)
sshpkt_fatal(ssh, r, "%s: parse cancel-tcpip-forward", __func__);
debug_f("cancel-tcpip-forward addr %s port %d",
fwd.listen_host, port);
if (port <= INT_MAX) {
fwd.listen_port = (int)port;
success = channel_cancel_rport_listener(ssh, &fwd);
}
} else if (strcmp(rtype, "streamlocal-forward@openssh.com") == 0) {
if ((r = sshpkt_get_cstring(ssh, &fwd.listen_path, NULL)) != 0)
sshpkt_fatal(ssh, r, "%s: parse streamlocal-forward@openssh.com", __func__);
debug_f("streamlocal-forward listen path %s",
fwd.listen_path);
/* check permissions */
if ((options.allow_streamlocal_forwarding & FORWARD_REMOTE) == 0
|| !auth_opts->permit_port_forwarding_flag ||
options.disable_forwarding ||
(pw->pw_uid != 0 && !use_privsep)) {
success = 0;
ssh_packet_send_debug(ssh, "Server has disabled "
"streamlocal forwarding.");
} else {
/* Start listening on the socket */
success = channel_setup_remote_fwd_listener(ssh,
&fwd, NULL, &options.fwd_opts);
}
} else if (strcmp(rtype, "cancel-streamlocal-forward@openssh.com") == 0) {
if ((r = sshpkt_get_cstring(ssh, &fwd.listen_path, NULL)) != 0)
sshpkt_fatal(ssh, r, "%s: parse cancel-streamlocal-forward@openssh.com", __func__);
debug_f("cancel-streamlocal-forward path %s",
fwd.listen_path);
success = channel_cancel_rport_listener(ssh, &fwd);
} else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) {
no_more_sessions = 1;
success = 1;
} else if (strcmp(rtype, "hostkeys-prove-00@openssh.com") == 0) {
success = server_input_hostkeys_prove(ssh, &resp);
}
/* XXX sshpkt_get_end() */
if (want_reply) {
if ((r = sshpkt_start(ssh, success ?
SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE)) != 0 ||
(success && resp != NULL && (r = sshpkt_putb(ssh, resp)) != 0) ||
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: send reply", __func__);
}
free(fwd.listen_host);
free(fwd.listen_path);
free(rtype);
sshbuf_free(resp);
return 0;
}
static int
server_input_channel_req(int type, u_int32_t seq, struct ssh *ssh)
{
Channel *c;
int r, success = 0;
char *rtype = NULL;
u_char want_reply = 0;
u_int id = 0;
if ((r = sshpkt_get_u32(ssh, &id)) != 0 ||
(r = sshpkt_get_cstring(ssh, &rtype, NULL)) != 0 ||
(r = sshpkt_get_u8(ssh, &want_reply)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
debug("server_input_channel_req: channel %u request %s reply %d",
id, rtype, want_reply);
if (id >= INT_MAX || (c = channel_lookup(ssh, (int)id)) == NULL) {
ssh_packet_disconnect(ssh, "%s: unknown channel %d",
__func__, id);
}
if (!strcmp(rtype, "eow@openssh.com")) {
if ((r = sshpkt_get_end(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
chan_rcvd_eow(ssh, c);
} else if ((c->type == SSH_CHANNEL_LARVAL ||
c->type == SSH_CHANNEL_OPEN) && strcmp(c->ctype, "session") == 0)
success = session_input_channel_req(ssh, c, rtype);
if (want_reply && !(c->flags & CHAN_CLOSE_SENT)) {
if (!c->have_remote_id)
fatal_f("channel %d: no remote_id", c->self);
if ((r = sshpkt_start(ssh, success ?
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE)) != 0 ||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: send reply", __func__);
}
free(rtype);
return 0;
}
static void
server_init_dispatch(struct ssh *ssh)
{
debug("server_init_dispatch");
ssh_dispatch_init(ssh, &dispatch_protocol_error);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_DATA, &channel_input_data);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
ssh_dispatch_set(ssh, SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
/* client_alive */
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_SUCCESS, &server_input_keep_alive);
ssh_dispatch_set(ssh, SSH2_MSG_CHANNEL_FAILURE, &server_input_keep_alive);
ssh_dispatch_set(ssh, SSH2_MSG_REQUEST_SUCCESS, &server_input_keep_alive);
ssh_dispatch_set(ssh, SSH2_MSG_REQUEST_FAILURE, &server_input_keep_alive);
/* rekeying */
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
}
diff --git a/session.c b/session.c
index 4b155f913f2c..c02f7d25e5e3 100644
--- a/session.c
+++ b/session.c
@@ -1,2716 +1,2716 @@
-/* $OpenBSD: session.c,v 1.327 2020/12/14 03:13:12 djm Exp $ */
+/* $OpenBSD: session.c,v 1.328 2021/04/03 06:18:41 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
* SSH2 support by Markus Friedl.
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/param.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <netdb.h>
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <limits.h>
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "ssh.h"
#include "ssh2.h"
#include "sshpty.h"
#include "packet.h"
#include "sshbuf.h"
#include "ssherr.h"
#include "match.h"
#include "uidswap.h"
#include "compat.h"
#include "channels.h"
#include "sshkey.h"
#include "cipher.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
#include "hostfile.h"
#include "auth.h"
#include "auth-options.h"
#include "authfd.h"
#include "pathnames.h"
#include "log.h"
#include "misc.h"
#include "servconf.h"
#include "sshlogin.h"
#include "serverloop.h"
#include "canohost.h"
#include "session.h"
#include "kex.h"
#include "monitor_wrap.h"
#include "sftp.h"
#include "atomicio.h"
#if defined(KRB5) && defined(USE_AFS)
#include <kafs.h>
#endif
#ifdef WITH_SELINUX
#include <selinux/selinux.h>
#endif
#define IS_INTERNAL_SFTP(c) \
(!strncmp(c, INTERNAL_SFTP_NAME, sizeof(INTERNAL_SFTP_NAME) - 1) && \
(c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\0' || \
c[sizeof(INTERNAL_SFTP_NAME) - 1] == ' ' || \
c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\t'))
/* func */
Session *session_new(void);
void session_set_fds(struct ssh *, Session *, int, int, int, int, int);
void session_pty_cleanup(Session *);
void session_proctitle(Session *);
int session_setup_x11fwd(struct ssh *, Session *);
int do_exec_pty(struct ssh *, Session *, const char *);
int do_exec_no_pty(struct ssh *, Session *, const char *);
int do_exec(struct ssh *, Session *, const char *);
void do_login(struct ssh *, Session *, const char *);
void do_child(struct ssh *, Session *, const char *);
void do_motd(void);
int check_quietlogin(Session *, const char *);
static void do_authenticated2(struct ssh *, Authctxt *);
static int session_pty_req(struct ssh *, Session *);
/* import */
extern ServerOptions options;
extern char *__progname;
extern int debug_flag;
extern u_int utmp_len;
extern int startup_pipe;
extern void destroy_sensitive_data(void);
extern struct sshbuf *loginmsg;
extern struct sshauthopt *auth_opts;
extern char *tun_fwd_ifnames; /* serverloop.c */
/* original command from peer. */
const char *original_command = NULL;
/* data */
static int sessions_first_unused = -1;
static int sessions_nalloc = 0;
static Session *sessions = NULL;
#define SUBSYSTEM_NONE 0
#define SUBSYSTEM_EXT 1
#define SUBSYSTEM_INT_SFTP 2
#define SUBSYSTEM_INT_SFTP_ERROR 3
#ifdef HAVE_LOGIN_CAP
login_cap_t *lc;
#endif
static int is_child = 0;
static int in_chroot = 0;
/* File containing userauth info, if ExposeAuthInfo set */
static char *auth_info_file = NULL;
/* Name and directory of socket for authentication agent forwarding. */
static char *auth_sock_name = NULL;
static char *auth_sock_dir = NULL;
/* removes the agent forwarding socket */
static void
auth_sock_cleanup_proc(struct passwd *pw)
{
if (auth_sock_name != NULL) {
temporarily_use_uid(pw);
unlink(auth_sock_name);
rmdir(auth_sock_dir);
auth_sock_name = NULL;
restore_uid();
}
}
static int
auth_input_request_forwarding(struct ssh *ssh, struct passwd * pw)
{
Channel *nc;
int sock = -1;
if (auth_sock_name != NULL) {
error("authentication forwarding requested twice.");
return 0;
}
/* Temporarily drop privileged uid for mkdir/bind. */
temporarily_use_uid(pw);
/* Allocate a buffer for the socket name, and format the name. */
auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX");
/* Create private directory for socket */
if (mkdtemp(auth_sock_dir) == NULL) {
ssh_packet_send_debug(ssh, "Agent forwarding disabled: "
"mkdtemp() failed: %.100s", strerror(errno));
restore_uid();
free(auth_sock_dir);
auth_sock_dir = NULL;
goto authsock_err;
}
xasprintf(&auth_sock_name, "%s/agent.%ld",
auth_sock_dir, (long) getpid());
/* Start a Unix listener on auth_sock_name. */
sock = unix_listener(auth_sock_name, SSH_LISTEN_BACKLOG, 0);
/* Restore the privileged uid. */
restore_uid();
/* Check for socket/bind/listen failure. */
if (sock < 0)
goto authsock_err;
/* Allocate a channel for the authentication agent socket. */
nc = channel_new(ssh, "auth socket",
SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
0, "auth socket", 1);
nc->path = xstrdup(auth_sock_name);
return 1;
authsock_err:
free(auth_sock_name);
if (auth_sock_dir != NULL) {
temporarily_use_uid(pw);
rmdir(auth_sock_dir);
restore_uid();
free(auth_sock_dir);
}
if (sock != -1)
close(sock);
auth_sock_name = NULL;
auth_sock_dir = NULL;
return 0;
}
static void
display_loginmsg(void)
{
int r;
if (sshbuf_len(loginmsg) == 0)
return;
if ((r = sshbuf_put_u8(loginmsg, 0)) != 0)
fatal_fr(r, "sshbuf_put_u8");
printf("%s", (char *)sshbuf_ptr(loginmsg));
sshbuf_reset(loginmsg);
}
static void
prepare_auth_info_file(struct passwd *pw, struct sshbuf *info)
{
int fd = -1, success = 0;
if (!options.expose_userauth_info || info == NULL)
return;
temporarily_use_uid(pw);
auth_info_file = xstrdup("/tmp/sshauth.XXXXXXXXXXXXXXX");
if ((fd = mkstemp(auth_info_file)) == -1) {
error_f("mkstemp: %s", strerror(errno));
goto out;
}
if (atomicio(vwrite, fd, sshbuf_mutable_ptr(info),
sshbuf_len(info)) != sshbuf_len(info)) {
error_f("write: %s", strerror(errno));
goto out;
}
if (close(fd) != 0) {
error_f("close: %s", strerror(errno));
goto out;
}
success = 1;
out:
if (!success) {
if (fd != -1)
close(fd);
free(auth_info_file);
auth_info_file = NULL;
}
restore_uid();
}
static void
set_fwdpermit_from_authopts(struct ssh *ssh, const struct sshauthopt *opts)
{
char *tmp, *cp, *host;
int port;
size_t i;
if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) {
channel_clear_permission(ssh, FORWARD_USER, FORWARD_LOCAL);
for (i = 0; i < auth_opts->npermitopen; i++) {
tmp = cp = xstrdup(auth_opts->permitopen[i]);
/* This shouldn't fail as it has already been checked */
if ((host = hpdelim(&cp)) == NULL)
fatal_f("internal error: hpdelim");
host = cleanhostname(host);
if (cp == NULL || (port = permitopen_port(cp)) < 0)
fatal_f("internal error: permitopen port");
channel_add_permission(ssh,
FORWARD_USER, FORWARD_LOCAL, host, port);
free(tmp);
}
}
if ((options.allow_tcp_forwarding & FORWARD_REMOTE) != 0) {
channel_clear_permission(ssh, FORWARD_USER, FORWARD_REMOTE);
for (i = 0; i < auth_opts->npermitlisten; i++) {
tmp = cp = xstrdup(auth_opts->permitlisten[i]);
/* This shouldn't fail as it has already been checked */
if ((host = hpdelim(&cp)) == NULL)
fatal_f("internal error: hpdelim");
host = cleanhostname(host);
if (cp == NULL || (port = permitopen_port(cp)) < 0)
fatal_f("internal error: permitlisten port");
channel_add_permission(ssh,
FORWARD_USER, FORWARD_REMOTE, host, port);
free(tmp);
}
}
}
void
do_authenticated(struct ssh *ssh, Authctxt *authctxt)
{
setproctitle("%s", authctxt->pw->pw_name);
auth_log_authopts("active", auth_opts, 0);
/* setup the channel layer */
/* XXX - streamlocal? */
set_fwdpermit_from_authopts(ssh, auth_opts);
if (!auth_opts->permit_port_forwarding_flag ||
options.disable_forwarding) {
channel_disable_admin(ssh, FORWARD_LOCAL);
channel_disable_admin(ssh, FORWARD_REMOTE);
} else {
if ((options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
channel_disable_admin(ssh, FORWARD_LOCAL);
else
channel_permit_all(ssh, FORWARD_LOCAL);
if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0)
channel_disable_admin(ssh, FORWARD_REMOTE);
else
channel_permit_all(ssh, FORWARD_REMOTE);
}
auth_debug_send(ssh);
prepare_auth_info_file(authctxt->pw, authctxt->session_info);
do_authenticated2(ssh, authctxt);
do_cleanup(ssh, authctxt);
}
/* Check untrusted xauth strings for metacharacters */
static int
xauth_valid_string(const char *s)
{
size_t i;
for (i = 0; s[i] != '\0'; i++) {
if (!isalnum((u_char)s[i]) &&
s[i] != '.' && s[i] != ':' && s[i] != '/' &&
s[i] != '-' && s[i] != '_')
return 0;
}
return 1;
}
#define USE_PIPES 1
/*
* This is called to fork and execute a command when we have no tty. This
* will call do_child from the child, and server_loop from the parent after
* setting up file descriptors and such.
*/
int
do_exec_no_pty(struct ssh *ssh, Session *s, const char *command)
{
pid_t pid;
#ifdef USE_PIPES
int pin[2], pout[2], perr[2];
if (s == NULL)
fatal("do_exec_no_pty: no session");
/* Allocate pipes for communicating with the program. */
if (pipe(pin) == -1) {
error_f("pipe in: %.100s", strerror(errno));
return -1;
}
if (pipe(pout) == -1) {
error_f("pipe out: %.100s", strerror(errno));
close(pin[0]);
close(pin[1]);
return -1;
}
if (pipe(perr) == -1) {
error_f("pipe err: %.100s", strerror(errno));
close(pin[0]);
close(pin[1]);
close(pout[0]);
close(pout[1]);
return -1;
}
#else
int inout[2], err[2];
if (s == NULL)
fatal("do_exec_no_pty: no session");
/* Uses socket pairs to communicate with the program. */
if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) {
error_f("socketpair #1: %.100s", strerror(errno));
return -1;
}
if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) == -1) {
error_f("socketpair #2: %.100s", strerror(errno));
close(inout[0]);
close(inout[1]);
return -1;
}
#endif
session_proctitle(s);
/* Fork the child. */
switch ((pid = fork())) {
case -1:
error_f("fork: %.100s", strerror(errno));
#ifdef USE_PIPES
close(pin[0]);
close(pin[1]);
close(pout[0]);
close(pout[1]);
close(perr[0]);
close(perr[1]);
#else
close(inout[0]);
close(inout[1]);
close(err[0]);
close(err[1]);
#endif
return -1;
case 0:
is_child = 1;
/*
* Create a new session and process group since the 4.4BSD
* setlogin() affects the entire process group.
*/
if (setsid() == -1)
error("setsid failed: %.100s", strerror(errno));
#ifdef USE_PIPES
/*
* Redirect stdin. We close the parent side of the socket
* pair, and make the child side the standard input.
*/
close(pin[1]);
if (dup2(pin[0], 0) == -1)
perror("dup2 stdin");
close(pin[0]);
/* Redirect stdout. */
close(pout[0]);
if (dup2(pout[1], 1) == -1)
perror("dup2 stdout");
close(pout[1]);
/* Redirect stderr. */
close(perr[0]);
if (dup2(perr[1], 2) == -1)
perror("dup2 stderr");
close(perr[1]);
#else
/*
* Redirect stdin, stdout, and stderr. Stdin and stdout will
* use the same socket, as some programs (particularly rdist)
* seem to depend on it.
*/
close(inout[1]);
close(err[1]);
if (dup2(inout[0], 0) == -1) /* stdin */
perror("dup2 stdin");
if (dup2(inout[0], 1) == -1) /* stdout (same as stdin) */
perror("dup2 stdout");
close(inout[0]);
if (dup2(err[0], 2) == -1) /* stderr */
perror("dup2 stderr");
close(err[0]);
#endif
/* Do processing for the child (exec command etc). */
do_child(ssh, s, command);
/* NOTREACHED */
default:
break;
}
#ifdef HAVE_CYGWIN
cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
#endif
s->pid = pid;
/* Set interactive/non-interactive mode. */
ssh_packet_set_interactive(ssh, s->display != NULL,
options.ip_qos_interactive, options.ip_qos_bulk);
/*
* Clear loginmsg, since it's the child's responsibility to display
* it to the user, otherwise multiple sessions may accumulate
* multiple copies of the login messages.
*/
sshbuf_reset(loginmsg);
#ifdef USE_PIPES
/* We are the parent. Close the child sides of the pipes. */
close(pin[0]);
close(pout[1]);
close(perr[1]);
session_set_fds(ssh, s, pin[1], pout[0], perr[0],
s->is_subsystem, 0);
#else
/* We are the parent. Close the child sides of the socket pairs. */
close(inout[0]);
close(err[0]);
/*
* Enter the interactive session. Note: server_loop must be able to
* handle the case that fdin and fdout are the same.
*/
session_set_fds(ssh, s, inout[1], inout[1], err[1],
s->is_subsystem, 0);
#endif
return 0;
}
/*
* This is called to fork and execute a command when we have a tty. This
* will call do_child from the child, and server_loop from the parent after
* setting up file descriptors, controlling tty, updating wtmp, utmp,
* lastlog, and other such operations.
*/
int
do_exec_pty(struct ssh *ssh, Session *s, const char *command)
{
int fdout, ptyfd, ttyfd, ptymaster;
pid_t pid;
if (s == NULL)
fatal("do_exec_pty: no session");
ptyfd = s->ptyfd;
ttyfd = s->ttyfd;
/*
* Create another descriptor of the pty master side for use as the
* standard input. We could use the original descriptor, but this
* simplifies code in server_loop. The descriptor is bidirectional.
* Do this before forking (and cleanup in the child) so as to
* detect and gracefully fail out-of-fd conditions.
*/
if ((fdout = dup(ptyfd)) == -1) {
error_f("dup #1: %s", strerror(errno));
close(ttyfd);
close(ptyfd);
return -1;
}
/* we keep a reference to the pty master */
if ((ptymaster = dup(ptyfd)) == -1) {
error_f("dup #2: %s", strerror(errno));
close(ttyfd);
close(ptyfd);
close(fdout);
return -1;
}
/* Fork the child. */
switch ((pid = fork())) {
case -1:
error_f("fork: %.100s", strerror(errno));
close(fdout);
close(ptymaster);
close(ttyfd);
close(ptyfd);
return -1;
case 0:
is_child = 1;
close(fdout);
close(ptymaster);
/* Close the master side of the pseudo tty. */
close(ptyfd);
/* Make the pseudo tty our controlling tty. */
pty_make_controlling_tty(&ttyfd, s->tty);
/* Redirect stdin/stdout/stderr from the pseudo tty. */
if (dup2(ttyfd, 0) == -1)
error("dup2 stdin: %s", strerror(errno));
if (dup2(ttyfd, 1) == -1)
error("dup2 stdout: %s", strerror(errno));
if (dup2(ttyfd, 2) == -1)
error("dup2 stderr: %s", strerror(errno));
/* Close the extra descriptor for the pseudo tty. */
close(ttyfd);
/* record login, etc. similar to login(1) */
#ifndef HAVE_OSF_SIA
do_login(ssh, s, command);
#endif
/*
* Do common processing for the child, such as execing
* the command.
*/
do_child(ssh, s, command);
/* NOTREACHED */
default:
break;
}
#ifdef HAVE_CYGWIN
cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
#endif
s->pid = pid;
/* Parent. Close the slave side of the pseudo tty. */
close(ttyfd);
/* Enter interactive session. */
s->ptymaster = ptymaster;
ssh_packet_set_interactive(ssh, 1,
options.ip_qos_interactive, options.ip_qos_bulk);
session_set_fds(ssh, s, ptyfd, fdout, -1, 1, 1);
return 0;
}
/*
* This is called to fork and execute a command. If another command is
* to be forced, execute that instead.
*/
int
do_exec(struct ssh *ssh, Session *s, const char *command)
{
int ret;
const char *forced = NULL, *tty = NULL;
char session_type[1024];
if (options.adm_forced_command) {
original_command = command;
command = options.adm_forced_command;
forced = "(config)";
} else if (auth_opts->force_command != NULL) {
original_command = command;
command = auth_opts->force_command;
forced = "(key-option)";
}
s->forced = 0;
if (forced != NULL) {
s->forced = 1;
if (IS_INTERNAL_SFTP(command)) {
s->is_subsystem = s->is_subsystem ?
SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
} else if (s->is_subsystem)
s->is_subsystem = SUBSYSTEM_EXT;
snprintf(session_type, sizeof(session_type),
"forced-command %s '%.900s'", forced, command);
} else if (s->is_subsystem) {
snprintf(session_type, sizeof(session_type),
"subsystem '%.900s'", s->subsys);
} else if (command == NULL) {
snprintf(session_type, sizeof(session_type), "shell");
} else {
/* NB. we don't log unforced commands to preserve privacy */
snprintf(session_type, sizeof(session_type), "command");
}
if (s->ttyfd != -1) {
tty = s->tty;
if (strncmp(tty, "/dev/", 5) == 0)
tty += 5;
}
verbose("Starting session: %s%s%s for %s from %.200s port %d id %d",
session_type,
tty == NULL ? "" : " on ",
tty == NULL ? "" : tty,
s->pw->pw_name,
ssh_remote_ipaddr(ssh),
ssh_remote_port(ssh),
s->self);
#ifdef SSH_AUDIT_EVENTS
if (command != NULL)
PRIVSEP(audit_run_command(command));
else if (s->ttyfd == -1) {
char *shell = s->pw->pw_shell;
if (shell[0] == '\0') /* empty shell means /bin/sh */
shell =_PATH_BSHELL;
PRIVSEP(audit_run_command(shell));
}
#endif
if (s->ttyfd != -1)
ret = do_exec_pty(ssh, s, command);
else
ret = do_exec_no_pty(ssh, s, command);
original_command = NULL;
/*
* Clear loginmsg: it's the child's responsibility to display
* it to the user, otherwise multiple sessions may accumulate
* multiple copies of the login messages.
*/
sshbuf_reset(loginmsg);
return ret;
}
/* administrative, login(1)-like work */
void
do_login(struct ssh *ssh, Session *s, const char *command)
{
socklen_t fromlen;
struct sockaddr_storage from;
struct passwd * pw = s->pw;
pid_t pid = getpid();
/*
* Get IP address of client. If the connection is not a socket, let
* the address be 0.0.0.0.
*/
memset(&from, 0, sizeof(from));
fromlen = sizeof(from);
if (ssh_packet_connection_is_on_socket(ssh)) {
if (getpeername(ssh_packet_get_connection_in(ssh),
(struct sockaddr *)&from, &fromlen) == -1) {
debug("getpeername: %.100s", strerror(errno));
cleanup_exit(255);
}
}
/* Record that there was a login on that tty from the remote host. */
if (!use_privsep)
record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
session_get_remote_name_or_ip(ssh, utmp_len,
options.use_dns),
(struct sockaddr *)&from, fromlen);
#ifdef USE_PAM
/*
* If password change is needed, do it now.
* This needs to occur before the ~/.hushlogin check.
*/
if (options.use_pam && !use_privsep && s->authctxt->force_pwchange) {
display_loginmsg();
do_pam_chauthtok();
s->authctxt->force_pwchange = 0;
/* XXX - signal [net] parent to enable forwardings */
}
#endif
if (check_quietlogin(s, command))
return;
display_loginmsg();
do_motd();
}
/*
* Display the message of the day.
*/
void
do_motd(void)
{
FILE *f;
char buf[256];
if (options.print_motd) {
#ifdef HAVE_LOGIN_CAP
f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",
"/etc/motd"), "r");
#else
f = fopen("/etc/motd", "r");
#endif
if (f) {
while (fgets(buf, sizeof(buf), f))
fputs(buf, stdout);
fclose(f);
}
}
}
/*
* Check for quiet login, either .hushlogin or command given.
*/
int
check_quietlogin(Session *s, const char *command)
{
char buf[256];
struct passwd *pw = s->pw;
struct stat st;
/* Return 1 if .hushlogin exists or a command given. */
if (command != NULL)
return 1;
snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);
#ifdef HAVE_LOGIN_CAP
if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0)
return 1;
#else
if (stat(buf, &st) >= 0)
return 1;
#endif
return 0;
}
/*
* Reads environment variables from the given file and adds/overrides them
* into the environment. If the file does not exist, this does nothing.
* Otherwise, it must consist of empty lines, comments (line starts with '#')
* and assignments of the form name=value. No other forms are allowed.
* If allowlist is not NULL, then it is interpreted as a pattern list and
* only variable names that match it will be accepted.
*/
static void
read_environment_file(char ***env, u_int *envsize,
const char *filename, const char *allowlist)
{
FILE *f;
char *line = NULL, *cp, *value;
size_t linesize = 0;
u_int lineno = 0;
f = fopen(filename, "r");
if (!f)
return;
while (getline(&line, &linesize, f) != -1) {
if (++lineno > 1000)
fatal("Too many lines in environment file %s", filename);
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
;
if (!*cp || *cp == '#' || *cp == '\n')
continue;
cp[strcspn(cp, "\n")] = '\0';
value = strchr(cp, '=');
if (value == NULL) {
fprintf(stderr, "Bad line %u in %.100s\n", lineno,
filename);
continue;
}
/*
* Replace the equals sign by nul, and advance value to
* the value string.
*/
*value = '\0';
value++;
if (allowlist != NULL &&
match_pattern_list(cp, allowlist, 0) != 1)
continue;
child_set_env(env, envsize, cp, value);
}
free(line);
fclose(f);
}
#ifdef HAVE_ETC_DEFAULT_LOGIN
/*
* Return named variable from specified environment, or NULL if not present.
*/
static char *
child_get_env(char **env, const char *name)
{
int i;
size_t len;
len = strlen(name);
for (i=0; env[i] != NULL; i++)
if (strncmp(name, env[i], len) == 0 && env[i][len] == '=')
return(env[i] + len + 1);
return NULL;
}
/*
* Read /etc/default/login.
* We pick up the PATH (or SUPATH for root) and UMASK.
*/
static void
read_etc_default_login(char ***env, u_int *envsize, uid_t uid)
{
char **tmpenv = NULL, *var;
u_int i, tmpenvsize = 0;
u_long mask;
/*
* We don't want to copy the whole file to the child's environment,
* so we use a temporary environment and copy the variables we're
* interested in.
*/
read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login",
options.permit_user_env_allowlist);
if (tmpenv == NULL)
return;
if (uid == 0)
var = child_get_env(tmpenv, "SUPATH");
else
var = child_get_env(tmpenv, "PATH");
if (var != NULL)
child_set_env(env, envsize, "PATH", var);
if ((var = child_get_env(tmpenv, "UMASK")) != NULL)
if (sscanf(var, "%5lo", &mask) == 1)
umask((mode_t)mask);
for (i = 0; tmpenv[i] != NULL; i++)
free(tmpenv[i]);
free(tmpenv);
}
#endif /* HAVE_ETC_DEFAULT_LOGIN */
#if defined(USE_PAM) || defined(HAVE_CYGWIN)
static void
copy_environment_denylist(char **source, char ***env, u_int *envsize,
const char *denylist)
{
char *var_name, *var_val;
int i;
if (source == NULL)
return;
for(i = 0; source[i] != NULL; i++) {
var_name = xstrdup(source[i]);
if ((var_val = strstr(var_name, "=")) == NULL) {
free(var_name);
continue;
}
*var_val++ = '\0';
if (denylist == NULL ||
match_pattern_list(var_name, denylist, 0) != 1) {
debug3("Copy environment: %s=%s", var_name, var_val);
child_set_env(env, envsize, var_name, var_val);
}
free(var_name);
}
}
#endif /* defined(USE_PAM) || defined(HAVE_CYGWIN) */
#ifdef HAVE_CYGWIN
static void
copy_environment(char **source, char ***env, u_int *envsize)
{
copy_environment_denylist(source, env, envsize, NULL);
}
#endif
static char **
do_setup_env(struct ssh *ssh, Session *s, const char *shell)
{
char buf[256];
size_t n;
u_int i, envsize;
char *ocp, *cp, *value, **env, *laddr;
struct passwd *pw = s->pw;
#if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN)
char *path = NULL;
#endif
/* Initialize the environment. */
envsize = 100;
env = xcalloc(envsize, sizeof(char *));
env[0] = NULL;
#ifdef HAVE_CYGWIN
/*
* The Windows environment contains some setting which are
* important for a running system. They must not be dropped.
*/
{
char **p;
p = fetch_windows_environment();
copy_environment(p, &env, &envsize);
free_windows_environment(p);
}
#endif
#ifdef GSSAPI
/* Allow any GSSAPI methods that we've used to alter
* the child's environment as they see fit
*/
ssh_gssapi_do_child(&env, &envsize);
#endif
/* Set basic environment. */
for (i = 0; i < s->num_env; i++)
child_set_env(&env, &envsize, s->env[i].name, s->env[i].val);
child_set_env(&env, &envsize, "USER", pw->pw_name);
child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
#ifdef _AIX
child_set_env(&env, &envsize, "LOGIN", pw->pw_name);
#endif
child_set_env(&env, &envsize, "HOME", pw->pw_dir);
#ifdef HAVE_LOGIN_CAP
if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH) < 0)
child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
else
child_set_env(&env, &envsize, "PATH", getenv("PATH"));
#else /* HAVE_LOGIN_CAP */
# ifndef HAVE_CYGWIN
/*
* There's no standard path on Windows. The path contains
* important components pointing to the system directories,
* needed for loading shared libraries. So the path better
* remains intact here.
*/
# ifdef HAVE_ETC_DEFAULT_LOGIN
read_etc_default_login(&env, &envsize, pw->pw_uid);
path = child_get_env(env, "PATH");
# endif /* HAVE_ETC_DEFAULT_LOGIN */
if (path == NULL || *path == '\0') {
child_set_env(&env, &envsize, "PATH",
s->pw->pw_uid == 0 ? SUPERUSER_PATH : _PATH_STDPATH);
}
# endif /* HAVE_CYGWIN */
#endif /* HAVE_LOGIN_CAP */
if (!options.use_pam) {
snprintf(buf, sizeof buf, "%.200s/%.50s",
_PATH_MAILDIR, pw->pw_name);
child_set_env(&env, &envsize, "MAIL", buf);
}
/* Normal systems set SHELL by default. */
child_set_env(&env, &envsize, "SHELL", shell);
if (getenv("TZ"))
child_set_env(&env, &envsize, "TZ", getenv("TZ"));
if (s->term)
child_set_env(&env, &envsize, "TERM", s->term);
if (s->display)
child_set_env(&env, &envsize, "DISPLAY", s->display);
/*
* Since we clear KRB5CCNAME at startup, if it's set now then it
* must have been set by a native authentication method (eg AIX or
* SIA), so copy it to the child.
*/
{
char *cp;
if ((cp = getenv("KRB5CCNAME")) != NULL)
child_set_env(&env, &envsize, "KRB5CCNAME", cp);
}
#ifdef _AIX
{
char *cp;
if ((cp = getenv("AUTHSTATE")) != NULL)
child_set_env(&env, &envsize, "AUTHSTATE", cp);
read_environment_file(&env, &envsize, "/etc/environment",
options.permit_user_env_allowlist);
}
#endif
#ifdef KRB5
if (s->authctxt->krb5_ccname)
child_set_env(&env, &envsize, "KRB5CCNAME",
s->authctxt->krb5_ccname);
#endif
if (auth_sock_name != NULL)
child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
auth_sock_name);
/* Set custom environment options from pubkey authentication. */
if (options.permit_user_env) {
for (n = 0 ; n < auth_opts->nenv; n++) {
ocp = xstrdup(auth_opts->env[n]);
cp = strchr(ocp, '=');
if (cp != NULL) {
*cp = '\0';
/* Apply PermitUserEnvironment allowlist */
if (options.permit_user_env_allowlist == NULL ||
match_pattern_list(ocp,
options.permit_user_env_allowlist, 0) == 1)
child_set_env(&env, &envsize,
ocp, cp + 1);
}
free(ocp);
}
}
/* read $HOME/.ssh/environment. */
if (options.permit_user_env) {
snprintf(buf, sizeof buf, "%.200s/%s/environment",
pw->pw_dir, _PATH_SSH_USER_DIR);
read_environment_file(&env, &envsize, buf,
options.permit_user_env_allowlist);
}
#ifdef USE_PAM
/*
* Pull in any environment variables that may have
* been set by PAM.
*/
if (options.use_pam) {
char **p;
/*
* Don't allow PAM-internal env vars to leak
* back into the session environment.
*/
#define PAM_ENV_DENYLIST "SSH_AUTH_INFO*,SSH_CONNECTION*"
p = fetch_pam_child_environment();
copy_environment_denylist(p, &env, &envsize,
PAM_ENV_DENYLIST);
free_pam_environment(p);
p = fetch_pam_environment();
copy_environment_denylist(p, &env, &envsize,
PAM_ENV_DENYLIST);
free_pam_environment(p);
}
#endif /* USE_PAM */
/* Environment specified by admin */
for (i = 0; i < options.num_setenv; i++) {
cp = xstrdup(options.setenv[i]);
if ((value = strchr(cp, '=')) == NULL) {
/* shouldn't happen; vars are checked in servconf.c */
fatal("Invalid config SetEnv: %s", options.setenv[i]);
}
*value++ = '\0';
child_set_env(&env, &envsize, cp, value);
}
/* SSH_CLIENT deprecated */
snprintf(buf, sizeof buf, "%.50s %d %d",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
ssh_local_port(ssh));
child_set_env(&env, &envsize, "SSH_CLIENT", buf);
laddr = get_local_ipaddr(ssh_packet_get_connection_in(ssh));
snprintf(buf, sizeof buf, "%.50s %d %.50s %d",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
laddr, ssh_local_port(ssh));
free(laddr);
child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
if (tun_fwd_ifnames != NULL)
child_set_env(&env, &envsize, "SSH_TUNNEL", tun_fwd_ifnames);
if (auth_info_file != NULL)
child_set_env(&env, &envsize, "SSH_USER_AUTH", auth_info_file);
if (s->ttyfd != -1)
child_set_env(&env, &envsize, "SSH_TTY", s->tty);
if (original_command)
child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
original_command);
if (debug_flag) {
/* dump the environment */
fprintf(stderr, "Environment:\n");
for (i = 0; env[i]; i++)
fprintf(stderr, " %.200s\n", env[i]);
}
return env;
}
/*
* Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found
* first in this order).
*/
static void
do_rc_files(struct ssh *ssh, Session *s, const char *shell)
{
FILE *f = NULL;
char *cmd = NULL, *user_rc = NULL;
int do_xauth;
struct stat st;
do_xauth =
s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
xasprintf(&user_rc, "%s/%s", s->pw->pw_dir, _PATH_SSH_USER_RC);
/* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */
if (!s->is_subsystem && options.adm_forced_command == NULL &&
auth_opts->permit_user_rc && options.permit_user_rc &&
stat(user_rc, &st) >= 0) {
if (xasprintf(&cmd, "%s -c '%s %s'", shell, _PATH_BSHELL,
user_rc) == -1)
fatal_f("xasprintf: %s", strerror(errno));
if (debug_flag)
fprintf(stderr, "Running %s\n", cmd);
f = popen(cmd, "w");
if (f) {
if (do_xauth)
fprintf(f, "%s %s\n", s->auth_proto,
s->auth_data);
pclose(f);
} else
fprintf(stderr, "Could not run %s\n",
user_rc);
} else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
if (debug_flag)
fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
_PATH_SSH_SYSTEM_RC);
f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");
if (f) {
if (do_xauth)
fprintf(f, "%s %s\n", s->auth_proto,
s->auth_data);
pclose(f);
} else
fprintf(stderr, "Could not run %s\n",
_PATH_SSH_SYSTEM_RC);
} else if (do_xauth && options.xauth_location != NULL) {
/* Add authority data to .Xauthority if appropriate. */
if (debug_flag) {
fprintf(stderr,
"Running %.500s remove %.100s\n",
options.xauth_location, s->auth_display);
fprintf(stderr,
"%.500s add %.100s %.100s %.100s\n",
options.xauth_location, s->auth_display,
s->auth_proto, s->auth_data);
}
if (xasprintf(&cmd, "%s -q -", options.xauth_location) == -1)
fatal_f("xasprintf: %s", strerror(errno));
f = popen(cmd, "w");
if (f) {
fprintf(f, "remove %s\n",
s->auth_display);
fprintf(f, "add %s %s %s\n",
s->auth_display, s->auth_proto,
s->auth_data);
pclose(f);
} else {
fprintf(stderr, "Could not run %s\n",
cmd);
}
}
free(cmd);
free(user_rc);
}
static void
do_nologin(struct passwd *pw)
{
FILE *f = NULL;
char buf[1024], *nl, *def_nl = _PATH_NOLOGIN;
struct stat sb;
#ifdef HAVE_LOGIN_CAP
if (login_getcapbool(lc, "ignorenologin", 0) || pw->pw_uid == 0)
return;
nl = login_getcapstr(lc, "nologin", def_nl, def_nl);
#else
if (pw->pw_uid == 0)
return;
nl = def_nl;
#endif
if (stat(nl, &sb) == -1)
return;
/* /etc/nologin exists. Print its contents if we can and exit. */
logit("User %.100s not allowed because %s exists", pw->pw_name, nl);
if ((f = fopen(nl, "r")) != NULL) {
while (fgets(buf, sizeof(buf), f))
fputs(buf, stderr);
fclose(f);
}
exit(254);
}
/*
* Chroot into a directory after checking it for safety: all path components
* must be root-owned directories with strict permissions.
*/
static void
safely_chroot(const char *path, uid_t uid)
{
const char *cp;
char component[PATH_MAX];
struct stat st;
if (!path_absolute(path))
fatal("chroot path does not begin at root");
if (strlen(path) >= sizeof(component))
fatal("chroot path too long");
/*
* Descend the path, checking that each component is a
* root-owned directory with strict permissions.
*/
for (cp = path; cp != NULL;) {
if ((cp = strchr(cp, '/')) == NULL)
strlcpy(component, path, sizeof(component));
else {
cp++;
memcpy(component, path, cp - path);
component[cp - path] = '\0';
}
debug3_f("checking '%s'", component);
if (stat(component, &st) != 0)
fatal_f("stat(\"%s\"): %s",
component, strerror(errno));
if (st.st_uid != 0 || (st.st_mode & 022) != 0)
fatal("bad ownership or modes for chroot "
"directory %s\"%s\"",
cp == NULL ? "" : "component ", component);
if (!S_ISDIR(st.st_mode))
fatal("chroot path %s\"%s\" is not a directory",
cp == NULL ? "" : "component ", component);
}
if (chdir(path) == -1)
fatal("Unable to chdir to chroot path \"%s\": "
"%s", path, strerror(errno));
if (chroot(path) == -1)
fatal("chroot(\"%s\"): %s", path, strerror(errno));
if (chdir("/") == -1)
fatal_f("chdir(/) after chroot: %s", strerror(errno));
verbose("Changed root directory to \"%s\"", path);
}
/* Set login name, uid, gid, and groups. */
void
do_setusercontext(struct passwd *pw)
{
char uidstr[32], *chroot_path, *tmp;
platform_setusercontext(pw);
if (platform_privileged_uidswap()) {
#ifdef HAVE_LOGIN_CAP
if (setusercontext(lc, pw, pw->pw_uid,
(LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) {
perror("unable to set user context");
exit(1);
}
#else
if (setlogin(pw->pw_name) < 0)
error("setlogin failed: %s", strerror(errno));
if (setgid(pw->pw_gid) < 0) {
perror("setgid");
exit(1);
}
/* Initialize the group list. */
if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
perror("initgroups");
exit(1);
}
endgrent();
#endif
platform_setusercontext_post_groups(pw);
if (!in_chroot && options.chroot_directory != NULL &&
strcasecmp(options.chroot_directory, "none") != 0) {
- tmp = tilde_expand_filename(options.chroot_directory,
+ tmp = tilde_expand_filename(options.chroot_directory,
pw->pw_uid);
snprintf(uidstr, sizeof(uidstr), "%llu",
(unsigned long long)pw->pw_uid);
chroot_path = percent_expand(tmp, "h", pw->pw_dir,
"u", pw->pw_name, "U", uidstr, (char *)NULL);
safely_chroot(chroot_path, pw->pw_uid);
free(tmp);
free(chroot_path);
/* Make sure we don't attempt to chroot again */
free(options.chroot_directory);
options.chroot_directory = NULL;
in_chroot = 1;
}
#ifdef HAVE_LOGIN_CAP
if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) {
perror("unable to set user context (setuser)");
exit(1);
}
/*
* FreeBSD's setusercontext() will not apply the user's
* own umask setting unless running with the user's UID.
*/
(void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUMASK);
#else
# ifdef USE_LIBIAF
/*
* In a chroot environment, the set_id() will always fail;
* typically because of the lack of necessary authentication
* services and runtime such as ./usr/lib/libiaf.so,
* ./usr/lib/libpam.so.1, and ./etc/passwd We skip it in the
* internal sftp chroot case. We'll lose auditing and ACLs but
* permanently_set_uid will take care of the rest.
*/
if (!in_chroot && set_id(pw->pw_name) != 0)
fatal("set_id(%s) Failed", pw->pw_name);
# endif /* USE_LIBIAF */
/* Permanently switch to the desired uid. */
permanently_set_uid(pw);
#endif
} else if (options.chroot_directory != NULL &&
strcasecmp(options.chroot_directory, "none") != 0) {
fatal("server lacks privileges to chroot to ChrootDirectory");
}
if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
}
static void
do_pwchange(Session *s)
{
fflush(NULL);
fprintf(stderr, "WARNING: Your password has expired.\n");
if (s->ttyfd != -1) {
fprintf(stderr,
"You must change your password now and login again!\n");
#ifdef WITH_SELINUX
setexeccon(NULL);
#endif
#ifdef PASSWD_NEEDS_USERNAME
execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name,
(char *)NULL);
#else
execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL);
#endif
perror("passwd");
} else {
fprintf(stderr,
"Password change required but no TTY available.\n");
}
exit(1);
}
static void
child_close_fds(struct ssh *ssh)
{
extern int auth_sock;
if (auth_sock != -1) {
close(auth_sock);
auth_sock = -1;
}
if (ssh_packet_get_connection_in(ssh) ==
ssh_packet_get_connection_out(ssh))
close(ssh_packet_get_connection_in(ssh));
else {
close(ssh_packet_get_connection_in(ssh));
close(ssh_packet_get_connection_out(ssh));
}
/*
* Close all descriptors related to channels. They will still remain
* open in the parent.
*/
/* XXX better use close-on-exec? -markus */
channel_close_all(ssh);
/*
* Close any extra file descriptors. Note that there may still be
* descriptors left by system functions. They will be closed later.
*/
endpwent();
/* Stop directing logs to a high-numbered fd before we close it */
log_redirect_stderr_to(NULL);
/*
* Close any extra open file descriptors so that we don't have them
* hanging around in clients. Note that we want to do this after
* initgroups, because at least on Solaris 2.3 it leaves file
* descriptors open.
*/
closefrom(STDERR_FILENO + 1);
}
/*
* Performs common processing for the child, such as setting up the
* environment, closing extra file descriptors, setting the user and group
* ids, and executing the command or shell.
*/
#define ARGV_MAX 10
void
do_child(struct ssh *ssh, Session *s, const char *command)
{
extern char **environ;
char **env, *argv[ARGV_MAX], remote_id[512];
const char *shell, *shell0;
struct passwd *pw = s->pw;
int r = 0;
sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
/* remove hostkey from the child's memory */
destroy_sensitive_data();
ssh_packet_clear_keys(ssh);
/* Force a password change */
if (s->authctxt->force_pwchange) {
do_setusercontext(pw);
child_close_fds(ssh);
do_pwchange(s);
exit(1);
}
/*
* Login(1) does this as well, and it needs uid 0 for the "-h"
* switch, so we let login(1) to this for us.
*/
#ifdef HAVE_OSF_SIA
session_setup_sia(pw, s->ttyfd == -1 ? NULL : s->tty);
if (!check_quietlogin(s, command))
do_motd();
#else /* HAVE_OSF_SIA */
/* When PAM is enabled we rely on it to do the nologin check */
if (!options.use_pam)
do_nologin(pw);
do_setusercontext(pw);
/*
* PAM session modules in do_setusercontext may have
* generated messages, so if this in an interactive
* login then display them too.
*/
if (!check_quietlogin(s, command))
display_loginmsg();
#endif /* HAVE_OSF_SIA */
#ifdef USE_PAM
if (options.use_pam && !is_pam_session_open()) {
debug3("PAM session not opened, exiting");
display_loginmsg();
exit(254);
}
#endif
/*
* Get the shell from the password data. An empty shell field is
* legal, and means /bin/sh.
*/
shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
/*
* Make sure $SHELL points to the shell from the password file,
* even if shell is overridden from login.conf
*/
env = do_setup_env(ssh, s, shell);
#ifdef HAVE_LOGIN_CAP
shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
#endif
/*
* Close the connection descriptors; note that this is the child, and
* the server will still have the socket open, and it is important
* that we do not shutdown it. Note that the descriptors cannot be
* closed before building the environment, as we call
* ssh_remote_ipaddr there.
*/
child_close_fds(ssh);
/*
* Must take new environment into use so that .ssh/rc,
* /etc/ssh/sshrc and xauth are run in the proper environment.
*/
environ = env;
#if defined(KRB5) && defined(USE_AFS)
/*
* At this point, we check to see if AFS is active and if we have
* a valid Kerberos 5 TGT. If so, it seems like a good idea to see
* if we can (and need to) extend the ticket into an AFS token. If
* we don't do this, we run into potential problems if the user's
* home directory is in AFS and it's not world-readable.
*/
if (options.kerberos_get_afs_token && k_hasafs() &&
(s->authctxt->krb5_ctx != NULL)) {
char cell[64];
debug("Getting AFS token");
k_setpag();
if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
krb5_afslog(s->authctxt->krb5_ctx,
s->authctxt->krb5_fwd_ccache, cell, NULL);
krb5_afslog_home(s->authctxt->krb5_ctx,
s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir);
}
#endif
/* Change current directory to the user's home directory. */
if (chdir(pw->pw_dir) == -1) {
/* Suppress missing homedir warning for chroot case */
#ifdef HAVE_LOGIN_CAP
r = login_getcapbool(lc, "requirehome", 0);
#endif
if (r || !in_chroot) {
fprintf(stderr, "Could not chdir to home "
"directory %s: %s\n", pw->pw_dir,
strerror(errno));
}
if (r)
exit(1);
}
closefrom(STDERR_FILENO + 1);
do_rc_files(ssh, s, shell);
/* restore SIGPIPE for child */
ssh_signal(SIGPIPE, SIG_DFL);
if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) {
error("Connection from %s: refusing non-sftp session",
remote_id);
printf("This service allows sftp connections only.\n");
fflush(NULL);
exit(1);
} else if (s->is_subsystem == SUBSYSTEM_INT_SFTP) {
extern int optind, optreset;
int i;
char *p, *args;
setproctitle("%s@%s", s->pw->pw_name, INTERNAL_SFTP_NAME);
args = xstrdup(command ? command : "sftp-server");
for (i = 0, (p = strtok(args, " ")); p; (p = strtok(NULL, " ")))
if (i < ARGV_MAX - 1)
argv[i++] = p;
argv[i] = NULL;
optind = optreset = 1;
__progname = argv[0];
#ifdef WITH_SELINUX
ssh_selinux_change_context("sftpd_t");
#endif
exit(sftp_server_main(i, argv, s->pw));
}
fflush(NULL);
/* Get the last component of the shell name. */
if ((shell0 = strrchr(shell, '/')) != NULL)
shell0++;
else
shell0 = shell;
/*
* If we have no command, execute the shell. In this case, the shell
* name to be passed in argv[0] is preceded by '-' to indicate that
* this is a login shell.
*/
if (!command) {
char argv0[256];
/* Start the shell. Set initial character to '-'. */
argv0[0] = '-';
if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1)
>= sizeof(argv0) - 1) {
errno = EINVAL;
perror(shell);
exit(1);
}
/* Execute the shell. */
argv[0] = argv0;
argv[1] = NULL;
execve(shell, argv, env);
/* Executing the shell failed. */
perror(shell);
exit(1);
}
/*
* Execute the command using the user's shell. This uses the -c
* option to execute the command.
*/
argv[0] = (char *) shell0;
argv[1] = "-c";
argv[2] = (char *) command;
argv[3] = NULL;
execve(shell, argv, env);
perror(shell);
exit(1);
}
void
session_unused(int id)
{
debug3_f("session id %d unused", id);
if (id >= options.max_sessions ||
id >= sessions_nalloc) {
fatal_f("insane session id %d (max %d nalloc %d)",
id, options.max_sessions, sessions_nalloc);
}
memset(&sessions[id], 0, sizeof(*sessions));
sessions[id].self = id;
sessions[id].used = 0;
sessions[id].chanid = -1;
sessions[id].ptyfd = -1;
sessions[id].ttyfd = -1;
sessions[id].ptymaster = -1;
sessions[id].x11_chanids = NULL;
sessions[id].next_unused = sessions_first_unused;
sessions_first_unused = id;
}
Session *
session_new(void)
{
Session *s, *tmp;
if (sessions_first_unused == -1) {
if (sessions_nalloc >= options.max_sessions)
return NULL;
debug2_f("allocate (allocated %d max %d)",
sessions_nalloc, options.max_sessions);
tmp = xrecallocarray(sessions, sessions_nalloc,
sessions_nalloc + 1, sizeof(*sessions));
if (tmp == NULL) {
error_f("cannot allocate %d sessions",
sessions_nalloc + 1);
return NULL;
}
sessions = tmp;
session_unused(sessions_nalloc++);
}
if (sessions_first_unused >= sessions_nalloc ||
sessions_first_unused < 0) {
fatal_f("insane first_unused %d max %d nalloc %d",
sessions_first_unused, options.max_sessions,
sessions_nalloc);
}
s = &sessions[sessions_first_unused];
if (s->used)
fatal_f("session %d already used", sessions_first_unused);
sessions_first_unused = s->next_unused;
s->used = 1;
s->next_unused = -1;
debug("session_new: session %d", s->self);
return s;
}
static void
session_dump(void)
{
int i;
for (i = 0; i < sessions_nalloc; i++) {
Session *s = &sessions[i];
debug("dump: used %d next_unused %d session %d %p "
"channel %d pid %ld",
s->used,
s->next_unused,
s->self,
s,
s->chanid,
(long)s->pid);
}
}
int
session_open(Authctxt *authctxt, int chanid)
{
Session *s = session_new();
debug("session_open: channel %d", chanid);
if (s == NULL) {
error("no more sessions");
return 0;
}
s->authctxt = authctxt;
s->pw = authctxt->pw;
if (s->pw == NULL || !authctxt->valid)
fatal("no user for session %d", s->self);
debug("session_open: session %d: link with channel %d", s->self, chanid);
s->chanid = chanid;
return 1;
}
Session *
session_by_tty(char *tty)
{
int i;
for (i = 0; i < sessions_nalloc; i++) {
Session *s = &sessions[i];
if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
debug("session_by_tty: session %d tty %s", i, tty);
return s;
}
}
debug("session_by_tty: unknown tty %.100s", tty);
session_dump();
return NULL;
}
static Session *
session_by_channel(int id)
{
int i;
for (i = 0; i < sessions_nalloc; i++) {
Session *s = &sessions[i];
if (s->used && s->chanid == id) {
debug("session_by_channel: session %d channel %d",
i, id);
return s;
}
}
debug("session_by_channel: unknown channel %d", id);
session_dump();
return NULL;
}
static Session *
session_by_x11_channel(int id)
{
int i, j;
for (i = 0; i < sessions_nalloc; i++) {
Session *s = &sessions[i];
if (s->x11_chanids == NULL || !s->used)
continue;
for (j = 0; s->x11_chanids[j] != -1; j++) {
if (s->x11_chanids[j] == id) {
debug("session_by_x11_channel: session %d "
"channel %d", s->self, id);
return s;
}
}
}
debug("session_by_x11_channel: unknown channel %d", id);
session_dump();
return NULL;
}
static Session *
session_by_pid(pid_t pid)
{
int i;
debug("session_by_pid: pid %ld", (long)pid);
for (i = 0; i < sessions_nalloc; i++) {
Session *s = &sessions[i];
if (s->used && s->pid == pid)
return s;
}
error("session_by_pid: unknown pid %ld", (long)pid);
session_dump();
return NULL;
}
static int
session_window_change_req(struct ssh *ssh, Session *s)
{
int r;
if ((r = sshpkt_get_u32(ssh, &s->col)) != 0 ||
(r = sshpkt_get_u32(ssh, &s->row)) != 0 ||
(r = sshpkt_get_u32(ssh, &s->xpixel)) != 0 ||
(r = sshpkt_get_u32(ssh, &s->ypixel)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
return 1;
}
static int
session_pty_req(struct ssh *ssh, Session *s)
{
int r;
if (!auth_opts->permit_pty_flag || !options.permit_tty) {
debug("Allocating a pty not permitted for this connection.");
return 0;
}
if (s->ttyfd != -1) {
ssh_packet_disconnect(ssh, "Protocol error: you already have a pty.");
return 0;
}
if ((r = sshpkt_get_cstring(ssh, &s->term, NULL)) != 0 ||
(r = sshpkt_get_u32(ssh, &s->col)) != 0 ||
(r = sshpkt_get_u32(ssh, &s->row)) != 0 ||
(r = sshpkt_get_u32(ssh, &s->xpixel)) != 0 ||
(r = sshpkt_get_u32(ssh, &s->ypixel)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
if (strcmp(s->term, "") == 0) {
free(s->term);
s->term = NULL;
}
/* Allocate a pty and open it. */
debug("Allocating pty.");
if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
sizeof(s->tty)))) {
free(s->term);
s->term = NULL;
s->ptyfd = -1;
s->ttyfd = -1;
error("session_pty_req: session %d alloc failed", s->self);
return 0;
}
debug("session_pty_req: session %d alloc %s", s->self, s->tty);
ssh_tty_parse_modes(ssh, s->ttyfd);
if ((r = sshpkt_get_end(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
if (!use_privsep)
pty_setowner(s->pw, s->tty);
/* Set window size from the packet. */
pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
session_proctitle(s);
return 1;
}
static int
session_subsystem_req(struct ssh *ssh, Session *s)
{
struct stat st;
int r, success = 0;
char *prog, *cmd;
u_int i;
if ((r = sshpkt_get_cstring(ssh, &s->subsys, NULL)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
debug2("subsystem request for %.100s by user %s", s->subsys,
s->pw->pw_name);
for (i = 0; i < options.num_subsystems; i++) {
if (strcmp(s->subsys, options.subsystem_name[i]) == 0) {
prog = options.subsystem_command[i];
cmd = options.subsystem_args[i];
if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) {
s->is_subsystem = SUBSYSTEM_INT_SFTP;
debug("subsystem: %s", prog);
} else {
if (stat(prog, &st) == -1)
debug("subsystem: cannot stat %s: %s",
prog, strerror(errno));
s->is_subsystem = SUBSYSTEM_EXT;
debug("subsystem: exec() %s", cmd);
}
success = do_exec(ssh, s, cmd) == 0;
break;
}
}
if (!success)
logit("subsystem request for %.100s by user %s failed, "
"subsystem not found", s->subsys, s->pw->pw_name);
return success;
}
static int
session_x11_req(struct ssh *ssh, Session *s)
{
int r, success;
u_char single_connection = 0;
if (s->auth_proto != NULL || s->auth_data != NULL) {
error("session_x11_req: session %d: "
"x11 forwarding already active", s->self);
return 0;
}
if ((r = sshpkt_get_u8(ssh, &single_connection)) != 0 ||
(r = sshpkt_get_cstring(ssh, &s->auth_proto, NULL)) != 0 ||
(r = sshpkt_get_cstring(ssh, &s->auth_data, NULL)) != 0 ||
(r = sshpkt_get_u32(ssh, &s->screen)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
s->single_connection = single_connection;
if (xauth_valid_string(s->auth_proto) &&
xauth_valid_string(s->auth_data))
success = session_setup_x11fwd(ssh, s);
else {
success = 0;
error("Invalid X11 forwarding data");
}
if (!success) {
free(s->auth_proto);
free(s->auth_data);
s->auth_proto = NULL;
s->auth_data = NULL;
}
return success;
}
static int
session_shell_req(struct ssh *ssh, Session *s)
{
int r;
if ((r = sshpkt_get_end(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
return do_exec(ssh, s, NULL) == 0;
}
static int
session_exec_req(struct ssh *ssh, Session *s)
{
u_int success;
int r;
char *command = NULL;
if ((r = sshpkt_get_cstring(ssh, &command, NULL)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
success = do_exec(ssh, s, command) == 0;
free(command);
return success;
}
static int
session_break_req(struct ssh *ssh, Session *s)
{
int r;
if ((r = sshpkt_get_u32(ssh, NULL)) != 0 || /* ignore */
(r = sshpkt_get_end(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
if (s->ptymaster == -1 || tcsendbreak(s->ptymaster, 0) == -1)
return 0;
return 1;
}
static int
session_env_req(struct ssh *ssh, Session *s)
{
char *name, *val;
u_int i;
int r;
if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0 ||
(r = sshpkt_get_cstring(ssh, &val, NULL)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
/* Don't set too many environment variables */
if (s->num_env > 128) {
debug2("Ignoring env request %s: too many env vars", name);
goto fail;
}
for (i = 0; i < options.num_accept_env; i++) {
if (match_pattern(name, options.accept_env[i])) {
debug2("Setting env %d: %s=%s", s->num_env, name, val);
s->env = xrecallocarray(s->env, s->num_env,
s->num_env + 1, sizeof(*s->env));
s->env[s->num_env].name = name;
s->env[s->num_env].val = val;
s->num_env++;
return (1);
}
}
debug2("Ignoring env request %s: disallowed name", name);
fail:
free(name);
free(val);
return (0);
}
/*
* Conversion of signals from ssh channel request names.
* Subset of signals from RFC 4254 section 6.10C, with SIGINFO as
* local extension.
*/
static int
name2sig(char *name)
{
#define SSH_SIG(x) if (strcmp(name, #x) == 0) return SIG ## x
SSH_SIG(HUP);
SSH_SIG(INT);
SSH_SIG(KILL);
SSH_SIG(QUIT);
SSH_SIG(TERM);
SSH_SIG(USR1);
SSH_SIG(USR2);
#undef SSH_SIG
#ifdef SIGINFO
if (strcmp(name, "INFO@openssh.com") == 0)
return SIGINFO;
#endif
return -1;
}
static int
session_signal_req(struct ssh *ssh, Session *s)
{
char *signame = NULL;
int r, sig, success = 0;
if ((r = sshpkt_get_cstring(ssh, &signame, NULL)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0) {
error_fr(r, "parse");
goto out;
}
if ((sig = name2sig(signame)) == -1) {
error_f("unsupported signal \"%s\"", signame);
goto out;
}
if (s->pid <= 0) {
error_f("no pid for session %d", s->self);
goto out;
}
if (s->forced || s->is_subsystem) {
error_f("refusing to send signal %s to %s session",
signame, s->forced ? "forced-command" : "subsystem");
goto out;
}
if (!use_privsep || mm_is_monitor()) {
error_f("session signalling requires privilege separation");
goto out;
}
debug_f("signal %s, killpg(%ld, %d)", signame, (long)s->pid, sig);
temporarily_use_uid(s->pw);
r = killpg(s->pid, sig);
restore_uid();
if (r != 0) {
error_f("killpg(%ld, %d): %s", (long)s->pid,
sig, strerror(errno));
goto out;
}
/* success */
success = 1;
out:
free(signame);
return success;
}
static int
session_auth_agent_req(struct ssh *ssh, Session *s)
{
static int called = 0;
int r;
if ((r = sshpkt_get_end(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
if (!auth_opts->permit_agent_forwarding_flag ||
!options.allow_agent_forwarding) {
debug_f("agent forwarding disabled");
return 0;
}
if (called) {
return 0;
} else {
called = 1;
return auth_input_request_forwarding(ssh, s->pw);
}
}
int
session_input_channel_req(struct ssh *ssh, Channel *c, const char *rtype)
{
int success = 0;
Session *s;
if ((s = session_by_channel(c->self)) == NULL) {
logit_f("no session %d req %.100s", c->self, rtype);
return 0;
}
debug_f("session %d req %s", s->self, rtype);
/*
* a session is in LARVAL state until a shell, a command
* or a subsystem is executed
*/
if (c->type == SSH_CHANNEL_LARVAL) {
if (strcmp(rtype, "shell") == 0) {
success = session_shell_req(ssh, s);
} else if (strcmp(rtype, "exec") == 0) {
success = session_exec_req(ssh, s);
} else if (strcmp(rtype, "pty-req") == 0) {
success = session_pty_req(ssh, s);
} else if (strcmp(rtype, "x11-req") == 0) {
success = session_x11_req(ssh, s);
} else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) {
success = session_auth_agent_req(ssh, s);
} else if (strcmp(rtype, "subsystem") == 0) {
success = session_subsystem_req(ssh, s);
} else if (strcmp(rtype, "env") == 0) {
success = session_env_req(ssh, s);
}
}
if (strcmp(rtype, "window-change") == 0) {
success = session_window_change_req(ssh, s);
} else if (strcmp(rtype, "break") == 0) {
success = session_break_req(ssh, s);
} else if (strcmp(rtype, "signal") == 0) {
success = session_signal_req(ssh, s);
}
return success;
}
void
session_set_fds(struct ssh *ssh, Session *s,
int fdin, int fdout, int fderr, int ignore_fderr, int is_tty)
{
/*
* now that have a child and a pipe to the child,
* we can activate our channel and register the fd's
*/
if (s->chanid == -1)
fatal("no channel for session %d", s->self);
channel_set_fds(ssh, s->chanid,
fdout, fdin, fderr,
ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
1, is_tty, CHAN_SES_WINDOW_DEFAULT);
}
/*
* Function to perform pty cleanup. Also called if we get aborted abnormally
* (e.g., due to a dropped connection).
*/
void
session_pty_cleanup2(Session *s)
{
if (s == NULL) {
error_f("no session");
return;
}
if (s->ttyfd == -1)
return;
debug_f("session %d release %s", s->self, s->tty);
/* Record that the user has logged out. */
if (s->pid != 0)
record_logout(s->pid, s->tty, s->pw->pw_name);
/* Release the pseudo-tty. */
if (getuid() == 0)
pty_release(s->tty);
/*
* Close the server side of the socket pairs. We must do this after
* the pty cleanup, so that another process doesn't get this pty
* while we're still cleaning up.
*/
if (s->ptymaster != -1 && close(s->ptymaster) == -1)
error("close(s->ptymaster/%d): %s",
s->ptymaster, strerror(errno));
/* unlink pty from session */
s->ttyfd = -1;
}
void
session_pty_cleanup(Session *s)
{
PRIVSEP(session_pty_cleanup2(s));
}
static char *
sig2name(int sig)
{
#define SSH_SIG(x) if (sig == SIG ## x) return #x
SSH_SIG(ABRT);
SSH_SIG(ALRM);
SSH_SIG(FPE);
SSH_SIG(HUP);
SSH_SIG(ILL);
SSH_SIG(INT);
SSH_SIG(KILL);
SSH_SIG(PIPE);
SSH_SIG(QUIT);
SSH_SIG(SEGV);
SSH_SIG(TERM);
SSH_SIG(USR1);
SSH_SIG(USR2);
#undef SSH_SIG
return "SIG@openssh.com";
}
static void
session_close_x11(struct ssh *ssh, int id)
{
Channel *c;
if ((c = channel_by_id(ssh, id)) == NULL) {
debug_f("x11 channel %d missing", id);
} else {
/* Detach X11 listener */
debug_f("detach x11 channel %d", id);
channel_cancel_cleanup(ssh, id);
if (c->ostate != CHAN_OUTPUT_CLOSED)
chan_mark_dead(ssh, c);
}
}
static void
session_close_single_x11(struct ssh *ssh, int id, void *arg)
{
Session *s;
u_int i;
debug3_f("channel %d", id);
channel_cancel_cleanup(ssh, id);
if ((s = session_by_x11_channel(id)) == NULL)
fatal_f("no x11 channel %d", id);
for (i = 0; s->x11_chanids[i] != -1; i++) {
debug_f("session %d: closing channel %d",
s->self, s->x11_chanids[i]);
/*
* The channel "id" is already closing, but make sure we
* close all of its siblings.
*/
if (s->x11_chanids[i] != id)
session_close_x11(ssh, s->x11_chanids[i]);
}
free(s->x11_chanids);
s->x11_chanids = NULL;
free(s->display);
s->display = NULL;
free(s->auth_proto);
s->auth_proto = NULL;
free(s->auth_data);
s->auth_data = NULL;
free(s->auth_display);
s->auth_display = NULL;
}
static void
session_exit_message(struct ssh *ssh, Session *s, int status)
{
Channel *c;
int r;
if ((c = channel_lookup(ssh, s->chanid)) == NULL)
fatal_f("session %d: no channel %d", s->self, s->chanid);
debug_f("session %d channel %d pid %ld",
s->self, s->chanid, (long)s->pid);
if (WIFEXITED(status)) {
channel_request_start(ssh, s->chanid, "exit-status", 0);
if ((r = sshpkt_put_u32(ssh, WEXITSTATUS(status))) != 0 ||
(r = sshpkt_send(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: exit reply", __func__);
} else if (WIFSIGNALED(status)) {
channel_request_start(ssh, s->chanid, "exit-signal", 0);
#ifndef WCOREDUMP
# define WCOREDUMP(x) (0)
#endif
if ((r = sshpkt_put_cstring(ssh, sig2name(WTERMSIG(status)))) != 0 ||
(r = sshpkt_put_u8(ssh, WCOREDUMP(status)? 1 : 0)) != 0 ||
(r = sshpkt_put_cstring(ssh, "")) != 0 ||
(r = sshpkt_put_cstring(ssh, "")) != 0 ||
(r = sshpkt_send(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: exit reply", __func__);
} else {
/* Some weird exit cause. Just exit. */
ssh_packet_disconnect(ssh, "wait returned status %04x.", status);
}
/* disconnect channel */
debug_f("release channel %d", s->chanid);
/*
* Adjust cleanup callback attachment to send close messages when
* the channel gets EOF. The session will be then be closed
* by session_close_by_channel when the child sessions close their fds.
*/
channel_register_cleanup(ssh, c->self, session_close_by_channel, 1);
/*
* emulate a write failure with 'chan_write_failed', nobody will be
* interested in data we write.
* Note that we must not call 'chan_read_failed', since there could
* be some more data waiting in the pipe.
*/
if (c->ostate != CHAN_OUTPUT_CLOSED)
chan_write_failed(ssh, c);
}
void
session_close(struct ssh *ssh, Session *s)
{
u_int i;
verbose("Close session: user %s from %.200s port %d id %d",
s->pw->pw_name,
ssh_remote_ipaddr(ssh),
ssh_remote_port(ssh),
s->self);
if (s->ttyfd != -1)
session_pty_cleanup(s);
free(s->term);
free(s->display);
free(s->x11_chanids);
free(s->auth_display);
free(s->auth_data);
free(s->auth_proto);
free(s->subsys);
if (s->env != NULL) {
for (i = 0; i < s->num_env; i++) {
free(s->env[i].name);
free(s->env[i].val);
}
free(s->env);
}
session_proctitle(s);
session_unused(s->self);
}
void
session_close_by_pid(struct ssh *ssh, pid_t pid, int status)
{
Session *s = session_by_pid(pid);
if (s == NULL) {
debug_f("no session for pid %ld", (long)pid);
return;
}
if (s->chanid != -1)
session_exit_message(ssh, s, status);
if (s->ttyfd != -1)
session_pty_cleanup(s);
s->pid = 0;
}
/*
* this is called when a channel dies before
* the session 'child' itself dies
*/
void
session_close_by_channel(struct ssh *ssh, int id, void *arg)
{
Session *s = session_by_channel(id);
u_int i;
if (s == NULL) {
debug_f("no session for id %d", id);
return;
}
debug_f("channel %d child %ld", id, (long)s->pid);
if (s->pid != 0) {
debug_f("channel %d: has child, ttyfd %d", id, s->ttyfd);
/*
* delay detach of session, but release pty, since
* the fd's to the child are already closed
*/
if (s->ttyfd != -1)
session_pty_cleanup(s);
return;
}
/* detach by removing callback */
channel_cancel_cleanup(ssh, s->chanid);
/* Close any X11 listeners associated with this session */
if (s->x11_chanids != NULL) {
for (i = 0; s->x11_chanids[i] != -1; i++) {
session_close_x11(ssh, s->x11_chanids[i]);
s->x11_chanids[i] = -1;
}
}
s->chanid = -1;
session_close(ssh, s);
}
void
session_destroy_all(struct ssh *ssh, void (*closefunc)(Session *))
{
int i;
for (i = 0; i < sessions_nalloc; i++) {
Session *s = &sessions[i];
if (s->used) {
if (closefunc != NULL)
closefunc(s);
else
session_close(ssh, s);
}
}
}
static char *
session_tty_list(void)
{
static char buf[1024];
int i;
char *cp;
buf[0] = '\0';
for (i = 0; i < sessions_nalloc; i++) {
Session *s = &sessions[i];
if (s->used && s->ttyfd != -1) {
if (strncmp(s->tty, "/dev/", 5) != 0) {
cp = strrchr(s->tty, '/');
cp = (cp == NULL) ? s->tty : cp + 1;
} else
cp = s->tty + 5;
if (buf[0] != '\0')
strlcat(buf, ",", sizeof buf);
strlcat(buf, cp, sizeof buf);
}
}
if (buf[0] == '\0')
strlcpy(buf, "notty", sizeof buf);
return buf;
}
void
session_proctitle(Session *s)
{
if (s->pw == NULL)
error("no user for session %d", s->self);
else
setproctitle("%s@%s", s->pw->pw_name, session_tty_list());
}
int
session_setup_x11fwd(struct ssh *ssh, Session *s)
{
struct stat st;
char display[512], auth_display[512];
char hostname[NI_MAXHOST];
u_int i;
if (!auth_opts->permit_x11_forwarding_flag) {
ssh_packet_send_debug(ssh, "X11 forwarding disabled by key options.");
return 0;
}
if (!options.x11_forwarding) {
debug("X11 forwarding disabled in server configuration file.");
return 0;
}
if (options.xauth_location == NULL ||
(stat(options.xauth_location, &st) == -1)) {
ssh_packet_send_debug(ssh, "No xauth program; cannot forward X11.");
return 0;
}
if (s->display != NULL) {
debug("X11 display already set.");
return 0;
}
if (x11_create_display_inet(ssh, options.x11_display_offset,
options.x11_use_localhost, s->single_connection,
&s->display_number, &s->x11_chanids) == -1) {
debug("x11_create_display_inet failed.");
return 0;
}
for (i = 0; s->x11_chanids[i] != -1; i++) {
channel_register_cleanup(ssh, s->x11_chanids[i],
session_close_single_x11, 0);
}
/* Set up a suitable value for the DISPLAY variable. */
if (gethostname(hostname, sizeof(hostname)) == -1)
fatal("gethostname: %.100s", strerror(errno));
/*
* auth_display must be used as the displayname when the
* authorization entry is added with xauth(1). This will be
* different than the DISPLAY string for localhost displays.
*/
if (options.x11_use_localhost) {
snprintf(display, sizeof display, "localhost:%u.%u",
s->display_number, s->screen);
snprintf(auth_display, sizeof auth_display, "unix:%u.%u",
s->display_number, s->screen);
s->display = xstrdup(display);
s->auth_display = xstrdup(auth_display);
} else {
#ifdef IPADDR_IN_DISPLAY
struct hostent *he;
struct in_addr my_addr;
he = gethostbyname(hostname);
if (he == NULL) {
error("Can't get IP address for X11 DISPLAY.");
ssh_packet_send_debug(ssh, "Can't get IP address for X11 DISPLAY.");
return 0;
}
memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr));
snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr),
s->display_number, s->screen);
#else
snprintf(display, sizeof display, "%.400s:%u.%u", hostname,
s->display_number, s->screen);
#endif
s->display = xstrdup(display);
s->auth_display = xstrdup(display);
}
return 1;
}
static void
do_authenticated2(struct ssh *ssh, Authctxt *authctxt)
{
server_loop2(ssh, authctxt);
}
void
do_cleanup(struct ssh *ssh, Authctxt *authctxt)
{
static int called = 0;
debug("do_cleanup");
/* no cleanup if we're in the child for login shell */
if (is_child)
return;
/* avoid double cleanup */
if (called)
return;
called = 1;
if (authctxt == NULL)
return;
#ifdef USE_PAM
if (options.use_pam) {
sshpam_cleanup();
sshpam_thread_cleanup();
}
#endif
if (!authctxt->authenticated)
return;
#ifdef KRB5
if (options.kerberos_ticket_cleanup &&
authctxt->krb5_ctx)
krb5_cleanup_proc(authctxt);
#endif
#ifdef GSSAPI
if (options.gss_cleanup_creds)
ssh_gssapi_cleanup_creds();
#endif
/* remove agent socket */
auth_sock_cleanup_proc(authctxt->pw);
/* remove userauth info */
if (auth_info_file != NULL) {
temporarily_use_uid(authctxt->pw);
unlink(auth_info_file);
restore_uid();
free(auth_info_file);
auth_info_file = NULL;
}
/*
* Cleanup ptys/utmp only if privsep is disabled,
* or if running in monitor.
*/
if (!use_privsep || mm_is_monitor())
session_destroy_all(ssh, session_pty_cleanup2);
}
/* Return a name for the remote host that fits inside utmp_size */
const char *
session_get_remote_name_or_ip(struct ssh *ssh, u_int utmp_size, int use_dns)
{
const char *remote = "";
if (utmp_size > 0)
remote = auth_get_canonical_hostname(ssh, use_dns);
if (utmp_size == 0 || strlen(remote) > utmp_size)
remote = ssh_remote_ipaddr(ssh);
return remote;
}
diff --git a/sftp-client.c b/sftp-client.c
index 4603b0098779..cadaee6bdaa2 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -1,2010 +1,2098 @@
-/* $OpenBSD: sftp-client.c,v 1.139 2020/12/04 02:41:10 djm Exp $ */
+/* $OpenBSD: sftp-client.c,v 1.142 2021/04/03 06:18:41 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* XXX: memleaks */
/* XXX: signed vs unsigned */
/* XXX: remove all logging, only return status codes */
/* XXX: copy between two remote sites */
#include "includes.h"
#include <sys/types.h>
#ifdef HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
#include "openbsd-compat/sys-queue.h"
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/uio.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "xmalloc.h"
#include "ssherr.h"
#include "sshbuf.h"
#include "log.h"
#include "atomicio.h"
#include "progressmeter.h"
#include "misc.h"
#include "utf8.h"
#include "sftp.h"
#include "sftp-common.h"
#include "sftp-client.h"
extern volatile sig_atomic_t interrupted;
extern int showprogress;
+/* Default size of buffer for up/download */
+#define DEFAULT_COPY_BUFLEN 32768
+
+/* Default number of concurrent outstanding requests */
+#define DEFAULT_NUM_REQUESTS 64
+
/* Minimum amount of data to read at a time */
#define MIN_READ_SIZE 512
/* Maximum depth to descend in directory trees */
#define MAX_DIR_DEPTH 64
/* Directory separator characters */
#ifdef HAVE_CYGWIN
# define SFTP_DIRECTORY_CHARS "/\\"
#else /* HAVE_CYGWIN */
# define SFTP_DIRECTORY_CHARS "/"
#endif /* HAVE_CYGWIN */
struct sftp_conn {
int fd_in;
int fd_out;
- u_int transfer_buflen;
+ u_int download_buflen;
+ u_int upload_buflen;
u_int num_requests;
u_int version;
u_int msg_id;
#define SFTP_EXT_POSIX_RENAME 0x00000001
#define SFTP_EXT_STATVFS 0x00000002
#define SFTP_EXT_FSTATVFS 0x00000004
#define SFTP_EXT_HARDLINK 0x00000008
#define SFTP_EXT_FSYNC 0x00000010
#define SFTP_EXT_LSETSTAT 0x00000020
+#define SFTP_EXT_LIMITS 0x00000040
u_int exts;
u_int64_t limit_kbps;
struct bwlimit bwlimit_in, bwlimit_out;
};
static u_char *
get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len,
const char *errfmt, ...) __attribute__((format(printf, 4, 5)));
/* ARGSUSED */
static int
sftpio(void *_bwlimit, size_t amount)
{
struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
refresh_progress_meter(0);
if (bwlimit != NULL)
bandwidth_limit(bwlimit, amount);
return 0;
}
static void
send_msg(struct sftp_conn *conn, struct sshbuf *m)
{
u_char mlen[4];
struct iovec iov[2];
if (sshbuf_len(m) > SFTP_MAX_MSG_LENGTH)
fatal("Outbound message too long %zu", sshbuf_len(m));
/* Send length first */
put_u32(mlen, sshbuf_len(m));
iov[0].iov_base = mlen;
iov[0].iov_len = sizeof(mlen);
iov[1].iov_base = (u_char *)sshbuf_ptr(m);
iov[1].iov_len = sshbuf_len(m);
if (atomiciov6(writev, conn->fd_out, iov, 2, sftpio,
conn->limit_kbps > 0 ? &conn->bwlimit_out : NULL) !=
sshbuf_len(m) + sizeof(mlen))
fatal("Couldn't send packet: %s", strerror(errno));
sshbuf_reset(m);
}
static void
get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial)
{
u_int msg_len;
u_char *p;
int r;
if ((r = sshbuf_reserve(m, 4, &p)) != 0)
fatal_fr(r, "reserve");
if (atomicio6(read, conn->fd_in, p, 4, sftpio,
conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) != 4) {
if (errno == EPIPE || errno == ECONNRESET)
fatal("Connection closed");
else
fatal("Couldn't read packet: %s", strerror(errno));
}
if ((r = sshbuf_get_u32(m, &msg_len)) != 0)
fatal_fr(r, "sshbuf_get_u32");
if (msg_len > SFTP_MAX_MSG_LENGTH) {
do_log2(initial ? SYSLOG_LEVEL_ERROR : SYSLOG_LEVEL_FATAL,
"Received message too long %u", msg_len);
fatal("Ensure the remote shell produces no output "
"for non-interactive sessions.");
}
if ((r = sshbuf_reserve(m, msg_len, &p)) != 0)
fatal_fr(r, "reserve");
if (atomicio6(read, conn->fd_in, p, msg_len, sftpio,
conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL)
!= msg_len) {
if (errno == EPIPE)
fatal("Connection closed");
else
fatal("Read packet: %s", strerror(errno));
}
}
static void
get_msg(struct sftp_conn *conn, struct sshbuf *m)
{
get_msg_extended(conn, m, 0);
}
static void
send_string_request(struct sftp_conn *conn, u_int id, u_int code, const char *s,
u_int len)
{
struct sshbuf *msg;
int r;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, code)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_string(msg, s, len)) != 0)
fatal_fr(r, "compose");
send_msg(conn, msg);
debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
sshbuf_free(msg);
}
static void
send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code,
const void *s, u_int len, Attrib *a)
{
struct sshbuf *msg;
int r;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, code)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_string(msg, s, len)) != 0 ||
(r = encode_attrib(msg, a)) != 0)
fatal_fr(r, "compose");
send_msg(conn, msg);
debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
sshbuf_free(msg);
}
static u_int
get_status(struct sftp_conn *conn, u_int expected_id)
{
struct sshbuf *msg;
u_char type;
u_int id, status;
int r;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
get_msg(conn, msg);
if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
(r = sshbuf_get_u32(msg, &id)) != 0)
fatal_fr(r, "compose");
if (id != expected_id)
fatal("ID mismatch (%u != %u)", id, expected_id);
if (type != SSH2_FXP_STATUS)
fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
SSH2_FXP_STATUS, type);
if ((r = sshbuf_get_u32(msg, &status)) != 0)
fatal_fr(r, "parse");
sshbuf_free(msg);
debug3("SSH2_FXP_STATUS %u", status);
return status;
}
static u_char *
get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len,
const char *errfmt, ...)
{
struct sshbuf *msg;
u_int id, status;
u_char type;
u_char *handle;
char errmsg[256];
va_list args;
int r;
va_start(args, errfmt);
if (errfmt != NULL)
vsnprintf(errmsg, sizeof(errmsg), errfmt, args);
va_end(args);
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
get_msg(conn, msg);
if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
(r = sshbuf_get_u32(msg, &id)) != 0)
fatal_fr(r, "parse");
if (id != expected_id)
fatal("%s: ID mismatch (%u != %u)",
errfmt == NULL ? __func__ : errmsg, id, expected_id);
if (type == SSH2_FXP_STATUS) {
if ((r = sshbuf_get_u32(msg, &status)) != 0)
fatal_fr(r, "parse status");
if (errfmt != NULL)
error("%s: %s", errmsg, fx2txt(status));
sshbuf_free(msg);
return(NULL);
} else if (type != SSH2_FXP_HANDLE)
fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u",
errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type);
if ((r = sshbuf_get_string(msg, &handle, len)) != 0)
fatal_fr(r, "parse handle");
sshbuf_free(msg);
return handle;
}
static Attrib *
get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet)
{
struct sshbuf *msg;
u_int id;
u_char type;
int r;
static Attrib a;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
get_msg(conn, msg);
if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
(r = sshbuf_get_u32(msg, &id)) != 0)
fatal_fr(r, "parse");
debug3("Received stat reply T:%u I:%u", type, id);
if (id != expected_id)
fatal("ID mismatch (%u != %u)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
u_int status;
if ((r = sshbuf_get_u32(msg, &status)) != 0)
fatal_fr(r, "parse status");
if (quiet)
debug("Couldn't stat remote file: %s", fx2txt(status));
else
error("Couldn't stat remote file: %s", fx2txt(status));
sshbuf_free(msg);
return(NULL);
} else if (type != SSH2_FXP_ATTRS) {
fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
SSH2_FXP_ATTRS, type);
}
if ((r = decode_attrib(msg, &a)) != 0) {
error_fr(r, "decode_attrib");
sshbuf_free(msg);
return NULL;
}
sshbuf_free(msg);
return &a;
}
static int
get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st,
u_int expected_id, int quiet)
{
struct sshbuf *msg;
u_char type;
u_int id;
u_int64_t flag;
int r;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
get_msg(conn, msg);
if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
(r = sshbuf_get_u32(msg, &id)) != 0)
fatal_fr(r, "parse");
debug3("Received statvfs reply T:%u I:%u", type, id);
if (id != expected_id)
fatal("ID mismatch (%u != %u)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
u_int status;
if ((r = sshbuf_get_u32(msg, &status)) != 0)
fatal_fr(r, "parse status");
if (quiet)
debug("Couldn't statvfs: %s", fx2txt(status));
else
error("Couldn't statvfs: %s", fx2txt(status));
sshbuf_free(msg);
return -1;
} else if (type != SSH2_FXP_EXTENDED_REPLY) {
fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
SSH2_FXP_EXTENDED_REPLY, type);
}
memset(st, 0, sizeof(*st));
if ((r = sshbuf_get_u64(msg, &st->f_bsize)) != 0 ||
(r = sshbuf_get_u64(msg, &st->f_frsize)) != 0 ||
(r = sshbuf_get_u64(msg, &st->f_blocks)) != 0 ||
(r = sshbuf_get_u64(msg, &st->f_bfree)) != 0 ||
(r = sshbuf_get_u64(msg, &st->f_bavail)) != 0 ||
(r = sshbuf_get_u64(msg, &st->f_files)) != 0 ||
(r = sshbuf_get_u64(msg, &st->f_ffree)) != 0 ||
(r = sshbuf_get_u64(msg, &st->f_favail)) != 0 ||
(r = sshbuf_get_u64(msg, &st->f_fsid)) != 0 ||
(r = sshbuf_get_u64(msg, &flag)) != 0 ||
(r = sshbuf_get_u64(msg, &st->f_namemax)) != 0)
fatal_fr(r, "parse statvfs");
st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;
sshbuf_free(msg);
return 0;
}
struct sftp_conn *
do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
u_int64_t limit_kbps)
{
u_char type;
struct sshbuf *msg;
struct sftp_conn *ret;
int r;
ret = xcalloc(1, sizeof(*ret));
ret->msg_id = 1;
ret->fd_in = fd_in;
ret->fd_out = fd_out;
- ret->transfer_buflen = transfer_buflen;
- ret->num_requests = num_requests;
+ ret->download_buflen = ret->upload_buflen =
+ transfer_buflen ? transfer_buflen : DEFAULT_COPY_BUFLEN;
+ ret->num_requests =
+ num_requests ? num_requests : DEFAULT_NUM_REQUESTS;
ret->exts = 0;
ret->limit_kbps = 0;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, SSH2_FXP_INIT)) != 0 ||
(r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0)
fatal_fr(r, "parse");
send_msg(ret, msg);
- sshbuf_reset(msg);
-
get_msg_extended(ret, msg, 1);
/* Expecting a VERSION reply */
if ((r = sshbuf_get_u8(msg, &type)) != 0)
fatal_fr(r, "parse type");
if (type != SSH2_FXP_VERSION) {
error("Invalid packet back from SSH2_FXP_INIT (type %u)",
type);
sshbuf_free(msg);
free(ret);
return(NULL);
}
if ((r = sshbuf_get_u32(msg, &ret->version)) != 0)
fatal_fr(r, "parse version");
debug2("Remote version: %u", ret->version);
/* Check for extensions */
while (sshbuf_len(msg) > 0) {
char *name;
u_char *value;
size_t vlen;
int known = 0;
if ((r = sshbuf_get_cstring(msg, &name, NULL)) != 0 ||
(r = sshbuf_get_string(msg, &value, &vlen)) != 0)
fatal_fr(r, "parse extension");
if (strcmp(name, "posix-rename@openssh.com") == 0 &&
strcmp((char *)value, "1") == 0) {
ret->exts |= SFTP_EXT_POSIX_RENAME;
known = 1;
} else if (strcmp(name, "statvfs@openssh.com") == 0 &&
strcmp((char *)value, "2") == 0) {
ret->exts |= SFTP_EXT_STATVFS;
known = 1;
} else if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
strcmp((char *)value, "2") == 0) {
ret->exts |= SFTP_EXT_FSTATVFS;
known = 1;
} else if (strcmp(name, "hardlink@openssh.com") == 0 &&
strcmp((char *)value, "1") == 0) {
ret->exts |= SFTP_EXT_HARDLINK;
known = 1;
} else if (strcmp(name, "fsync@openssh.com") == 0 &&
strcmp((char *)value, "1") == 0) {
ret->exts |= SFTP_EXT_FSYNC;
known = 1;
} else if (strcmp(name, "lsetstat@openssh.com") == 0 &&
strcmp((char *)value, "1") == 0) {
ret->exts |= SFTP_EXT_LSETSTAT;
known = 1;
+ } else if (strcmp(name, "limits@openssh.com") == 0 &&
+ strcmp((char *)value, "1") == 0) {
+ ret->exts |= SFTP_EXT_LIMITS;
+ known = 1;
}
if (known) {
debug2("Server supports extension \"%s\" revision %s",
name, value);
} else {
debug2("Unrecognised server extension \"%s\"", name);
}
free(name);
free(value);
}
sshbuf_free(msg);
+ /* Query the server for its limits */
+ if (ret->exts & SFTP_EXT_LIMITS) {
+ struct sftp_limits limits;
+ if (do_limits(ret, &limits) != 0)
+ fatal_f("limits failed");
+
+ /* If the caller did not specify, find a good value */
+ if (transfer_buflen == 0) {
+ ret->download_buflen = limits.read_length;
+ ret->upload_buflen = limits.write_length;
+ debug("Using server download size %u", ret->download_buflen);
+ debug("Using server upload size %u", ret->upload_buflen);
+ }
+
+ /* Use the server limit to scale down our value only */
+ if (num_requests == 0 && limits.open_handles) {
+ ret->num_requests =
+ MINIMUM(DEFAULT_NUM_REQUESTS, limits.open_handles);
+ debug("Server handle limit %llu; using %u",
+ (unsigned long long)limits.open_handles,
+ ret->num_requests);
+ }
+ }
+
/* Some filexfer v.0 servers don't support large packets */
- if (ret->version == 0)
- ret->transfer_buflen = MINIMUM(ret->transfer_buflen, 20480);
+ if (ret->version == 0) {
+ ret->download_buflen = MINIMUM(ret->download_buflen, 20480);
+ ret->upload_buflen = MINIMUM(ret->upload_buflen, 20480);
+ }
ret->limit_kbps = limit_kbps;
if (ret->limit_kbps > 0) {
bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps,
- ret->transfer_buflen);
+ ret->download_buflen);
bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps,
- ret->transfer_buflen);
+ ret->upload_buflen);
}
return ret;
}
u_int
sftp_proto_version(struct sftp_conn *conn)
{
return conn->version;
}
+int
+do_limits(struct sftp_conn *conn, struct sftp_limits *limits)
+{
+ u_int id, msg_id;
+ u_char type;
+ struct sshbuf *msg;
+ int r;
+
+ if ((conn->exts & SFTP_EXT_LIMITS) == 0) {
+ error("Server does not support limits@openssh.com extension");
+ return -1;
+ }
+
+ if ((msg = sshbuf_new()) == NULL)
+ fatal_f("sshbuf_new failed");
+
+ id = conn->msg_id++;
+ if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
+ (r = sshbuf_put_u32(msg, id)) != 0 ||
+ (r = sshbuf_put_cstring(msg, "limits@openssh.com")) != 0)
+ fatal_fr(r, "compose");
+ send_msg(conn, msg);
+ debug3("Sent message limits@openssh.com I:%u", id);
+
+ get_msg(conn, msg);
+
+ if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
+ (r = sshbuf_get_u32(msg, &msg_id)) != 0)
+ fatal_fr(r, "parse");
+
+ debug3("Received limits reply T:%u I:%u", type, msg_id);
+ if (id != msg_id)
+ fatal("ID mismatch (%u != %u)", msg_id, id);
+ if (type != SSH2_FXP_EXTENDED_REPLY) {
+ fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
+ SSH2_FXP_EXTENDED_REPLY, type);
+ }
+
+ memset(limits, 0, sizeof(*limits));
+ if ((r = sshbuf_get_u64(msg, &limits->packet_length)) != 0 ||
+ (r = sshbuf_get_u64(msg, &limits->read_length)) != 0 ||
+ (r = sshbuf_get_u64(msg, &limits->write_length)) != 0 ||
+ (r = sshbuf_get_u64(msg, &limits->open_handles)) != 0)
+ fatal_fr(r, "parse limits");
+
+ sshbuf_free(msg);
+
+ return 0;
+}
+
int
do_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len)
{
u_int id, status;
struct sshbuf *msg;
int r;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
id = conn->msg_id++;
if ((r = sshbuf_put_u8(msg, SSH2_FXP_CLOSE)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_string(msg, handle, handle_len)) != 0)
fatal_fr(r, "parse");
send_msg(conn, msg);
debug3("Sent message SSH2_FXP_CLOSE I:%u", id);
status = get_status(conn, id);
if (status != SSH2_FX_OK)
error("Couldn't close file: %s", fx2txt(status));
sshbuf_free(msg);
return status == SSH2_FX_OK ? 0 : -1;
}
static int
do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag,
SFTP_DIRENT ***dir)
{
struct sshbuf *msg;
u_int count, id, i, expected_id, ents = 0;
size_t handle_len;
u_char type, *handle;
int status = SSH2_FX_FAILURE;
int r;
if (dir)
*dir = NULL;
id = conn->msg_id++;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPENDIR)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_cstring(msg, path)) != 0)
fatal_fr(r, "compose OPENDIR");
send_msg(conn, msg);
handle = get_handle(conn, id, &handle_len,
"remote readdir(\"%s\")", path);
if (handle == NULL) {
sshbuf_free(msg);
return -1;
}
if (dir) {
ents = 0;
*dir = xcalloc(1, sizeof(**dir));
(*dir)[0] = NULL;
}
for (; !interrupted;) {
id = expected_id = conn->msg_id++;
debug3("Sending SSH2_FXP_READDIR I:%u", id);
sshbuf_reset(msg);
if ((r = sshbuf_put_u8(msg, SSH2_FXP_READDIR)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_string(msg, handle, handle_len)) != 0)
fatal_fr(r, "compose READDIR");
send_msg(conn, msg);
sshbuf_reset(msg);
get_msg(conn, msg);
if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
(r = sshbuf_get_u32(msg, &id)) != 0)
fatal_fr(r, "parse");
debug3("Received reply T:%u I:%u", type, id);
if (id != expected_id)
fatal("ID mismatch (%u != %u)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
u_int rstatus;
if ((r = sshbuf_get_u32(msg, &rstatus)) != 0)
fatal_fr(r, "parse status");
debug3("Received SSH2_FXP_STATUS %d", rstatus);
if (rstatus == SSH2_FX_EOF)
break;
error("Couldn't read directory: %s", fx2txt(rstatus));
goto out;
} else if (type != SSH2_FXP_NAME)
fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
SSH2_FXP_NAME, type);
if ((r = sshbuf_get_u32(msg, &count)) != 0)
fatal_fr(r, "parse count");
if (count > SSHBUF_SIZE_MAX)
fatal_f("nonsensical number of entries");
if (count == 0)
break;
debug3("Received %d SSH2_FXP_NAME responses", count);
for (i = 0; i < count; i++) {
char *filename, *longname;
Attrib a;
if ((r = sshbuf_get_cstring(msg, &filename,
NULL)) != 0 ||
(r = sshbuf_get_cstring(msg, &longname,
NULL)) != 0)
fatal_fr(r, "parse filenames");
if ((r = decode_attrib(msg, &a)) != 0) {
error_fr(r, "couldn't decode attrib");
free(filename);
free(longname);
goto out;
}
if (print_flag)
mprintf("%s\n", longname);
/*
* Directory entries should never contain '/'
* These can be used to attack recursive ops
* (e.g. send '../../../../etc/passwd')
*/
if (strpbrk(filename, SFTP_DIRECTORY_CHARS) != NULL) {
error("Server sent suspect path \"%s\" "
"during readdir of \"%s\"", filename, path);
} else if (dir) {
*dir = xreallocarray(*dir, ents + 2, sizeof(**dir));
(*dir)[ents] = xcalloc(1, sizeof(***dir));
(*dir)[ents]->filename = xstrdup(filename);
(*dir)[ents]->longname = xstrdup(longname);
memcpy(&(*dir)[ents]->a, &a, sizeof(a));
(*dir)[++ents] = NULL;
}
free(filename);
free(longname);
}
}
status = 0;
out:
sshbuf_free(msg);
do_close(conn, handle, handle_len);
free(handle);
if (status != 0 && dir != NULL) {
/* Don't return results on error */
free_sftp_dirents(*dir);
*dir = NULL;
} else if (interrupted && dir != NULL && *dir != NULL) {
/* Don't return partial matches on interrupt */
free_sftp_dirents(*dir);
*dir = xcalloc(1, sizeof(**dir));
**dir = NULL;
}
return status == SSH2_FX_OK ? 0 : -1;
}
int
do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir)
{
return(do_lsreaddir(conn, path, 0, dir));
}
void free_sftp_dirents(SFTP_DIRENT **s)
{
int i;
if (s == NULL)
return;
for (i = 0; s[i]; i++) {
free(s[i]->filename);
free(s[i]->longname);
free(s[i]);
}
free(s);
}
int
do_rm(struct sftp_conn *conn, const char *path)
{
u_int status, id;
debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
id = conn->msg_id++;
send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path));
status = get_status(conn, id);
if (status != SSH2_FX_OK)
error("Couldn't delete file: %s", fx2txt(status));
return status == SSH2_FX_OK ? 0 : -1;
}
int
do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag)
{
u_int status, id;
id = conn->msg_id++;
send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path,
strlen(path), a);
status = get_status(conn, id);
if (status != SSH2_FX_OK && print_flag)
error("Couldn't create directory: %s", fx2txt(status));
return status == SSH2_FX_OK ? 0 : -1;
}
int
do_rmdir(struct sftp_conn *conn, const char *path)
{
u_int status, id;
id = conn->msg_id++;
send_string_request(conn, id, SSH2_FXP_RMDIR, path,
strlen(path));
status = get_status(conn, id);
if (status != SSH2_FX_OK)
error("Couldn't remove directory: %s", fx2txt(status));
return status == SSH2_FX_OK ? 0 : -1;
}
Attrib *
do_stat(struct sftp_conn *conn, const char *path, int quiet)
{
u_int id;
id = conn->msg_id++;
send_string_request(conn, id,
conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
path, strlen(path));
return(get_decode_stat(conn, id, quiet));
}
Attrib *
do_lstat(struct sftp_conn *conn, const char *path, int quiet)
{
u_int id;
if (conn->version == 0) {
if (quiet)
debug("Server version does not support lstat operation");
else
logit("Server version does not support lstat operation");
return(do_stat(conn, path, quiet));
}
id = conn->msg_id++;
send_string_request(conn, id, SSH2_FXP_LSTAT, path,
strlen(path));
return(get_decode_stat(conn, id, quiet));
}
#ifdef notyet
Attrib *
do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
int quiet)
{
u_int id;
id = conn->msg_id++;
send_string_request(conn, id, SSH2_FXP_FSTAT, handle,
handle_len);
return(get_decode_stat(conn, id, quiet));
}
#endif
int
do_setstat(struct sftp_conn *conn, const char *path, Attrib *a)
{
u_int status, id;
id = conn->msg_id++;
send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path,
strlen(path), a);
status = get_status(conn, id);
if (status != SSH2_FX_OK)
error("Couldn't setstat on \"%s\": %s", path,
fx2txt(status));
return status == SSH2_FX_OK ? 0 : -1;
}
int
do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
Attrib *a)
{
u_int status, id;
id = conn->msg_id++;
send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle,
handle_len, a);
status = get_status(conn, id);
if (status != SSH2_FX_OK)
error("Couldn't fsetstat: %s", fx2txt(status));
return status == SSH2_FX_OK ? 0 : -1;
}
char *
do_realpath(struct sftp_conn *conn, const char *path)
{
struct sshbuf *msg;
u_int expected_id, count, id;
char *filename, *longname;
Attrib a;
u_char type;
int r;
expected_id = id = conn->msg_id++;
send_string_request(conn, id, SSH2_FXP_REALPATH, path,
strlen(path));
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
get_msg(conn, msg);
if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
(r = sshbuf_get_u32(msg, &id)) != 0)
fatal_fr(r, "parse");
if (id != expected_id)
fatal("ID mismatch (%u != %u)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
u_int status;
if ((r = sshbuf_get_u32(msg, &status)) != 0)
fatal_fr(r, "parse status");
error("Couldn't canonicalize: %s", fx2txt(status));
sshbuf_free(msg);
return NULL;
} else if (type != SSH2_FXP_NAME)
fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
SSH2_FXP_NAME, type);
if ((r = sshbuf_get_u32(msg, &count)) != 0)
fatal_fr(r, "parse count");
if (count != 1)
fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 ||
(r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 ||
(r = decode_attrib(msg, &a)) != 0)
fatal_fr(r, "parse filename/attrib");
debug3("SSH_FXP_REALPATH %s -> %s size %lu", path, filename,
(unsigned long)a.size);
free(longname);
sshbuf_free(msg);
return(filename);
}
int
do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath,
int force_legacy)
{
struct sshbuf *msg;
u_int status, id;
int r, use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
/* Send rename request */
id = conn->msg_id++;
if (use_ext) {
if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_cstring(msg,
"posix-rename@openssh.com")) != 0)
fatal_fr(r, "compose posix-rename");
} else {
if ((r = sshbuf_put_u8(msg, SSH2_FXP_RENAME)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0)
fatal_fr(r, "compose rename");
}
if ((r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
(r = sshbuf_put_cstring(msg, newpath)) != 0)
fatal_fr(r, "compose paths");
send_msg(conn, msg);
debug3("Sent message %s \"%s\" -> \"%s\"",
use_ext ? "posix-rename@openssh.com" :
"SSH2_FXP_RENAME", oldpath, newpath);
sshbuf_free(msg);
status = get_status(conn, id);
if (status != SSH2_FX_OK)
error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
newpath, fx2txt(status));
return status == SSH2_FX_OK ? 0 : -1;
}
int
do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
{
struct sshbuf *msg;
u_int status, id;
int r;
if ((conn->exts & SFTP_EXT_HARDLINK) == 0) {
error("Server does not support hardlink@openssh.com extension");
return -1;
}
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
/* Send link request */
id = conn->msg_id++;
if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_cstring(msg, "hardlink@openssh.com")) != 0 ||
(r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
(r = sshbuf_put_cstring(msg, newpath)) != 0)
fatal_fr(r, "compose");
send_msg(conn, msg);
debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"",
- oldpath, newpath);
+ oldpath, newpath);
sshbuf_free(msg);
status = get_status(conn, id);
if (status != SSH2_FX_OK)
error("Couldn't link file \"%s\" to \"%s\": %s", oldpath,
newpath, fx2txt(status));
return status == SSH2_FX_OK ? 0 : -1;
}
int
do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
{
struct sshbuf *msg;
u_int status, id;
int r;
if (conn->version < 3) {
error("This server does not support the symlink operation");
return(SSH2_FX_OP_UNSUPPORTED);
}
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
/* Send symlink request */
id = conn->msg_id++;
if ((r = sshbuf_put_u8(msg, SSH2_FXP_SYMLINK)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
(r = sshbuf_put_cstring(msg, newpath)) != 0)
fatal_fr(r, "compose");
send_msg(conn, msg);
debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
newpath);
sshbuf_free(msg);
status = get_status(conn, id);
if (status != SSH2_FX_OK)
error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath,
newpath, fx2txt(status));
return status == SSH2_FX_OK ? 0 : -1;
}
int
do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len)
{
struct sshbuf *msg;
u_int status, id;
int r;
/* Silently return if the extension is not supported */
if ((conn->exts & SFTP_EXT_FSYNC) == 0)
return -1;
/* Send fsync request */
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
id = conn->msg_id++;
if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 ||
(r = sshbuf_put_string(msg, handle, handle_len)) != 0)
fatal_fr(r, "compose");
send_msg(conn, msg);
debug3("Sent message fsync@openssh.com I:%u", id);
sshbuf_free(msg);
status = get_status(conn, id);
if (status != SSH2_FX_OK)
error("Couldn't sync file: %s", fx2txt(status));
return status == SSH2_FX_OK ? 0 : -1;
}
#ifdef notyet
char *
do_readlink(struct sftp_conn *conn, const char *path)
{
struct sshbuf *msg;
u_int expected_id, count, id;
char *filename, *longname;
Attrib a;
u_char type;
int r;
expected_id = id = conn->msg_id++;
send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path));
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
get_msg(conn, msg);
if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
(r = sshbuf_get_u32(msg, &id)) != 0)
fatal_fr(r, "parse");
if (id != expected_id)
fatal("ID mismatch (%u != %u)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
u_int status;
if ((r = sshbuf_get_u32(msg, &status)) != 0)
fatal_fr(r, "parse status");
error("Couldn't readlink: %s", fx2txt(status));
sshbuf_free(msg);
return(NULL);
} else if (type != SSH2_FXP_NAME)
fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
SSH2_FXP_NAME, type);
if ((r = sshbuf_get_u32(msg, &count)) != 0)
fatal_fr(r, "parse count");
if (count != 1)
fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 ||
(r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 ||
(r = decode_attrib(msg, &a)) != 0)
fatal_fr(r, "parse filenames/attrib");
debug3("SSH_FXP_READLINK %s -> %s", path, filename);
free(longname);
sshbuf_free(msg);
return filename;
}
#endif
int
do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
int quiet)
{
struct sshbuf *msg;
u_int id;
int r;
if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
error("Server does not support statvfs@openssh.com extension");
return -1;
}
id = conn->msg_id++;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 ||
(r = sshbuf_put_cstring(msg, path)) != 0)
fatal_fr(r, "compose");
send_msg(conn, msg);
sshbuf_free(msg);
return get_decode_statvfs(conn, st, id, quiet);
}
#ifdef notyet
int
do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
struct sftp_statvfs *st, int quiet)
{
struct sshbuf *msg;
u_int id;
if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
error("Server does not support fstatvfs@openssh.com extension");
return -1;
}
id = conn->msg_id++;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 ||
(r = sshbuf_put_string(msg, handle, handle_len)) != 0)
fatal_fr(r, "compose");
send_msg(conn, msg);
sshbuf_free(msg);
return get_decode_statvfs(conn, st, id, quiet);
}
#endif
int
do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a)
{
struct sshbuf *msg;
u_int status, id;
int r;
if ((conn->exts & SFTP_EXT_LSETSTAT) == 0) {
error("Server does not support lsetstat@openssh.com extension");
return -1;
}
id = conn->msg_id++;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 ||
(r = sshbuf_put_cstring(msg, path)) != 0 ||
(r = encode_attrib(msg, a)) != 0)
fatal_fr(r, "compose");
send_msg(conn, msg);
sshbuf_free(msg);
status = get_status(conn, id);
if (status != SSH2_FX_OK)
error("Couldn't setstat on \"%s\": %s", path,
fx2txt(status));
return status == SSH2_FX_OK ? 0 : -1;
}
static void
send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
u_int len, const u_char *handle, u_int handle_len)
{
struct sshbuf *msg;
int r;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, SSH2_FXP_READ)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_string(msg, handle, handle_len)) != 0 ||
(r = sshbuf_put_u64(msg, offset)) != 0 ||
(r = sshbuf_put_u32(msg, len)) != 0)
fatal_fr(r, "compose");
send_msg(conn, msg);
sshbuf_free(msg);
}
int
do_download(struct sftp_conn *conn, const char *remote_path,
const char *local_path, Attrib *a, int preserve_flag, int resume_flag,
int fsync_flag)
{
Attrib junk;
struct sshbuf *msg;
u_char *handle;
int local_fd = -1, write_error;
int read_error, write_errno, lmodified = 0, reordered = 0, r;
u_int64_t offset = 0, size, highwater;
u_int mode, id, buflen, num_req, max_req, status = SSH2_FX_OK;
off_t progress_counter;
size_t handle_len;
struct stat st;
struct request {
u_int id;
size_t len;
u_int64_t offset;
TAILQ_ENTRY(request) tq;
};
TAILQ_HEAD(reqhead, request) requests;
struct request *req;
u_char type;
TAILQ_INIT(&requests);
if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL)
return -1;
/* Do not preserve set[ug]id here, as we do not preserve ownership */
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
mode = a->perm & 0777;
else
mode = 0666;
if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
(!S_ISREG(a->perm))) {
error("Cannot download non-regular file: %s", remote_path);
return(-1);
}
if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
size = a->size;
else
size = 0;
- buflen = conn->transfer_buflen;
+ buflen = conn->download_buflen;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
attrib_clear(&junk); /* Send empty attributes */
/* Send open request */
id = conn->msg_id++;
if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_cstring(msg, remote_path)) != 0 ||
(r = sshbuf_put_u32(msg, SSH2_FXF_READ)) != 0 ||
(r = encode_attrib(msg, &junk)) != 0)
fatal_fr(r, "compose");
send_msg(conn, msg);
debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
handle = get_handle(conn, id, &handle_len,
"remote open(\"%s\")", remote_path);
if (handle == NULL) {
sshbuf_free(msg);
return(-1);
}
local_fd = open(local_path,
O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR);
if (local_fd == -1) {
error("Couldn't open local file \"%s\" for writing: %s",
local_path, strerror(errno));
goto fail;
}
offset = highwater = 0;
if (resume_flag) {
if (fstat(local_fd, &st) == -1) {
error("Unable to stat local file \"%s\": %s",
local_path, strerror(errno));
goto fail;
}
if (st.st_size < 0) {
error("\"%s\" has negative size", local_path);
goto fail;
}
if ((u_int64_t)st.st_size > size) {
error("Unable to resume download of \"%s\": "
"local file is larger than remote", local_path);
fail:
do_close(conn, handle, handle_len);
sshbuf_free(msg);
free(handle);
if (local_fd != -1)
close(local_fd);
return -1;
}
offset = highwater = st.st_size;
}
/* Read from remote and write to local */
write_error = read_error = write_errno = num_req = 0;
max_req = 1;
progress_counter = offset;
if (showprogress && size != 0)
start_progress_meter(remote_path, size, &progress_counter);
while (num_req > 0 || max_req > 0) {
u_char *data;
size_t len;
/*
* Simulate EOF on interrupt: stop sending new requests and
* allow outstanding requests to drain gracefully
*/
if (interrupted) {
if (num_req == 0) /* If we haven't started yet... */
break;
max_req = 0;
}
/* Send some more requests */
while (num_req < max_req) {
debug3("Request range %llu -> %llu (%d/%d)",
(unsigned long long)offset,
(unsigned long long)offset + buflen - 1,
num_req, max_req);
req = xcalloc(1, sizeof(*req));
req->id = conn->msg_id++;
req->len = buflen;
req->offset = offset;
offset += buflen;
num_req++;
TAILQ_INSERT_TAIL(&requests, req, tq);
send_read_request(conn, req->id, req->offset,
req->len, handle, handle_len);
}
sshbuf_reset(msg);
get_msg(conn, msg);
if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
(r = sshbuf_get_u32(msg, &id)) != 0)
fatal_fr(r, "parse");
debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
/* Find the request in our queue */
for (req = TAILQ_FIRST(&requests);
req != NULL && req->id != id;
req = TAILQ_NEXT(req, tq))
;
if (req == NULL)
fatal("Unexpected reply %u", id);
switch (type) {
case SSH2_FXP_STATUS:
if ((r = sshbuf_get_u32(msg, &status)) != 0)
fatal_fr(r, "parse status");
if (status != SSH2_FX_EOF)
read_error = 1;
max_req = 0;
TAILQ_REMOVE(&requests, req, tq);
free(req);
num_req--;
break;
case SSH2_FXP_DATA:
if ((r = sshbuf_get_string(msg, &data, &len)) != 0)
fatal_fr(r, "parse data");
debug3("Received data %llu -> %llu",
(unsigned long long)req->offset,
(unsigned long long)req->offset + len - 1);
if (len > req->len)
fatal("Received more data than asked for "
"%zu > %zu", len, req->len);
lmodified = 1;
if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
atomicio(vwrite, local_fd, data, len) != len) &&
!write_error) {
write_errno = errno;
write_error = 1;
max_req = 0;
}
else if (!reordered && req->offset <= highwater)
highwater = req->offset + len;
else if (!reordered && req->offset > highwater)
reordered = 1;
progress_counter += len;
free(data);
if (len == req->len) {
TAILQ_REMOVE(&requests, req, tq);
free(req);
num_req--;
} else {
/* Resend the request for the missing data */
debug3("Short data block, re-requesting "
"%llu -> %llu (%2d)",
(unsigned long long)req->offset + len,
(unsigned long long)req->offset +
req->len - 1, num_req);
req->id = conn->msg_id++;
req->len -= len;
req->offset += len;
send_read_request(conn, req->id,
req->offset, req->len, handle, handle_len);
/* Reduce the request size */
if (len < buflen)
buflen = MAXIMUM(MIN_READ_SIZE, len);
}
if (max_req > 0) { /* max_req = 0 iff EOF received */
if (size > 0 && offset > size) {
/* Only one request at a time
* after the expected EOF */
debug3("Finish at %llu (%2d)",
(unsigned long long)offset,
num_req);
max_req = 1;
} else if (max_req < conn->num_requests) {
++max_req;
}
}
break;
default:
fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
SSH2_FXP_DATA, type);
}
}
if (showprogress && size)
stop_progress_meter();
/* Sanity check */
if (TAILQ_FIRST(&requests) != NULL)
fatal("Transfer complete, but requests still in queue");
/* Truncate at highest contiguous point to avoid holes on interrupt */
if (read_error || write_error || interrupted) {
if (reordered && resume_flag) {
error("Unable to resume download of \"%s\": "
"server reordered requests", local_path);
}
debug("truncating at %llu", (unsigned long long)highwater);
if (ftruncate(local_fd, highwater) == -1)
error("ftruncate \"%s\": %s", local_path,
strerror(errno));
}
if (read_error) {
error("Couldn't read from remote file \"%s\" : %s",
remote_path, fx2txt(status));
status = -1;
do_close(conn, handle, handle_len);
} else if (write_error) {
error("Couldn't write to \"%s\": %s", local_path,
strerror(write_errno));
status = SSH2_FX_FAILURE;
do_close(conn, handle, handle_len);
} else {
if (do_close(conn, handle, handle_len) != 0 || interrupted)
status = SSH2_FX_FAILURE;
else
status = SSH2_FX_OK;
/* Override umask and utimes if asked */
#ifdef HAVE_FCHMOD
if (preserve_flag && fchmod(local_fd, mode) == -1)
#else
if (preserve_flag && chmod(local_path, mode) == -1)
#endif /* HAVE_FCHMOD */
error("Couldn't set mode on \"%s\": %s", local_path,
strerror(errno));
if (preserve_flag &&
(a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
struct timeval tv[2];
tv[0].tv_sec = a->atime;
tv[1].tv_sec = a->mtime;
tv[0].tv_usec = tv[1].tv_usec = 0;
if (utimes(local_path, tv) == -1)
error("Can't set times on \"%s\": %s",
local_path, strerror(errno));
}
if (resume_flag && !lmodified)
logit("File \"%s\" was not modified", local_path);
else if (fsync_flag) {
debug("syncing \"%s\"", local_path);
if (fsync(local_fd) == -1)
error("Couldn't sync file \"%s\": %s",
local_path, strerror(errno));
}
}
close(local_fd);
sshbuf_free(msg);
free(handle);
return status == SSH2_FX_OK ? 0 : -1;
}
static int
download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
int depth, Attrib *dirattrib, int preserve_flag, int print_flag,
int resume_flag, int fsync_flag)
{
int i, ret = 0;
SFTP_DIRENT **dir_entries;
char *filename, *new_src = NULL, *new_dst = NULL;
mode_t mode = 0777, tmpmode = mode;
if (depth >= MAX_DIR_DEPTH) {
error("Maximum directory depth exceeded: %d levels", depth);
return -1;
}
if (dirattrib == NULL &&
(dirattrib = do_stat(conn, src, 1)) == NULL) {
error("Unable to stat remote directory \"%s\"", src);
return -1;
}
if (!S_ISDIR(dirattrib->perm)) {
error("\"%s\" is not a directory", src);
return -1;
}
if (print_flag)
mprintf("Retrieving %s\n", src);
if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
mode = dirattrib->perm & 01777;
tmpmode = mode | (S_IWUSR|S_IXUSR);
} else {
debug("Server did not send permissions for "
"directory \"%s\"", dst);
}
if (mkdir(dst, tmpmode) == -1 && errno != EEXIST) {
error("mkdir %s: %s", dst, strerror(errno));
return -1;
}
if (do_readdir(conn, src, &dir_entries) == -1) {
error("%s: Failed to get directory contents", src);
return -1;
}
for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
free(new_dst);
free(new_src);
filename = dir_entries[i]->filename;
new_dst = path_append(dst, filename);
new_src = path_append(src, filename);
if (S_ISDIR(dir_entries[i]->a.perm)) {
if (strcmp(filename, ".") == 0 ||
strcmp(filename, "..") == 0)
continue;
if (download_dir_internal(conn, new_src, new_dst,
depth + 1, &(dir_entries[i]->a), preserve_flag,
print_flag, resume_flag, fsync_flag) == -1)
ret = -1;
} else if (S_ISREG(dir_entries[i]->a.perm) ) {
if (do_download(conn, new_src, new_dst,
&(dir_entries[i]->a), preserve_flag,
resume_flag, fsync_flag) == -1) {
error("Download of file %s to %s failed",
new_src, new_dst);
ret = -1;
}
} else
logit("%s: not a regular file\n", new_src);
}
free(new_dst);
free(new_src);
if (preserve_flag) {
if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
struct timeval tv[2];
tv[0].tv_sec = dirattrib->atime;
tv[1].tv_sec = dirattrib->mtime;
tv[0].tv_usec = tv[1].tv_usec = 0;
if (utimes(dst, tv) == -1)
error("Can't set times on \"%s\": %s",
dst, strerror(errno));
} else
debug("Server did not send times for directory "
"\"%s\"", dst);
}
if (mode != tmpmode && chmod(dst, mode) == -1)
error("Can't set final mode on \"%s\": %s", dst,
strerror(errno));
free_sftp_dirents(dir_entries);
return ret;
}
int
download_dir(struct sftp_conn *conn, const char *src, const char *dst,
Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,
int fsync_flag)
{
char *src_canon;
int ret;
if ((src_canon = do_realpath(conn, src)) == NULL) {
error("Unable to canonicalize path \"%s\"", src);
return -1;
}
ret = download_dir_internal(conn, src_canon, dst, 0,
dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag);
free(src_canon);
return ret;
}
int
do_upload(struct sftp_conn *conn, const char *local_path,
const char *remote_path, int preserve_flag, int resume, int fsync_flag)
{
int r, local_fd;
u_int status = SSH2_FX_OK;
u_int id;
u_char type;
off_t offset, progress_counter;
u_char *handle, *data;
struct sshbuf *msg;
struct stat sb;
Attrib a, *c = NULL;
u_int32_t startid;
u_int32_t ackid;
struct outstanding_ack {
u_int id;
u_int len;
off_t offset;
TAILQ_ENTRY(outstanding_ack) tq;
};
TAILQ_HEAD(ackhead, outstanding_ack) acks;
struct outstanding_ack *ack = NULL;
size_t handle_len;
TAILQ_INIT(&acks);
if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
error("Couldn't open local file \"%s\" for reading: %s",
local_path, strerror(errno));
return(-1);
}
if (fstat(local_fd, &sb) == -1) {
error("Couldn't fstat local file \"%s\": %s",
local_path, strerror(errno));
close(local_fd);
return(-1);
}
if (!S_ISREG(sb.st_mode)) {
error("%s is not a regular file", local_path);
close(local_fd);
return(-1);
}
stat_to_attrib(&sb, &a);
a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
a.perm &= 0777;
if (!preserve_flag)
a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
if (resume) {
/* Get remote file size if it exists */
if ((c = do_stat(conn, remote_path, 0)) == NULL) {
close(local_fd);
return -1;
}
if ((off_t)c->size >= sb.st_size) {
error("destination file bigger or same size as "
- "source file");
+ "source file");
close(local_fd);
return -1;
}
if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) {
close(local_fd);
return -1;
}
}
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
/* Send open request */
id = conn->msg_id++;
if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_cstring(msg, remote_path)) != 0 ||
(r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|
(resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC))) != 0 ||
(r = encode_attrib(msg, &a)) != 0)
fatal_fr(r, "compose");
send_msg(conn, msg);
debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
sshbuf_reset(msg);
handle = get_handle(conn, id, &handle_len,
"remote open(\"%s\")", remote_path);
if (handle == NULL) {
close(local_fd);
sshbuf_free(msg);
return -1;
}
startid = ackid = id + 1;
- data = xmalloc(conn->transfer_buflen);
+ data = xmalloc(conn->upload_buflen);
/* Read from local and write to remote */
offset = progress_counter = (resume ? c->size : 0);
if (showprogress)
start_progress_meter(local_path, sb.st_size,
&progress_counter);
for (;;) {
int len;
/*
* Can't use atomicio here because it returns 0 on EOF,
* thus losing the last block of the file.
* Simulate an EOF on interrupt, allowing ACKs from the
* server to drain.
*/
if (interrupted || status != SSH2_FX_OK)
len = 0;
else do
- len = read(local_fd, data, conn->transfer_buflen);
+ len = read(local_fd, data, conn->upload_buflen);
while ((len == -1) &&
(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
if (len == -1)
fatal("Couldn't read from \"%s\": %s", local_path,
strerror(errno));
if (len != 0) {
ack = xcalloc(1, sizeof(*ack));
ack->id = ++id;
ack->offset = offset;
ack->len = len;
TAILQ_INSERT_TAIL(&acks, ack, tq);
sshbuf_reset(msg);
if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 ||
(r = sshbuf_put_u32(msg, ack->id)) != 0 ||
(r = sshbuf_put_string(msg, handle,
handle_len)) != 0 ||
(r = sshbuf_put_u64(msg, offset)) != 0 ||
(r = sshbuf_put_string(msg, data, len)) != 0)
fatal_fr(r, "compose");
send_msg(conn, msg);
debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
id, (unsigned long long)offset, len);
} else if (TAILQ_FIRST(&acks) == NULL)
break;
if (ack == NULL)
fatal("Unexpected ACK %u", id);
if (id == startid || len == 0 ||
id - ackid >= conn->num_requests) {
u_int rid;
sshbuf_reset(msg);
get_msg(conn, msg);
if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
(r = sshbuf_get_u32(msg, &rid)) != 0)
fatal_fr(r, "parse");
if (type != SSH2_FXP_STATUS)
fatal("Expected SSH2_FXP_STATUS(%d) packet, "
"got %d", SSH2_FXP_STATUS, type);
if ((r = sshbuf_get_u32(msg, &status)) != 0)
fatal_fr(r, "parse status");
debug3("SSH2_FXP_STATUS %u", status);
/* Find the request in our queue */
for (ack = TAILQ_FIRST(&acks);
ack != NULL && ack->id != rid;
ack = TAILQ_NEXT(ack, tq))
;
if (ack == NULL)
fatal("Can't find request for ID %u", rid);
TAILQ_REMOVE(&acks, ack, tq);
debug3("In write loop, ack for %u %u bytes at %lld",
ack->id, ack->len, (long long)ack->offset);
++ackid;
progress_counter += ack->len;
free(ack);
}
offset += len;
if (offset < 0)
fatal_f("offset < 0");
}
sshbuf_free(msg);
if (showprogress)
stop_progress_meter();
free(data);
if (status != SSH2_FX_OK) {
error("Couldn't write to remote file \"%s\": %s",
remote_path, fx2txt(status));
status = SSH2_FX_FAILURE;
}
if (close(local_fd) == -1) {
error("Couldn't close local file \"%s\": %s", local_path,
strerror(errno));
status = SSH2_FX_FAILURE;
}
/* Override umask and utimes if asked */
if (preserve_flag)
do_fsetstat(conn, handle, handle_len, &a);
if (fsync_flag)
(void)do_fsync(conn, handle, handle_len);
if (do_close(conn, handle, handle_len) != 0)
status = SSH2_FX_FAILURE;
free(handle);
return status == SSH2_FX_OK ? 0 : -1;
}
static int
upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
int depth, int preserve_flag, int print_flag, int resume, int fsync_flag)
{
int ret = 0;
DIR *dirp;
struct dirent *dp;
char *filename, *new_src = NULL, *new_dst = NULL;
struct stat sb;
Attrib a, *dirattrib;
u_int32_t saved_perm;
if (depth >= MAX_DIR_DEPTH) {
error("Maximum directory depth exceeded: %d levels", depth);
return -1;
}
if (stat(src, &sb) == -1) {
error("Couldn't stat directory \"%s\": %s",
src, strerror(errno));
return -1;
}
if (!S_ISDIR(sb.st_mode)) {
error("\"%s\" is not a directory", src);
return -1;
}
if (print_flag)
mprintf("Entering %s\n", src);
attrib_clear(&a);
stat_to_attrib(&sb, &a);
a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
a.perm &= 01777;
if (!preserve_flag)
a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
/*
* sftp lacks a portable status value to match errno EEXIST,
* so if we get a failure back then we must check whether
* the path already existed and is a directory. Ensure we can
* write to the directory we create for the duration of the transfer.
*/
saved_perm = a.perm;
a.perm |= (S_IWUSR|S_IXUSR);
if (do_mkdir(conn, dst, &a, 0) != 0) {
if ((dirattrib = do_stat(conn, dst, 0)) == NULL)
return -1;
if (!S_ISDIR(dirattrib->perm)) {
error("\"%s\" exists but is not a directory", dst);
return -1;
}
}
a.perm = saved_perm;
if ((dirp = opendir(src)) == NULL) {
error("Failed to open dir \"%s\": %s", src, strerror(errno));
return -1;
}
while (((dp = readdir(dirp)) != NULL) && !interrupted) {
if (dp->d_ino == 0)
continue;
free(new_dst);
free(new_src);
filename = dp->d_name;
new_dst = path_append(dst, filename);
new_src = path_append(src, filename);
if (lstat(new_src, &sb) == -1) {
logit("%s: lstat failed: %s", filename,
strerror(errno));
ret = -1;
} else if (S_ISDIR(sb.st_mode)) {
if (strcmp(filename, ".") == 0 ||
strcmp(filename, "..") == 0)
continue;
if (upload_dir_internal(conn, new_src, new_dst,
depth + 1, preserve_flag, print_flag, resume,
fsync_flag) == -1)
ret = -1;
} else if (S_ISREG(sb.st_mode)) {
if (do_upload(conn, new_src, new_dst,
preserve_flag, resume, fsync_flag) == -1) {
error("Uploading of file %s to %s failed!",
new_src, new_dst);
ret = -1;
}
} else
logit("%s: not a regular file\n", filename);
}
free(new_dst);
free(new_src);
do_setstat(conn, dst, &a);
(void) closedir(dirp);
return ret;
}
int
upload_dir(struct sftp_conn *conn, const char *src, const char *dst,
int preserve_flag, int print_flag, int resume, int fsync_flag)
{
char *dst_canon;
int ret;
if ((dst_canon = do_realpath(conn, dst)) == NULL) {
error("Unable to canonicalize path \"%s\"", dst);
return -1;
}
ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
print_flag, resume, fsync_flag);
free(dst_canon);
return ret;
}
char *
path_append(const char *p1, const char *p2)
{
char *ret;
size_t len = strlen(p1) + strlen(p2) + 2;
ret = xmalloc(len);
strlcpy(ret, p1, len);
if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/')
strlcat(ret, "/", len);
strlcat(ret, p2, len);
return(ret);
}
char *
make_absolute(char *p, const char *pwd)
{
char *abs_str;
/* Derelativise */
if (p && !path_absolute(p)) {
abs_str = path_append(pwd, p);
free(p);
return(abs_str);
} else
return(p);
}
int
remote_is_dir(struct sftp_conn *conn, const char *path)
{
Attrib *a;
/* XXX: report errors? */
if ((a = do_stat(conn, path, 1)) == NULL)
return(0);
if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
return(0);
return(S_ISDIR(a->perm));
}
int
local_is_dir(const char *path)
{
struct stat sb;
/* XXX: report errors? */
if (stat(path, &sb) == -1)
return(0);
return(S_ISDIR(sb.st_mode));
}
/* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
int
globpath_is_dir(const char *pathname)
{
size_t l = strlen(pathname);
return l > 0 && pathname[l - 1] == '/';
}
diff --git a/sftp-client.h b/sftp-client.h
index 32a24a3c4302..6f6c49fb2099 100644
--- a/sftp-client.h
+++ b/sftp-client.h
@@ -1,158 +1,169 @@
-/* $OpenBSD: sftp-client.h,v 1.29 2020/12/04 02:41:10 djm Exp $ */
+/* $OpenBSD: sftp-client.h,v 1.30 2021/03/31 22:16:34 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* Client side of SSH2 filexfer protocol */
#ifndef _SFTP_CLIENT_H
#define _SFTP_CLIENT_H
#ifdef USE_SYSTEM_GLOB
# include <glob.h>
#else
# include "openbsd-compat/glob.h"
#endif
typedef struct SFTP_DIRENT SFTP_DIRENT;
struct SFTP_DIRENT {
char *filename;
char *longname;
Attrib a;
};
/*
* Used for statvfs responses on the wire from the server, because the
* server's native format may be larger than the client's.
*/
struct sftp_statvfs {
u_int64_t f_bsize;
u_int64_t f_frsize;
u_int64_t f_blocks;
u_int64_t f_bfree;
u_int64_t f_bavail;
u_int64_t f_files;
u_int64_t f_ffree;
u_int64_t f_favail;
u_int64_t f_fsid;
u_int64_t f_flag;
u_int64_t f_namemax;
};
+/* Used for limits response on the wire from the server */
+struct sftp_limits {
+ u_int64_t packet_length;
+ u_int64_t read_length;
+ u_int64_t write_length;
+ u_int64_t open_handles;
+};
+
/*
* Initialise a SSH filexfer connection. Returns NULL on error or
* a pointer to a initialized sftp_conn struct on success.
*/
struct sftp_conn *do_init(int, int, u_int, u_int, u_int64_t);
u_int sftp_proto_version(struct sftp_conn *);
+/* Query server limits */
+int do_limits(struct sftp_conn *, struct sftp_limits *);
+
/* Close file referred to by 'handle' */
int do_close(struct sftp_conn *, const u_char *, u_int);
/* Read contents of 'path' to NULL-terminated array 'dir' */
int do_readdir(struct sftp_conn *, const char *, SFTP_DIRENT ***);
/* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from do_readdir) */
void free_sftp_dirents(SFTP_DIRENT **);
/* Delete file 'path' */
int do_rm(struct sftp_conn *, const char *);
/* Create directory 'path' */
int do_mkdir(struct sftp_conn *, const char *, Attrib *, int);
/* Remove directory 'path' */
int do_rmdir(struct sftp_conn *, const char *);
/* Get file attributes of 'path' (follows symlinks) */
Attrib *do_stat(struct sftp_conn *, const char *, int);
/* Get file attributes of 'path' (does not follow symlinks) */
Attrib *do_lstat(struct sftp_conn *, const char *, int);
/* Set file attributes of 'path' */
int do_setstat(struct sftp_conn *, const char *, Attrib *);
/* Set file attributes of open file 'handle' */
int do_fsetstat(struct sftp_conn *, const u_char *, u_int, Attrib *);
/* Set file attributes of 'path', not following symlinks */
int do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a);
/* Canonicalise 'path' - caller must free result */
char *do_realpath(struct sftp_conn *, const char *);
/* Get statistics for filesystem hosting file at "path" */
int do_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int);
/* Rename 'oldpath' to 'newpath' */
int do_rename(struct sftp_conn *, const char *, const char *, int force_legacy);
/* Link 'oldpath' to 'newpath' */
int do_hardlink(struct sftp_conn *, const char *, const char *);
/* Rename 'oldpath' to 'newpath' */
int do_symlink(struct sftp_conn *, const char *, const char *);
/* Call fsync() on open file 'handle' */
int do_fsync(struct sftp_conn *conn, u_char *, u_int);
/*
* Download 'remote_path' to 'local_path'. Preserve permissions and times
* if 'pflag' is set
*/
int do_download(struct sftp_conn *, const char *, const char *,
Attrib *, int, int, int);
/*
* Recursively download 'remote_directory' to 'local_directory'. Preserve
* times if 'pflag' is set
*/
int download_dir(struct sftp_conn *, const char *, const char *,
Attrib *, int, int, int, int);
/*
* Upload 'local_path' to 'remote_path'. Preserve permissions and times
* if 'pflag' is set
*/
int do_upload(struct sftp_conn *, const char *, const char *, int, int, int);
/*
* Recursively upload 'local_directory' to 'remote_directory'. Preserve
* times if 'pflag' is set
*/
int upload_dir(struct sftp_conn *, const char *, const char *, int, int, int,
int);
/* Concatenate paths, taking care of slashes. Caller must free result. */
char *path_append(const char *, const char *);
/* Make absolute path if relative path and CWD is given. Does not modify
* original if the the path is already absolute. */
char *make_absolute(char *, const char *);
/* Check if remote path is directory */
int remote_is_dir(struct sftp_conn *conn, const char *path);
/* Check if local path is directory */
int local_is_dir(const char *path);
/* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
int globpath_is_dir(const char *pathname);
#endif
diff --git a/sftp-server.0 b/sftp-server.0
index 36c5f846f283..e265f498803a 100644
--- a/sftp-server.0
+++ b/sftp-server.0
@@ -1,98 +1,98 @@
SFTP-SERVER(8) System Manager's Manual SFTP-SERVER(8)
NAME
sftp-server M-bM-^@M-^S OpenSSH SFTP server subsystem
SYNOPSIS
sftp-server [-ehR] [-d start_directory] [-f log_facility] [-l log_level]
[-P denied_requests] [-p allowed_requests] [-u umask]
sftp-server -Q protocol_feature
DESCRIPTION
sftp-server is a program that speaks the server side of SFTP protocol to
stdout and expects client requests from stdin. sftp-server is not
intended to be called directly, but from sshd(8) using the Subsystem
option.
Command-line flags to sftp-server should be specified in the Subsystem
declaration. See sshd_config(5) for more information.
Valid options are:
-d start_directory
specifies an alternate starting directory for users. The
pathname may contain the following tokens that are expanded at
runtime: %% is replaced by a literal '%', %d is replaced by the
home directory of the user being authenticated, and %u is
replaced by the username of that user. The default is to use the
user's home directory. This option is useful in conjunction with
the sshd_config(5) ChrootDirectory option.
-e Causes sftp-server to print logging information to stderr instead
of syslog for debugging.
-f log_facility
Specifies the facility code that is used when logging messages
from sftp-server. The possible values are: DAEMON, USER, AUTH,
LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
The default is AUTH.
-h Displays sftp-server usage information.
-l log_level
Specifies which messages will be logged by sftp-server. The
possible values are: QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG,
DEBUG1, DEBUG2, and DEBUG3. INFO and VERBOSE log transactions
that sftp-server performs on behalf of the client. DEBUG and
DEBUG1 are equivalent. DEBUG2 and DEBUG3 each specify higher
levels of debugging output. The default is ERROR.
-P denied_requests
Specify a comma-separated list of SFTP protocol requests that are
banned by the server. sftp-server will reply to any denied
request with a failure. The -Q flag can be used to determine the
supported request types. If both denied and allowed lists are
specified, then the denied list is applied before the allowed
list.
-p allowed_requests
Specify a comma-separated list of SFTP protocol requests that are
permitted by the server. All request types that are not on the
allowed list will be logged and replied to with a failure
message.
Care must be taken when using this feature to ensure that
requests made implicitly by SFTP clients are permitted.
-Q protocol_feature
Query protocol features supported by sftp-server. At present the
only feature that may be queried is M-bM-^@M-^\requestsM-bM-^@M-^], which may be used
to deny or allow specific requests (flags -P and -p
respectively).
-R Places this instance of sftp-server into a read-only mode.
Attempts to open files for writing, as well as other operations
that change the state of the filesystem, will be denied.
-u umask
Sets an explicit umask(2) to be applied to newly-created files
and directories, instead of the user's default mask.
On some systems, sftp-server must be able to access /dev/log for logging
to work, and use of sftp-server in a chroot configuration therefore
requires that syslogd(8) establish a logging socket inside the chroot
directory.
SEE ALSO
sftp(1), ssh(1), sshd_config(5), sshd(8)
T. Ylonen and S. Lehtinen, SSH File Transfer Protocol, draft-ietf-secsh-
filexfer-02.txt, October 2001, work in progress material.
HISTORY
sftp-server first appeared in OpenBSD 2.8.
AUTHORS
Markus Friedl <markus@openbsd.org>
-OpenBSD 6.8 June 22, 2020 OpenBSD 6.8
+OpenBSD 6.9 June 22, 2020 OpenBSD 6.9
diff --git a/sftp-server.c b/sftp-server.c
index 7300900ace62..838f0488cde7 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -1,1810 +1,1850 @@
-/* $OpenBSD: sftp-server.c,v 1.122 2021/02/18 00:30:17 djm Exp $ */
+/* $OpenBSD: sftp-server.c,v 1.127 2021/04/03 06:18:41 djm Exp $ */
/*
* Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
#ifdef HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <stdarg.h>
#include "xmalloc.h"
#include "sshbuf.h"
#include "ssherr.h"
#include "log.h"
#include "misc.h"
#include "match.h"
#include "uidswap.h"
#include "sftp.h"
#include "sftp-common.h"
char *sftp_realpath(const char *, char *); /* sftp-realpath.c */
/* Maximum data read that we are willing to accept */
-#define SFTP_MAX_READ_LENGTH (64 * 1024)
+#define SFTP_MAX_READ_LENGTH (SFTP_MAX_MSG_LENGTH - 1024)
/* Our verbosity */
static LogLevel log_level = SYSLOG_LEVEL_ERROR;
/* Our client */
static struct passwd *pw = NULL;
static char *client_addr = NULL;
/* input and output queue */
struct sshbuf *iqueue;
struct sshbuf *oqueue;
/* Version of client */
static u_int version;
/* SSH2_FXP_INIT received */
static int init_done;
/* Disable writes */
static int readonly;
/* Requests that are allowed/denied */
static char *request_allowlist, *request_denylist;
/* portable attributes, etc. */
typedef struct Stat Stat;
struct Stat {
char *name;
char *long_name;
Attrib attrib;
};
/* Packet handlers */
static void process_open(u_int32_t id);
static void process_close(u_int32_t id);
static void process_read(u_int32_t id);
static void process_write(u_int32_t id);
static void process_stat(u_int32_t id);
static void process_lstat(u_int32_t id);
static void process_fstat(u_int32_t id);
static void process_setstat(u_int32_t id);
static void process_fsetstat(u_int32_t id);
static void process_opendir(u_int32_t id);
static void process_readdir(u_int32_t id);
static void process_remove(u_int32_t id);
static void process_mkdir(u_int32_t id);
static void process_rmdir(u_int32_t id);
static void process_realpath(u_int32_t id);
static void process_rename(u_int32_t id);
static void process_readlink(u_int32_t id);
static void process_symlink(u_int32_t id);
static void process_extended_posix_rename(u_int32_t id);
static void process_extended_statvfs(u_int32_t id);
static void process_extended_fstatvfs(u_int32_t id);
static void process_extended_hardlink(u_int32_t id);
static void process_extended_fsync(u_int32_t id);
static void process_extended_lsetstat(u_int32_t id);
static void process_extended_limits(u_int32_t id);
static void process_extended(u_int32_t id);
struct sftp_handler {
const char *name; /* user-visible name for fine-grained perms */
const char *ext_name; /* extended request name */
u_int type; /* packet type, for non extended packets */
void (*handler)(u_int32_t);
int does_write; /* if nonzero, banned for readonly mode */
};
static const struct sftp_handler handlers[] = {
/* NB. SSH2_FXP_OPEN does the readonly check in the handler itself */
{ "open", NULL, SSH2_FXP_OPEN, process_open, 0 },
{ "close", NULL, SSH2_FXP_CLOSE, process_close, 0 },
{ "read", NULL, SSH2_FXP_READ, process_read, 0 },
{ "write", NULL, SSH2_FXP_WRITE, process_write, 1 },
{ "lstat", NULL, SSH2_FXP_LSTAT, process_lstat, 0 },
{ "fstat", NULL, SSH2_FXP_FSTAT, process_fstat, 0 },
{ "setstat", NULL, SSH2_FXP_SETSTAT, process_setstat, 1 },
{ "fsetstat", NULL, SSH2_FXP_FSETSTAT, process_fsetstat, 1 },
{ "opendir", NULL, SSH2_FXP_OPENDIR, process_opendir, 0 },
{ "readdir", NULL, SSH2_FXP_READDIR, process_readdir, 0 },
{ "remove", NULL, SSH2_FXP_REMOVE, process_remove, 1 },
{ "mkdir", NULL, SSH2_FXP_MKDIR, process_mkdir, 1 },
{ "rmdir", NULL, SSH2_FXP_RMDIR, process_rmdir, 1 },
{ "realpath", NULL, SSH2_FXP_REALPATH, process_realpath, 0 },
{ "stat", NULL, SSH2_FXP_STAT, process_stat, 0 },
{ "rename", NULL, SSH2_FXP_RENAME, process_rename, 1 },
{ "readlink", NULL, SSH2_FXP_READLINK, process_readlink, 0 },
{ "symlink", NULL, SSH2_FXP_SYMLINK, process_symlink, 1 },
{ NULL, NULL, 0, NULL, 0 }
};
/* SSH2_FXP_EXTENDED submessages */
static const struct sftp_handler extended_handlers[] = {
{ "posix-rename", "posix-rename@openssh.com", 0,
- process_extended_posix_rename, 1 },
+ process_extended_posix_rename, 1 },
{ "statvfs", "statvfs@openssh.com", 0, process_extended_statvfs, 0 },
{ "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 },
{ "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 },
{ "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 },
{ "lsetstat", "lsetstat@openssh.com", 0, process_extended_lsetstat, 1 },
{ "limits", "limits@openssh.com", 0, process_extended_limits, 1 },
{ NULL, NULL, 0, NULL, 0 }
};
+static const struct sftp_handler *
+extended_handler_byname(const char *name)
+{
+ int i;
+
+ for (i = 0; extended_handlers[i].handler != NULL; i++) {
+ if (strcmp(name, extended_handlers[i].ext_name) == 0)
+ return &extended_handlers[i];
+ }
+ return NULL;
+}
+
static int
request_permitted(const struct sftp_handler *h)
{
char *result;
if (readonly && h->does_write) {
verbose("Refusing %s request in read-only mode", h->name);
return 0;
}
if (request_denylist != NULL &&
((result = match_list(h->name, request_denylist, NULL))) != NULL) {
free(result);
verbose("Refusing denylisted %s request", h->name);
return 0;
}
if (request_allowlist != NULL &&
((result = match_list(h->name, request_allowlist, NULL))) != NULL) {
free(result);
debug2("Permitting allowlisted %s request", h->name);
return 1;
}
if (request_allowlist != NULL) {
verbose("Refusing non-allowlisted %s request", h->name);
return 0;
}
return 1;
}
static int
errno_to_portable(int unixerrno)
{
int ret = 0;
switch (unixerrno) {
case 0:
ret = SSH2_FX_OK;
break;
case ENOENT:
case ENOTDIR:
case EBADF:
case ELOOP:
ret = SSH2_FX_NO_SUCH_FILE;
break;
case EPERM:
case EACCES:
case EFAULT:
ret = SSH2_FX_PERMISSION_DENIED;
break;
case ENAMETOOLONG:
case EINVAL:
ret = SSH2_FX_BAD_MESSAGE;
break;
case ENOSYS:
ret = SSH2_FX_OP_UNSUPPORTED;
break;
default:
ret = SSH2_FX_FAILURE;
break;
}
return ret;
}
static int
flags_from_portable(int pflags)
{
int flags = 0;
if ((pflags & SSH2_FXF_READ) &&
(pflags & SSH2_FXF_WRITE)) {
flags = O_RDWR;
} else if (pflags & SSH2_FXF_READ) {
flags = O_RDONLY;
} else if (pflags & SSH2_FXF_WRITE) {
flags = O_WRONLY;
}
if (pflags & SSH2_FXF_APPEND)
flags |= O_APPEND;
if (pflags & SSH2_FXF_CREAT)
flags |= O_CREAT;
if (pflags & SSH2_FXF_TRUNC)
flags |= O_TRUNC;
if (pflags & SSH2_FXF_EXCL)
flags |= O_EXCL;
return flags;
}
static const char *
string_from_portable(int pflags)
{
static char ret[128];
*ret = '\0';
#define PAPPEND(str) { \
if (*ret != '\0') \
strlcat(ret, ",", sizeof(ret)); \
strlcat(ret, str, sizeof(ret)); \
}
if (pflags & SSH2_FXF_READ)
PAPPEND("READ")
if (pflags & SSH2_FXF_WRITE)
PAPPEND("WRITE")
if (pflags & SSH2_FXF_APPEND)
PAPPEND("APPEND")
if (pflags & SSH2_FXF_CREAT)
PAPPEND("CREATE")
if (pflags & SSH2_FXF_TRUNC)
PAPPEND("TRUNCATE")
if (pflags & SSH2_FXF_EXCL)
PAPPEND("EXCL")
return ret;
}
/* handle handles */
typedef struct Handle Handle;
struct Handle {
int use;
DIR *dirp;
int fd;
int flags;
char *name;
u_int64_t bytes_read, bytes_write;
int next_unused;
};
enum {
HANDLE_UNUSED,
HANDLE_DIR,
HANDLE_FILE
};
static Handle *handles = NULL;
static u_int num_handles = 0;
static int first_unused_handle = -1;
static void handle_unused(int i)
{
handles[i].use = HANDLE_UNUSED;
handles[i].next_unused = first_unused_handle;
first_unused_handle = i;
}
static int
handle_new(int use, const char *name, int fd, int flags, DIR *dirp)
{
int i;
if (first_unused_handle == -1) {
if (num_handles + 1 <= num_handles)
return -1;
num_handles++;
handles = xreallocarray(handles, num_handles, sizeof(Handle));
handle_unused(num_handles - 1);
}
i = first_unused_handle;
first_unused_handle = handles[i].next_unused;
handles[i].use = use;
handles[i].dirp = dirp;
handles[i].fd = fd;
handles[i].flags = flags;
handles[i].name = xstrdup(name);
handles[i].bytes_read = handles[i].bytes_write = 0;
return i;
}
static int
handle_is_ok(int i, int type)
{
return i >= 0 && (u_int)i < num_handles && handles[i].use == type;
}
static int
handle_to_string(int handle, u_char **stringp, int *hlenp)
{
if (stringp == NULL || hlenp == NULL)
return -1;
*stringp = xmalloc(sizeof(int32_t));
put_u32(*stringp, handle);
*hlenp = sizeof(int32_t);
return 0;
}
static int
handle_from_string(const u_char *handle, u_int hlen)
{
int val;
if (hlen != sizeof(int32_t))
return -1;
val = get_u32(handle);
if (handle_is_ok(val, HANDLE_FILE) ||
handle_is_ok(val, HANDLE_DIR))
return val;
return -1;
}
static char *
handle_to_name(int handle)
{
if (handle_is_ok(handle, HANDLE_DIR)||
handle_is_ok(handle, HANDLE_FILE))
return handles[handle].name;
return NULL;
}
static DIR *
handle_to_dir(int handle)
{
if (handle_is_ok(handle, HANDLE_DIR))
return handles[handle].dirp;
return NULL;
}
static int
handle_to_fd(int handle)
{
if (handle_is_ok(handle, HANDLE_FILE))
return handles[handle].fd;
return -1;
}
static int
handle_to_flags(int handle)
{
if (handle_is_ok(handle, HANDLE_FILE))
return handles[handle].flags;
return 0;
}
static void
handle_update_read(int handle, ssize_t bytes)
{
if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
handles[handle].bytes_read += bytes;
}
static void
handle_update_write(int handle, ssize_t bytes)
{
if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
handles[handle].bytes_write += bytes;
}
static u_int64_t
handle_bytes_read(int handle)
{
if (handle_is_ok(handle, HANDLE_FILE))
return (handles[handle].bytes_read);
return 0;
}
static u_int64_t
handle_bytes_write(int handle)
{
if (handle_is_ok(handle, HANDLE_FILE))
return (handles[handle].bytes_write);
return 0;
}
static int
handle_close(int handle)
{
int ret = -1;
if (handle_is_ok(handle, HANDLE_FILE)) {
ret = close(handles[handle].fd);
free(handles[handle].name);
handle_unused(handle);
} else if (handle_is_ok(handle, HANDLE_DIR)) {
ret = closedir(handles[handle].dirp);
free(handles[handle].name);
handle_unused(handle);
} else {
errno = ENOENT;
}
return ret;
}
static void
handle_log_close(int handle, char *emsg)
{
if (handle_is_ok(handle, HANDLE_FILE)) {
logit("%s%sclose \"%s\" bytes read %llu written %llu",
emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
handle_to_name(handle),
(unsigned long long)handle_bytes_read(handle),
(unsigned long long)handle_bytes_write(handle));
} else {
logit("%s%sclosedir \"%s\"",
emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
handle_to_name(handle));
}
}
static void
handle_log_exit(void)
{
u_int i;
for (i = 0; i < num_handles; i++)
if (handles[i].use != HANDLE_UNUSED)
handle_log_close(i, "forced");
}
static int
get_handle(struct sshbuf *queue, int *hp)
{
u_char *handle;
int r;
size_t hlen;
*hp = -1;
if ((r = sshbuf_get_string(queue, &handle, &hlen)) != 0)
return r;
if (hlen < 256)
*hp = handle_from_string(handle, hlen);
free(handle);
return 0;
}
/* send replies */
static void
send_msg(struct sshbuf *m)
{
int r;
if ((r = sshbuf_put_stringb(oqueue, m)) != 0)
fatal_fr(r, "enqueue");
sshbuf_reset(m);
}
static const char *
status_to_message(u_int32_t status)
{
const char *status_messages[] = {
"Success", /* SSH_FX_OK */
"End of file", /* SSH_FX_EOF */
"No such file", /* SSH_FX_NO_SUCH_FILE */
"Permission denied", /* SSH_FX_PERMISSION_DENIED */
"Failure", /* SSH_FX_FAILURE */
"Bad message", /* SSH_FX_BAD_MESSAGE */
"No connection", /* SSH_FX_NO_CONNECTION */
"Connection lost", /* SSH_FX_CONNECTION_LOST */
"Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
"Unknown error" /* Others */
};
return (status_messages[MINIMUM(status,SSH2_FX_MAX)]);
}
static void
send_status(u_int32_t id, u_int32_t status)
{
struct sshbuf *msg;
int r;
debug3("request %u: sent status %u", id, status);
if (log_level > SYSLOG_LEVEL_VERBOSE ||
(status != SSH2_FX_OK && status != SSH2_FX_EOF))
logit("sent status %s", status_to_message(status));
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, SSH2_FXP_STATUS)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_u32(msg, status)) != 0)
fatal_fr(r, "compose");
if (version >= 3) {
if ((r = sshbuf_put_cstring(msg,
status_to_message(status))) != 0 ||
(r = sshbuf_put_cstring(msg, "")) != 0)
fatal_fr(r, "compose message");
}
send_msg(msg);
sshbuf_free(msg);
}
static void
send_data_or_handle(char type, u_int32_t id, const u_char *data, int dlen)
{
struct sshbuf *msg;
int r;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, type)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_string(msg, data, dlen)) != 0)
fatal_fr(r, "compose");
send_msg(msg);
sshbuf_free(msg);
}
static void
send_data(u_int32_t id, const u_char *data, int dlen)
{
debug("request %u: sent data len %d", id, dlen);
send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
}
static void
send_handle(u_int32_t id, int handle)
{
u_char *string;
int hlen;
handle_to_string(handle, &string, &hlen);
debug("request %u: sent handle handle %d", id, handle);
send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
free(string);
}
static void
send_names(u_int32_t id, int count, const Stat *stats)
{
struct sshbuf *msg;
int i, r;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, SSH2_FXP_NAME)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_u32(msg, count)) != 0)
fatal_fr(r, "compose");
debug("request %u: sent names count %d", id, count);
for (i = 0; i < count; i++) {
if ((r = sshbuf_put_cstring(msg, stats[i].name)) != 0 ||
(r = sshbuf_put_cstring(msg, stats[i].long_name)) != 0 ||
(r = encode_attrib(msg, &stats[i].attrib)) != 0)
fatal_fr(r, "compose filenames/attrib");
}
send_msg(msg);
sshbuf_free(msg);
}
static void
send_attrib(u_int32_t id, const Attrib *a)
{
struct sshbuf *msg;
int r;
debug("request %u: sent attrib have 0x%x", id, a->flags);
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, SSH2_FXP_ATTRS)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = encode_attrib(msg, a)) != 0)
fatal_fr(r, "compose");
send_msg(msg);
sshbuf_free(msg);
}
static void
send_statvfs(u_int32_t id, struct statvfs *st)
{
struct sshbuf *msg;
u_int64_t flag;
int r;
flag = (st->f_flag & ST_RDONLY) ? SSH2_FXE_STATVFS_ST_RDONLY : 0;
flag |= (st->f_flag & ST_NOSUID) ? SSH2_FXE_STATVFS_ST_NOSUID : 0;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED_REPLY)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_u64(msg, st->f_bsize)) != 0 ||
(r = sshbuf_put_u64(msg, st->f_frsize)) != 0 ||
(r = sshbuf_put_u64(msg, st->f_blocks)) != 0 ||
(r = sshbuf_put_u64(msg, st->f_bfree)) != 0 ||
(r = sshbuf_put_u64(msg, st->f_bavail)) != 0 ||
(r = sshbuf_put_u64(msg, st->f_files)) != 0 ||
(r = sshbuf_put_u64(msg, st->f_ffree)) != 0 ||
(r = sshbuf_put_u64(msg, st->f_favail)) != 0 ||
(r = sshbuf_put_u64(msg, FSID_TO_ULONG(st->f_fsid))) != 0 ||
(r = sshbuf_put_u64(msg, flag)) != 0 ||
(r = sshbuf_put_u64(msg, st->f_namemax)) != 0)
fatal_fr(r, "compose");
send_msg(msg);
sshbuf_free(msg);
}
+/*
+ * Prepare SSH2_FXP_VERSION extension advertisement for a single extension.
+ * The extension is checked for permission prior to advertisment.
+ */
+static int
+compose_extension(struct sshbuf *msg, const char *name, const char *ver)
+{
+ int r;
+ const struct sftp_handler *exthnd;
+
+ if ((exthnd = extended_handler_byname(name)) == NULL)
+ fatal_f("internal error: no handler for %s", name);
+ if (!request_permitted(exthnd)) {
+ debug2_f("refusing to advertise disallowed extension %s", name);
+ return 0;
+ }
+ if ((r = sshbuf_put_cstring(msg, name)) != 0 ||
+ (r = sshbuf_put_cstring(msg, ver)) != 0)
+ fatal_fr(r, "compose %s", name);
+ return 0;
+}
+
/* parse incoming */
static void
process_init(void)
{
struct sshbuf *msg;
int r;
if ((r = sshbuf_get_u32(iqueue, &version)) != 0)
fatal_fr(r, "parse");
verbose("received client version %u", version);
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, SSH2_FXP_VERSION)) != 0 ||
- (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0 ||
- /* POSIX rename extension */
- (r = sshbuf_put_cstring(msg, "posix-rename@openssh.com")) != 0 ||
- (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */
- /* statvfs extension */
- (r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 ||
- (r = sshbuf_put_cstring(msg, "2")) != 0 || /* version */
- /* fstatvfs extension */
- (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 ||
- (r = sshbuf_put_cstring(msg, "2")) != 0 || /* version */
- /* hardlink extension */
- (r = sshbuf_put_cstring(msg, "hardlink@openssh.com")) != 0 ||
- (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */
- /* fsync extension */
- (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 ||
- (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */
- /* lsetstat extension */
- (r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 ||
- (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */
- /* limits extension */
- (r = sshbuf_put_cstring(msg, "limits@openssh.com")) != 0 ||
- (r = sshbuf_put_cstring(msg, "1")) != 0) /* version */
+ (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0)
fatal_fr(r, "compose");
+
+ /* extension advertisments */
+ compose_extension(msg, "posix-rename@openssh.com", "1");
+ compose_extension(msg, "statvfs@openssh.com", "2");
+ compose_extension(msg, "fstatvfs@openssh.com", "2");
+ compose_extension(msg, "hardlink@openssh.com", "1");
+ compose_extension(msg, "fsync@openssh.com", "1");
+ compose_extension(msg, "lsetstat@openssh.com", "1");
+ compose_extension(msg, "limits@openssh.com", "1");
+
send_msg(msg);
sshbuf_free(msg);
}
static void
process_open(u_int32_t id)
{
u_int32_t pflags;
Attrib a;
char *name;
int r, handle, fd, flags, mode, status = SSH2_FX_FAILURE;
if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
(r = sshbuf_get_u32(iqueue, &pflags)) != 0 || /* portable flags */
(r = decode_attrib(iqueue, &a)) != 0)
fatal_fr(r, "parse");
debug3("request %u: open flags %d", id, pflags);
flags = flags_from_portable(pflags);
mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a.perm : 0666;
logit("open \"%s\" flags %s mode 0%o",
name, string_from_portable(pflags), mode);
if (readonly &&
((flags & O_ACCMODE) != O_RDONLY ||
(flags & (O_CREAT|O_TRUNC)) != 0)) {
verbose("Refusing open request in read-only mode");
status = SSH2_FX_PERMISSION_DENIED;
} else {
fd = open(name, flags, mode);
if (fd == -1) {
status = errno_to_portable(errno);
} else {
handle = handle_new(HANDLE_FILE, name, fd, flags, NULL);
if (handle < 0) {
close(fd);
} else {
send_handle(id, handle);
status = SSH2_FX_OK;
}
}
}
if (status != SSH2_FX_OK)
send_status(id, status);
free(name);
}
static void
process_close(u_int32_t id)
{
int r, handle, ret, status = SSH2_FX_FAILURE;
if ((r = get_handle(iqueue, &handle)) != 0)
fatal_fr(r, "parse");
debug3("request %u: close handle %u", id, handle);
handle_log_close(handle, NULL);
ret = handle_close(handle);
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
send_status(id, status);
}
static void
process_read(u_int32_t id)
{
- u_char buf[SFTP_MAX_READ_LENGTH];
+ static u_char *buf;
+ static size_t buflen;
u_int32_t len;
int r, handle, fd, ret, status = SSH2_FX_FAILURE;
u_int64_t off;
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");
- debug("request %u: read \"%s\" (handle %d) off %llu len %d",
+ debug("request %u: read \"%s\" (handle %d) off %llu len %u",
id, handle_to_name(handle), handle, (unsigned long long)off, len);
- if (len > sizeof buf) {
- len = sizeof buf;
- debug2("read change len %d", len);
+ if ((fd = handle_to_fd(handle)) == -1)
+ goto out;
+ if (len > SFTP_MAX_READ_LENGTH) {
+ debug2("read change len %u to %u", len, SFTP_MAX_READ_LENGTH);
+ len = SFTP_MAX_READ_LENGTH;
}
- fd = handle_to_fd(handle);
- if (fd >= 0) {
- if (lseek(fd, off, SEEK_SET) == -1) {
- error("process_read: seek failed");
- status = errno_to_portable(errno);
- } else {
- ret = read(fd, buf, len);
- if (ret == -1) {
- status = errno_to_portable(errno);
- } else if (ret == 0) {
- status = SSH2_FX_EOF;
- } else {
- send_data(id, buf, ret);
- status = SSH2_FX_OK;
- handle_update_read(handle, ret);
- }
- }
+ if (len > buflen) {
+ debug3_f("allocate %zu => %u", buflen, len);
+ if ((buf = realloc(NULL, len)) == NULL)
+ fatal_f("realloc failed");
+ buflen = len;
+ }
+ if (lseek(fd, off, SEEK_SET) == -1) {
+ status = errno_to_portable(errno);
+ error_f("seek \"%.100s\": %s", handle_to_name(handle),
+ strerror(errno));
+ goto out;
+ }
+ if (len == 0) {
+ /* weird, but not strictly disallowed */
+ ret = 0;
+ } else if ((ret = read(fd, buf, len)) == -1) {
+ status = errno_to_portable(errno);
+ error_f("read \"%.100s\": %s", handle_to_name(handle),
+ strerror(errno));
+ goto out;
+ } else if (ret == 0) {
+ status = SSH2_FX_EOF;
+ goto out;
}
+ send_data(id, buf, ret);
+ handle_update_read(handle, ret);
+ /* success */
+ status = SSH2_FX_OK;
+ out:
if (status != SSH2_FX_OK)
send_status(id, status);
}
static void
process_write(u_int32_t id)
{
u_int64_t off;
size_t len;
int r, handle, fd, ret, status;
u_char *data;
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");
debug("request %u: write \"%s\" (handle %d) off %llu len %zu",
id, handle_to_name(handle), handle, (unsigned long long)off, len);
fd = handle_to_fd(handle);
if (fd < 0)
status = SSH2_FX_FAILURE;
else {
if (!(handle_to_flags(handle) & O_APPEND) &&
- lseek(fd, off, SEEK_SET) == -1) {
+ lseek(fd, off, SEEK_SET) == -1) {
status = errno_to_portable(errno);
- error_f("seek failed");
+ error_f("seek \"%.100s\": %s", handle_to_name(handle),
+ strerror(errno));
} else {
/* XXX ATOMICIO ? */
ret = write(fd, data, len);
if (ret == -1) {
- error_f("write: %s", strerror(errno));
status = errno_to_portable(errno);
+ error_f("write \"%.100s\": %s",
+ handle_to_name(handle), strerror(errno));
} else if ((size_t)ret == len) {
status = SSH2_FX_OK;
handle_update_write(handle, ret);
} else {
debug2_f("nothing at all written");
status = SSH2_FX_FAILURE;
}
}
}
send_status(id, status);
free(data);
}
static void
process_do_stat(u_int32_t id, int do_lstat)
{
Attrib a;
struct stat st;
char *name;
int r, status = SSH2_FX_FAILURE;
if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0)
fatal_fr(r, "parse");
debug3("request %u: %sstat", id, do_lstat ? "l" : "");
verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
r = do_lstat ? lstat(name, &st) : stat(name, &st);
if (r == -1) {
status = errno_to_portable(errno);
} else {
stat_to_attrib(&st, &a);
send_attrib(id, &a);
status = SSH2_FX_OK;
}
if (status != SSH2_FX_OK)
send_status(id, status);
free(name);
}
static void
process_stat(u_int32_t id)
{
process_do_stat(id, 0);
}
static void
process_lstat(u_int32_t id)
{
process_do_stat(id, 1);
}
static void
process_fstat(u_int32_t id)
{
Attrib a;
struct stat st;
int fd, r, handle, status = SSH2_FX_FAILURE;
if ((r = get_handle(iqueue, &handle)) != 0)
fatal_fr(r, "parse");
debug("request %u: fstat \"%s\" (handle %u)",
id, handle_to_name(handle), handle);
fd = handle_to_fd(handle);
if (fd >= 0) {
r = fstat(fd, &st);
if (r == -1) {
status = errno_to_portable(errno);
} else {
stat_to_attrib(&st, &a);
send_attrib(id, &a);
status = SSH2_FX_OK;
}
}
if (status != SSH2_FX_OK)
send_status(id, status);
}
static struct timeval *
attrib_to_tv(const Attrib *a)
{
static struct timeval tv[2];
tv[0].tv_sec = a->atime;
tv[0].tv_usec = 0;
tv[1].tv_sec = a->mtime;
tv[1].tv_usec = 0;
return tv;
}
static struct timespec *
attrib_to_ts(const Attrib *a)
{
static struct timespec ts[2];
ts[0].tv_sec = a->atime;
ts[0].tv_nsec = 0;
ts[1].tv_sec = a->mtime;
ts[1].tv_nsec = 0;
return ts;
}
static void
process_setstat(u_int32_t id)
{
Attrib a;
char *name;
int r, status = SSH2_FX_OK;
if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
(r = decode_attrib(iqueue, &a)) != 0)
fatal_fr(r, "parse");
debug("request %u: setstat name \"%s\"", id, name);
if (a.flags & SSH2_FILEXFER_ATTR_SIZE) {
logit("set \"%s\" size %llu",
name, (unsigned long long)a.size);
r = truncate(name, a.size);
if (r == -1)
status = errno_to_portable(errno);
}
if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
logit("set \"%s\" mode %04o", name, a.perm);
r = chmod(name, a.perm & 07777);
if (r == -1)
status = errno_to_portable(errno);
}
if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
char buf[64];
time_t t = a.mtime;
strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
localtime(&t));
logit("set \"%s\" modtime %s", name, buf);
r = utimes(name, attrib_to_tv(&a));
if (r == -1)
status = errno_to_portable(errno);
}
if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) {
logit("set \"%s\" owner %lu group %lu", name,
(u_long)a.uid, (u_long)a.gid);
r = chown(name, a.uid, a.gid);
if (r == -1)
status = errno_to_portable(errno);
}
send_status(id, status);
free(name);
}
static void
process_fsetstat(u_int32_t id)
{
Attrib a;
int handle, fd, r;
int status = SSH2_FX_OK;
if ((r = get_handle(iqueue, &handle)) != 0 ||
(r = decode_attrib(iqueue, &a)) != 0)
fatal_fr(r, "parse");
debug("request %u: fsetstat handle %d", id, handle);
fd = handle_to_fd(handle);
if (fd < 0)
status = SSH2_FX_FAILURE;
else {
char *name = handle_to_name(handle);
if (a.flags & SSH2_FILEXFER_ATTR_SIZE) {
logit("set \"%s\" size %llu",
name, (unsigned long long)a.size);
r = ftruncate(fd, a.size);
if (r == -1)
status = errno_to_portable(errno);
}
if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
logit("set \"%s\" mode %04o", name, a.perm);
#ifdef HAVE_FCHMOD
r = fchmod(fd, a.perm & 07777);
#else
r = chmod(name, a.perm & 07777);
#endif
if (r == -1)
status = errno_to_portable(errno);
}
if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
char buf[64];
time_t t = a.mtime;
strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
localtime(&t));
logit("set \"%s\" modtime %s", name, buf);
#ifdef HAVE_FUTIMES
r = futimes(fd, attrib_to_tv(&a));
#else
r = utimes(name, attrib_to_tv(&a));
#endif
if (r == -1)
status = errno_to_portable(errno);
}
if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) {
logit("set \"%s\" owner %lu group %lu", name,
(u_long)a.uid, (u_long)a.gid);
#ifdef HAVE_FCHOWN
r = fchown(fd, a.uid, a.gid);
#else
r = chown(name, a.uid, a.gid);
#endif
if (r == -1)
status = errno_to_portable(errno);
}
}
send_status(id, status);
}
static void
process_opendir(u_int32_t id)
{
DIR *dirp = NULL;
char *path;
int r, handle, status = SSH2_FX_FAILURE;
if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0)
fatal_fr(r, "parse");
debug3("request %u: opendir", id);
logit("opendir \"%s\"", path);
dirp = opendir(path);
if (dirp == NULL) {
status = errno_to_portable(errno);
} else {
handle = handle_new(HANDLE_DIR, path, 0, 0, dirp);
if (handle < 0) {
closedir(dirp);
} else {
send_handle(id, handle);
status = SSH2_FX_OK;
}
}
if (status != SSH2_FX_OK)
send_status(id, status);
free(path);
}
static void
process_readdir(u_int32_t id)
{
DIR *dirp;
struct dirent *dp;
char *path;
int r, handle;
if ((r = get_handle(iqueue, &handle)) != 0)
fatal_fr(r, "parse");
debug("request %u: readdir \"%s\" (handle %d)", id,
handle_to_name(handle), handle);
dirp = handle_to_dir(handle);
path = handle_to_name(handle);
if (dirp == NULL || path == NULL) {
send_status(id, SSH2_FX_FAILURE);
} else {
struct stat st;
char pathname[PATH_MAX];
Stat *stats;
int nstats = 10, count = 0, i;
stats = xcalloc(nstats, sizeof(Stat));
while ((dp = readdir(dirp)) != NULL) {
if (count >= nstats) {
nstats *= 2;
stats = xreallocarray(stats, nstats, sizeof(Stat));
}
/* XXX OVERFLOW ? */
snprintf(pathname, sizeof pathname, "%s%s%s", path,
strcmp(path, "/") ? "/" : "", dp->d_name);
if (lstat(pathname, &st) == -1)
continue;
stat_to_attrib(&st, &(stats[count].attrib));
stats[count].name = xstrdup(dp->d_name);
stats[count].long_name = ls_file(dp->d_name, &st, 0, 0);
count++;
/* send up to 100 entries in one message */
/* XXX check packet size instead */
if (count == 100)
break;
}
if (count > 0) {
send_names(id, count, stats);
for (i = 0; i < count; i++) {
free(stats[i].name);
free(stats[i].long_name);
}
} else {
send_status(id, SSH2_FX_EOF);
}
free(stats);
}
}
static void
process_remove(u_int32_t id)
{
char *name;
int r, status = SSH2_FX_FAILURE;
if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0)
fatal_fr(r, "parse");
debug3("request %u: remove", id);
logit("remove name \"%s\"", name);
r = unlink(name);
status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
send_status(id, status);
free(name);
}
static void
process_mkdir(u_int32_t id)
{
Attrib a;
char *name;
int r, mode, status = SSH2_FX_FAILURE;
if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
(r = decode_attrib(iqueue, &a)) != 0)
fatal_fr(r, "parse");
mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
a.perm & 07777 : 0777;
debug3("request %u: mkdir", id);
logit("mkdir name \"%s\" mode 0%o", name, mode);
r = mkdir(name, mode);
status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
send_status(id, status);
free(name);
}
static void
process_rmdir(u_int32_t id)
{
char *name;
int r, status;
if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0)
fatal_fr(r, "parse");
debug3("request %u: rmdir", id);
logit("rmdir name \"%s\"", name);
r = rmdir(name);
status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
send_status(id, status);
free(name);
}
static void
process_realpath(u_int32_t id)
{
char resolvedname[PATH_MAX];
char *path;
int r;
if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0)
fatal_fr(r, "parse");
if (path[0] == '\0') {
free(path);
path = xstrdup(".");
}
debug3("request %u: realpath", id);
verbose("realpath \"%s\"", path);
if (sftp_realpath(path, resolvedname) == NULL) {
send_status(id, errno_to_portable(errno));
} else {
Stat s;
attrib_clear(&s.attrib);
s.name = s.long_name = resolvedname;
send_names(id, 1, &s);
}
free(path);
}
static void
process_rename(u_int32_t id)
{
char *oldpath, *newpath;
int r, status;
struct stat sb;
if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 ||
(r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
fatal_fr(r, "parse");
debug3("request %u: rename", id);
logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
status = SSH2_FX_FAILURE;
if (lstat(oldpath, &sb) == -1)
status = errno_to_portable(errno);
else if (S_ISREG(sb.st_mode)) {
/* Race-free rename of regular files */
if (link(oldpath, newpath) == -1) {
if (errno == EOPNOTSUPP || errno == ENOSYS
#ifdef EXDEV
|| errno == EXDEV
#endif
#ifdef LINK_OPNOTSUPP_ERRNO
|| errno == LINK_OPNOTSUPP_ERRNO
#endif
) {
struct stat st;
/*
* fs doesn't support links, so fall back to
* stat+rename. This is racy.
*/
if (stat(newpath, &st) == -1) {
if (rename(oldpath, newpath) == -1)
status =
errno_to_portable(errno);
else
status = SSH2_FX_OK;
}
} else {
status = errno_to_portable(errno);
}
} else if (unlink(oldpath) == -1) {
status = errno_to_portable(errno);
/* clean spare link */
unlink(newpath);
} else
status = SSH2_FX_OK;
} else if (stat(newpath, &sb) == -1) {
if (rename(oldpath, newpath) == -1)
status = errno_to_portable(errno);
else
status = SSH2_FX_OK;
}
send_status(id, status);
free(oldpath);
free(newpath);
}
static void
process_readlink(u_int32_t id)
{
int r, len;
char buf[PATH_MAX];
char *path;
if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0)
fatal_fr(r, "parse");
debug3("request %u: readlink", id);
verbose("readlink \"%s\"", path);
if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
send_status(id, errno_to_portable(errno));
else {
Stat s;
buf[len] = '\0';
attrib_clear(&s.attrib);
s.name = s.long_name = buf;
send_names(id, 1, &s);
}
free(path);
}
static void
process_symlink(u_int32_t id)
{
char *oldpath, *newpath;
int r, status;
if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 ||
(r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
fatal_fr(r, "parse");
debug3("request %u: symlink", id);
logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
/* this will fail if 'newpath' exists */
r = symlink(oldpath, newpath);
status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
send_status(id, status);
free(oldpath);
free(newpath);
}
static void
process_extended_posix_rename(u_int32_t id)
{
char *oldpath, *newpath;
int r, status;
if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 ||
(r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
fatal_fr(r, "parse");
debug3("request %u: posix-rename", id);
logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
r = rename(oldpath, newpath);
status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
send_status(id, status);
free(oldpath);
free(newpath);
}
static void
process_extended_statvfs(u_int32_t id)
{
char *path;
struct statvfs st;
int r;
if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0)
fatal_fr(r, "parse");
debug3("request %u: statvfs", id);
logit("statvfs \"%s\"", path);
if (statvfs(path, &st) != 0)
send_status(id, errno_to_portable(errno));
else
send_statvfs(id, &st);
- free(path);
+ free(path);
}
static void
process_extended_fstatvfs(u_int32_t id)
{
int r, handle, fd;
struct statvfs st;
if ((r = get_handle(iqueue, &handle)) != 0)
fatal_fr(r, "parse");
debug("request %u: fstatvfs \"%s\" (handle %u)",
id, handle_to_name(handle), handle);
if ((fd = handle_to_fd(handle)) < 0) {
send_status(id, SSH2_FX_FAILURE);
return;
}
if (fstatvfs(fd, &st) != 0)
send_status(id, errno_to_portable(errno));
else
send_statvfs(id, &st);
}
static void
process_extended_hardlink(u_int32_t id)
{
char *oldpath, *newpath;
int r, status;
if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 ||
(r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0)
fatal_fr(r, "parse");
debug3("request %u: hardlink", id);
logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath);
r = link(oldpath, newpath);
status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
send_status(id, status);
free(oldpath);
free(newpath);
}
static void
process_extended_fsync(u_int32_t id)
{
int handle, fd, r, status = SSH2_FX_OP_UNSUPPORTED;
if ((r = get_handle(iqueue, &handle)) != 0)
fatal_fr(r, "parse");
debug3("request %u: fsync (handle %u)", id, handle);
verbose("fsync \"%s\"", handle_to_name(handle));
if ((fd = handle_to_fd(handle)) < 0)
status = SSH2_FX_NO_SUCH_FILE;
else if (handle_is_ok(handle, HANDLE_FILE)) {
r = fsync(fd);
status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
}
send_status(id, status);
}
static void
process_extended_lsetstat(u_int32_t id)
{
Attrib a;
char *name;
int r, status = SSH2_FX_OK;
if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
(r = decode_attrib(iqueue, &a)) != 0)
fatal_fr(r, "parse");
debug("request %u: lsetstat name \"%s\"", id, name);
if (a.flags & SSH2_FILEXFER_ATTR_SIZE) {
/* nonsensical for links */
status = SSH2_FX_BAD_MESSAGE;
goto out;
}
if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
logit("set \"%s\" mode %04o", name, a.perm);
r = fchmodat(AT_FDCWD, name,
a.perm & 07777, AT_SYMLINK_NOFOLLOW);
if (r == -1)
status = errno_to_portable(errno);
}
if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
char buf[64];
time_t t = a.mtime;
strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
localtime(&t));
logit("set \"%s\" modtime %s", name, buf);
r = utimensat(AT_FDCWD, name,
attrib_to_ts(&a), AT_SYMLINK_NOFOLLOW);
if (r == -1)
status = errno_to_portable(errno);
}
if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) {
logit("set \"%s\" owner %lu group %lu", name,
(u_long)a.uid, (u_long)a.gid);
r = fchownat(AT_FDCWD, name, a.uid, a.gid,
AT_SYMLINK_NOFOLLOW);
if (r == -1)
status = errno_to_portable(errno);
}
out:
send_status(id, status);
free(name);
}
static void
process_extended_limits(u_int32_t id)
{
struct sshbuf *msg;
int r;
uint64_t nfiles = 0;
+#ifdef HAVE_GETRLIMIT
struct rlimit rlim;
+#endif
debug("request %u: limits", id);
+#ifdef HAVE_GETRLIMIT
if (getrlimit(RLIMIT_NOFILE, &rlim) != -1 && rlim.rlim_cur > 5)
nfiles = rlim.rlim_cur - 5; /* stdio(3) + syslog + spare */
+#endif
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED_REPLY)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
/* max-packet-length */
(r = sshbuf_put_u64(msg, SFTP_MAX_MSG_LENGTH)) != 0 ||
/* max-read-length */
(r = sshbuf_put_u64(msg, SFTP_MAX_READ_LENGTH)) != 0 ||
/* max-write-length */
(r = sshbuf_put_u64(msg, SFTP_MAX_MSG_LENGTH - 1024)) != 0 ||
/* max-open-handles */
(r = sshbuf_put_u64(msg, nfiles)) != 0)
fatal_fr(r, "compose");
send_msg(msg);
sshbuf_free(msg);
}
static void
process_extended(u_int32_t id)
{
char *request;
- int i, r;
+ int r;
+ const struct sftp_handler *exthand;
if ((r = sshbuf_get_cstring(iqueue, &request, NULL)) != 0)
fatal_fr(r, "parse");
- for (i = 0; extended_handlers[i].handler != NULL; i++) {
- if (strcmp(request, extended_handlers[i].ext_name) == 0) {
- if (!request_permitted(&extended_handlers[i]))
- send_status(id, SSH2_FX_PERMISSION_DENIED);
- else
- extended_handlers[i].handler(id);
- break;
- }
- }
- if (extended_handlers[i].handler == NULL) {
+ if ((exthand = extended_handler_byname(request)) == NULL) {
error("Unknown extended request \"%.100s\"", request);
send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
+ } else {
+ if (!request_permitted(exthand))
+ send_status(id, SSH2_FX_PERMISSION_DENIED);
+ else
+ exthand->handler(id);
}
free(request);
}
/* stolen from ssh-agent */
static void
process(void)
{
u_int msg_len;
u_int buf_len;
u_int consumed;
u_char type;
const u_char *cp;
int i, r;
u_int32_t id;
buf_len = sshbuf_len(iqueue);
if (buf_len < 5)
return; /* Incomplete message. */
cp = sshbuf_ptr(iqueue);
msg_len = get_u32(cp);
if (msg_len > SFTP_MAX_MSG_LENGTH) {
error("bad message from %s local user %s",
client_addr, pw->pw_name);
sftp_server_cleanup_exit(11);
}
if (buf_len < msg_len + 4)
return;
if ((r = sshbuf_consume(iqueue, 4)) != 0)
fatal_fr(r, "consume");
buf_len -= 4;
if ((r = sshbuf_get_u8(iqueue, &type)) != 0)
fatal_fr(r, "parse type");
switch (type) {
case SSH2_FXP_INIT:
process_init();
init_done = 1;
break;
case SSH2_FXP_EXTENDED:
if (!init_done)
fatal("Received extended request before init");
if ((r = sshbuf_get_u32(iqueue, &id)) != 0)
fatal_fr(r, "parse extended ID");
process_extended(id);
break;
default:
if (!init_done)
fatal("Received %u request before init", type);
if ((r = sshbuf_get_u32(iqueue, &id)) != 0)
fatal_fr(r, "parse ID");
for (i = 0; handlers[i].handler != NULL; i++) {
if (type == handlers[i].type) {
if (!request_permitted(&handlers[i])) {
send_status(id,
SSH2_FX_PERMISSION_DENIED);
} else {
handlers[i].handler(id);
}
break;
}
}
if (handlers[i].handler == NULL)
error("Unknown message %u", type);
}
/* discard the remaining bytes from the current packet */
if (buf_len < sshbuf_len(iqueue)) {
error("iqueue grew unexpectedly");
sftp_server_cleanup_exit(255);
}
consumed = buf_len - sshbuf_len(iqueue);
if (msg_len < consumed) {
error("msg_len %u < consumed %u", msg_len, consumed);
sftp_server_cleanup_exit(255);
}
if (msg_len > consumed &&
(r = sshbuf_consume(iqueue, msg_len - consumed)) != 0)
fatal_fr(r, "consume");
}
/* Cleanup handler that logs active handles upon normal exit */
void
sftp_server_cleanup_exit(int i)
{
if (pw != NULL && client_addr != NULL) {
handle_log_exit();
logit("session closed for local user %s from [%s]",
pw->pw_name, client_addr);
}
_exit(i);
}
static void
sftp_server_usage(void)
{
extern char *__progname;
fprintf(stderr,
"usage: %s [-ehR] [-d start_directory] [-f log_facility] "
"[-l log_level]\n\t[-P denied_requests] "
"[-p allowed_requests] [-u umask]\n"
" %s -Q protocol_feature\n",
__progname, __progname);
exit(1);
}
int
sftp_server_main(int argc, char **argv, struct passwd *user_pw)
{
fd_set *rset, *wset;
int i, r, in, out, max, ch, skipargs = 0, log_stderr = 0;
ssize_t len, olen, set_size;
SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
char *cp, *homedir = NULL, uidstr[32], buf[4*4096];
long mask;
extern char *optarg;
extern char *__progname;
__progname = ssh_get_progname(argv[0]);
log_init(__progname, log_level, log_facility, log_stderr);
pw = pwcopy(user_pw);
while (!skipargs && (ch = getopt(argc, argv,
"d:f:l:P:p:Q:u:cehR")) != -1) {
switch (ch) {
case 'Q':
if (strcasecmp(optarg, "requests") != 0) {
fprintf(stderr, "Invalid query type\n");
exit(1);
}
for (i = 0; handlers[i].handler != NULL; i++)
printf("%s\n", handlers[i].name);
for (i = 0; extended_handlers[i].handler != NULL; i++)
printf("%s\n", extended_handlers[i].name);
exit(0);
break;
case 'R':
readonly = 1;
break;
case 'c':
/*
* Ignore all arguments if we are invoked as a
* shell using "sftp-server -c command"
*/
skipargs = 1;
break;
case 'e':
log_stderr = 1;
break;
case 'l':
log_level = log_level_number(optarg);
if (log_level == SYSLOG_LEVEL_NOT_SET)
error("Invalid log level \"%s\"", optarg);
break;
case 'f':
log_facility = log_facility_number(optarg);
if (log_facility == SYSLOG_FACILITY_NOT_SET)
error("Invalid log facility \"%s\"", optarg);
break;
case 'd':
cp = tilde_expand_filename(optarg, user_pw->pw_uid);
snprintf(uidstr, sizeof(uidstr), "%llu",
(unsigned long long)pw->pw_uid);
homedir = percent_expand(cp, "d", user_pw->pw_dir,
"u", user_pw->pw_name, "U", uidstr, (char *)NULL);
free(cp);
break;
case 'p':
if (request_allowlist != NULL)
fatal("Permitted requests already set");
request_allowlist = xstrdup(optarg);
break;
case 'P':
if (request_denylist != NULL)
fatal("Refused requests already set");
request_denylist = xstrdup(optarg);
break;
case 'u':
errno = 0;
mask = strtol(optarg, &cp, 8);
if (mask < 0 || mask > 0777 || *cp != '\0' ||
cp == optarg || (mask == 0 && errno != 0))
fatal("Invalid umask \"%s\"", optarg);
(void)umask((mode_t)mask);
break;
case 'h':
default:
sftp_server_usage();
}
}
log_init(__progname, log_level, log_facility, log_stderr);
/*
* On platforms where we can, avoid making /proc/self/{mem,maps}
* available to the user so that sftp access doesn't automatically
* imply arbitrary code execution access that will break
* restricted configurations.
*/
platform_disable_tracing(1); /* strict */
/* Drop any fine-grained privileges we don't need */
platform_pledge_sftp_server();
if ((cp = getenv("SSH_CONNECTION")) != NULL) {
client_addr = xstrdup(cp);
if ((cp = strchr(client_addr, ' ')) == NULL) {
error("Malformed SSH_CONNECTION variable: \"%s\"",
getenv("SSH_CONNECTION"));
sftp_server_cleanup_exit(255);
}
*cp = '\0';
} else
client_addr = xstrdup("UNKNOWN");
logit("session opened for local user %s from [%s]",
pw->pw_name, client_addr);
in = STDIN_FILENO;
out = STDOUT_FILENO;
#ifdef HAVE_CYGWIN
setmode(in, O_BINARY);
setmode(out, O_BINARY);
#endif
max = 0;
if (in > max)
max = in;
if (out > max)
max = out;
if ((iqueue = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((oqueue = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
rset = xcalloc(howmany(max + 1, NFDBITS), sizeof(fd_mask));
wset = xcalloc(howmany(max + 1, NFDBITS), sizeof(fd_mask));
if (homedir != NULL) {
if (chdir(homedir) != 0) {
error("chdir to \"%s\" failed: %s", homedir,
strerror(errno));
}
}
set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
for (;;) {
memset(rset, 0, set_size);
memset(wset, 0, set_size);
/*
* Ensure that we can read a full buffer and handle
* the worst-case length packet it can generate,
* otherwise apply backpressure by stopping reads.
*/
if ((r = sshbuf_check_reserve(iqueue, sizeof(buf))) == 0 &&
(r = sshbuf_check_reserve(oqueue,
SFTP_MAX_MSG_LENGTH)) == 0)
FD_SET(in, rset);
else if (r != SSH_ERR_NO_BUFFER_SPACE)
fatal_fr(r, "reserve");
olen = sshbuf_len(oqueue);
if (olen > 0)
FD_SET(out, wset);
if (select(max+1, rset, wset, NULL, NULL) == -1) {
if (errno == EINTR)
continue;
error("select: %s", strerror(errno));
sftp_server_cleanup_exit(2);
}
/* copy stdin to iqueue */
if (FD_ISSET(in, rset)) {
len = read(in, buf, sizeof buf);
if (len == 0) {
debug("read eof");
sftp_server_cleanup_exit(0);
} else if (len == -1) {
error("read: %s", strerror(errno));
sftp_server_cleanup_exit(1);
} else if ((r = sshbuf_put(iqueue, buf, len)) != 0)
fatal_fr(r, "sshbuf_put");
}
/* send oqueue to stdout */
if (FD_ISSET(out, wset)) {
len = write(out, sshbuf_ptr(oqueue), olen);
if (len == -1) {
error("write: %s", strerror(errno));
sftp_server_cleanup_exit(1);
} else if ((r = sshbuf_consume(oqueue, len)) != 0)
fatal_fr(r, "consume");
}
/*
* Process requests from client if we can fit the results
* into the output buffer, otherwise stop processing input
* and let the output queue drain.
*/
r = sshbuf_check_reserve(oqueue, SFTP_MAX_MSG_LENGTH);
if (r == 0)
process();
else if (r != SSH_ERR_NO_BUFFER_SPACE)
fatal_fr(r, "reserve");
}
}
diff --git a/sftp.0 b/sftp.0
index 26104057d4fa..6495555d46ad 100644
--- a/sftp.0
+++ b/sftp.0
@@ -1,412 +1,412 @@
SFTP(1) General Commands Manual SFTP(1)
NAME
sftp M-bM-^@M-^S OpenSSH secure file transfer
SYNOPSIS
sftp [-46AaCfNpqrv] [-B buffer_size] [-b batchfile] [-c cipher]
[-D sftp_server_path] [-F ssh_config] [-i identity_file]
[-J destination] [-l limit] [-o ssh_option] [-P port]
[-R num_requests] [-S program] [-s subsystem | sftp_server]
destination
DESCRIPTION
sftp is a file transfer program, similar to ftp(1), which performs all
operations over an encrypted ssh(1) transport. It may also use many
features of ssh, such as public key authentication and compression.
The destination may be specified either as [user@]host[:path] or as a URI
in the form sftp://[user@]host[:port][/path].
If the destination includes a path and it is not a directory, sftp will
retrieve files automatically if a non-interactive authentication method
is used; otherwise it will do so after successful interactive
authentication.
If no path is specified, or if the path is a directory, sftp will log in
to the specified host and enter interactive command mode, changing to the
remote directory if one was specified. An optional trailing slash can be
used to force the path to be interpreted as a directory.
Since the destination formats use colon characters to delimit host names
from path names or port numbers, IPv6 addresses must be enclosed in
square brackets to avoid ambiguity.
The options are as follows:
-4 Forces sftp to use IPv4 addresses only.
-6 Forces sftp to use IPv6 addresses only.
-A Allows forwarding of ssh-agent(1) to the remote system. The
default is not to forward an authentication agent.
-a Attempt to continue interrupted transfers rather than overwriting
existing partial or complete copies of files. If the partial
contents differ from those being transferred, then the resultant
file is likely to be corrupt.
-B buffer_size
Specify the size of the buffer that sftp uses when transferring
files. Larger buffers require fewer round trips at the cost of
higher memory consumption. The default is 32768 bytes.
-b batchfile
Batch mode reads a series of commands from an input batchfile
instead of stdin. Since it lacks user interaction it should be
used in conjunction with non-interactive authentication to
obviate the need to enter a password at connection time (see
sshd(8) and ssh-keygen(1) for details).
A batchfile of M-bM-^@M-^X-M-bM-^@M-^Y may be used to indicate standard input. sftp
will abort if any of the following commands fail: get, put,
reget, reput, rename, ln, rm, mkdir, chdir, ls, lchdir, chmod,
chown, chgrp, lpwd, df, symlink, and lmkdir.
Termination on error can be suppressed on a command by command
basis by prefixing the command with a M-bM-^@M-^X-M-bM-^@M-^Y character (for example,
-rm /tmp/blah*). Echo of the command may be suppressed by
prefixing the command with a M-bM-^@M-^X@M-bM-^@M-^Y character. These two prefixes
may be combined in any order, for example -@ls /bsd.
-C Enables compression (via ssh's -C flag).
-c cipher
Selects the cipher to use for encrypting the data transfers.
This option is directly passed to ssh(1).
-D sftp_server_path
Connect directly to a local sftp server (rather than via ssh(1)).
This option may be useful in debugging the client and server.
-F ssh_config
Specifies an alternative per-user configuration file for ssh(1).
This option is directly passed to ssh(1).
-f Requests that files be flushed to disk immediately after
transfer. When uploading files, this feature is only enabled if
the server implements the "fsync@openssh.com" extension.
-i identity_file
Selects the file from which the identity (private key) for public
key authentication is read. This option is directly passed to
ssh(1).
-J destination
Connect to the target host by first making an sftp connection to
the jump host described by destination and then establishing a
TCP forwarding to the ultimate destination from there. Multiple
jump hops may be specified separated by comma characters. This
is a shortcut to specify a ProxyJump configuration directive.
This option is directly passed to ssh(1).
-l limit
Limits the used bandwidth, specified in Kbit/s.
-N Disables quiet mode, e.g. to override the implicit quiet mode set
by the -b flag.
-o ssh_option
Can be used to pass options to ssh in the format used in
ssh_config(5). This is useful for specifying options for which
there is no separate sftp command-line flag. For example, to
specify an alternate port use: sftp -oPort=24. For full details
of the options listed below, and their possible values, see
ssh_config(5).
AddressFamily
BatchMode
BindAddress
BindInterface
CanonicalDomains
CanonicalizeFallbackLocal
CanonicalizeHostname
CanonicalizeMaxDots
CanonicalizePermittedCNAMEs
CASignatureAlgorithms
CertificateFile
ChallengeResponseAuthentication
CheckHostIP
Ciphers
Compression
ConnectionAttempts
ConnectTimeout
ControlMaster
ControlPath
ControlPersist
GlobalKnownHostsFile
GSSAPIAuthentication
GSSAPIDelegateCredentials
HashKnownHosts
Host
HostbasedAcceptedAlgorithms
HostbasedAuthentication
HostKeyAlgorithms
HostKeyAlias
Hostname
IdentitiesOnly
IdentityAgent
IdentityFile
IPQoS
KbdInteractiveAuthentication
KbdInteractiveDevices
KexAlgorithms
KnownHostsCommand
LogLevel
MACs
NoHostAuthenticationForLocalhost
NumberOfPasswordPrompts
PasswordAuthentication
PKCS11Provider
Port
PreferredAuthentications
ProxyCommand
ProxyJump
PubkeyAcceptedAlgorithms
PubkeyAuthentication
RekeyLimit
SendEnv
ServerAliveInterval
ServerAliveCountMax
SetEnv
StrictHostKeyChecking
TCPKeepAlive
UpdateHostKeys
User
UserKnownHostsFile
VerifyHostKeyDNS
-P port
Specifies the port to connect to on the remote host.
-p Preserves modification times, access times, and modes from the
original files transferred.
-q Quiet mode: disables the progress meter as well as warning and
diagnostic messages from ssh(1).
-R num_requests
Specify how many requests may be outstanding at any one time.
Increasing this may slightly improve file transfer speed but will
increase memory usage. The default is 64 outstanding requests.
-r Recursively copy entire directories when uploading and
downloading. Note that sftp does not follow symbolic links
encountered in the tree traversal.
-S program
Name of the program to use for the encrypted connection. The
program must understand ssh(1) options.
-s subsystem | sftp_server
Specifies the SSH2 subsystem or the path for an sftp server on
the remote host. A path is useful when the remote sshd(8) does
not have an sftp subsystem configured.
-v Raise logging level. This option is also passed to ssh.
INTERACTIVE COMMANDS
Once in interactive mode, sftp understands a set of commands similar to
those of ftp(1). Commands are case insensitive. Pathnames that contain
spaces must be enclosed in quotes. Any special characters contained
within pathnames that are recognized by glob(3) must be escaped with
backslashes (M-bM-^@M-^X\M-bM-^@M-^Y).
bye Quit sftp.
cd [path]
Change remote directory to path. If path is not specified, then
change directory to the one the session started in.
chgrp [-h] grp path
Change group of file path to grp. path may contain glob(7)
characters and may match multiple files. grp must be a numeric
GID.
If the -h flag is specified, then symlinks will not be followed.
Note that this is only supported by servers that implement the
"lsetstat@openssh.com" extension.
chmod [-h] mode path
Change permissions of file path to mode. path may contain
glob(7) characters and may match multiple files.
If the -h flag is specified, then symlinks will not be followed.
Note that this is only supported by servers that implement the
"lsetstat@openssh.com" extension.
chown [-h] own path
Change owner of file path to own. path may contain glob(7)
characters and may match multiple files. own must be a numeric
UID.
If the -h flag is specified, then symlinks will not be followed.
Note that this is only supported by servers that implement the
"lsetstat@openssh.com" extension.
df [-hi] [path]
Display usage information for the filesystem holding the current
directory (or path if specified). If the -h flag is specified,
the capacity information will be displayed using "human-readable"
suffixes. The -i flag requests display of inode information in
addition to capacity information. This command is only supported
on servers that implement the M-bM-^@M-^\statvfs@openssh.comM-bM-^@M-^] extension.
exit Quit sftp.
get [-afpR] remote-path [local-path]
Retrieve the remote-path and store it on the local machine. If
the local path name is not specified, it is given the same name
it has on the remote machine. remote-path may contain glob(7)
characters and may match multiple files. If it does and
local-path is specified, then local-path must specify a
directory.
If the -a flag is specified, then attempt to resume partial
transfers of existing files. Note that resumption assumes that
any partial copy of the local file matches the remote copy. If
the remote file contents differ from the partial local copy then
the resultant file is likely to be corrupt.
If the -f flag is specified, then fsync(2) will be called after
the file transfer has completed to flush the file to disk.
If the -p flag is specified, then full file permissions and
access times are copied too.
If the -R flag is specified then directories will be copied
recursively. Note that sftp does not follow symbolic links when
performing recursive transfers.
help Display help text.
lcd [path]
Change local directory to path. If path is not specified, then
change directory to the local user's home directory.
lls [ls-options [path]]
Display local directory listing of either path or current
directory if path is not specified. ls-options may contain any
flags supported by the local system's ls(1) command. path may
contain glob(7) characters and may match multiple files.
lmkdir path
Create local directory specified by path.
ln [-s] oldpath newpath
Create a link from oldpath to newpath. If the -s flag is
specified the created link is a symbolic link, otherwise it is a
hard link.
lpwd Print local working directory.
ls [-1afhlnrSt] [path]
Display a remote directory listing of either path or the current
directory if path is not specified. path may contain glob(7)
characters and may match multiple files.
The following flags are recognized and alter the behaviour of ls
accordingly:
-1 Produce single columnar output.
-a List files beginning with a dot (M-bM-^@M-^X.M-bM-^@M-^Y).
-f Do not sort the listing. The default sort order is
lexicographical.
-h When used with a long format option, use unit suffixes:
Byte, Kilobyte, Megabyte, Gigabyte, Terabyte, Petabyte,
and Exabyte in order to reduce the number of digits to
four or fewer using powers of 2 for sizes (K=1024,
M=1048576, etc.).
-l Display additional details including permissions and
ownership information.
-n Produce a long listing with user and group information
presented numerically.
-r Reverse the sort order of the listing.
-S Sort the listing by file size.
-t Sort the listing by last modification time.
lumask umask
Set local umask to umask.
mkdir path
Create remote directory specified by path.
progress
Toggle display of progress meter.
put [-afpR] local-path [remote-path]
Upload local-path and store it on the remote machine. If the
remote path name is not specified, it is given the same name it
has on the local machine. local-path may contain glob(7)
characters and may match multiple files. If it does and
remote-path is specified, then remote-path must specify a
directory.
If the -a flag is specified, then attempt to resume partial
transfers of existing files. Note that resumption assumes that
any partial copy of the remote file matches the local copy. If
the local file contents differ from the remote local copy then
the resultant file is likely to be corrupt.
If the -f flag is specified, then a request will be sent to the
server to call fsync(2) after the file has been transferred.
Note that this is only supported by servers that implement the
"fsync@openssh.com" extension.
If the -p flag is specified, then full file permissions and
access times are copied too.
If the -R flag is specified then directories will be copied
recursively. Note that sftp does not follow symbolic links when
performing recursive transfers.
pwd Display remote working directory.
quit Quit sftp.
reget [-fpR] remote-path [local-path]
Resume download of remote-path. Equivalent to get with the -a
flag set.
reput [-fpR] local-path [remote-path]
Resume upload of local-path. Equivalent to put with the -a flag
set.
rename oldpath newpath
Rename remote file from oldpath to newpath.
rm path
Delete remote file specified by path.
rmdir path
Remove remote directory specified by path.
symlink oldpath newpath
Create a symbolic link from oldpath to newpath.
version
Display the sftp protocol version.
!command
Execute command in local shell.
! Escape to local shell.
? Synonym for help.
SEE ALSO
ftp(1), ls(1), scp(1), ssh(1), ssh-add(1), ssh-keygen(1), ssh_config(5),
glob(7), sftp-server(8), sshd(8)
T. Ylonen and S. Lehtinen, SSH File Transfer Protocol, draft-ietf-secsh-
filexfer-00.txt, January 2001, work in progress material.
-OpenBSD 6.8 February 12, 2021 OpenBSD 6.8
+OpenBSD 6.9 February 12, 2021 OpenBSD 6.9
diff --git a/sftp.c b/sftp.c
index fb3c08d1958e..3f46c55316aa 100644
--- a/sftp.c
+++ b/sftp.c
@@ -1,2568 +1,2565 @@
-/* $OpenBSD: sftp.c,v 1.206 2021/01/08 02:44:14 djm Exp $ */
+/* $OpenBSD: sftp.c,v 1.209 2021/04/03 06:58:30 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/ioctl.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/wait.h>
#ifdef HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
#include <ctype.h>
#include <errno.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#ifdef HAVE_LIBGEN_H
#include <libgen.h>
#endif
#ifdef HAVE_LOCALE_H
# include <locale.h>
#endif
#ifdef USE_LIBEDIT
#include <histedit.h>
#else
typedef void EditLine;
#endif
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_UTIL_H
# include <util.h>
#endif
#include "xmalloc.h"
#include "log.h"
#include "pathnames.h"
#include "misc.h"
#include "utf8.h"
#include "sftp.h"
#include "ssherr.h"
#include "sshbuf.h"
#include "sftp-common.h"
#include "sftp-client.h"
-#define DEFAULT_COPY_BUFLEN 32768 /* Size of buffer for up/download */
-#define DEFAULT_NUM_REQUESTS 64 /* # concurrent outstanding requests */
-
/* File to read commands from */
FILE* infile;
/* Are we in batchfile mode? */
int batchmode = 0;
/* PID of ssh transport process */
static volatile pid_t sshpid = -1;
-/* Suppress diagnositic messages */
+/* Suppress diagnostic messages */
int quiet = 0;
/* This is set to 0 if the progressmeter is not desired. */
int showprogress = 1;
/* When this option is set, we always recursively download/upload directories */
int global_rflag = 0;
/* When this option is set, we resume download or upload if possible */
int global_aflag = 0;
/* When this option is set, the file transfers will always preserve times */
int global_pflag = 0;
/* When this option is set, transfers will have fsync() called on each file */
int global_fflag = 0;
/* SIGINT received during command processing */
volatile sig_atomic_t interrupted = 0;
/* I wish qsort() took a separate ctx for the comparison function...*/
int sort_flag;
glob_t *sort_glob;
/* Context used for commandline completion */
struct complete_ctx {
struct sftp_conn *conn;
char **remote_pathp;
};
int remote_glob(struct sftp_conn *, const char *, int,
int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
extern char *__progname;
/* Separators for interactive commands */
#define WHITESPACE " \t\r\n"
/* ls flags */
#define LS_LONG_VIEW 0x0001 /* Full view ala ls -l */
#define LS_SHORT_VIEW 0x0002 /* Single row view ala ls -1 */
#define LS_NUMERIC_VIEW 0x0004 /* Long view with numeric uid/gid */
#define LS_NAME_SORT 0x0008 /* Sort by name (default) */
#define LS_TIME_SORT 0x0010 /* Sort by mtime */
#define LS_SIZE_SORT 0x0020 /* Sort by file size */
#define LS_REVERSE_SORT 0x0040 /* Reverse sort order */
#define LS_SHOW_ALL 0x0080 /* Don't skip filenames starting with '.' */
#define LS_SI_UNITS 0x0100 /* Display sizes as K, M, G, etc. */
#define VIEW_FLAGS (LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW|LS_SI_UNITS)
#define SORT_FLAGS (LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT)
/* Commands for interactive mode */
enum sftp_command {
I_CHDIR = 1,
I_CHGRP,
I_CHMOD,
I_CHOWN,
I_DF,
I_GET,
I_HELP,
I_LCHDIR,
I_LINK,
I_LLS,
I_LMKDIR,
I_LPWD,
I_LS,
I_LUMASK,
I_MKDIR,
I_PUT,
I_PWD,
I_QUIT,
I_REGET,
I_RENAME,
I_REPUT,
I_RM,
I_RMDIR,
I_SHELL,
I_SYMLINK,
I_VERSION,
I_PROGRESS,
};
struct CMD {
const char *c;
const int n;
const int t;
};
/* Type of completion */
#define NOARGS 0
#define REMOTE 1
#define LOCAL 2
static const struct CMD cmds[] = {
{ "bye", I_QUIT, NOARGS },
{ "cd", I_CHDIR, REMOTE },
{ "chdir", I_CHDIR, REMOTE },
{ "chgrp", I_CHGRP, REMOTE },
{ "chmod", I_CHMOD, REMOTE },
{ "chown", I_CHOWN, REMOTE },
{ "df", I_DF, REMOTE },
{ "dir", I_LS, REMOTE },
{ "exit", I_QUIT, NOARGS },
{ "get", I_GET, REMOTE },
{ "help", I_HELP, NOARGS },
{ "lcd", I_LCHDIR, LOCAL },
{ "lchdir", I_LCHDIR, LOCAL },
{ "lls", I_LLS, LOCAL },
{ "lmkdir", I_LMKDIR, LOCAL },
{ "ln", I_LINK, REMOTE },
{ "lpwd", I_LPWD, LOCAL },
{ "ls", I_LS, REMOTE },
{ "lumask", I_LUMASK, NOARGS },
{ "mkdir", I_MKDIR, REMOTE },
{ "mget", I_GET, REMOTE },
{ "mput", I_PUT, LOCAL },
{ "progress", I_PROGRESS, NOARGS },
{ "put", I_PUT, LOCAL },
{ "pwd", I_PWD, REMOTE },
{ "quit", I_QUIT, NOARGS },
{ "reget", I_REGET, REMOTE },
{ "rename", I_RENAME, REMOTE },
{ "reput", I_REPUT, LOCAL },
{ "rm", I_RM, REMOTE },
{ "rmdir", I_RMDIR, REMOTE },
{ "symlink", I_SYMLINK, REMOTE },
{ "version", I_VERSION, NOARGS },
{ "!", I_SHELL, NOARGS },
{ "?", I_HELP, NOARGS },
{ NULL, -1, -1 }
};
/* ARGSUSED */
static void
killchild(int signo)
{
pid_t pid;
pid = sshpid;
if (pid > 1) {
kill(pid, SIGTERM);
waitpid(pid, NULL, 0);
}
_exit(1);
}
/* ARGSUSED */
static void
suspchild(int signo)
{
if (sshpid > 1) {
kill(sshpid, signo);
while (waitpid(sshpid, NULL, WUNTRACED) == -1 && errno == EINTR)
continue;
}
kill(getpid(), SIGSTOP);
}
/* ARGSUSED */
static void
cmd_interrupt(int signo)
{
const char msg[] = "\rInterrupt \n";
int olderrno = errno;
(void)write(STDERR_FILENO, msg, sizeof(msg) - 1);
interrupted = 1;
errno = olderrno;
}
/*ARGSUSED*/
static void
sigchld_handler(int sig)
{
int save_errno = errno;
pid_t pid;
const char msg[] = "\rConnection closed. \n";
/* Report if ssh transport process dies. */
while ((pid = waitpid(sshpid, NULL, WNOHANG)) == -1 && errno == EINTR)
continue;
if (pid == sshpid) {
(void)write(STDERR_FILENO, msg, sizeof(msg) - 1);
sshpid = -1;
}
errno = save_errno;
}
static void
help(void)
{
printf("Available commands:\n"
"bye Quit sftp\n"
"cd path Change remote directory to 'path'\n"
"chgrp [-h] grp path Change group of file 'path' to 'grp'\n"
"chmod [-h] mode path Change permissions of file 'path' to 'mode'\n"
"chown [-h] own path Change owner of file 'path' to 'own'\n"
"df [-hi] [path] Display statistics for current directory or\n"
" filesystem containing 'path'\n"
"exit Quit sftp\n"
"get [-afpR] remote [local] Download file\n"
"help Display this help text\n"
"lcd path Change local directory to 'path'\n"
"lls [ls-options [path]] Display local directory listing\n"
"lmkdir path Create local directory\n"
"ln [-s] oldpath newpath Link remote file (-s for symlink)\n"
"lpwd Print local working directory\n"
"ls [-1afhlnrSt] [path] Display remote directory listing\n"
"lumask umask Set local umask to 'umask'\n"
"mkdir path Create remote directory\n"
"progress Toggle display of progress meter\n"
"put [-afpR] local [remote] Upload file\n"
"pwd Display remote working directory\n"
"quit Quit sftp\n"
"reget [-fpR] remote [local] Resume download file\n"
"rename oldpath newpath Rename remote file\n"
"reput [-fpR] local [remote] Resume upload file\n"
"rm path Delete remote file\n"
"rmdir path Remove remote directory\n"
"symlink oldpath newpath Symlink remote file\n"
"version Show SFTP version\n"
"!command Execute 'command' in local shell\n"
"! Escape to local shell\n"
"? Synonym for help\n");
}
static void
local_do_shell(const char *args)
{
int status;
char *shell;
pid_t pid;
if (!*args)
args = NULL;
if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
shell = _PATH_BSHELL;
if ((pid = fork()) == -1)
fatal("Couldn't fork: %s", strerror(errno));
if (pid == 0) {
/* XXX: child has pipe fds to ssh subproc open - issue? */
if (args) {
debug3("Executing %s -c \"%s\"", shell, args);
execl(shell, shell, "-c", args, (char *)NULL);
} else {
debug3("Executing %s", shell);
execl(shell, shell, (char *)NULL);
}
fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell,
strerror(errno));
_exit(1);
}
while (waitpid(pid, &status, 0) == -1)
if (errno != EINTR)
fatal("Couldn't wait for child: %s", strerror(errno));
if (!WIFEXITED(status))
error("Shell exited abnormally");
else if (WEXITSTATUS(status))
error("Shell exited with status %d", WEXITSTATUS(status));
}
static void
local_do_ls(const char *args)
{
if (!args || !*args)
local_do_shell(_PATH_LS);
else {
int len = strlen(_PATH_LS " ") + strlen(args) + 1;
char *buf = xmalloc(len);
/* XXX: quoting - rip quoting code from ftp? */
snprintf(buf, len, _PATH_LS " %s", args);
local_do_shell(buf);
free(buf);
}
}
/* Strip one path (usually the pwd) from the start of another */
static char *
path_strip(const char *path, const char *strip)
{
size_t len;
if (strip == NULL)
return (xstrdup(path));
len = strlen(strip);
if (strncmp(path, strip, len) == 0) {
if (strip[len - 1] != '/' && path[len] == '/')
len++;
return (xstrdup(path + len));
}
return (xstrdup(path));
}
static int
parse_getput_flags(const char *cmd, char **argv, int argc,
int *aflag, int *fflag, int *pflag, int *rflag)
{
extern int opterr, optind, optopt, optreset;
int ch;
optind = optreset = 1;
opterr = 0;
*aflag = *fflag = *rflag = *pflag = 0;
while ((ch = getopt(argc, argv, "afPpRr")) != -1) {
switch (ch) {
case 'a':
*aflag = 1;
break;
case 'f':
*fflag = 1;
break;
case 'p':
case 'P':
*pflag = 1;
break;
case 'r':
case 'R':
*rflag = 1;
break;
default:
error("%s: Invalid flag -%c", cmd, optopt);
return -1;
}
}
return optind;
}
static int
parse_link_flags(const char *cmd, char **argv, int argc, int *sflag)
{
extern int opterr, optind, optopt, optreset;
int ch;
optind = optreset = 1;
opterr = 0;
*sflag = 0;
while ((ch = getopt(argc, argv, "s")) != -1) {
switch (ch) {
case 's':
*sflag = 1;
break;
default:
error("%s: Invalid flag -%c", cmd, optopt);
return -1;
}
}
return optind;
}
static int
parse_rename_flags(const char *cmd, char **argv, int argc, int *lflag)
{
extern int opterr, optind, optopt, optreset;
int ch;
optind = optreset = 1;
opterr = 0;
*lflag = 0;
while ((ch = getopt(argc, argv, "l")) != -1) {
switch (ch) {
case 'l':
*lflag = 1;
break;
default:
error("%s: Invalid flag -%c", cmd, optopt);
return -1;
}
}
return optind;
}
static int
parse_ls_flags(char **argv, int argc, int *lflag)
{
extern int opterr, optind, optopt, optreset;
int ch;
optind = optreset = 1;
opterr = 0;
*lflag = LS_NAME_SORT;
while ((ch = getopt(argc, argv, "1Safhlnrt")) != -1) {
switch (ch) {
case '1':
*lflag &= ~VIEW_FLAGS;
*lflag |= LS_SHORT_VIEW;
break;
case 'S':
*lflag &= ~SORT_FLAGS;
*lflag |= LS_SIZE_SORT;
break;
case 'a':
*lflag |= LS_SHOW_ALL;
break;
case 'f':
*lflag &= ~SORT_FLAGS;
break;
case 'h':
*lflag |= LS_SI_UNITS;
break;
case 'l':
*lflag &= ~LS_SHORT_VIEW;
*lflag |= LS_LONG_VIEW;
break;
case 'n':
*lflag &= ~LS_SHORT_VIEW;
*lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW;
break;
case 'r':
*lflag |= LS_REVERSE_SORT;
break;
case 't':
*lflag &= ~SORT_FLAGS;
*lflag |= LS_TIME_SORT;
break;
default:
error("ls: Invalid flag -%c", optopt);
return -1;
}
}
return optind;
}
static int
parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag)
{
extern int opterr, optind, optopt, optreset;
int ch;
optind = optreset = 1;
opterr = 0;
*hflag = *iflag = 0;
while ((ch = getopt(argc, argv, "hi")) != -1) {
switch (ch) {
case 'h':
*hflag = 1;
break;
case 'i':
*iflag = 1;
break;
default:
error("%s: Invalid flag -%c", cmd, optopt);
return -1;
}
}
return optind;
}
static int
parse_ch_flags(const char *cmd, char **argv, int argc, int *hflag)
{
extern int opterr, optind, optopt, optreset;
int ch;
optind = optreset = 1;
opterr = 0;
*hflag = 0;
while ((ch = getopt(argc, argv, "h")) != -1) {
switch (ch) {
case 'h':
*hflag = 1;
break;
default:
error("%s: Invalid flag -%c", cmd, optopt);
return -1;
}
}
return optind;
}
static int
parse_no_flags(const char *cmd, char **argv, int argc)
{
extern int opterr, optind, optopt, optreset;
int ch;
optind = optreset = 1;
opterr = 0;
while ((ch = getopt(argc, argv, "")) != -1) {
switch (ch) {
default:
error("%s: Invalid flag -%c", cmd, optopt);
return -1;
}
}
return optind;
}
static int
process_get(struct sftp_conn *conn, const char *src, const char *dst,
const char *pwd, int pflag, int rflag, int resume, int fflag)
{
char *abs_src = NULL;
char *abs_dst = NULL;
glob_t g;
char *filename, *tmp=NULL;
int i, r, err = 0;
abs_src = xstrdup(src);
abs_src = make_absolute(abs_src, pwd);
memset(&g, 0, sizeof(g));
debug3("Looking up %s", abs_src);
if ((r = remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) != 0) {
if (r == GLOB_NOSPACE) {
error("Too many matches for \"%s\".", abs_src);
} else {
error("File \"%s\" not found.", abs_src);
}
err = -1;
goto out;
}
/*
* If multiple matches then dst must be a directory or
* unspecified.
*/
if (g.gl_matchc > 1 && dst != NULL && !local_is_dir(dst)) {
error("Multiple source paths, but destination "
"\"%s\" is not a directory", dst);
err = -1;
goto out;
}
for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
tmp = xstrdup(g.gl_pathv[i]);
if ((filename = basename(tmp)) == NULL) {
error("basename %s: %s", tmp, strerror(errno));
free(tmp);
err = -1;
goto out;
}
if (g.gl_matchc == 1 && dst) {
if (local_is_dir(dst)) {
abs_dst = path_append(dst, filename);
} else {
abs_dst = xstrdup(dst);
}
} else if (dst) {
abs_dst = path_append(dst, filename);
} else {
abs_dst = xstrdup(filename);
}
free(tmp);
resume |= global_aflag;
if (!quiet && resume)
mprintf("Resuming %s to %s\n",
g.gl_pathv[i], abs_dst);
else if (!quiet && !resume)
mprintf("Fetching %s to %s\n",
g.gl_pathv[i], abs_dst);
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
pflag || global_pflag, 1, resume,
fflag || global_fflag) == -1)
err = -1;
} else {
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
pflag || global_pflag, resume,
fflag || global_fflag) == -1)
err = -1;
}
free(abs_dst);
abs_dst = NULL;
}
out:
free(abs_src);
globfree(&g);
return(err);
}
static int
process_put(struct sftp_conn *conn, const char *src, const char *dst,
const char *pwd, int pflag, int rflag, int resume, int fflag)
{
char *tmp_dst = NULL;
char *abs_dst = NULL;
char *tmp = NULL, *filename = NULL;
glob_t g;
int err = 0;
int i, dst_is_dir = 1;
struct stat sb;
if (dst) {
tmp_dst = xstrdup(dst);
tmp_dst = make_absolute(tmp_dst, pwd);
}
memset(&g, 0, sizeof(g));
debug3("Looking up %s", src);
if (glob(src, GLOB_NOCHECK | GLOB_MARK, NULL, &g)) {
error("File \"%s\" not found.", src);
err = -1;
goto out;
}
/* If we aren't fetching to pwd then stash this status for later */
if (tmp_dst != NULL)
dst_is_dir = remote_is_dir(conn, tmp_dst);
/* If multiple matches, dst may be directory or unspecified */
if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) {
error("Multiple paths match, but destination "
"\"%s\" is not a directory", tmp_dst);
err = -1;
goto out;
}
for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
if (stat(g.gl_pathv[i], &sb) == -1) {
err = -1;
error("stat %s: %s", g.gl_pathv[i], strerror(errno));
continue;
}
tmp = xstrdup(g.gl_pathv[i]);
if ((filename = basename(tmp)) == NULL) {
error("basename %s: %s", tmp, strerror(errno));
free(tmp);
err = -1;
goto out;
}
if (g.gl_matchc == 1 && tmp_dst) {
/* If directory specified, append filename */
if (dst_is_dir)
abs_dst = path_append(tmp_dst, filename);
else
abs_dst = xstrdup(tmp_dst);
} else if (tmp_dst) {
abs_dst = path_append(tmp_dst, filename);
} else {
abs_dst = make_absolute(xstrdup(filename), pwd);
}
free(tmp);
- resume |= global_aflag;
+ resume |= global_aflag;
if (!quiet && resume)
mprintf("Resuming upload of %s to %s\n",
g.gl_pathv[i], abs_dst);
else if (!quiet && !resume)
mprintf("Uploading %s to %s\n",
g.gl_pathv[i], abs_dst);
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
if (upload_dir(conn, g.gl_pathv[i], abs_dst,
pflag || global_pflag, 1, resume,
fflag || global_fflag) == -1)
err = -1;
} else {
if (do_upload(conn, g.gl_pathv[i], abs_dst,
pflag || global_pflag, resume,
fflag || global_fflag) == -1)
err = -1;
}
}
out:
free(abs_dst);
free(tmp_dst);
globfree(&g);
return(err);
}
static int
sdirent_comp(const void *aa, const void *bb)
{
SFTP_DIRENT *a = *(SFTP_DIRENT **)aa;
SFTP_DIRENT *b = *(SFTP_DIRENT **)bb;
int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1;
#define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1))
if (sort_flag & LS_NAME_SORT)
return (rmul * strcmp(a->filename, b->filename));
else if (sort_flag & LS_TIME_SORT)
return (rmul * NCMP(a->a.mtime, b->a.mtime));
else if (sort_flag & LS_SIZE_SORT)
return (rmul * NCMP(a->a.size, b->a.size));
fatal("Unknown ls sort type");
}
/* sftp ls.1 replacement for directories */
static int
do_ls_dir(struct sftp_conn *conn, const char *path,
const char *strip_path, int lflag)
{
int n;
u_int c = 1, colspace = 0, columns = 1;
SFTP_DIRENT **d;
if ((n = do_readdir(conn, path, &d)) != 0)
return (n);
if (!(lflag & LS_SHORT_VIEW)) {
u_int m = 0, width = 80;
struct winsize ws;
char *tmp;
/* Count entries for sort and find longest filename */
for (n = 0; d[n] != NULL; n++) {
if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL))
m = MAXIMUM(m, strlen(d[n]->filename));
}
/* Add any subpath that also needs to be counted */
tmp = path_strip(path, strip_path);
m += strlen(tmp);
free(tmp);
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
width = ws.ws_col;
columns = width / (m + 2);
columns = MAXIMUM(columns, 1);
colspace = width / columns;
colspace = MINIMUM(colspace, width);
}
if (lflag & SORT_FLAGS) {
for (n = 0; d[n] != NULL; n++)
; /* count entries */
sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT);
qsort(d, n, sizeof(*d), sdirent_comp);
}
for (n = 0; d[n] != NULL && !interrupted; n++) {
char *tmp, *fname;
if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL))
continue;
tmp = path_append(path, d[n]->filename);
fname = path_strip(tmp, strip_path);
free(tmp);
if (lflag & LS_LONG_VIEW) {
if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) {
char *lname;
struct stat sb;
memset(&sb, 0, sizeof(sb));
attrib_to_stat(&d[n]->a, &sb);
lname = ls_file(fname, &sb, 1,
(lflag & LS_SI_UNITS));
mprintf("%s\n", lname);
free(lname);
} else
mprintf("%s\n", d[n]->longname);
} else {
mprintf("%-*s", colspace, fname);
if (c >= columns) {
printf("\n");
c = 1;
} else
c++;
}
free(fname);
}
if (!(lflag & LS_LONG_VIEW) && (c != 1))
printf("\n");
free_sftp_dirents(d);
return (0);
}
static int
sglob_comp(const void *aa, const void *bb)
{
u_int a = *(const u_int *)aa;
u_int b = *(const u_int *)bb;
const char *ap = sort_glob->gl_pathv[a];
const char *bp = sort_glob->gl_pathv[b];
const struct stat *as = sort_glob->gl_statv[a];
const struct stat *bs = sort_glob->gl_statv[b];
int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1;
#define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1))
if (sort_flag & LS_NAME_SORT)
return (rmul * strcmp(ap, bp));
else if (sort_flag & LS_TIME_SORT) {
#if defined(HAVE_STRUCT_STAT_ST_MTIM)
if (timespeccmp(&as->st_mtim, &bs->st_mtim, ==))
return 0;
return timespeccmp(&as->st_mtim, &bs->st_mtim, <) ?
rmul : -rmul;
#elif defined(HAVE_STRUCT_STAT_ST_MTIME)
return (rmul * NCMP(as->st_mtime, bs->st_mtime));
#else
return rmul * 1;
#endif
} else if (sort_flag & LS_SIZE_SORT)
return (rmul * NCMP(as->st_size, bs->st_size));
fatal("Unknown ls sort type");
}
/* sftp ls.1 replacement which handles path globs */
static int
do_globbed_ls(struct sftp_conn *conn, const char *path,
const char *strip_path, int lflag)
{
char *fname, *lname;
glob_t g;
int err, r;
struct winsize ws;
u_int i, j, nentries, *indices = NULL, c = 1;
u_int colspace = 0, columns = 1, m = 0, width = 80;
memset(&g, 0, sizeof(g));
if ((r = remote_glob(conn, path,
GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT|GLOB_NOSORT,
NULL, &g)) != 0 ||
(g.gl_pathc && !g.gl_matchc)) {
if (g.gl_pathc)
globfree(&g);
if (r == GLOB_NOSPACE) {
error("Can't ls: Too many matches for \"%s\"", path);
} else {
error("Can't ls: \"%s\" not found", path);
}
return -1;
}
if (interrupted)
goto out;
/*
* If the glob returns a single match and it is a directory,
* then just list its contents.
*/
if (g.gl_matchc == 1 && g.gl_statv[0] != NULL &&
S_ISDIR(g.gl_statv[0]->st_mode)) {
err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag);
globfree(&g);
return err;
}
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
width = ws.ws_col;
if (!(lflag & LS_SHORT_VIEW)) {
/* Count entries for sort and find longest filename */
for (i = 0; g.gl_pathv[i]; i++)
m = MAXIMUM(m, strlen(g.gl_pathv[i]));
columns = width / (m + 2);
columns = MAXIMUM(columns, 1);
colspace = width / columns;
}
/*
* Sorting: rather than mess with the contents of glob_t, prepare
* an array of indices into it and sort that. For the usual
* unsorted case, the indices are just the identity 1=1, 2=2, etc.
*/
for (nentries = 0; g.gl_pathv[nentries] != NULL; nentries++)
; /* count entries */
indices = calloc(nentries, sizeof(*indices));
for (i = 0; i < nentries; i++)
indices[i] = i;
if (lflag & SORT_FLAGS) {
sort_glob = &g;
sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT);
qsort(indices, nentries, sizeof(*indices), sglob_comp);
sort_glob = NULL;
}
for (j = 0; j < nentries && !interrupted; j++) {
i = indices[j];
fname = path_strip(g.gl_pathv[i], strip_path);
if (lflag & LS_LONG_VIEW) {
if (g.gl_statv[i] == NULL) {
error("no stat information for %s", fname);
continue;
}
lname = ls_file(fname, g.gl_statv[i], 1,
(lflag & LS_SI_UNITS));
mprintf("%s\n", lname);
free(lname);
} else {
mprintf("%-*s", colspace, fname);
if (c >= columns) {
printf("\n");
c = 1;
} else
c++;
}
free(fname);
}
if (!(lflag & LS_LONG_VIEW) && (c != 1))
printf("\n");
out:
if (g.gl_pathc)
globfree(&g);
free(indices);
return 0;
}
static int
do_df(struct sftp_conn *conn, const char *path, int hflag, int iflag)
{
struct sftp_statvfs st;
char s_used[FMT_SCALED_STRSIZE], s_avail[FMT_SCALED_STRSIZE];
char s_root[FMT_SCALED_STRSIZE], s_total[FMT_SCALED_STRSIZE];
char s_icapacity[16], s_dcapacity[16];
if (do_statvfs(conn, path, &st, 1) == -1)
return -1;
if (st.f_files == 0)
strlcpy(s_icapacity, "ERR", sizeof(s_icapacity));
else {
snprintf(s_icapacity, sizeof(s_icapacity), "%3llu%%",
(unsigned long long)(100 * (st.f_files - st.f_ffree) /
st.f_files));
}
if (st.f_blocks == 0)
strlcpy(s_dcapacity, "ERR", sizeof(s_dcapacity));
else {
snprintf(s_dcapacity, sizeof(s_dcapacity), "%3llu%%",
(unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
st.f_blocks));
}
if (iflag) {
printf(" Inodes Used Avail "
"(root) %%Capacity\n");
printf("%11llu %11llu %11llu %11llu %s\n",
(unsigned long long)st.f_files,
(unsigned long long)(st.f_files - st.f_ffree),
(unsigned long long)st.f_favail,
(unsigned long long)st.f_ffree, s_icapacity);
} else if (hflag) {
strlcpy(s_used, "error", sizeof(s_used));
strlcpy(s_avail, "error", sizeof(s_avail));
strlcpy(s_root, "error", sizeof(s_root));
strlcpy(s_total, "error", sizeof(s_total));
fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used);
fmt_scaled(st.f_bavail * st.f_frsize, s_avail);
fmt_scaled(st.f_bfree * st.f_frsize, s_root);
fmt_scaled(st.f_blocks * st.f_frsize, s_total);
printf(" Size Used Avail (root) %%Capacity\n");
printf("%7sB %7sB %7sB %7sB %s\n",
s_total, s_used, s_avail, s_root, s_dcapacity);
} else {
printf(" Size Used Avail "
"(root) %%Capacity\n");
printf("%12llu %12llu %12llu %12llu %s\n",
(unsigned long long)(st.f_frsize * st.f_blocks / 1024),
(unsigned long long)(st.f_frsize *
(st.f_blocks - st.f_bfree) / 1024),
(unsigned long long)(st.f_frsize * st.f_bavail / 1024),
(unsigned long long)(st.f_frsize * st.f_bfree / 1024),
s_dcapacity);
}
return 0;
}
/*
* Undo escaping of glob sequences in place. Used to undo extra escaping
* applied in makeargv() when the string is destined for a function that
* does not glob it.
*/
static void
undo_glob_escape(char *s)
{
size_t i, j;
for (i = j = 0;;) {
if (s[i] == '\0') {
s[j] = '\0';
return;
}
if (s[i] != '\\') {
s[j++] = s[i++];
continue;
}
/* s[i] == '\\' */
++i;
switch (s[i]) {
case '?':
case '[':
case '*':
case '\\':
s[j++] = s[i++];
break;
case '\0':
s[j++] = '\\';
s[j] = '\0';
return;
default:
s[j++] = '\\';
s[j++] = s[i++];
break;
}
}
}
/*
* Split a string into an argument vector using sh(1)-style quoting,
* comment and escaping rules, but with some tweaks to handle glob(3)
* wildcards.
* The "sloppy" flag allows for recovery from missing terminating quote, for
* use in parsing incomplete commandlines during tab autocompletion.
*
* Returns NULL on error or a NULL-terminated array of arguments.
*
* If "lastquote" is not NULL, the quoting character used for the last
* argument is placed in *lastquote ("\0", "'" or "\"").
*
* If "terminated" is not NULL, *terminated will be set to 1 when the
* last argument's quote has been properly terminated or 0 otherwise.
* This parameter is only of use if "sloppy" is set.
*/
#define MAXARGS 128
#define MAXARGLEN 8192
static char **
makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
u_int *terminated)
{
int argc, quot;
size_t i, j;
static char argvs[MAXARGLEN];
static char *argv[MAXARGS + 1];
enum { MA_START, MA_SQUOTE, MA_DQUOTE, MA_UNQUOTED } state, q;
*argcp = argc = 0;
if (strlen(arg) > sizeof(argvs) - 1) {
args_too_longs:
error("string too long");
return NULL;
}
if (terminated != NULL)
*terminated = 1;
if (lastquote != NULL)
*lastquote = '\0';
state = MA_START;
i = j = 0;
for (;;) {
if ((size_t)argc >= sizeof(argv) / sizeof(*argv)){
error("Too many arguments.");
return NULL;
}
if (isspace((unsigned char)arg[i])) {
if (state == MA_UNQUOTED) {
/* Terminate current argument */
argvs[j++] = '\0';
argc++;
state = MA_START;
} else if (state != MA_START)
argvs[j++] = arg[i];
} else if (arg[i] == '"' || arg[i] == '\'') {
q = arg[i] == '"' ? MA_DQUOTE : MA_SQUOTE;
if (state == MA_START) {
argv[argc] = argvs + j;
state = q;
if (lastquote != NULL)
*lastquote = arg[i];
} else if (state == MA_UNQUOTED)
state = q;
else if (state == q)
state = MA_UNQUOTED;
else
argvs[j++] = arg[i];
} else if (arg[i] == '\\') {
if (state == MA_SQUOTE || state == MA_DQUOTE) {
quot = state == MA_SQUOTE ? '\'' : '"';
/* Unescape quote we are in */
/* XXX support \n and friends? */
if (arg[i + 1] == quot) {
i++;
argvs[j++] = arg[i];
} else if (arg[i + 1] == '?' ||
arg[i + 1] == '[' || arg[i + 1] == '*') {
/*
* Special case for sftp: append
* double-escaped glob sequence -
* glob will undo one level of
* escaping. NB. string can grow here.
*/
if (j >= sizeof(argvs) - 5)
goto args_too_longs;
argvs[j++] = '\\';
argvs[j++] = arg[i++];
argvs[j++] = '\\';
argvs[j++] = arg[i];
} else {
argvs[j++] = arg[i++];
argvs[j++] = arg[i];
}
} else {
if (state == MA_START) {
argv[argc] = argvs + j;
state = MA_UNQUOTED;
if (lastquote != NULL)
*lastquote = '\0';
}
if (arg[i + 1] == '?' || arg[i + 1] == '[' ||
arg[i + 1] == '*' || arg[i + 1] == '\\') {
/*
* Special case for sftp: append
* escaped glob sequence -
* glob will undo one level of
* escaping.
*/
argvs[j++] = arg[i++];
argvs[j++] = arg[i];
} else {
/* Unescape everything */
/* XXX support \n and friends? */
i++;
argvs[j++] = arg[i];
}
}
} else if (arg[i] == '#') {
if (state == MA_SQUOTE || state == MA_DQUOTE)
argvs[j++] = arg[i];
else
goto string_done;
} else if (arg[i] == '\0') {
if (state == MA_SQUOTE || state == MA_DQUOTE) {
if (sloppy) {
state = MA_UNQUOTED;
if (terminated != NULL)
*terminated = 0;
goto string_done;
}
error("Unterminated quoted argument");
return NULL;
}
string_done:
if (state == MA_UNQUOTED) {
argvs[j++] = '\0';
argc++;
}
break;
} else {
if (state == MA_START) {
argv[argc] = argvs + j;
state = MA_UNQUOTED;
if (lastquote != NULL)
*lastquote = '\0';
}
if ((state == MA_SQUOTE || state == MA_DQUOTE) &&
(arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) {
/*
* Special case for sftp: escape quoted
* glob(3) wildcards. NB. string can grow
* here.
*/
if (j >= sizeof(argvs) - 3)
goto args_too_longs;
argvs[j++] = '\\';
argvs[j++] = arg[i];
} else
argvs[j++] = arg[i];
}
i++;
}
*argcp = argc;
return argv;
}
static int
parse_args(const char **cpp, int *ignore_errors, int *disable_echo, int *aflag,
int *fflag, int *hflag, int *iflag, int *lflag, int *pflag,
int *rflag, int *sflag,
unsigned long *n_arg, char **path1, char **path2)
{
const char *cmd, *cp = *cpp;
char *cp2, **argv;
int base = 0;
long long ll;
int path1_mandatory = 0, i, cmdnum, optidx, argc;
/* Skip leading whitespace */
cp = cp + strspn(cp, WHITESPACE);
/*
* Check for leading '-' (disable error processing) and '@' (suppress
* command echo)
*/
*ignore_errors = 0;
*disable_echo = 0;
for (;*cp != '\0'; cp++) {
if (*cp == '-') {
*ignore_errors = 1;
} else if (*cp == '@') {
*disable_echo = 1;
} else {
/* all other characters terminate prefix processing */
break;
}
}
cp = cp + strspn(cp, WHITESPACE);
/* Ignore blank lines and lines which begin with comment '#' char */
if (*cp == '\0' || *cp == '#')
return (0);
if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL)
return -1;
/* Figure out which command we have */
for (i = 0; cmds[i].c != NULL; i++) {
if (argv[0] != NULL && strcasecmp(cmds[i].c, argv[0]) == 0)
break;
}
cmdnum = cmds[i].n;
cmd = cmds[i].c;
/* Special case */
if (*cp == '!') {
cp++;
cmdnum = I_SHELL;
} else if (cmdnum == -1) {
error("Invalid command.");
return -1;
}
/* Get arguments and parse flags */
*aflag = *fflag = *hflag = *iflag = *lflag = *pflag = 0;
*rflag = *sflag = 0;
*path1 = *path2 = NULL;
optidx = 1;
switch (cmdnum) {
case I_GET:
case I_REGET:
case I_REPUT:
case I_PUT:
if ((optidx = parse_getput_flags(cmd, argv, argc,
aflag, fflag, pflag, rflag)) == -1)
return -1;
/* Get first pathname (mandatory) */
if (argc - optidx < 1) {
error("You must specify at least one path after a "
"%s command.", cmd);
return -1;
}
*path1 = xstrdup(argv[optidx]);
/* Get second pathname (optional) */
if (argc - optidx > 1) {
*path2 = xstrdup(argv[optidx + 1]);
/* Destination is not globbed */
undo_glob_escape(*path2);
}
break;
case I_LINK:
if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
return -1;
goto parse_two_paths;
case I_RENAME:
if ((optidx = parse_rename_flags(cmd, argv, argc, lflag)) == -1)
return -1;
goto parse_two_paths;
case I_SYMLINK:
if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
return -1;
parse_two_paths:
if (argc - optidx < 2) {
error("You must specify two paths after a %s "
"command.", cmd);
return -1;
}
*path1 = xstrdup(argv[optidx]);
*path2 = xstrdup(argv[optidx + 1]);
/* Paths are not globbed */
undo_glob_escape(*path1);
undo_glob_escape(*path2);
break;
case I_RM:
case I_MKDIR:
case I_RMDIR:
case I_LMKDIR:
path1_mandatory = 1;
/* FALLTHROUGH */
case I_CHDIR:
case I_LCHDIR:
if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
return -1;
/* Get pathname (mandatory) */
if (argc - optidx < 1) {
if (!path1_mandatory)
break; /* return a NULL path1 */
error("You must specify a path after a %s command.",
cmd);
return -1;
}
*path1 = xstrdup(argv[optidx]);
/* Only "rm" globs */
if (cmdnum != I_RM)
undo_glob_escape(*path1);
break;
case I_DF:
if ((optidx = parse_df_flags(cmd, argv, argc, hflag,
iflag)) == -1)
return -1;
/* Default to current directory if no path specified */
if (argc - optidx < 1)
*path1 = NULL;
else {
*path1 = xstrdup(argv[optidx]);
undo_glob_escape(*path1);
}
break;
case I_LS:
if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1)
return(-1);
/* Path is optional */
if (argc - optidx > 0)
*path1 = xstrdup(argv[optidx]);
break;
case I_LLS:
/* Skip ls command and following whitespace */
cp = cp + strlen(cmd) + strspn(cp, WHITESPACE);
case I_SHELL:
/* Uses the rest of the line */
break;
case I_LUMASK:
case I_CHMOD:
base = 8;
/* FALLTHROUGH */
case I_CHOWN:
case I_CHGRP:
if ((optidx = parse_ch_flags(cmd, argv, argc, hflag)) == -1)
return -1;
/* Get numeric arg (mandatory) */
if (argc - optidx < 1)
goto need_num_arg;
errno = 0;
ll = strtoll(argv[optidx], &cp2, base);
if (cp2 == argv[optidx] || *cp2 != '\0' ||
((ll == LLONG_MIN || ll == LLONG_MAX) && errno == ERANGE) ||
ll < 0 || ll > UINT32_MAX) {
need_num_arg:
error("You must supply a numeric argument "
"to the %s command.", cmd);
return -1;
}
*n_arg = ll;
if (cmdnum == I_LUMASK)
break;
/* Get pathname (mandatory) */
if (argc - optidx < 2) {
error("You must specify a path after a %s command.",
cmd);
return -1;
}
*path1 = xstrdup(argv[optidx + 1]);
break;
case I_QUIT:
case I_PWD:
case I_LPWD:
case I_HELP:
case I_VERSION:
case I_PROGRESS:
if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
return -1;
break;
default:
fatal("Command not implemented");
}
*cpp = cp;
return(cmdnum);
}
static int
parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
const char *startdir, int err_abort, int echo_command)
{
const char *ocmd = cmd;
char *path1, *path2, *tmp;
int ignore_errors = 0, disable_echo = 1;
int aflag = 0, fflag = 0, hflag = 0, iflag = 0;
int lflag = 0, pflag = 0, rflag = 0, sflag = 0;
int cmdnum, i;
unsigned long n_arg = 0;
Attrib a, *aa;
char path_buf[PATH_MAX];
int err = 0;
glob_t g;
path1 = path2 = NULL;
cmdnum = parse_args(&cmd, &ignore_errors, &disable_echo, &aflag, &fflag,
&hflag, &iflag, &lflag, &pflag, &rflag, &sflag, &n_arg,
&path1, &path2);
if (ignore_errors != 0)
err_abort = 0;
if (echo_command && !disable_echo)
mprintf("sftp> %s\n", ocmd);
memset(&g, 0, sizeof(g));
/* Perform command */
switch (cmdnum) {
case 0:
/* Blank line */
break;
case -1:
/* Unrecognized command */
err = -1;
break;
case I_REGET:
aflag = 1;
/* FALLTHROUGH */
case I_GET:
err = process_get(conn, path1, path2, *pwd, pflag,
rflag, aflag, fflag);
break;
case I_REPUT:
aflag = 1;
/* FALLTHROUGH */
case I_PUT:
err = process_put(conn, path1, path2, *pwd, pflag,
rflag, aflag, fflag);
break;
case I_RENAME:
path1 = make_absolute(path1, *pwd);
path2 = make_absolute(path2, *pwd);
err = do_rename(conn, path1, path2, lflag);
break;
case I_SYMLINK:
sflag = 1;
/* FALLTHROUGH */
case I_LINK:
if (!sflag)
path1 = make_absolute(path1, *pwd);
path2 = make_absolute(path2, *pwd);
err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
break;
case I_RM:
path1 = make_absolute(path1, *pwd);
remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
if (!quiet)
mprintf("Removing %s\n", g.gl_pathv[i]);
err = do_rm(conn, g.gl_pathv[i]);
if (err != 0 && err_abort)
break;
}
break;
case I_MKDIR:
path1 = make_absolute(path1, *pwd);
attrib_clear(&a);
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
a.perm = 0777;
err = do_mkdir(conn, path1, &a, 1);
break;
case I_RMDIR:
path1 = make_absolute(path1, *pwd);
err = do_rmdir(conn, path1);
break;
case I_CHDIR:
if (path1 == NULL || *path1 == '\0')
path1 = xstrdup(startdir);
path1 = make_absolute(path1, *pwd);
if ((tmp = do_realpath(conn, path1)) == NULL) {
err = 1;
break;
}
if ((aa = do_stat(conn, tmp, 0)) == NULL) {
free(tmp);
err = 1;
break;
}
if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
error("Can't change directory: Can't check target");
free(tmp);
err = 1;
break;
}
if (!S_ISDIR(aa->perm)) {
error("Can't change directory: \"%s\" is not "
"a directory", tmp);
free(tmp);
err = 1;
break;
}
free(*pwd);
*pwd = tmp;
break;
case I_LS:
if (!path1) {
do_ls_dir(conn, *pwd, *pwd, lflag);
break;
}
/* Strip pwd off beginning of non-absolute paths */
tmp = NULL;
if (!path_absolute(path1))
tmp = *pwd;
path1 = make_absolute(path1, *pwd);
err = do_globbed_ls(conn, path1, tmp, lflag);
break;
case I_DF:
/* Default to current directory if no path specified */
if (path1 == NULL)
path1 = xstrdup(*pwd);
path1 = make_absolute(path1, *pwd);
err = do_df(conn, path1, hflag, iflag);
break;
case I_LCHDIR:
if (path1 == NULL || *path1 == '\0')
path1 = xstrdup("~");
tmp = tilde_expand_filename(path1, getuid());
free(path1);
path1 = tmp;
if (chdir(path1) == -1) {
error("Couldn't change local directory to "
"\"%s\": %s", path1, strerror(errno));
err = 1;
}
break;
case I_LMKDIR:
if (mkdir(path1, 0777) == -1) {
error("Couldn't create local directory "
"\"%s\": %s", path1, strerror(errno));
err = 1;
}
break;
case I_LLS:
local_do_ls(cmd);
break;
case I_SHELL:
local_do_shell(cmd);
break;
case I_LUMASK:
umask(n_arg);
printf("Local umask: %03lo\n", n_arg);
break;
case I_CHMOD:
path1 = make_absolute(path1, *pwd);
attrib_clear(&a);
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
a.perm = n_arg;
remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
if (!quiet)
mprintf("Changing mode on %s\n",
g.gl_pathv[i]);
err = (hflag ? do_lsetstat : do_setstat)(conn,
g.gl_pathv[i], &a);
if (err != 0 && err_abort)
break;
}
break;
case I_CHOWN:
case I_CHGRP:
path1 = make_absolute(path1, *pwd);
remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
if (!(aa = (hflag ? do_lstat : do_stat)(conn,
g.gl_pathv[i], 0))) {
if (err_abort) {
err = -1;
break;
} else
continue;
}
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
error("Can't get current ownership of "
"remote file \"%s\"", g.gl_pathv[i]);
if (err_abort) {
err = -1;
break;
} else
continue;
}
aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
if (cmdnum == I_CHOWN) {
if (!quiet)
mprintf("Changing owner on %s\n",
g.gl_pathv[i]);
aa->uid = n_arg;
} else {
if (!quiet)
mprintf("Changing group on %s\n",
g.gl_pathv[i]);
aa->gid = n_arg;
}
err = (hflag ? do_lsetstat : do_setstat)(conn,
g.gl_pathv[i], aa);
if (err != 0 && err_abort)
break;
}
break;
case I_PWD:
mprintf("Remote working directory: %s\n", *pwd);
break;
case I_LPWD:
if (!getcwd(path_buf, sizeof(path_buf))) {
error("Couldn't get local cwd: %s", strerror(errno));
err = -1;
break;
}
mprintf("Local working directory: %s\n", path_buf);
break;
case I_QUIT:
/* Processed below */
break;
case I_HELP:
help();
break;
case I_VERSION:
printf("SFTP protocol version %u\n", sftp_proto_version(conn));
break;
case I_PROGRESS:
showprogress = !showprogress;
if (showprogress)
printf("Progress meter enabled\n");
else
printf("Progress meter disabled\n");
break;
default:
fatal("%d is not implemented", cmdnum);
}
if (g.gl_pathc)
globfree(&g);
free(path1);
free(path2);
/* If an unignored error occurs in batch mode we should abort. */
if (err_abort && err != 0)
return (-1);
else if (cmdnum == I_QUIT)
return (1);
return (0);
}
#ifdef USE_LIBEDIT
static char *
prompt(EditLine *el)
{
return ("sftp> ");
}
/* Display entries in 'list' after skipping the first 'len' chars */
static void
complete_display(char **list, u_int len)
{
u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen;
struct winsize ws;
char *tmp;
/* Count entries for sort and find longest */
for (y = 0; list[y]; y++)
m = MAXIMUM(m, strlen(list[y]));
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
width = ws.ws_col;
m = m > len ? m - len : 0;
columns = width / (m + 2);
columns = MAXIMUM(columns, 1);
colspace = width / columns;
colspace = MINIMUM(colspace, width);
printf("\n");
m = 1;
for (y = 0; list[y]; y++) {
llen = strlen(list[y]);
tmp = llen > len ? list[y] + len : "";
mprintf("%-*s", colspace, tmp);
if (m >= columns) {
printf("\n");
m = 1;
} else
m++;
}
printf("\n");
}
/*
* Given a "list" of words that begin with a common prefix of "word",
* attempt to find an autocompletion to extends "word" by the next
* characters common to all entries in "list".
*/
static char *
complete_ambiguous(const char *word, char **list, size_t count)
{
if (word == NULL)
return NULL;
if (count > 0) {
u_int y, matchlen = strlen(list[0]);
/* Find length of common stem */
for (y = 1; list[y]; y++) {
u_int x;
for (x = 0; x < matchlen; x++)
if (list[0][x] != list[y][x])
break;
matchlen = x;
}
if (matchlen > strlen(word)) {
char *tmp = xstrdup(list[0]);
tmp[matchlen] = '\0';
return tmp;
}
}
return xstrdup(word);
}
/* Autocomplete a sftp command */
static int
complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote,
int terminated)
{
u_int y, count = 0, cmdlen, tmplen;
char *tmp, **list, argterm[3];
const LineInfo *lf;
list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *));
/* No command specified: display all available commands */
if (cmd == NULL) {
for (y = 0; cmds[y].c; y++)
list[count++] = xstrdup(cmds[y].c);
list[count] = NULL;
complete_display(list, 0);
for (y = 0; list[y] != NULL; y++)
free(list[y]);
free(list);
return count;
}
/* Prepare subset of commands that start with "cmd" */
cmdlen = strlen(cmd);
for (y = 0; cmds[y].c; y++) {
if (!strncasecmp(cmd, cmds[y].c, cmdlen))
list[count++] = xstrdup(cmds[y].c);
}
list[count] = NULL;
if (count == 0) {
free(list);
return 0;
}
/* Complete ambiguous command */
tmp = complete_ambiguous(cmd, list, count);
if (count > 1)
complete_display(list, 0);
for (y = 0; list[y]; y++)
free(list[y]);
free(list);
if (tmp != NULL) {
tmplen = strlen(tmp);
cmdlen = strlen(cmd);
/* If cmd may be extended then do so */
if (tmplen > cmdlen)
if (el_insertstr(el, tmp + cmdlen) == -1)
fatal("el_insertstr failed.");
lf = el_line(el);
/* Terminate argument cleanly */
if (count == 1) {
y = 0;
if (!terminated)
argterm[y++] = quote;
if (lastarg || *(lf->cursor) != ' ')
argterm[y++] = ' ';
argterm[y] = '\0';
if (y > 0 && el_insertstr(el, argterm) == -1)
fatal("el_insertstr failed.");
}
free(tmp);
}
return count;
}
/*
* Determine whether a particular sftp command's arguments (if any)
* represent local or remote files.
*/
static int
complete_is_remote(char *cmd) {
int i;
if (cmd == NULL)
return -1;
for (i = 0; cmds[i].c; i++) {
if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c)))
return cmds[i].t;
}
return -1;
}
/* Autocomplete a filename "file" */
static int
complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
char *file, int remote, int lastarg, char quote, int terminated)
{
glob_t g;
char *tmp, *tmp2, ins[8];
u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs;
int clen;
const LineInfo *lf;
/* Glob from "file" location */
if (file == NULL)
tmp = xstrdup("*");
else
xasprintf(&tmp, "%s*", file);
/* Check if the path is absolute. */
isabs = path_absolute(tmp);
memset(&g, 0, sizeof(g));
if (remote != LOCAL) {
tmp = make_absolute(tmp, remote_path);
remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
} else
glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
/* Determine length of pwd so we can trim completion display */
for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) {
/* Terminate counting on first unescaped glob metacharacter */
if (tmp[tmplen] == '*' || tmp[tmplen] == '?') {
if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0')
hadglob = 1;
break;
}
if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0')
tmplen++;
if (tmp[tmplen] == '/')
pwdlen = tmplen + 1; /* track last seen '/' */
}
free(tmp);
tmp = NULL;
if (g.gl_matchc == 0)
goto out;
if (g.gl_matchc > 1)
complete_display(g.gl_pathv, pwdlen);
/* Don't try to extend globs */
if (file == NULL || hadglob)
goto out;
tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc);
tmp = path_strip(tmp2, isabs ? NULL : remote_path);
free(tmp2);
if (tmp == NULL)
goto out;
tmplen = strlen(tmp);
filelen = strlen(file);
/* Count the number of escaped characters in the input string. */
cesc = isesc = 0;
for (i = 0; i < filelen; i++) {
if (!isesc && file[i] == '\\' && i + 1 < filelen){
isesc = 1;
cesc++;
} else
isesc = 0;
}
if (tmplen > (filelen - cesc)) {
tmp2 = tmp + filelen - cesc;
len = strlen(tmp2);
/* quote argument on way out */
for (i = 0; i < len; i += clen) {
if ((clen = mblen(tmp2 + i, len - i)) < 0 ||
(size_t)clen > sizeof(ins) - 2)
fatal("invalid multibyte character");
ins[0] = '\\';
memcpy(ins + 1, tmp2 + i, clen);
ins[clen + 1] = '\0';
switch (tmp2[i]) {
case '\'':
case '"':
case '\\':
case '\t':
case '[':
case ' ':
case '#':
case '*':
if (quote == '\0' || tmp2[i] == quote) {
if (el_insertstr(el, ins) == -1)
fatal("el_insertstr "
"failed.");
break;
}
/* FALLTHROUGH */
default:
if (el_insertstr(el, ins + 1) == -1)
fatal("el_insertstr failed.");
break;
}
}
}
lf = el_line(el);
if (g.gl_matchc == 1) {
i = 0;
if (!terminated && quote != '\0')
ins[i++] = quote;
if (*(lf->cursor - 1) != '/' &&
(lastarg || *(lf->cursor) != ' '))
ins[i++] = ' ';
ins[i] = '\0';
if (i > 0 && el_insertstr(el, ins) == -1)
fatal("el_insertstr failed.");
}
free(tmp);
out:
globfree(&g);
return g.gl_matchc;
}
/* tab-completion hook function, called via libedit */
static unsigned char
complete(EditLine *el, int ch)
{
char **argv, *line, quote;
int argc, carg;
u_int cursor, len, terminated, ret = CC_ERROR;
const LineInfo *lf;
struct complete_ctx *complete_ctx;
lf = el_line(el);
if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0)
fatal_f("el_get failed");
/* Figure out which argument the cursor points to */
cursor = lf->cursor - lf->buffer;
line = xmalloc(cursor + 1);
memcpy(line, lf->buffer, cursor);
line[cursor] = '\0';
argv = makeargv(line, &carg, 1, &quote, &terminated);
free(line);
/* Get all the arguments on the line */
len = lf->lastchar - lf->buffer;
line = xmalloc(len + 1);
memcpy(line, lf->buffer, len);
line[len] = '\0';
argv = makeargv(line, &argc, 1, NULL, NULL);
/* Ensure cursor is at EOL or a argument boundary */
if (line[cursor] != ' ' && line[cursor] != '\0' &&
line[cursor] != '\n') {
free(line);
return ret;
}
if (carg == 0) {
/* Show all available commands */
complete_cmd_parse(el, NULL, argc == carg, '\0', 1);
ret = CC_REDISPLAY;
} else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ') {
/* Handle the command parsing */
if (complete_cmd_parse(el, argv[0], argc == carg,
quote, terminated) != 0)
ret = CC_REDISPLAY;
} else if (carg >= 1) {
/* Handle file parsing */
int remote = complete_is_remote(argv[0]);
char *filematch = NULL;
if (carg > 1 && line[cursor-1] != ' ')
filematch = argv[carg - 1];
if (remote != 0 &&
complete_match(el, complete_ctx->conn,
*complete_ctx->remote_pathp, filematch,
remote, carg == argc, quote, terminated) != 0)
ret = CC_REDISPLAY;
}
free(line);
return ret;
}
#endif /* USE_LIBEDIT */
static int
interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
{
char *remote_path;
char *dir = NULL, *startdir = NULL;
char cmd[2048];
int err, interactive;
EditLine *el = NULL;
#ifdef USE_LIBEDIT
History *hl = NULL;
HistEvent hev;
extern char *__progname;
struct complete_ctx complete_ctx;
if (!batchmode && isatty(STDIN_FILENO)) {
if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL)
fatal("Couldn't initialise editline");
if ((hl = history_init()) == NULL)
fatal("Couldn't initialise editline history");
history(hl, &hev, H_SETSIZE, 100);
el_set(el, EL_HIST, history, hl);
el_set(el, EL_PROMPT, prompt);
el_set(el, EL_EDITOR, "emacs");
el_set(el, EL_TERMINAL, NULL);
el_set(el, EL_SIGNAL, 1);
el_source(el, NULL);
/* Tab Completion */
el_set(el, EL_ADDFN, "ftp-complete",
"Context sensitive argument completion", complete);
complete_ctx.conn = conn;
complete_ctx.remote_pathp = &remote_path;
el_set(el, EL_CLIENTDATA, (void*)&complete_ctx);
el_set(el, EL_BIND, "^I", "ftp-complete", NULL);
/* enable ctrl-left-arrow and ctrl-right-arrow */
el_set(el, EL_BIND, "\\e[1;5C", "em-next-word", NULL);
el_set(el, EL_BIND, "\\e\\e[C", "em-next-word", NULL);
el_set(el, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL);
el_set(el, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL);
/* make ^w match ksh behaviour */
el_set(el, EL_BIND, "^w", "ed-delete-prev-word", NULL);
}
#endif /* USE_LIBEDIT */
remote_path = do_realpath(conn, ".");
if (remote_path == NULL)
fatal("Need cwd");
startdir = xstrdup(remote_path);
if (file1 != NULL) {
dir = xstrdup(file1);
dir = make_absolute(dir, remote_path);
if (remote_is_dir(conn, dir) && file2 == NULL) {
if (!quiet)
mprintf("Changing to: %s\n", dir);
snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
if (parse_dispatch_command(conn, cmd,
&remote_path, startdir, 1, 0) != 0) {
free(dir);
free(startdir);
free(remote_path);
free(conn);
return (-1);
}
} else {
/* XXX this is wrong wrt quoting */
snprintf(cmd, sizeof cmd, "get%s %s%s%s",
global_aflag ? " -a" : "", dir,
file2 == NULL ? "" : " ",
file2 == NULL ? "" : file2);
err = parse_dispatch_command(conn, cmd,
&remote_path, startdir, 1, 0);
free(dir);
free(startdir);
free(remote_path);
free(conn);
return (err);
}
free(dir);
}
setvbuf(stdout, NULL, _IOLBF, 0);
setvbuf(infile, NULL, _IOLBF, 0);
interactive = !batchmode && isatty(STDIN_FILENO);
err = 0;
for (;;) {
ssh_signal(SIGINT, SIG_IGN);
if (el == NULL) {
if (interactive)
printf("sftp> ");
if (fgets(cmd, sizeof(cmd), infile) == NULL) {
if (interactive)
printf("\n");
break;
}
} else {
#ifdef USE_LIBEDIT
const char *line;
int count = 0;
if ((line = el_gets(el, &count)) == NULL ||
count <= 0) {
printf("\n");
- break;
+ break;
}
history(hl, &hev, H_ENTER, line);
if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) {
fprintf(stderr, "Error: input line too long\n");
continue;
}
#endif /* USE_LIBEDIT */
}
cmd[strcspn(cmd, "\n")] = '\0';
/* Handle user interrupts gracefully during commands */
interrupted = 0;
ssh_signal(SIGINT, cmd_interrupt);
err = parse_dispatch_command(conn, cmd, &remote_path,
startdir, batchmode, !interactive && el == NULL);
if (err != 0)
break;
}
ssh_signal(SIGCHLD, SIG_DFL);
free(remote_path);
free(startdir);
free(conn);
#ifdef USE_LIBEDIT
if (el != NULL)
el_end(el);
#endif /* USE_LIBEDIT */
/* err == 1 signifies normal "quit" exit */
return (err >= 0 ? 0 : -1);
}
static void
connect_to_server(char *path, char **args, int *in, int *out)
{
int c_in, c_out;
#ifdef USE_PIPES
int pin[2], pout[2];
if ((pipe(pin) == -1) || (pipe(pout) == -1))
fatal("pipe: %s", strerror(errno));
*in = pin[0];
*out = pout[1];
c_in = pout[0];
c_out = pin[1];
#else /* USE_PIPES */
int inout[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1)
fatal("socketpair: %s", strerror(errno));
*in = *out = inout[0];
c_in = c_out = inout[1];
#endif /* USE_PIPES */
if ((sshpid = fork()) == -1)
fatal("fork: %s", strerror(errno));
else if (sshpid == 0) {
if ((dup2(c_in, STDIN_FILENO) == -1) ||
(dup2(c_out, STDOUT_FILENO) == -1)) {
fprintf(stderr, "dup2: %s\n", strerror(errno));
_exit(1);
}
close(*in);
close(*out);
close(c_in);
close(c_out);
/*
* The underlying ssh is in the same process group, so we must
* ignore SIGINT if we want to gracefully abort commands,
* otherwise the signal will make it to the ssh process and
* kill it too. Contrawise, since sftp sends SIGTERMs to the
* underlying ssh, it must *not* ignore that signal.
*/
ssh_signal(SIGINT, SIG_IGN);
ssh_signal(SIGTERM, SIG_DFL);
execvp(path, args);
fprintf(stderr, "exec: %s: %s\n", path, strerror(errno));
_exit(1);
}
ssh_signal(SIGTERM, killchild);
ssh_signal(SIGINT, killchild);
ssh_signal(SIGHUP, killchild);
ssh_signal(SIGTSTP, suspchild);
ssh_signal(SIGTTIN, suspchild);
ssh_signal(SIGTTOU, suspchild);
ssh_signal(SIGCHLD, sigchld_handler);
close(c_in);
close(c_out);
}
static void
usage(void)
{
extern char *__progname;
fprintf(stderr,
"usage: %s [-46AaCfNpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n"
" [-D sftp_server_path] [-F ssh_config] [-i identity_file]\n"
" [-J destination] [-l limit] [-o ssh_option] [-P port]\n"
" [-R num_requests] [-S program] [-s subsystem | sftp_server]\n"
" destination\n",
__progname);
exit(1);
}
int
main(int argc, char **argv)
{
int in, out, ch, err, tmp, port = -1, noisy = 0;
char *host = NULL, *user, *cp, *file2 = NULL;
int debug_level = 0;
char *file1 = NULL, *sftp_server = NULL;
char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL;
const char *errstr;
LogLevel ll = SYSLOG_LEVEL_INFO;
arglist args;
extern int optind;
extern char *optarg;
struct sftp_conn *conn;
- size_t copy_buffer_len = DEFAULT_COPY_BUFLEN;
- size_t num_requests = DEFAULT_NUM_REQUESTS;
+ size_t copy_buffer_len = 0;
+ size_t num_requests = 0;
long long limit_kbps = 0;
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
sanitise_stdfd();
msetlocale();
seed_rng();
__progname = ssh_get_progname(argv[0]);
memset(&args, '\0', sizeof(args));
args.list = NULL;
addargs(&args, "%s", ssh_program);
addargs(&args, "-oForwardX11 no");
addargs(&args, "-oPermitLocalCommand no");
addargs(&args, "-oClearAllForwardings yes");
ll = SYSLOG_LEVEL_INFO;
infile = stdin;
while ((ch = getopt(argc, argv,
"1246AafhNpqrvCc:D:i:l:o:s:S:b:B:F:J:P:R:")) != -1) {
switch (ch) {
/* Passed through to ssh(1) */
case 'A':
case '4':
case '6':
case 'C':
addargs(&args, "-%c", ch);
break;
/* Passed through to ssh(1) with argument */
case 'F':
case 'J':
case 'c':
case 'i':
case 'o':
addargs(&args, "-%c", ch);
addargs(&args, "%s", optarg);
break;
case 'q':
ll = SYSLOG_LEVEL_ERROR;
quiet = 1;
showprogress = 0;
addargs(&args, "-%c", ch);
break;
case 'P':
port = a2port(optarg);
if (port <= 0)
fatal("Bad port \"%s\"\n", optarg);
break;
case 'v':
if (debug_level < 3) {
addargs(&args, "-v");
ll = SYSLOG_LEVEL_DEBUG1 + debug_level;
}
debug_level++;
break;
case '1':
fatal("SSH protocol v.1 is no longer supported");
break;
case '2':
/* accept silently */
break;
case 'a':
global_aflag = 1;
break;
case 'B':
copy_buffer_len = strtol(optarg, &cp, 10);
if (copy_buffer_len == 0 || *cp != '\0')
fatal("Invalid buffer size \"%s\"", optarg);
break;
case 'b':
if (batchmode)
fatal("Batch file already specified.");
/* Allow "-" as stdin */
if (strcmp(optarg, "-") != 0 &&
(infile = fopen(optarg, "r")) == NULL)
fatal("%s (%s).", strerror(errno), optarg);
showprogress = 0;
quiet = batchmode = 1;
addargs(&args, "-obatchmode yes");
break;
case 'f':
global_fflag = 1;
break;
case 'N':
noisy = 1; /* Used to clear quiet mode after getopt */
break;
case 'p':
global_pflag = 1;
break;
case 'D':
sftp_direct = optarg;
break;
case 'l':
limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
&errstr);
if (errstr != NULL)
usage();
limit_kbps *= 1024; /* kbps */
break;
case 'r':
global_rflag = 1;
break;
case 'R':
num_requests = strtol(optarg, &cp, 10);
if (num_requests == 0 || *cp != '\0')
fatal("Invalid number of requests \"%s\"",
optarg);
break;
case 's':
sftp_server = optarg;
break;
case 'S':
ssh_program = optarg;
replacearg(&args, 0, "%s", ssh_program);
break;
case 'h':
default:
usage();
}
}
/* Do this last because we want the user to be able to override it */
addargs(&args, "-oForwardAgent no");
if (!isatty(STDERR_FILENO))
showprogress = 0;
if (noisy)
quiet = 0;
log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
if (sftp_direct == NULL) {
if (optind == argc || argc > (optind + 2))
usage();
argv += optind;
switch (parse_uri("sftp", *argv, &user, &host, &tmp, &file1)) {
case -1:
usage();
break;
case 0:
if (tmp != -1)
port = tmp;
break;
default:
/* Try with user, host and path. */
if (parse_user_host_path(*argv, &user, &host,
&file1) == 0)
break;
/* Try with user and host. */
if (parse_user_host_port(*argv, &user, &host, NULL)
== 0)
break;
/* Treat as a plain hostname. */
host = xstrdup(*argv);
host = cleanhostname(host);
break;
}
file2 = *(argv + 1);
if (!*host) {
fprintf(stderr, "Missing hostname\n");
usage();
}
if (port != -1)
addargs(&args, "-oPort %d", port);
if (user != NULL) {
addargs(&args, "-l");
addargs(&args, "%s", user);
}
/* no subsystem if the server-spec contains a '/' */
if (sftp_server == NULL || strchr(sftp_server, '/') == NULL)
addargs(&args, "-s");
addargs(&args, "--");
addargs(&args, "%s", host);
addargs(&args, "%s", (sftp_server != NULL ?
sftp_server : "sftp"));
connect_to_server(ssh_program, args.list, &in, &out);
} else {
args.list = NULL;
addargs(&args, "sftp-server");
connect_to_server(sftp_direct, args.list, &in, &out);
}
freeargs(&args);
conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps);
if (conn == NULL)
fatal("Couldn't initialise connection to server");
if (!quiet) {
if (sftp_direct == NULL)
fprintf(stderr, "Connected to %s.\n", host);
else
fprintf(stderr, "Attached to %s.\n", sftp_direct);
}
err = interactive_loop(conn, file1, file2);
#if !defined(USE_PIPES)
shutdown(in, SHUT_RDWR);
shutdown(out, SHUT_RDWR);
#endif
close(in);
close(out);
if (batchmode)
fclose(infile);
while (waitpid(sshpid, NULL, 0) == -1 && sshpid > 1)
if (errno != EINTR)
fatal("Couldn't wait for ssh process: %s",
strerror(errno));
exit(err == 0 ? 0 : 1);
}
diff --git a/srclimit.c b/srclimit.c
index e2446f13130a..5014ed79f296 100644
--- a/srclimit.c
+++ b/srclimit.c
@@ -1,140 +1,140 @@
/*
* Copyright (c) 2020 Darren Tucker <dtucker@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <limits.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include "addr.h"
#include "canohost.h"
#include "log.h"
#include "misc.h"
#include "srclimit.h"
#include "xmalloc.h"
static int max_children, max_persource, ipv4_masklen, ipv6_masklen;
/* Per connection state, used to enforce unauthenticated connection limit. */
static struct child_info {
int id;
struct xaddr addr;
} *child;
void
srclimit_init(int max, int persource, int ipv4len, int ipv6len)
{
int i;
max_children = max;
ipv4_masklen = ipv4len;
ipv6_masklen = ipv6len;
max_persource = persource;
if (max_persource == INT_MAX) /* no limit */
return;
debug("%s: max connections %d, per source %d, masks %d,%d", __func__,
max, persource, ipv4len, ipv6len);
if (max <= 0)
fatal("%s: invalid number of sockets: %d", __func__, max);
child = xcalloc(max_children, sizeof(*child));
for (i = 0; i < max_children; i++)
child[i].id = -1;
}
/* returns 1 if connection allowed, 0 if not allowed. */
int
srclimit_check_allow(int sock, int id)
{
struct xaddr xa, xb, xmask;
struct sockaddr_storage addr;
socklen_t addrlen = sizeof(addr);
struct sockaddr *sa = (struct sockaddr *)&addr;
int i, bits, first_unused, count = 0;
char xas[NI_MAXHOST];
if (max_persource == INT_MAX) /* no limit */
return 1;
debug("%s: sock %d id %d limit %d", __func__, sock, id, max_persource);
if (getpeername(sock, sa, &addrlen) != 0)
return 1; /* not remote socket? */
if (addr_sa_to_xaddr(sa, addrlen, &xa) != 0)
return 1; /* unknown address family? */
/* Mask address off address to desired size. */
bits = xa.af == AF_INET ? ipv4_masklen : ipv6_masklen;
if (addr_netmask(xa.af, bits, &xmask) != 0 ||
addr_and(&xb, &xa, &xmask) != 0) {
debug3("%s: invalid mask %d bits", __func__, bits);
return 1;
}
first_unused = max_children;
/* Count matching entries and find first unused one. */
for (i = 0; i < max_children; i++) {
if (child[i].id == -1) {
if (i < first_unused)
first_unused = i;
} else if (addr_cmp(&child[i].addr, &xb) == 0) {
count++;
}
}
if (addr_ntop(&xa, xas, sizeof(xas)) != 0) {
debug3("%s: addr ntop failed", __func__);
return 1;
}
debug3("%s: new unauthenticated connection from %s/%d, at %d of %d",
- __func__, xas, bits, count, max_persource);
+ __func__, xas, bits, count, max_persource);
if (first_unused == max_children) { /* no free slot found */
debug3("%s: no free slot", __func__);
return 0;
}
if (first_unused < 0 || first_unused >= max_children)
fatal("%s: internal error: first_unused out of range",
__func__);
if (count >= max_persource)
return 0;
/* Connection allowed, store masked address. */
child[first_unused].id = id;
memcpy(&child[first_unused].addr, &xb, sizeof(xb));
return 1;
}
void
srclimit_done(int id)
{
int i;
if (max_persource == INT_MAX) /* no limit */
return;
debug("%s: id %d", __func__, id);
/* Clear corresponding state entry. */
for (i = 0; i < max_children; i++) {
if (child[i].id == id) {
child[i].id = -1;
return;
}
}
}
diff --git a/ssh-add.0 b/ssh-add.0
index d73af0f43cc1..d955d3237127 100644
--- a/ssh-add.0
+++ b/ssh-add.0
@@ -1,152 +1,152 @@
SSH-ADD(1) General Commands Manual SSH-ADD(1)
NAME
ssh-add M-bM-^@M-^S adds private key identities to the OpenSSH authentication agent
SYNOPSIS
ssh-add [-cDdKkLlqvXx] [-E fingerprint_hash] [-S provider] [-t life]
[file ...]
ssh-add -s pkcs11
ssh-add -e pkcs11
ssh-add -T pubkey ...
DESCRIPTION
ssh-add adds private key identities to the authentication agent,
ssh-agent(1). When run without arguments, it adds the files
~/.ssh/id_rsa, ~/.ssh/id_dsa, ~/.ssh/id_ecdsa, ~/.ssh/id_ecdsa_sk,
~/.ssh/id_ed25519, and ~/.ssh/id_ed25519_sk. After loading a private
key, ssh-add will try to load corresponding certificate information from
the filename obtained by appending -cert.pub to the name of the private
key file. Alternative file names can be given on the command line.
If any file requires a passphrase, ssh-add asks for the passphrase from
the user. The passphrase is read from the user's tty. ssh-add retries
the last passphrase if multiple identity files are given.
The authentication agent must be running and the SSH_AUTH_SOCK
environment variable must contain the name of its socket for ssh-add to
work.
The options are as follows:
-c Indicates that added identities should be subject to confirmation
before being used for authentication. Confirmation is performed
by ssh-askpass(1). Successful confirmation is signaled by a zero
exit status from ssh-askpass(1), rather than text entered into
the requester.
-D Deletes all identities from the agent.
-d Instead of adding identities, removes identities from the agent.
If ssh-add has been run without arguments, the keys for the
default identities and their corresponding certificates will be
removed. Otherwise, the argument list will be interpreted as a
list of paths to public key files to specify keys and
certificates to be removed from the agent. If no public key is
found at a given path, ssh-add will append .pub and retry. If
the argument list consists of M-bM-^@M-^\-M-bM-^@M-^] then ssh-add will read public
keys to be removed from standard input.
-E fingerprint_hash
Specifies the hash algorithm used when displaying key
fingerprints. Valid options are: M-bM-^@M-^\md5M-bM-^@M-^] and M-bM-^@M-^\sha256M-bM-^@M-^]. The
default is M-bM-^@M-^\sha256M-bM-^@M-^].
-e pkcs11
Remove keys provided by the PKCS#11 shared library pkcs11.
-K Load resident keys from a FIDO authenticator.
-k When loading keys into or deleting keys from the agent, process
plain private keys only and skip certificates.
-L Lists public key parameters of all identities currently
represented by the agent.
-l Lists fingerprints of all identities currently represented by the
agent.
-q Be quiet after a successful operation.
-S provider
Specifies a path to a library that will be used when adding FIDO
authenticator-hosted keys, overriding the default of using the
internal USB HID support.
-s pkcs11
Add keys provided by the PKCS#11 shared library pkcs11.
-T pubkey ...
Tests whether the private keys that correspond to the specified
pubkey files are usable by performing sign and verify operations
on each.
-t life
Set a maximum lifetime when adding identities to an agent. The
lifetime may be specified in seconds or in a time format
specified in sshd_config(5).
-v Verbose mode. Causes ssh-add to print debugging messages about
its progress. This is helpful in debugging problems. Multiple
-v options increase the verbosity. The maximum is 3.
-X Unlock the agent.
-x Lock the agent with a password.
ENVIRONMENT
DISPLAY, SSH_ASKPASS and SSH_ASKPASS_REQUIRE
If ssh-add needs a passphrase, it will read the passphrase from
the current terminal if it was run from a terminal. If ssh-add
does not have a terminal associated with it but DISPLAY and
SSH_ASKPASS are set, it will execute the program specified by
SSH_ASKPASS (by default M-bM-^@M-^\ssh-askpassM-bM-^@M-^]) and open an X11 window to
read the passphrase. This is particularly useful when calling
ssh-add from a .xsession or related script.
SSH_ASKPASS_REQUIRE allows further control over the use of an
askpass program. If this variable is set to M-bM-^@M-^\neverM-bM-^@M-^] then ssh-add
will never attempt to use one. If it is set to M-bM-^@M-^\preferM-bM-^@M-^], then
ssh-add will prefer to use the askpass program instead of the TTY
when requesting passwords. Finally, if the variable is set to
M-bM-^@M-^\forceM-bM-^@M-^], then the askpass program will be used for all passphrase
input regardless of whether DISPLAY is set.
SSH_AUTH_SOCK
Identifies the path of a UNIX-domain socket used to communicate
with the agent.
SSH_SK_PROVIDER
Specifies a path to a library that will be used when loading any
FIDO authenticator-hosted keys, overriding the default of using
the built-in USB HID support.
FILES
~/.ssh/id_dsa
~/.ssh/id_ecdsa
~/.ssh/id_ecdsa_sk
~/.ssh/id_ed25519
~/.ssh/id_ed25519_sk
~/.ssh/id_rsa
Contains the DSA, ECDSA, authenticator-hosted ECDSA, Ed25519,
authenticator-hosted Ed25519 or RSA authentication identity of
the user.
Identity files should not be readable by anyone but the user. Note that
ssh-add ignores identity files if they are accessible by others.
EXIT STATUS
Exit status is 0 on success, 1 if the specified command fails, and 2 if
ssh-add is unable to contact the authentication agent.
SEE ALSO
ssh(1), ssh-agent(1), ssh-askpass(1), ssh-keygen(1), sshd(8)
AUTHORS
OpenSSH is a derivative of the original and free ssh 1.2.12 release by
Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo
de Raadt and Dug Song removed many bugs, re-added newer features and
created OpenSSH. Markus Friedl contributed the support for SSH protocol
versions 1.5 and 2.0.
-OpenBSD 6.8 July 14, 2020 OpenBSD 6.8
+OpenBSD 6.9 July 14, 2020 OpenBSD 6.9
diff --git a/ssh-add.c b/ssh-add.c
index 7edb9f9a7be9..92192fcfa23c 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -1,864 +1,864 @@
-/* $OpenBSD: ssh-add.c,v 1.159 2021/01/11 02:12:58 dtucker Exp $ */
+/* $OpenBSD: ssh-add.c,v 1.160 2021/04/03 06:18:41 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Adds an identity to the authentication server, or removes an identity.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
* SSH2 implementation,
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifdef WITH_OPENSSL
# include <openssl/evp.h>
# include "openbsd-compat/openssl-compat.h"
#endif
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include "xmalloc.h"
#include "ssh.h"
#include "log.h"
#include "sshkey.h"
#include "sshbuf.h"
#include "authfd.h"
#include "authfile.h"
#include "pathnames.h"
#include "misc.h"
#include "ssherr.h"
#include "digest.h"
#include "ssh-sk.h"
#include "sk-api.h"
/* argv0 */
extern char *__progname;
/* Default files to add */
static char *default_files[] = {
#ifdef WITH_OPENSSL
_PATH_SSH_CLIENT_ID_RSA,
_PATH_SSH_CLIENT_ID_DSA,
#ifdef OPENSSL_HAS_ECC
_PATH_SSH_CLIENT_ID_ECDSA,
_PATH_SSH_CLIENT_ID_ECDSA_SK,
#endif
#endif /* WITH_OPENSSL */
_PATH_SSH_CLIENT_ID_ED25519,
_PATH_SSH_CLIENT_ID_ED25519_SK,
_PATH_SSH_CLIENT_ID_XMSS,
NULL
};
static int fingerprint_hash = SSH_FP_HASH_DEFAULT;
/* Default lifetime (0 == forever) */
static int lifetime = 0;
/* User has to confirm key use */
static int confirm = 0;
/* Maximum number of signatures (XMSS) */
static u_int maxsign = 0;
static u_int minleft = 0;
/* we keep a cache of one passphrase */
static char *pass = NULL;
static void
clear_pass(void)
{
if (pass) {
freezero(pass, strlen(pass));
pass = NULL;
}
}
static int
delete_one(int agent_fd, const struct sshkey *key, const char *comment,
const char *path, int qflag)
{
int r;
if ((r = ssh_remove_identity(agent_fd, key)) != 0) {
fprintf(stderr, "Could not remove identity \"%s\": %s\n",
path, ssh_err(r));
return r;
}
if (!qflag) {
fprintf(stderr, "Identity removed: %s %s (%s)\n", path,
sshkey_type(key), comment);
}
return 0;
}
static int
delete_stdin(int agent_fd, int qflag)
{
char *line = NULL, *cp;
size_t linesize = 0;
struct sshkey *key = NULL;
int lnum = 0, r, ret = -1;
while (getline(&line, &linesize, stdin) != -1) {
lnum++;
sshkey_free(key);
key = NULL;
line[strcspn(line, "\n")] = '\0';
cp = line + strspn(line, " \t");
if (*cp == '#' || *cp == '\0')
continue;
if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
fatal_f("sshkey_new");
if ((r = sshkey_read(key, &cp)) != 0) {
error_r(r, "(stdin):%d: invalid key", lnum);
continue;
}
if (delete_one(agent_fd, key, cp, "(stdin)", qflag) == 0)
ret = 0;
}
sshkey_free(key);
free(line);
return ret;
}
static int
delete_file(int agent_fd, const char *filename, int key_only, int qflag)
{
struct sshkey *public, *cert = NULL;
char *certpath = NULL, *comment = NULL;
int r, ret = -1;
if (strcmp(filename, "-") == 0)
return delete_stdin(agent_fd, qflag);
if ((r = sshkey_load_public(filename, &public, &comment)) != 0) {
printf("Bad key file %s: %s\n", filename, ssh_err(r));
return -1;
}
if (delete_one(agent_fd, public, comment, filename, qflag) == 0)
ret = 0;
if (key_only)
goto out;
/* Now try to delete the corresponding certificate too */
free(comment);
comment = NULL;
xasprintf(&certpath, "%s-cert.pub", filename);
if ((r = sshkey_load_public(certpath, &cert, &comment)) != 0) {
if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT)
error_r(r, "Failed to load certificate \"%s\"", certpath);
goto out;
}
if (!sshkey_equal_public(cert, public))
fatal("Certificate %s does not match private key %s",
certpath, filename);
if (delete_one(agent_fd, cert, comment, certpath, qflag) == 0)
ret = 0;
out:
sshkey_free(cert);
sshkey_free(public);
free(certpath);
free(comment);
return ret;
}
/* Send a request to remove all identities. */
static int
delete_all(int agent_fd, int qflag)
{
int ret = -1;
/*
* Since the agent might be forwarded, old or non-OpenSSH, when asked
* to remove all keys, attempt to remove both protocol v.1 and v.2
* keys.
*/
if (ssh_remove_all_identities(agent_fd, 2) == 0)
ret = 0;
/* ignore error-code for ssh1 */
ssh_remove_all_identities(agent_fd, 1);
if (ret != 0)
fprintf(stderr, "Failed to remove all identities.\n");
else if (!qflag)
fprintf(stderr, "All identities removed.\n");
return ret;
}
static int
add_file(int agent_fd, const char *filename, int key_only, int qflag,
const char *skprovider)
{
struct sshkey *private, *cert;
char *comment = NULL;
char msg[1024], *certpath = NULL;
int r, fd, ret = -1;
size_t i;
u_int32_t left;
struct sshbuf *keyblob;
struct ssh_identitylist *idlist;
if (strcmp(filename, "-") == 0) {
fd = STDIN_FILENO;
filename = "(stdin)";
} else if ((fd = open(filename, O_RDONLY)) == -1) {
perror(filename);
return -1;
}
/*
* Since we'll try to load a keyfile multiple times, permission errors
* will occur multiple times, so check perms first and bail if wrong.
*/
if (fd != STDIN_FILENO) {
if (sshkey_perm_ok(fd, filename) != 0) {
close(fd);
return -1;
}
}
if ((r = sshbuf_load_fd(fd, &keyblob)) != 0) {
fprintf(stderr, "Error loading key \"%s\": %s\n",
filename, ssh_err(r));
sshbuf_free(keyblob);
close(fd);
return -1;
}
close(fd);
/* At first, try empty passphrase */
if ((r = sshkey_parse_private_fileblob(keyblob, "", &private,
&comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) {
fprintf(stderr, "Error loading key \"%s\": %s\n",
filename, ssh_err(r));
goto fail_load;
}
/* try last */
if (private == NULL && pass != NULL) {
if ((r = sshkey_parse_private_fileblob(keyblob, pass, &private,
&comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) {
fprintf(stderr, "Error loading key \"%s\": %s\n",
filename, ssh_err(r));
goto fail_load;
}
}
if (private == NULL) {
/* clear passphrase since it did not work */
clear_pass();
snprintf(msg, sizeof msg, "Enter passphrase for %s%s: ",
filename, confirm ? " (will confirm each use)" : "");
for (;;) {
pass = read_passphrase(msg, RP_ALLOW_STDIN);
if (strcmp(pass, "") == 0)
goto fail_load;
if ((r = sshkey_parse_private_fileblob(keyblob, pass,
&private, &comment)) == 0)
break;
else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) {
fprintf(stderr,
"Error loading key \"%s\": %s\n",
filename, ssh_err(r));
fail_load:
clear_pass();
sshbuf_free(keyblob);
return -1;
}
clear_pass();
snprintf(msg, sizeof msg,
"Bad passphrase, try again for %s%s: ", filename,
confirm ? " (will confirm each use)" : "");
}
}
if (comment == NULL || *comment == '\0')
comment = xstrdup(filename);
sshbuf_free(keyblob);
/* For XMSS */
if ((r = sshkey_set_filename(private, filename)) != 0) {
fprintf(stderr, "Could not add filename to private key: %s (%s)\n",
filename, comment);
goto out;
}
if (maxsign && minleft &&
(r = ssh_fetch_identitylist(agent_fd, &idlist)) == 0) {
for (i = 0; i < idlist->nkeys; i++) {
if (!sshkey_equal_public(idlist->keys[i], private))
continue;
left = sshkey_signatures_left(idlist->keys[i]);
if (left < minleft) {
fprintf(stderr,
"Only %d signatures left.\n", left);
break;
}
fprintf(stderr, "Skipping update: ");
if (left == minleft) {
fprintf(stderr,
- "required signatures left (%d).\n", left);
+ "required signatures left (%d).\n", left);
} else {
fprintf(stderr,
- "more signatures left (%d) than"
+ "more signatures left (%d) than"
" required (%d).\n", left, minleft);
}
ssh_free_identitylist(idlist);
goto out;
}
ssh_free_identitylist(idlist);
}
if (sshkey_is_sk(private)) {
if (skprovider == NULL) {
fprintf(stderr, "Cannot load FIDO key %s "
"without provider\n", filename);
goto out;
}
if ((private->sk_flags & SSH_SK_USER_VERIFICATION_REQD) != 0) {
fprintf(stderr, "FIDO verify-required key %s is not "
"currently supported by ssh-agent\n", filename);
goto out;
}
} else {
/* Don't send provider constraint for other keys */
skprovider = NULL;
}
if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
lifetime, confirm, maxsign, skprovider)) == 0) {
ret = 0;
if (!qflag) {
fprintf(stderr, "Identity added: %s (%s)\n",
filename, comment);
if (lifetime != 0) {
fprintf(stderr,
"Lifetime set to %d seconds\n", lifetime);
}
if (confirm != 0) {
fprintf(stderr, "The user must confirm "
"each use of the key\n");
}
}
} else {
fprintf(stderr, "Could not add identity \"%s\": %s\n",
filename, ssh_err(r));
}
/* Skip trying to load the cert if requested */
if (key_only)
goto out;
/* Now try to add the certificate flavour too */
xasprintf(&certpath, "%s-cert.pub", filename);
if ((r = sshkey_load_public(certpath, &cert, NULL)) != 0) {
if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT)
error_r(r, "Failed to load certificate \"%s\"", certpath);
goto out;
}
if (!sshkey_equal_public(cert, private)) {
error("Certificate %s does not match private key %s",
certpath, filename);
sshkey_free(cert);
goto out;
}
/* Graft with private bits */
if ((r = sshkey_to_certified(private)) != 0) {
error_fr(r, "sshkey_to_certified");
sshkey_free(cert);
goto out;
}
if ((r = sshkey_cert_copy(cert, private)) != 0) {
error_fr(r, "sshkey_cert_copy");
sshkey_free(cert);
goto out;
}
sshkey_free(cert);
if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
lifetime, confirm, maxsign, skprovider)) != 0) {
error_r(r, "Certificate %s (%s) add failed", certpath,
private->cert->key_id);
goto out;
}
/* success */
if (!qflag) {
fprintf(stderr, "Certificate added: %s (%s)\n", certpath,
private->cert->key_id);
if (lifetime != 0) {
fprintf(stderr, "Lifetime set to %d seconds\n",
lifetime);
}
if (confirm != 0) {
fprintf(stderr, "The user must confirm each use "
"of the key\n");
}
}
out:
free(certpath);
free(comment);
sshkey_free(private);
return ret;
}
static int
update_card(int agent_fd, int add, const char *id, int qflag)
{
char *pin = NULL;
int r, ret = -1;
if (add) {
if ((pin = read_passphrase("Enter passphrase for PKCS#11: ",
RP_ALLOW_STDIN)) == NULL)
return -1;
}
if ((r = ssh_update_card(agent_fd, add, id, pin == NULL ? "" : pin,
lifetime, confirm)) == 0) {
ret = 0;
if (!qflag) {
fprintf(stderr, "Card %s: %s\n",
add ? "added" : "removed", id);
}
} else {
fprintf(stderr, "Could not %s card \"%s\": %s\n",
add ? "add" : "remove", id, ssh_err(r));
ret = -1;
}
free(pin);
return ret;
}
static int
test_key(int agent_fd, const char *filename)
{
struct sshkey *key = NULL;
u_char *sig = NULL;
size_t slen = 0;
int r, ret = -1;
char data[1024];
if ((r = sshkey_load_public(filename, &key, NULL)) != 0) {
error_r(r, "Couldn't read public key %s", filename);
return -1;
}
arc4random_buf(data, sizeof(data));
if ((r = ssh_agent_sign(agent_fd, key, &sig, &slen, data, sizeof(data),
NULL, 0)) != 0) {
error_r(r, "Agent signature failed for %s", filename);
goto done;
}
if ((r = sshkey_verify(key, sig, slen, data, sizeof(data),
NULL, 0, NULL)) != 0) {
error_r(r, "Signature verification failed for %s", filename);
goto done;
}
/* success */
ret = 0;
done:
free(sig);
sshkey_free(key);
return ret;
}
static int
list_identities(int agent_fd, int do_fp)
{
char *fp;
int r;
struct ssh_identitylist *idlist;
u_int32_t left;
size_t i;
if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) {
if (r != SSH_ERR_AGENT_NO_IDENTITIES)
fprintf(stderr, "error fetching identities: %s\n",
ssh_err(r));
else
printf("The agent has no identities.\n");
return -1;
}
for (i = 0; i < idlist->nkeys; i++) {
if (do_fp) {
fp = sshkey_fingerprint(idlist->keys[i],
fingerprint_hash, SSH_FP_DEFAULT);
printf("%u %s %s (%s)\n", sshkey_size(idlist->keys[i]),
fp == NULL ? "(null)" : fp, idlist->comments[i],
sshkey_type(idlist->keys[i]));
free(fp);
} else {
if ((r = sshkey_write(idlist->keys[i], stdout)) != 0) {
fprintf(stderr, "sshkey_write: %s\n",
ssh_err(r));
continue;
}
fprintf(stdout, " %s", idlist->comments[i]);
left = sshkey_signatures_left(idlist->keys[i]);
if (left > 0)
fprintf(stdout,
" [signatures left %d]", left);
fprintf(stdout, "\n");
}
}
ssh_free_identitylist(idlist);
return 0;
}
static int
lock_agent(int agent_fd, int lock)
{
char prompt[100], *p1, *p2;
int r, passok = 1, ret = -1;
strlcpy(prompt, "Enter lock password: ", sizeof(prompt));
p1 = read_passphrase(prompt, RP_ALLOW_STDIN);
if (lock) {
strlcpy(prompt, "Again: ", sizeof prompt);
p2 = read_passphrase(prompt, RP_ALLOW_STDIN);
if (strcmp(p1, p2) != 0) {
fprintf(stderr, "Passwords do not match.\n");
passok = 0;
}
freezero(p2, strlen(p2));
}
if (passok) {
if ((r = ssh_lock_agent(agent_fd, lock, p1)) == 0) {
fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un");
ret = 0;
} else {
fprintf(stderr, "Failed to %slock agent: %s\n",
lock ? "" : "un", ssh_err(r));
}
}
freezero(p1, strlen(p1));
return (ret);
}
static int
load_resident_keys(int agent_fd, const char *skprovider, int qflag)
{
struct sshkey **keys;
size_t nkeys, i;
int r, ok = 0;
char *fp;
pass = read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN);
if ((r = sshsk_load_resident(skprovider, NULL, pass,
&keys, &nkeys)) != 0) {
error_r(r, "Unable to load resident keys");
return r;
}
for (i = 0; i < nkeys; i++) {
if ((fp = sshkey_fingerprint(keys[i],
fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
fatal_f("sshkey_fingerprint failed");
if ((r = ssh_add_identity_constrained(agent_fd, keys[i], "",
lifetime, confirm, maxsign, skprovider)) != 0) {
error("Unable to add key %s %s",
sshkey_type(keys[i]), fp);
free(fp);
ok = r;
continue;
}
if (ok == 0)
ok = 1;
if (!qflag) {
fprintf(stderr, "Resident identity added: %s %s\n",
sshkey_type(keys[i]), fp);
if (lifetime != 0) {
fprintf(stderr,
"Lifetime set to %d seconds\n", lifetime);
}
if (confirm != 0) {
fprintf(stderr, "The user must confirm "
"each use of the key\n");
}
}
free(fp);
sshkey_free(keys[i]);
}
free(keys);
if (nkeys == 0)
return SSH_ERR_KEY_NOT_FOUND;
return ok == 1 ? 0 : ok;
}
static int
do_file(int agent_fd, int deleting, int key_only, char *file, int qflag,
const char *skprovider)
{
if (deleting) {
if (delete_file(agent_fd, file, key_only, qflag) == -1)
return -1;
} else {
if (add_file(agent_fd, file, key_only, qflag, skprovider) == -1)
return -1;
}
return 0;
}
static void
usage(void)
{
fprintf(stderr,
"usage: ssh-add [-cDdKkLlqvXx] [-E fingerprint_hash] [-S provider] [-t life]\n"
#ifdef WITH_XMSS
" [-M maxsign] [-m minleft]\n"
#endif
" [file ...]\n"
" ssh-add -s pkcs11\n"
" ssh-add -e pkcs11\n"
" ssh-add -T pubkey ...\n"
);
}
int
main(int argc, char **argv)
{
extern char *optarg;
extern int optind;
int agent_fd;
char *pkcs11provider = NULL, *skprovider = NULL;
int r, i, ch, deleting = 0, ret = 0, key_only = 0, do_download = 0;
int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0;
SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
LogLevel log_level = SYSLOG_LEVEL_INFO;
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
sanitise_stdfd();
__progname = ssh_get_progname(argv[0]);
seed_rng();
log_init(__progname, log_level, log_facility, 1);
setvbuf(stdout, NULL, _IOLBF, 0);
/* First, get a connection to the authentication agent. */
switch (r = ssh_get_authentication_socket(&agent_fd)) {
case 0:
break;
case SSH_ERR_AGENT_NOT_PRESENT:
fprintf(stderr, "Could not open a connection to your "
"authentication agent.\n");
exit(2);
default:
fprintf(stderr, "Error connecting to agent: %s\n", ssh_err(r));
exit(2);
}
skprovider = getenv("SSH_SK_PROVIDER");
while ((ch = getopt(argc, argv, "vkKlLcdDTxXE:e:M:m:qs:S:t:")) != -1) {
switch (ch) {
case 'v':
if (log_level == SYSLOG_LEVEL_INFO)
log_level = SYSLOG_LEVEL_DEBUG1;
else if (log_level < SYSLOG_LEVEL_DEBUG3)
log_level++;
break;
case 'E':
fingerprint_hash = ssh_digest_alg_by_name(optarg);
if (fingerprint_hash == -1)
fatal("Invalid hash algorithm \"%s\"", optarg);
break;
case 'k':
key_only = 1;
break;
case 'K':
do_download = 1;
break;
case 'l':
case 'L':
if (lflag != 0)
fatal("-%c flag already specified", lflag);
lflag = ch;
break;
case 'x':
case 'X':
if (xflag != 0)
fatal("-%c flag already specified", xflag);
xflag = ch;
break;
case 'c':
confirm = 1;
break;
case 'm':
minleft = (int)strtonum(optarg, 1, UINT_MAX, NULL);
if (minleft == 0) {
usage();
ret = 1;
goto done;
}
break;
case 'M':
maxsign = (int)strtonum(optarg, 1, UINT_MAX, NULL);
if (maxsign == 0) {
usage();
ret = 1;
goto done;
}
break;
case 'd':
deleting = 1;
break;
case 'D':
Dflag = 1;
break;
case 's':
pkcs11provider = optarg;
break;
case 'S':
skprovider = optarg;
break;
case 'e':
deleting = 1;
pkcs11provider = optarg;
break;
case 't':
if ((lifetime = convtime(optarg)) == -1 ||
lifetime < 0 || (u_long)lifetime > UINT32_MAX) {
fprintf(stderr, "Invalid lifetime\n");
ret = 1;
goto done;
}
break;
case 'q':
qflag = 1;
break;
case 'T':
Tflag = 1;
break;
default:
usage();
ret = 1;
goto done;
}
}
log_init(__progname, log_level, log_facility, 1);
if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1)
fatal("Invalid combination of actions");
else if (xflag) {
if (lock_agent(agent_fd, xflag == 'x' ? 1 : 0) == -1)
ret = 1;
goto done;
} else if (lflag) {
if (list_identities(agent_fd, lflag == 'l' ? 1 : 0) == -1)
ret = 1;
goto done;
} else if (Dflag) {
if (delete_all(agent_fd, qflag) == -1)
ret = 1;
goto done;
}
#ifdef ENABLE_SK_INTERNAL
if (skprovider == NULL)
skprovider = "internal";
#endif
argc -= optind;
argv += optind;
if (Tflag) {
if (argc <= 0)
fatal("no keys to test");
for (r = i = 0; i < argc; i++)
r |= test_key(agent_fd, argv[i]);
ret = r == 0 ? 0 : 1;
goto done;
}
if (pkcs11provider != NULL) {
if (update_card(agent_fd, !deleting, pkcs11provider,
qflag) == -1)
ret = 1;
goto done;
}
if (do_download) {
if (skprovider == NULL)
fatal("Cannot download keys without provider");
if (load_resident_keys(agent_fd, skprovider, qflag) != 0)
ret = 1;
goto done;
}
if (argc == 0) {
char buf[PATH_MAX];
struct passwd *pw;
struct stat st;
int count = 0;
if ((pw = getpwuid(getuid())) == NULL) {
fprintf(stderr, "No user found with uid %u\n",
(u_int)getuid());
ret = 1;
goto done;
}
for (i = 0; default_files[i]; i++) {
snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir,
default_files[i]);
if (stat(buf, &st) == -1)
continue;
if (do_file(agent_fd, deleting, key_only, buf,
qflag, skprovider) == -1)
ret = 1;
else
count++;
}
if (count == 0)
ret = 1;
} else {
for (i = 0; i < argc; i++) {
if (do_file(agent_fd, deleting, key_only,
argv[i], qflag, skprovider) == -1)
ret = 1;
}
}
done:
clear_pass();
ssh_close_authentication_socket(agent_fd);
return ret;
}
diff --git a/ssh-agent.0 b/ssh-agent.0
index 71dddc27cff5..1da77c3046a2 100644
--- a/ssh-agent.0
+++ b/ssh-agent.0
@@ -1,119 +1,119 @@
SSH-AGENT(1) General Commands Manual SSH-AGENT(1)
NAME
ssh-agent M-bM-^@M-^S OpenSSH authentication agent
SYNOPSIS
ssh-agent [-c | -s] [-Dd] [-a bind_address] [-E fingerprint_hash]
[-P allowed_providers] [-t life]
ssh-agent [-a bind_address] [-E fingerprint_hash] [-P allowed_providers]
[-t life] command [arg ...]
ssh-agent [-c | -s] -k
DESCRIPTION
ssh-agent is a program to hold private keys used for public key
authentication. Through use of environment variables the agent can be
located and automatically used for authentication when logging in to
other machines using ssh(1).
The options are as follows:
-a bind_address
Bind the agent to the UNIX-domain socket bind_address. The
default is $TMPDIR/ssh-XXXXXXXXXX/agent.<ppid>.
-c Generate C-shell commands on stdout. This is the default if
SHELL looks like it's a csh style of shell.
-D Foreground mode. When this option is specified ssh-agent will
not fork.
-d Debug mode. When this option is specified ssh-agent will not
fork and will write debug information to standard error.
-E fingerprint_hash
Specifies the hash algorithm used when displaying key
fingerprints. Valid options are: M-bM-^@M-^\md5M-bM-^@M-^] and M-bM-^@M-^\sha256M-bM-^@M-^]. The
default is M-bM-^@M-^\sha256M-bM-^@M-^].
-k Kill the current agent (given by the SSH_AGENT_PID environment
variable).
-P allowed_providers
Specify a pattern-list of acceptable paths for PKCS#11 provider
and FIDO authenticator middleware shared libraries that may be
used with the -S or -s options to ssh-add(1). Libraries that do
not match the pattern list will be refused. See PATTERNS in
ssh_config(5) for a description of pattern-list syntax. The
default list is M-bM-^@M-^\/usr/lib/*,/usr/local/lib/*M-bM-^@M-^].
-s Generate Bourne shell commands on stdout. This is the default if
SHELL does not look like it's a csh style of shell.
-t life
Set a default value for the maximum lifetime of identities added
to the agent. The lifetime may be specified in seconds or in a
time format specified in sshd_config(5). A lifetime specified
for an identity with ssh-add(1) overrides this value. Without
this option the default maximum lifetime is forever.
command [arg ...]
If a command (and optional arguments) is given, this is executed
as a subprocess of the agent. The agent exits automatically when
the command given on the command line terminates.
There are two main ways to get an agent set up. The first is at the
start of an X session, where all other windows or programs are started as
children of the ssh-agent program. The agent starts a command under
which its environment variables are exported, for example ssh-agent xterm
&. When the command terminates, so does the agent.
The second method is used for a login session. When ssh-agent is
started, it prints the shell commands required to set its environment
variables, which in turn can be evaluated in the calling shell, for
example eval `ssh-agent -s`.
In both cases, ssh(1) looks at these environment variables and uses them
to establish a connection to the agent.
The agent initially does not have any private keys. Keys are added using
ssh-add(1) or by ssh(1) when AddKeysToAgent is set in ssh_config(5).
Multiple identities may be stored in ssh-agent concurrently and ssh(1)
will automatically use them if present. ssh-add(1) is also used to
remove keys from ssh-agent and to query the keys that are held in one.
Connections to ssh-agent may be forwarded from further remote hosts using
the -A option to ssh(1) (but see the caveats documented therein),
avoiding the need for authentication data to be stored on other machines.
Authentication passphrases and private keys never go over the network:
the connection to the agent is forwarded over SSH remote connections and
the result is returned to the requester, allowing the user access to
their identities anywhere in the network in a secure fashion.
ENVIRONMENT
SSH_AGENT_PID When ssh-agent starts, it stores the name of the agent's
process ID (PID) in this variable.
SSH_AUTH_SOCK When ssh-agent starts, it creates a UNIX-domain socket and
stores its pathname in this variable. It is accessible
only to the current user, but is easily abused by root or
another instance of the same user.
FILES
$TMPDIR/ssh-XXXXXXXXXX/agent.<ppid>
UNIX-domain sockets used to contain the connection to the
authentication agent. These sockets should only be readable by
the owner. The sockets should get automatically removed when the
agent exits.
SEE ALSO
ssh(1), ssh-add(1), ssh-keygen(1), ssh_config(5), sshd(8)
AUTHORS
OpenSSH is a derivative of the original and free ssh 1.2.12 release by
Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo
de Raadt and Dug Song removed many bugs, re-added newer features and
created OpenSSH. Markus Friedl contributed the support for SSH protocol
versions 1.5 and 2.0.
-OpenBSD 6.8 June 22, 2020 OpenBSD 6.8
+OpenBSD 6.9 June 22, 2020 OpenBSD 6.9
diff --git a/ssh-agent.c b/ssh-agent.c
index 58fe6ddf7526..48a47d45a91b 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,1642 +1,1642 @@
-/* $OpenBSD: ssh-agent.c,v 1.277 2021/02/12 03:14:18 djm Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.278 2021/04/03 06:18:41 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* The authentication agent program.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/wait.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_SYS_UN_H
# include <sys/un.h>
#endif
#include "openbsd-compat/sys-queue.h"
#ifdef WITH_OPENSSL
#include <openssl/evp.h>
#include "openbsd-compat/openssl-compat.h"
#endif
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#ifdef HAVE_POLL_H
# include <poll.h>
#endif
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_UTIL_H
# include <util.h>
#endif
#include "xmalloc.h"
#include "ssh.h"
#include "ssh2.h"
#include "sshbuf.h"
#include "sshkey.h"
#include "authfd.h"
#include "compat.h"
#include "log.h"
#include "misc.h"
#include "digest.h"
#include "ssherr.h"
#include "match.h"
#include "msg.h"
#include "ssherr.h"
#include "pathnames.h"
#include "ssh-pkcs11.h"
#include "sk-api.h"
#ifndef DEFAULT_ALLOWED_PROVIDERS
# define DEFAULT_ALLOWED_PROVIDERS "/usr/lib*/*,/usr/local/lib*/*"
#endif
/* Maximum accepted message length */
#define AGENT_MAX_LEN (256*1024)
/* Maximum bytes to read from client socket */
#define AGENT_RBUF_LEN (4096)
typedef enum {
AUTH_UNUSED = 0,
AUTH_SOCKET = 1,
AUTH_CONNECTION = 2,
} sock_type;
typedef struct socket_entry {
int fd;
sock_type type;
struct sshbuf *input;
struct sshbuf *output;
struct sshbuf *request;
} SocketEntry;
u_int sockets_alloc = 0;
SocketEntry *sockets = NULL;
typedef struct identity {
TAILQ_ENTRY(identity) next;
struct sshkey *key;
char *comment;
char *provider;
time_t death;
u_int confirm;
char *sk_provider;
} Identity;
struct idtable {
int nentries;
TAILQ_HEAD(idqueue, identity) idlist;
};
/* private key table */
struct idtable *idtab;
int max_fd = 0;
/* pid of shell == parent of agent */
pid_t parent_pid = -1;
time_t parent_alive_interval = 0;
/* pid of process for which cleanup_socket is applicable */
pid_t cleanup_pid = 0;
/* pathname and directory for AUTH_SOCKET */
char socket_name[PATH_MAX];
char socket_dir[PATH_MAX];
/* Pattern-list of allowed PKCS#11/Security key paths */
static char *allowed_providers;
/* locking */
#define LOCK_SIZE 32
#define LOCK_SALT_SIZE 16
#define LOCK_ROUNDS 1
int locked = 0;
u_char lock_pwhash[LOCK_SIZE];
u_char lock_salt[LOCK_SALT_SIZE];
extern char *__progname;
/* Default lifetime in seconds (0 == forever) */
static int lifetime = 0;
static int fingerprint_hash = SSH_FP_HASH_DEFAULT;
/* Refuse signing of non-SSH messages for web-origin FIDO keys */
static int restrict_websafe = 1;
static void
close_socket(SocketEntry *e)
{
close(e->fd);
sshbuf_free(e->input);
sshbuf_free(e->output);
sshbuf_free(e->request);
memset(e, '\0', sizeof(*e));
e->fd = -1;
e->type = AUTH_UNUSED;
}
static void
idtab_init(void)
{
idtab = xcalloc(1, sizeof(*idtab));
TAILQ_INIT(&idtab->idlist);
idtab->nentries = 0;
}
static void
free_identity(Identity *id)
{
sshkey_free(id->key);
free(id->provider);
free(id->comment);
free(id->sk_provider);
free(id);
}
/* return matching private key for given public key */
static Identity *
lookup_identity(struct sshkey *key)
{
Identity *id;
TAILQ_FOREACH(id, &idtab->idlist, next) {
if (sshkey_equal(key, id->key))
return (id);
}
return (NULL);
}
/* Check confirmation of keysign request */
static int
confirm_key(Identity *id, const char *extra)
{
char *p;
int ret = -1;
p = sshkey_fingerprint(id->key, fingerprint_hash, SSH_FP_DEFAULT);
if (p != NULL &&
ask_permission("Allow use of key %s?\nKey fingerprint %s.%s%s",
id->comment, p,
extra == NULL ? "" : "\n", extra == NULL ? "" : extra))
ret = 0;
free(p);
return (ret);
}
static void
send_status(SocketEntry *e, int success)
{
int r;
if ((r = sshbuf_put_u32(e->output, 1)) != 0 ||
(r = sshbuf_put_u8(e->output, success ?
SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE)) != 0)
fatal_fr(r, "compose");
}
/* send list of supported public keys to 'client' */
static void
process_request_identities(SocketEntry *e)
{
Identity *id;
struct sshbuf *msg;
int r;
debug2_f("entering");
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
(r = sshbuf_put_u32(msg, idtab->nentries)) != 0)
fatal_fr(r, "compose");
TAILQ_FOREACH(id, &idtab->idlist, next) {
- if ((r = sshkey_puts_opts(id->key, msg, SSHKEY_SERIALIZE_INFO))
- != 0 ||
+ if ((r = sshkey_puts_opts(id->key, msg,
+ SSHKEY_SERIALIZE_INFO)) != 0 ||
(r = sshbuf_put_cstring(msg, id->comment)) != 0) {
error_fr(r, "compose key/comment");
continue;
}
}
if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
fatal_fr(r, "enqueue");
sshbuf_free(msg);
}
static char *
agent_decode_alg(struct sshkey *key, u_int flags)
{
if (key->type == KEY_RSA) {
if (flags & SSH_AGENT_RSA_SHA2_256)
return "rsa-sha2-256";
else if (flags & SSH_AGENT_RSA_SHA2_512)
return "rsa-sha2-512";
} else if (key->type == KEY_RSA_CERT) {
if (flags & SSH_AGENT_RSA_SHA2_256)
return "rsa-sha2-256-cert-v01@openssh.com";
else if (flags & SSH_AGENT_RSA_SHA2_512)
return "rsa-sha2-512-cert-v01@openssh.com";
}
return NULL;
}
/*
* Attempt to parse the contents of a buffer as a SSH publickey userauth
* request, checking its contents for consistency and matching the embedded
* key against the one that is being used for signing.
* Note: does not modify msg buffer.
* Optionally extract the username and session ID from the request.
*/
static int
parse_userauth_request(struct sshbuf *msg, const struct sshkey *expected_key,
char **userp, struct sshbuf **sess_idp)
{
struct sshbuf *b = NULL, *sess_id = NULL;
char *user = NULL, *service = NULL, *method = NULL, *pkalg = NULL;
int r;
u_char t, sig_follows;
struct sshkey *mkey = NULL;
if (userp != NULL)
*userp = NULL;
if (sess_idp != NULL)
*sess_idp = NULL;
if ((b = sshbuf_fromb(msg)) == NULL)
fatal_f("sshbuf_fromb");
/* SSH userauth request */
if ((r = sshbuf_froms(b, &sess_id)) != 0)
goto out;
if (sshbuf_len(sess_id) == 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((r = sshbuf_get_u8(b, &t)) != 0 || /* SSH2_MSG_USERAUTH_REQUEST */
(r = sshbuf_get_cstring(b, &user, NULL)) != 0 || /* server user */
(r = sshbuf_get_cstring(b, &service, NULL)) != 0 || /* service */
(r = sshbuf_get_cstring(b, &method, NULL)) != 0 || /* method */
(r = sshbuf_get_u8(b, &sig_follows)) != 0 || /* sig-follows */
(r = sshbuf_get_cstring(b, &pkalg, NULL)) != 0 || /* alg */
(r = sshkey_froms(b, &mkey)) != 0) /* key */
goto out;
if (t != SSH2_MSG_USERAUTH_REQUEST ||
sig_follows != 1 ||
strcmp(service, "ssh-connection") != 0 ||
!sshkey_equal(expected_key, mkey) ||
sshkey_type_from_name(pkalg) != expected_key->type) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (strcmp(method, "publickey") != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (sshbuf_len(b) != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* success */
r = 0;
debug3_f("well formed userauth");
if (userp != NULL) {
*userp = user;
user = NULL;
}
if (sess_idp != NULL) {
*sess_idp = sess_id;
sess_id = NULL;
}
out:
sshbuf_free(b);
sshbuf_free(sess_id);
free(user);
free(service);
free(method);
free(pkalg);
sshkey_free(mkey);
return r;
}
/*
* Attempt to parse the contents of a buffer as a SSHSIG signature request.
* Note: does not modify buffer.
*/
static int
parse_sshsig_request(struct sshbuf *msg)
{
int r;
struct sshbuf *b;
if ((b = sshbuf_fromb(msg)) == NULL)
fatal_f("sshbuf_fromb");
if ((r = sshbuf_cmp(b, 0, "SSHSIG", 6)) != 0 ||
(r = sshbuf_consume(b, 6)) != 0 ||
(r = sshbuf_get_cstring(b, NULL, NULL)) != 0 || /* namespace */
(r = sshbuf_get_string_direct(b, NULL, NULL)) != 0 || /* reserved */
(r = sshbuf_get_cstring(b, NULL, NULL)) != 0 || /* hashalg */
(r = sshbuf_get_string_direct(b, NULL, NULL)) != 0) /* H(msg) */
goto out;
if (sshbuf_len(b) != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* success */
r = 0;
out:
sshbuf_free(b);
return r;
}
/*
* This function inspects a message to be signed by a FIDO key that has a
* web-like application string (i.e. one that does not begin with "ssh:".
* It checks that the message is one of those expected for SSH operations
* (pubkey userauth, sshsig, CA key signing) to exclude signing challenges
* for the web.
*/
static int
check_websafe_message_contents(struct sshkey *key, struct sshbuf *data)
{
if (parse_userauth_request(data, key, NULL, NULL) == 0) {
debug_f("signed data matches public key userauth request");
return 1;
}
if (parse_sshsig_request(data) == 0) {
debug_f("signed data matches SSHSIG signature request");
return 1;
}
/* XXX check CA signature operation */
error("web-origin key attempting to sign non-SSH message");
return 0;
}
/* ssh2 only */
static void
process_sign_request2(SocketEntry *e)
{
u_char *signature = NULL;
size_t slen = 0;
u_int compat = 0, flags;
int r, ok = -1;
char *fp = NULL;
struct sshbuf *msg = NULL, *data = NULL;
struct sshkey *key = NULL;
struct identity *id;
struct notifier_ctx *notifier = NULL;
debug_f("entering");
if ((msg = sshbuf_new()) == NULL || (data = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshkey_froms(e->request, &key)) != 0 ||
(r = sshbuf_get_stringb(e->request, data)) != 0 ||
(r = sshbuf_get_u32(e->request, &flags)) != 0) {
error_fr(r, "parse");
goto send;
}
if ((id = lookup_identity(key)) == NULL) {
verbose_f("%s key not found", sshkey_type(key));
goto send;
}
if (id->confirm && confirm_key(id, NULL) != 0) {
verbose_f("user refused key");
goto send;
}
if (sshkey_is_sk(id->key)) {
if (strncmp(id->key->sk_application, "ssh:", 4) != 0 &&
!check_websafe_message_contents(key, data)) {
/* error already logged */
goto send;
}
if ((id->key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
SSH_FP_DEFAULT)) == NULL)
fatal_f("fingerprint failed");
notifier = notify_start(0,
"Confirm user presence for key %s %s",
sshkey_type(id->key), fp);
}
}
/* XXX support PIN required FIDO keys */
if ((r = sshkey_sign(id->key, &signature, &slen,
sshbuf_ptr(data), sshbuf_len(data), agent_decode_alg(key, flags),
id->sk_provider, NULL, compat)) != 0) {
error_fr(r, "sshkey_sign");
goto send;
}
/* Success */
ok = 0;
send:
notify_complete(notifier, "User presence confirmed");
if (ok == 0) {
if ((r = sshbuf_put_u8(msg, SSH2_AGENT_SIGN_RESPONSE)) != 0 ||
(r = sshbuf_put_string(msg, signature, slen)) != 0)
fatal_fr(r, "compose");
} else if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0)
fatal_fr(r, "compose failure");
if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
fatal_fr(r, "enqueue");
sshbuf_free(data);
sshbuf_free(msg);
sshkey_free(key);
free(fp);
free(signature);
}
/* shared */
static void
process_remove_identity(SocketEntry *e)
{
int r, success = 0;
struct sshkey *key = NULL;
Identity *id;
debug2_f("entering");
if ((r = sshkey_froms(e->request, &key)) != 0) {
error_fr(r, "parse key");
goto done;
}
if ((id = lookup_identity(key)) == NULL) {
debug_f("key not found");
goto done;
}
/* We have this key, free it. */
if (idtab->nentries < 1)
fatal_f("internal error: nentries %d", idtab->nentries);
TAILQ_REMOVE(&idtab->idlist, id, next);
free_identity(id);
idtab->nentries--;
success = 1;
done:
sshkey_free(key);
send_status(e, success);
}
static void
process_remove_all_identities(SocketEntry *e)
{
Identity *id;
debug2_f("entering");
/* Loop over all identities and clear the keys. */
for (id = TAILQ_FIRST(&idtab->idlist); id;
id = TAILQ_FIRST(&idtab->idlist)) {
TAILQ_REMOVE(&idtab->idlist, id, next);
free_identity(id);
}
/* Mark that there are no identities. */
idtab->nentries = 0;
/* Send success. */
send_status(e, 1);
}
/* removes expired keys and returns number of seconds until the next expiry */
static time_t
reaper(void)
{
time_t deadline = 0, now = monotime();
Identity *id, *nxt;
for (id = TAILQ_FIRST(&idtab->idlist); id; id = nxt) {
nxt = TAILQ_NEXT(id, next);
if (id->death == 0)
continue;
if (now >= id->death) {
debug("expiring key '%s'", id->comment);
TAILQ_REMOVE(&idtab->idlist, id, next);
free_identity(id);
idtab->nentries--;
} else
deadline = (deadline == 0) ? id->death :
MINIMUM(deadline, id->death);
}
if (deadline == 0 || deadline <= now)
return 0;
else
return (deadline - now);
}
static int
parse_key_constraint_extension(struct sshbuf *m, char **sk_providerp)
{
char *ext_name = NULL;
int r;
if ((r = sshbuf_get_cstring(m, &ext_name, NULL)) != 0) {
error_fr(r, "parse constraint extension");
goto out;
}
debug_f("constraint ext %s", ext_name);
if (strcmp(ext_name, "sk-provider@openssh.com") == 0) {
if (sk_providerp == NULL) {
error_f("%s not valid here", ext_name);
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (*sk_providerp != NULL) {
error_f("%s already set", ext_name);
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((r = sshbuf_get_cstring(m, sk_providerp, NULL)) != 0) {
error_fr(r, "parse %s", ext_name);
goto out;
}
} else {
error_f("unsupported constraint \"%s\"", ext_name);
r = SSH_ERR_FEATURE_UNSUPPORTED;
goto out;
}
/* success */
r = 0;
out:
free(ext_name);
return r;
}
static int
parse_key_constraints(struct sshbuf *m, struct sshkey *k, time_t *deathp,
u_int *secondsp, int *confirmp, char **sk_providerp)
{
u_char ctype;
int r;
u_int seconds, maxsign = 0;
while (sshbuf_len(m)) {
if ((r = sshbuf_get_u8(m, &ctype)) != 0) {
error_fr(r, "parse constraint type");
goto out;
}
switch (ctype) {
case SSH_AGENT_CONSTRAIN_LIFETIME:
if (*deathp != 0) {
error_f("lifetime already set");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((r = sshbuf_get_u32(m, &seconds)) != 0) {
error_fr(r, "parse lifetime constraint");
goto out;
}
*deathp = monotime() + seconds;
*secondsp = seconds;
break;
case SSH_AGENT_CONSTRAIN_CONFIRM:
if (*confirmp != 0) {
error_f("confirm already set");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
*confirmp = 1;
break;
case SSH_AGENT_CONSTRAIN_MAXSIGN:
if (k == NULL) {
error_f("maxsign not valid here");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (maxsign != 0) {
error_f("maxsign already set");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((r = sshbuf_get_u32(m, &maxsign)) != 0) {
error_fr(r, "parse maxsign constraint");
goto out;
}
if ((r = sshkey_enable_maxsign(k, maxsign)) != 0) {
error_fr(r, "enable maxsign");
goto out;
}
break;
case SSH_AGENT_CONSTRAIN_EXTENSION:
if ((r = parse_key_constraint_extension(m,
sk_providerp)) != 0)
goto out; /* error already logged */
break;
default:
error_f("Unknown constraint %d", ctype);
r = SSH_ERR_FEATURE_UNSUPPORTED;
goto out;
}
}
/* success */
r = 0;
out:
return r;
}
static void
process_add_identity(SocketEntry *e)
{
Identity *id;
int success = 0, confirm = 0;
char *fp, *comment = NULL, *sk_provider = NULL;
char canonical_provider[PATH_MAX];
time_t death = 0;
u_int seconds = 0;
struct sshkey *k = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
debug2_f("entering");
if ((r = sshkey_private_deserialize(e->request, &k)) != 0 ||
k == NULL ||
(r = sshbuf_get_cstring(e->request, &comment, NULL)) != 0) {
error_fr(r, "parse");
goto out;
}
if (parse_key_constraints(e->request, k, &death, &seconds, &confirm,
&sk_provider) != 0) {
error_f("failed to parse constraints");
sshbuf_reset(e->request);
goto out;
}
if (sk_provider != NULL) {
if (!sshkey_is_sk(k)) {
error("Cannot add provider: %s is not an "
"authenticator-hosted key", sshkey_type(k));
goto out;
}
if (strcasecmp(sk_provider, "internal") == 0) {
debug_f("internal provider");
} else {
if (realpath(sk_provider, canonical_provider) == NULL) {
verbose("failed provider \"%.100s\": "
"realpath: %s", sk_provider,
strerror(errno));
goto out;
}
free(sk_provider);
sk_provider = xstrdup(canonical_provider);
if (match_pattern_list(sk_provider,
allowed_providers, 0) != 1) {
error("Refusing add key: "
"provider %s not allowed", sk_provider);
goto out;
}
}
}
if ((r = sshkey_shield_private(k)) != 0) {
error_fr(r, "shield private");
goto out;
}
if (lifetime && !death)
death = monotime() + lifetime;
if ((id = lookup_identity(k)) == NULL) {
id = xcalloc(1, sizeof(Identity));
TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
/* Increment the number of identities. */
idtab->nentries++;
} else {
/* key state might have been updated */
sshkey_free(id->key);
free(id->comment);
free(id->sk_provider);
}
/* success */
id->key = k;
id->comment = comment;
id->death = death;
id->confirm = confirm;
id->sk_provider = sk_provider;
if ((fp = sshkey_fingerprint(k, SSH_FP_HASH_DEFAULT,
SSH_FP_DEFAULT)) == NULL)
fatal_f("sshkey_fingerprint failed");
debug_f("add %s %s \"%.100s\" (life: %u) (confirm: %u) "
"(provider: %s)", sshkey_ssh_name(k), fp, comment, seconds,
confirm, sk_provider == NULL ? "none" : sk_provider);
free(fp);
/* transferred */
k = NULL;
comment = NULL;
sk_provider = NULL;
success = 1;
out:
free(sk_provider);
free(comment);
sshkey_free(k);
send_status(e, success);
}
/* XXX todo: encrypt sensitive data with passphrase */
static void
process_lock_agent(SocketEntry *e, int lock)
{
int r, success = 0, delay;
char *passwd;
u_char passwdhash[LOCK_SIZE];
static u_int fail_count = 0;
size_t pwlen;
debug2_f("entering");
/*
* This is deliberately fatal: the user has requested that we lock,
* but we can't parse their request properly. The only safe thing to
* do is abort.
*/
if ((r = sshbuf_get_cstring(e->request, &passwd, &pwlen)) != 0)
fatal_fr(r, "parse");
if (pwlen == 0) {
debug("empty password not supported");
} else if (locked && !lock) {
if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt),
passwdhash, sizeof(passwdhash), LOCK_ROUNDS) < 0)
fatal("bcrypt_pbkdf");
if (timingsafe_bcmp(passwdhash, lock_pwhash, LOCK_SIZE) == 0) {
debug("agent unlocked");
locked = 0;
fail_count = 0;
explicit_bzero(lock_pwhash, sizeof(lock_pwhash));
success = 1;
} else {
/* delay in 0.1s increments up to 10s */
if (fail_count < 100)
fail_count++;
delay = 100000 * fail_count;
debug("unlock failed, delaying %0.1lf seconds",
(double)delay/1000000);
usleep(delay);
}
explicit_bzero(passwdhash, sizeof(passwdhash));
} else if (!locked && lock) {
debug("agent locked");
locked = 1;
arc4random_buf(lock_salt, sizeof(lock_salt));
if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt),
lock_pwhash, sizeof(lock_pwhash), LOCK_ROUNDS) < 0)
fatal("bcrypt_pbkdf");
success = 1;
}
freezero(passwd, pwlen);
send_status(e, success);
}
static void
no_identities(SocketEntry *e)
{
struct sshbuf *msg;
int r;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_put_u8(msg, SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
(r = sshbuf_put_u32(msg, 0)) != 0 ||
(r = sshbuf_put_stringb(e->output, msg)) != 0)
fatal_fr(r, "compose");
sshbuf_free(msg);
}
#ifdef ENABLE_PKCS11
static void
process_add_smartcard_key(SocketEntry *e)
{
char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
char **comments = NULL;
int r, i, count = 0, success = 0, confirm = 0;
u_int seconds = 0;
time_t death = 0;
struct sshkey **keys = NULL, *k;
Identity *id;
debug2_f("entering");
if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||
(r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0) {
error_fr(r, "parse");
goto send;
}
if (parse_key_constraints(e->request, NULL, &death, &seconds, &confirm,
NULL) != 0) {
error_f("failed to parse constraints");
goto send;
}
if (realpath(provider, canonical_provider) == NULL) {
verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
provider, strerror(errno));
goto send;
}
if (match_pattern_list(canonical_provider, allowed_providers, 0) != 1) {
verbose("refusing PKCS#11 add of \"%.100s\": "
"provider not allowed", canonical_provider);
goto send;
}
debug_f("add %.100s", canonical_provider);
if (lifetime && !death)
death = monotime() + lifetime;
count = pkcs11_add_provider(canonical_provider, pin, &keys, &comments);
for (i = 0; i < count; i++) {
k = keys[i];
if (lookup_identity(k) == NULL) {
id = xcalloc(1, sizeof(Identity));
id->key = k;
keys[i] = NULL; /* transferred */
id->provider = xstrdup(canonical_provider);
if (*comments[i] != '\0') {
id->comment = comments[i];
comments[i] = NULL; /* transferred */
} else {
id->comment = xstrdup(canonical_provider);
}
id->death = death;
id->confirm = confirm;
TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
idtab->nentries++;
success = 1;
}
/* XXX update constraints for existing keys */
sshkey_free(keys[i]);
free(comments[i]);
}
send:
free(pin);
free(provider);
free(keys);
free(comments);
send_status(e, success);
}
static void
process_remove_smartcard_key(SocketEntry *e)
{
char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
int r, success = 0;
Identity *id, *nxt;
debug2_f("entering");
if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||
(r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0) {
error_fr(r, "parse");
goto send;
}
free(pin);
if (realpath(provider, canonical_provider) == NULL) {
verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
provider, strerror(errno));
goto send;
}
debug_f("remove %.100s", canonical_provider);
for (id = TAILQ_FIRST(&idtab->idlist); id; id = nxt) {
nxt = TAILQ_NEXT(id, next);
/* Skip file--based keys */
if (id->provider == NULL)
continue;
if (!strcmp(canonical_provider, id->provider)) {
TAILQ_REMOVE(&idtab->idlist, id, next);
free_identity(id);
idtab->nentries--;
}
}
if (pkcs11_del_provider(canonical_provider) == 0)
success = 1;
else
error_f("pkcs11_del_provider failed");
send:
free(provider);
send_status(e, success);
}
#endif /* ENABLE_PKCS11 */
/*
* dispatch incoming message.
* returns 1 on success, 0 for incomplete messages or -1 on error.
*/
static int
process_message(u_int socknum)
{
u_int msg_len;
u_char type;
const u_char *cp;
int r;
SocketEntry *e;
if (socknum >= sockets_alloc)
fatal_f("sock %u >= allocated %u", socknum, sockets_alloc);
e = &sockets[socknum];
if (sshbuf_len(e->input) < 5)
return 0; /* Incomplete message header. */
cp = sshbuf_ptr(e->input);
msg_len = PEEK_U32(cp);
if (msg_len > AGENT_MAX_LEN) {
debug_f("socket %u (fd=%d) message too long %u > %u",
socknum, e->fd, msg_len, AGENT_MAX_LEN);
return -1;
}
if (sshbuf_len(e->input) < msg_len + 4)
return 0; /* Incomplete message body. */
/* move the current input to e->request */
sshbuf_reset(e->request);
if ((r = sshbuf_get_stringb(e->input, e->request)) != 0 ||
(r = sshbuf_get_u8(e->request, &type)) != 0) {
if (r == SSH_ERR_MESSAGE_INCOMPLETE ||
r == SSH_ERR_STRING_TOO_LARGE) {
error_fr(r, "parse");
return -1;
}
fatal_fr(r, "parse");
}
debug_f("socket %u (fd=%d) type %d", socknum, e->fd, type);
/* check whether agent is locked */
if (locked && type != SSH_AGENTC_UNLOCK) {
sshbuf_reset(e->request);
switch (type) {
case SSH2_AGENTC_REQUEST_IDENTITIES:
/* send empty lists */
no_identities(e);
break;
default:
/* send a fail message for all other request types */
send_status(e, 0);
}
return 1;
}
switch (type) {
case SSH_AGENTC_LOCK:
case SSH_AGENTC_UNLOCK:
process_lock_agent(e, type == SSH_AGENTC_LOCK);
break;
case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
process_remove_all_identities(e); /* safe for !WITH_SSH1 */
break;
/* ssh2 */
case SSH2_AGENTC_SIGN_REQUEST:
process_sign_request2(e);
break;
case SSH2_AGENTC_REQUEST_IDENTITIES:
process_request_identities(e);
break;
case SSH2_AGENTC_ADD_IDENTITY:
case SSH2_AGENTC_ADD_ID_CONSTRAINED:
process_add_identity(e);
break;
case SSH2_AGENTC_REMOVE_IDENTITY:
process_remove_identity(e);
break;
case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
process_remove_all_identities(e);
break;
#ifdef ENABLE_PKCS11
case SSH_AGENTC_ADD_SMARTCARD_KEY:
case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED:
process_add_smartcard_key(e);
break;
case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
process_remove_smartcard_key(e);
break;
#endif /* ENABLE_PKCS11 */
default:
/* Unknown message. Respond with failure. */
error("Unknown message %d", type);
sshbuf_reset(e->request);
send_status(e, 0);
break;
}
return 1;
}
static void
new_socket(sock_type type, int fd)
{
u_int i, old_alloc, new_alloc;
debug_f("type = %s", type == AUTH_CONNECTION ? "CONNECTION" :
(type == AUTH_SOCKET ? "SOCKET" : "UNKNOWN"));
set_nonblock(fd);
if (fd > max_fd)
max_fd = fd;
for (i = 0; i < sockets_alloc; i++)
if (sockets[i].type == AUTH_UNUSED) {
sockets[i].fd = fd;
if ((sockets[i].input = sshbuf_new()) == NULL ||
(sockets[i].output = sshbuf_new()) == NULL ||
(sockets[i].request = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
sockets[i].type = type;
return;
}
old_alloc = sockets_alloc;
new_alloc = sockets_alloc + 10;
sockets = xrecallocarray(sockets, old_alloc, new_alloc,
sizeof(sockets[0]));
for (i = old_alloc; i < new_alloc; i++)
sockets[i].type = AUTH_UNUSED;
sockets_alloc = new_alloc;
sockets[old_alloc].fd = fd;
if ((sockets[old_alloc].input = sshbuf_new()) == NULL ||
(sockets[old_alloc].output = sshbuf_new()) == NULL ||
(sockets[old_alloc].request = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
sockets[old_alloc].type = type;
}
static int
handle_socket_read(u_int socknum)
{
struct sockaddr_un sunaddr;
socklen_t slen;
uid_t euid;
gid_t egid;
int fd;
slen = sizeof(sunaddr);
fd = accept(sockets[socknum].fd, (struct sockaddr *)&sunaddr, &slen);
if (fd == -1) {
error("accept from AUTH_SOCKET: %s", strerror(errno));
return -1;
}
if (getpeereid(fd, &euid, &egid) == -1) {
error("getpeereid %d failed: %s", fd, strerror(errno));
close(fd);
return -1;
}
if ((euid != 0) && (getuid() != euid)) {
error("uid mismatch: peer euid %u != uid %u",
(u_int) euid, (u_int) getuid());
close(fd);
return -1;
}
new_socket(AUTH_CONNECTION, fd);
return 0;
}
static int
handle_conn_read(u_int socknum)
{
char buf[AGENT_RBUF_LEN];
ssize_t len;
int r;
if ((len = read(sockets[socknum].fd, buf, sizeof(buf))) <= 0) {
if (len == -1) {
if (errno == EAGAIN || errno == EINTR)
return 0;
error_f("read error on socket %u (fd %d): %s",
socknum, sockets[socknum].fd, strerror(errno));
}
return -1;
}
if ((r = sshbuf_put(sockets[socknum].input, buf, len)) != 0)
fatal_fr(r, "compose");
explicit_bzero(buf, sizeof(buf));
for (;;) {
if ((r = process_message(socknum)) == -1)
return -1;
else if (r == 0)
break;
}
return 0;
}
static int
handle_conn_write(u_int socknum)
{
ssize_t len;
int r;
if (sshbuf_len(sockets[socknum].output) == 0)
return 0; /* shouldn't happen */
if ((len = write(sockets[socknum].fd,
sshbuf_ptr(sockets[socknum].output),
sshbuf_len(sockets[socknum].output))) <= 0) {
if (len == -1) {
if (errno == EAGAIN || errno == EINTR)
return 0;
error_f("read error on socket %u (fd %d): %s",
socknum, sockets[socknum].fd, strerror(errno));
}
return -1;
}
if ((r = sshbuf_consume(sockets[socknum].output, len)) != 0)
fatal_fr(r, "consume");
return 0;
}
static void
after_poll(struct pollfd *pfd, size_t npfd, u_int maxfds)
{
size_t i;
u_int socknum, activefds = npfd;
for (i = 0; i < npfd; i++) {
if (pfd[i].revents == 0)
continue;
/* Find sockets entry */
for (socknum = 0; socknum < sockets_alloc; socknum++) {
if (sockets[socknum].type != AUTH_SOCKET &&
sockets[socknum].type != AUTH_CONNECTION)
continue;
if (pfd[i].fd == sockets[socknum].fd)
break;
}
if (socknum >= sockets_alloc) {
error_f("no socket for fd %d", pfd[i].fd);
continue;
}
/* Process events */
switch (sockets[socknum].type) {
case AUTH_SOCKET:
if ((pfd[i].revents & (POLLIN|POLLERR)) == 0)
break;
if (npfd > maxfds) {
debug3("out of fds (active %u >= limit %u); "
"skipping accept", activefds, maxfds);
break;
}
if (handle_socket_read(socknum) == 0)
activefds++;
break;
case AUTH_CONNECTION:
if ((pfd[i].revents & (POLLIN|POLLERR)) != 0 &&
handle_conn_read(socknum) != 0) {
goto close_sock;
}
if ((pfd[i].revents & (POLLOUT|POLLHUP)) != 0 &&
handle_conn_write(socknum) != 0) {
close_sock:
if (activefds == 0)
fatal("activefds == 0 at close_sock");
close_socket(&sockets[socknum]);
activefds--;
break;
}
break;
default:
break;
}
}
}
static int
prepare_poll(struct pollfd **pfdp, size_t *npfdp, int *timeoutp, u_int maxfds)
{
struct pollfd *pfd = *pfdp;
size_t i, j, npfd = 0;
time_t deadline;
int r;
/* Count active sockets */
for (i = 0; i < sockets_alloc; i++) {
switch (sockets[i].type) {
case AUTH_SOCKET:
case AUTH_CONNECTION:
npfd++;
break;
case AUTH_UNUSED:
break;
default:
fatal("Unknown socket type %d", sockets[i].type);
break;
}
}
if (npfd != *npfdp &&
(pfd = recallocarray(pfd, *npfdp, npfd, sizeof(*pfd))) == NULL)
fatal_f("recallocarray failed");
*pfdp = pfd;
*npfdp = npfd;
for (i = j = 0; i < sockets_alloc; i++) {
switch (sockets[i].type) {
case AUTH_SOCKET:
if (npfd > maxfds) {
debug3("out of fds (active %zu >= limit %u); "
"skipping arming listener", npfd, maxfds);
break;
}
pfd[j].fd = sockets[i].fd;
pfd[j].revents = 0;
pfd[j].events = POLLIN;
j++;
break;
case AUTH_CONNECTION:
pfd[j].fd = sockets[i].fd;
pfd[j].revents = 0;
/*
* Only prepare to read if we can handle a full-size
* input read buffer and enqueue a max size reply..
*/
if ((r = sshbuf_check_reserve(sockets[i].input,
AGENT_RBUF_LEN)) == 0 &&
(r = sshbuf_check_reserve(sockets[i].output,
- AGENT_MAX_LEN)) == 0)
+ AGENT_MAX_LEN)) == 0)
pfd[j].events = POLLIN;
else if (r != SSH_ERR_NO_BUFFER_SPACE)
fatal_fr(r, "reserve");
if (sshbuf_len(sockets[i].output) > 0)
pfd[j].events |= POLLOUT;
j++;
break;
default:
break;
}
}
deadline = reaper();
if (parent_alive_interval != 0)
deadline = (deadline == 0) ? parent_alive_interval :
MINIMUM(deadline, parent_alive_interval);
if (deadline == 0) {
*timeoutp = -1; /* INFTIM */
} else {
if (deadline > INT_MAX / 1000)
*timeoutp = INT_MAX / 1000;
else
*timeoutp = deadline * 1000;
}
return (1);
}
static void
cleanup_socket(void)
{
if (cleanup_pid != 0 && getpid() != cleanup_pid)
return;
debug_f("cleanup");
if (socket_name[0])
unlink(socket_name);
if (socket_dir[0])
rmdir(socket_dir);
}
void
cleanup_exit(int i)
{
cleanup_socket();
_exit(i);
}
/*ARGSUSED*/
static void
cleanup_handler(int sig)
{
cleanup_socket();
#ifdef ENABLE_PKCS11
pkcs11_terminate();
#endif
_exit(2);
}
static void
check_parent_exists(void)
{
/*
* If our parent has exited then getppid() will return (pid_t)1,
* so testing for that should be safe.
*/
if (parent_pid != -1 && getppid() != parent_pid) {
/* printf("Parent has died - Authentication agent exiting.\n"); */
cleanup_socket();
_exit(2);
}
}
static void
usage(void)
{
fprintf(stderr,
"usage: ssh-agent [-c | -s] [-Dd] [-a bind_address] [-E fingerprint_hash]\n"
" [-P allowed_providers] [-t life]\n"
" ssh-agent [-a bind_address] [-E fingerprint_hash] [-P allowed_providers]\n"
" [-t life] command [arg ...]\n"
" ssh-agent [-c | -s] -k\n");
exit(1);
}
int
main(int ac, char **av)
{
int c_flag = 0, d_flag = 0, D_flag = 0, k_flag = 0, s_flag = 0;
int sock, ch, result, saved_errno;
char *shell, *format, *pidstr, *agentsocket = NULL;
#ifdef HAVE_SETRLIMIT
struct rlimit rlim;
#endif
extern int optind;
extern char *optarg;
pid_t pid;
char pidstrbuf[1 + 3 * sizeof pid];
size_t len;
mode_t prev_mask;
int timeout = -1; /* INFTIM */
struct pollfd *pfd = NULL;
size_t npfd = 0;
u_int maxfds;
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
sanitise_stdfd();
/* drop */
setegid(getgid());
setgid(getgid());
platform_disable_tracing(0); /* strict=no */
#ifdef RLIMIT_NOFILE
if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
fatal("%s: getrlimit: %s", __progname, strerror(errno));
#endif
__progname = ssh_get_progname(av[0]);
seed_rng();
while ((ch = getopt(ac, av, "cDdksE:a:O:P:t:")) != -1) {
switch (ch) {
case 'E':
fingerprint_hash = ssh_digest_alg_by_name(optarg);
if (fingerprint_hash == -1)
fatal("Invalid hash algorithm \"%s\"", optarg);
break;
case 'c':
if (s_flag)
usage();
c_flag++;
break;
case 'k':
k_flag++;
break;
case 'O':
if (strcmp(optarg, "no-restrict-websafe") == 0)
restrict_websafe = 0;
else
fatal("Unknown -O option");
break;
case 'P':
if (allowed_providers != NULL)
fatal("-P option already specified");
allowed_providers = xstrdup(optarg);
break;
case 's':
if (c_flag)
usage();
s_flag++;
break;
case 'd':
if (d_flag || D_flag)
usage();
d_flag++;
break;
case 'D':
if (d_flag || D_flag)
usage();
D_flag++;
break;
case 'a':
agentsocket = optarg;
break;
case 't':
if ((lifetime = convtime(optarg)) == -1) {
fprintf(stderr, "Invalid lifetime\n");
usage();
}
break;
default:
usage();
}
}
ac -= optind;
av += optind;
if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || D_flag))
usage();
if (allowed_providers == NULL)
allowed_providers = xstrdup(DEFAULT_ALLOWED_PROVIDERS);
if (ac == 0 && !c_flag && !s_flag) {
shell = getenv("SHELL");
if (shell != NULL && (len = strlen(shell)) > 2 &&
strncmp(shell + len - 3, "csh", 3) == 0)
c_flag = 1;
}
if (k_flag) {
const char *errstr = NULL;
pidstr = getenv(SSH_AGENTPID_ENV_NAME);
if (pidstr == NULL) {
fprintf(stderr, "%s not set, cannot kill agent\n",
SSH_AGENTPID_ENV_NAME);
exit(1);
}
pid = (int)strtonum(pidstr, 2, INT_MAX, &errstr);
if (errstr) {
fprintf(stderr,
"%s=\"%s\", which is not a good PID: %s\n",
SSH_AGENTPID_ENV_NAME, pidstr, errstr);
exit(1);
}
if (kill(pid, SIGTERM) == -1) {
perror("kill");
exit(1);
}
format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
printf(format, SSH_AUTHSOCKET_ENV_NAME);
printf(format, SSH_AGENTPID_ENV_NAME);
printf("echo Agent pid %ld killed;\n", (long)pid);
exit(0);
}
/*
* Minimum file descriptors:
* stdio (3) + listener (1) + syslog (1 maybe) + connection (1) +
* a few spare for libc / stack protectors / sanitisers, etc.
*/
#define SSH_AGENT_MIN_FDS (3+1+1+1+4)
if (rlim.rlim_cur < SSH_AGENT_MIN_FDS)
fatal("%s: file descriptor rlimit %lld too low (minimum %u)",
__progname, (long long)rlim.rlim_cur, SSH_AGENT_MIN_FDS);
maxfds = rlim.rlim_cur - SSH_AGENT_MIN_FDS;
parent_pid = getpid();
if (agentsocket == NULL) {
/* Create private directory for agent socket */
mktemp_proto(socket_dir, sizeof(socket_dir));
if (mkdtemp(socket_dir) == NULL) {
perror("mkdtemp: private socket dir");
exit(1);
}
snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir,
(long)parent_pid);
} else {
/* Try to use specified agent socket */
socket_dir[0] = '\0';
strlcpy(socket_name, agentsocket, sizeof socket_name);
}
/*
* Create socket early so it will exist before command gets run from
* the parent.
*/
prev_mask = umask(0177);
sock = unix_listener(socket_name, SSH_LISTEN_BACKLOG, 0);
if (sock < 0) {
/* XXX - unix_listener() calls error() not perror() */
*socket_name = '\0'; /* Don't unlink any existing file */
cleanup_exit(1);
}
umask(prev_mask);
/*
* Fork, and have the parent execute the command, if any, or present
* the socket data. The child continues as the authentication agent.
*/
if (D_flag || d_flag) {
log_init(__progname,
d_flag ? SYSLOG_LEVEL_DEBUG3 : SYSLOG_LEVEL_INFO,
SYSLOG_FACILITY_AUTH, 1);
format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
SSH_AUTHSOCKET_ENV_NAME);
printf("echo Agent pid %ld;\n", (long)parent_pid);
fflush(stdout);
goto skip;
}
pid = fork();
if (pid == -1) {
perror("fork");
cleanup_exit(1);
}
if (pid != 0) { /* Parent - execute the given command. */
close(sock);
snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid);
if (ac == 0) {
format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
SSH_AUTHSOCKET_ENV_NAME);
printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
SSH_AGENTPID_ENV_NAME);
printf("echo Agent pid %ld;\n", (long)pid);
exit(0);
}
if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) {
perror("setenv");
exit(1);
}
execvp(av[0], av);
perror(av[0]);
exit(1);
}
/* child */
log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);
if (setsid() == -1) {
error("setsid: %s", strerror(errno));
cleanup_exit(1);
}
(void)chdir("/");
if (stdfd_devnull(1, 1, 1) == -1)
error_f("stdfd_devnull failed");
#ifdef HAVE_SETRLIMIT
/* deny core dumps, since memory contains unencrypted private keys */
rlim.rlim_cur = rlim.rlim_max = 0;
if (setrlimit(RLIMIT_CORE, &rlim) == -1) {
error("setrlimit RLIMIT_CORE: %s", strerror(errno));
cleanup_exit(1);
}
#endif
skip:
cleanup_pid = getpid();
#ifdef ENABLE_PKCS11
pkcs11_init(0);
#endif
new_socket(AUTH_SOCKET, sock);
if (ac > 0)
parent_alive_interval = 10;
idtab_init();
ssh_signal(SIGPIPE, SIG_IGN);
ssh_signal(SIGINT, (d_flag | D_flag) ? cleanup_handler : SIG_IGN);
ssh_signal(SIGHUP, cleanup_handler);
ssh_signal(SIGTERM, cleanup_handler);
if (pledge("stdio rpath cpath unix id proc exec", NULL) == -1)
fatal("%s: pledge: %s", __progname, strerror(errno));
platform_pledge_agent();
while (1) {
prepare_poll(&pfd, &npfd, &timeout, maxfds);
result = poll(pfd, npfd, timeout);
saved_errno = errno;
if (parent_alive_interval != 0)
check_parent_exists();
(void) reaper(); /* remove expired keys */
if (result == -1) {
if (saved_errno == EINTR)
continue;
fatal("poll: %s", strerror(saved_errno));
} else if (result > 0)
after_poll(pfd, npfd, maxfds);
}
/* NOTREACHED */
}
diff --git a/ssh-keygen.0 b/ssh-keygen.0
index 75689a41bdad..66372d53c2b2 100644
--- a/ssh-keygen.0
+++ b/ssh-keygen.0
@@ -1,815 +1,815 @@
SSH-KEYGEN(1) General Commands Manual SSH-KEYGEN(1)
NAME
ssh-keygen M-bM-^@M-^S OpenSSH authentication key utility
SYNOPSIS
ssh-keygen [-q] [-a rounds] [-b bits] [-C comment] [-f output_keyfile]
[-m format] [-N new_passphrase] [-O option]
[-t dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa]
[-w provider] [-Z cipher]
ssh-keygen -p [-a rounds] [-f keyfile] [-m format] [-N new_passphrase]
[-P old_passphrase] [-Z cipher]
ssh-keygen -i [-f input_keyfile] [-m key_format]
ssh-keygen -e [-f input_keyfile] [-m key_format]
ssh-keygen -y [-f input_keyfile]
ssh-keygen -c [-a rounds] [-C comment] [-f keyfile] [-P passphrase]
ssh-keygen -l [-v] [-E fingerprint_hash] [-f input_keyfile]
ssh-keygen -B [-f input_keyfile]
ssh-keygen -D pkcs11
ssh-keygen -F hostname [-lv] [-f known_hosts_file]
ssh-keygen -H [-f known_hosts_file]
ssh-keygen -K [-a rounds] [-w provider]
ssh-keygen -R hostname [-f known_hosts_file]
ssh-keygen -r hostname [-g] [-f input_keyfile]
ssh-keygen -M generate [-O option] output_file
ssh-keygen -M screen [-f input_file] [-O option] output_file
ssh-keygen -I certificate_identity -s ca_key [-hU] [-D pkcs11_provider]
[-n principals] [-O option] [-V validity_interval]
[-z serial_number] file ...
ssh-keygen -L [-f input_keyfile]
ssh-keygen -A [-a rounds] [-f prefix_path]
ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]
file ...
ssh-keygen -Q [-l] -f krl_file file ...
ssh-keygen -Y find-principals -s signature_file -f allowed_signers_file
ssh-keygen -Y check-novalidate -n namespace -s signature_file
ssh-keygen -Y sign -f key_file -n namespace file ...
ssh-keygen -Y verify -f allowed_signers_file -I signer_identity
-n namespace -s signature_file [-r revocation_file]
DESCRIPTION
ssh-keygen generates, manages and converts authentication keys for
ssh(1). ssh-keygen can create keys for use by SSH protocol version 2.
The type of key to be generated is specified with the -t option. If
invoked without any arguments, ssh-keygen will generate an RSA key.
ssh-keygen is also used to generate groups for use in Diffie-Hellman
group exchange (DH-GEX). See the MODULI GENERATION section for details.
Finally, ssh-keygen can be used to generate and update Key Revocation
Lists, and to test whether given keys have been revoked by one. See the
KEY REVOCATION LISTS section for details.
Normally each user wishing to use SSH with public key authentication runs
this once to create the authentication key in ~/.ssh/id_dsa,
~/.ssh/id_ecdsa, ~/.ssh/id_ecdsa_sk, ~/.ssh/id_ed25519,
~/.ssh/id_ed25519_sk or ~/.ssh/id_rsa. Additionally, the system
administrator may use this to generate host keys, as seen in /etc/rc.
Normally this program generates the key and asks for a file in which to
store the private key. The public key is stored in a file with the same
name but M-bM-^@M-^\.pubM-bM-^@M-^] appended. The program also asks for a passphrase. The
passphrase may be empty to indicate no passphrase (host keys must have an
empty passphrase), or it may be a string of arbitrary length. A
passphrase is similar to a password, except it can be a phrase with a
series of words, punctuation, numbers, whitespace, or any string of
characters you want. Good passphrases are 10-30 characters long, are not
simple sentences or otherwise easily guessable (English prose has only
1-2 bits of entropy per character, and provides very bad passphrases),
and contain a mix of upper and lowercase letters, numbers, and non-
alphanumeric characters. The passphrase can be changed later by using
the -p option.
There is no way to recover a lost passphrase. If the passphrase is lost
or forgotten, a new key must be generated and the corresponding public
key copied to other machines.
ssh-keygen will by default write keys in an OpenSSH-specific format.
This format is preferred as it offers better protection for keys at rest
as well as allowing storage of key comments within the private key file
itself. The key comment may be useful to help identify the key. The
comment is initialized to M-bM-^@M-^\user@hostM-bM-^@M-^] when the key is created, but can be
changed using the -c option.
It is still possible for ssh-keygen to write the previously-used PEM
format private keys using the -m flag. This may be used when generating
new keys, and existing new-format keys may be converted using this option
in conjunction with the -p (change passphrase) flag.
After a key is generated, ssh-keygen will ask where the keys should be
placed to be activated.
The options are as follows:
-A For each of the key types (rsa, dsa, ecdsa and ed25519) for which
host keys do not exist, generate the host keys with the default
key file path, an empty passphrase, default bits for the key
type, and default comment. If -f has also been specified, its
argument is used as a prefix to the default path for the
resulting host key files. This is used by /etc/rc to generate
new host keys.
-a rounds
When saving a private key, this option specifies the number of
KDF (key derivation function, currently bcrypt_pbkdf(3)) rounds
used. Higher numbers result in slower passphrase verification
and increased resistance to brute-force password cracking (should
the keys be stolen). The default is 16 rounds.
-B Show the bubblebabble digest of specified private or public key
file.
-b bits
Specifies the number of bits in the key to create. For RSA keys,
the minimum size is 1024 bits and the default is 3072 bits.
Generally, 3072 bits is considered sufficient. DSA keys must be
exactly 1024 bits as specified by FIPS 186-2. For ECDSA keys,
the -b flag determines the key length by selecting from one of
three elliptic curve sizes: 256, 384 or 521 bits. Attempting to
use bit lengths other than these three values for ECDSA keys will
fail. ECDSA-SK, Ed25519 and Ed25519-SK keys have a fixed length
and the -b flag will be ignored.
-C comment
Provides a new comment.
-c Requests changing the comment in the private and public key
files. The program will prompt for the file containing the
private keys, for the passphrase if the key has one, and for the
new comment.
-D pkcs11
Download the public keys provided by the PKCS#11 shared library
pkcs11. When used in combination with -s, this option indicates
that a CA key resides in a PKCS#11 token (see the CERTIFICATES
section for details).
-E fingerprint_hash
Specifies the hash algorithm used when displaying key
fingerprints. Valid options are: M-bM-^@M-^\md5M-bM-^@M-^] and M-bM-^@M-^\sha256M-bM-^@M-^]. The
default is M-bM-^@M-^\sha256M-bM-^@M-^].
-e This option will read a private or public OpenSSH key file and
print to stdout a public key in one of the formats specified by
the -m option. The default export format is M-bM-^@M-^\RFC4716M-bM-^@M-^]. This
option allows exporting OpenSSH keys for use by other programs,
including several commercial SSH implementations.
-F hostname | [hostname]:port
Search for the specified hostname (with optional port number) in
a known_hosts file, listing any occurrences found. This option
is useful to find hashed host names or addresses and may also be
used in conjunction with the -H option to print found keys in a
hashed format.
-f filename
Specifies the filename of the key file.
-g Use generic DNS format when printing fingerprint resource records
using the -r command.
-H Hash a known_hosts file. This replaces all hostnames and
addresses with hashed representations within the specified file;
the original content is moved to a file with a .old suffix.
These hashes may be used normally by ssh and sshd, but they do
not reveal identifying information should the file's contents be
disclosed. This option will not modify existing hashed hostnames
and is therefore safe to use on files that mix hashed and non-
hashed names.
-h When signing a key, create a host certificate instead of a user
certificate. Please see the CERTIFICATES section for details.
-I certificate_identity
Specify the key identity when signing a public key. Please see
the CERTIFICATES section for details.
-i This option will read an unencrypted private (or public) key file
in the format specified by the -m option and print an OpenSSH
compatible private (or public) key to stdout. This option allows
importing keys from other software, including several commercial
SSH implementations. The default import format is M-bM-^@M-^\RFC4716M-bM-^@M-^].
-K Download resident keys from a FIDO authenticator. Public and
private key files will be written to the current directory for
each downloaded key. If multiple FIDO authenticators are
attached, keys will be downloaded from the first touched
authenticator.
-k Generate a KRL file. In this mode, ssh-keygen will generate a
KRL file at the location specified via the -f flag that revokes
every key or certificate presented on the command line.
Keys/certificates to be revoked may be specified by public key
file or using the format described in the KEY REVOCATION LISTS
section.
-L Prints the contents of one or more certificates.
-l Show fingerprint of specified public key file. For RSA and DSA
keys ssh-keygen tries to find the matching public key file and
prints its fingerprint. If combined with -v, a visual ASCII art
representation of the key is supplied with the fingerprint.
-M generate
Generate candidate Diffie-Hellman Group Exchange (DH-GEX)
parameters for eventual use by the
M-bM-^@M-^Xdiffie-hellman-group-exchange-*M-bM-^@M-^Y key exchange methods. The
numbers generated by this operation must be further screened
before use. See the MODULI GENERATION section for more
information.
-M screen
Screen candidate parameters for Diffie-Hellman Group Exchange.
This will accept a list of candidate numbers and test that they
are safe (Sophie Germain) primes with acceptable group
generators. The results of this operation may be added to the
/etc/moduli file. See the MODULI GENERATION section for more
information.
-m key_format
Specify a key format for key generation, the -i (import), -e
(export) conversion options, and the -p change passphrase
operation. The latter may be used to convert between OpenSSH
private key and PEM private key formats. The supported key
formats are: M-bM-^@M-^\RFC4716M-bM-^@M-^] (RFC 4716/SSH2 public or private key),
M-bM-^@M-^\PKCS8M-bM-^@M-^] (PKCS8 public or private key) or M-bM-^@M-^\PEMM-bM-^@M-^] (PEM public key).
By default OpenSSH will write newly-generated private keys in its
own format, but when converting public keys for export the
default format is M-bM-^@M-^\RFC4716M-bM-^@M-^]. Setting a format of M-bM-^@M-^\PEMM-bM-^@M-^] when
generating or updating a supported private key type will cause
the key to be stored in the legacy PEM private key format.
-N new_passphrase
Provides the new passphrase.
-n principals
Specify one or more principals (user or host names) to be
included in a certificate when signing a key. Multiple
principals may be specified, separated by commas. Please see the
CERTIFICATES section for details.
-O option
Specify a key/value option. These are specific to the operation
that ssh-keygen has been requested to perform.
When signing certificates, one of the options listed in the
CERTIFICATES section may be specified here.
When performing moduli generation or screening, one of the
options listed in the MODULI GENERATION section may be specified.
When generating a key that will be hosted on a FIDO
authenticator, this flag may be used to specify key-specific
options. Those supported at present are:
application
Override the default FIDO application/origin string of
M-bM-^@M-^\ssh:M-bM-^@M-^]. This may be useful when generating host or
domain-specific resident keys. The specified application
string must begin with M-bM-^@M-^\ssh:M-bM-^@M-^].
challenge=path
Specifies a path to a challenge string that will be
passed to the FIDO token during key generation. The
challenge string may be used as part of an out-of-band
protocol for key enrollment (a random challenge is used
by default).
device Explicitly specify a fido(4) device to use, rather than
letting the token middleware select one.
no-touch-required
Indicate that the generated private key should not
require touch events (user presence) when making
signatures. Note that sshd(8) will refuse such
signatures by default, unless overridden via an
authorized_keys option.
resident
Indicate that the key should be stored on the FIDO
authenticator itself. Resident keys may be supported on
FIDO2 tokens and typically require that a PIN be set on
the token prior to generation. Resident keys may be
loaded off the token using ssh-add(1).
user A username to be associated with a resident key,
overriding the empty default username. Specifying a
username may be useful when generating multiple resident
keys for the same application name.
verify-required
Indicate that this private key should require user
verification for each signature. Not all FIDO tokens
support this option. Currently PIN authentication is the
only supported verification method, but other methods may
be supported in the future.
write-attestation=path
May be used at key generation time to record the
attestation data returned from FIDO tokens during key
generation. Please note that this information is
potentially sensitive. By default, this information is
discarded.
The -O option may be specified multiple times.
-P passphrase
Provides the (old) passphrase.
-p Requests changing the passphrase of a private key file instead of
creating a new private key. The program will prompt for the file
containing the private key, for the old passphrase, and twice for
the new passphrase.
-Q Test whether keys have been revoked in a KRL. If the -l option
is also specified then the contents of the KRL will be printed.
-q Silence ssh-keygen.
-R hostname | [hostname]:port
Removes all keys belonging to the specified hostname (with
optional port number) from a known_hosts file. This option is
useful to delete hashed hosts (see the -H option above).
-r hostname
Print the SSHFP fingerprint resource record named hostname for
the specified public key file.
-s ca_key
Certify (sign) a public key using the specified CA key. Please
see the CERTIFICATES section for details.
When generating a KRL, -s specifies a path to a CA public key
file used to revoke certificates directly by key ID or serial
number. See the KEY REVOCATION LISTS section for details.
-t dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa
Specifies the type of key to create. The possible values are
M-bM-^@M-^\dsaM-bM-^@M-^], M-bM-^@M-^\ecdsaM-bM-^@M-^], M-bM-^@M-^\ecdsa-skM-bM-^@M-^], M-bM-^@M-^\ed25519M-bM-^@M-^], M-bM-^@M-^\ed25519-skM-bM-^@M-^], or M-bM-^@M-^\rsaM-bM-^@M-^].
This flag may also be used to specify the desired signature type
when signing certificates using an RSA CA key. The available RSA
signature variants are M-bM-^@M-^\ssh-rsaM-bM-^@M-^] (SHA1 signatures, not
recommended), M-bM-^@M-^\rsa-sha2-256M-bM-^@M-^], and M-bM-^@M-^\rsa-sha2-512M-bM-^@M-^] (the default).
-U When used in combination with -s, this option indicates that a CA
key resides in a ssh-agent(1). See the CERTIFICATES section for
more information.
-u Update a KRL. When specified with -k, keys listed via the
command line are added to the existing KRL rather than a new KRL
being created.
-V validity_interval
Specify a validity interval when signing a certificate. A
validity interval may consist of a single time, indicating that
the certificate is valid beginning now and expiring at that time,
or may consist of two times separated by a colon to indicate an
explicit time interval.
The start time may be specified as the string M-bM-^@M-^\alwaysM-bM-^@M-^] to
indicate the certificate has no specified start time, a date in
YYYYMMDD format, a time in YYYYMMDDHHMM[SS] format, a relative
time (to the current time) consisting of a minus sign followed by
an interval in the format described in the TIME FORMATS section
of sshd_config(5).
The end time may be specified as a YYYYMMDD date, a
YYYYMMDDHHMM[SS] time, a relative time starting with a plus
character or the string M-bM-^@M-^\foreverM-bM-^@M-^] to indicate that the
certificate has no expiry date.
For example: M-bM-^@M-^\+52w1dM-bM-^@M-^] (valid from now to 52 weeks and one day
from now), M-bM-^@M-^\-4w:+4wM-bM-^@M-^] (valid from four weeks ago to four weeks
from now), M-bM-^@M-^\20100101123000:20110101123000M-bM-^@M-^] (valid from 12:30 PM,
January 1st, 2010 to 12:30 PM, January 1st, 2011), M-bM-^@M-^\-1d:20110101M-bM-^@M-^]
(valid from yesterday to midnight, January 1st, 2011),
M-bM-^@M-^\-1m:foreverM-bM-^@M-^] (valid from one minute ago and never expiring).
-v Verbose mode. Causes ssh-keygen to print debugging messages
about its progress. This is helpful for debugging moduli
generation. Multiple -v options increase the verbosity. The
maximum is 3.
-w provider
Specifies a path to a library that will be used when creating
FIDO authenticator-hosted keys, overriding the default of using
the internal USB HID support.
-Y find-principals
Find the principal(s) associated with the public key of a
signature, provided using the -s flag in an authorized signers
file provided using the -f flag. The format of the allowed
signers file is documented in the ALLOWED SIGNERS section below.
If one or more matching principals are found, they are returned
on standard output.
-Y check-novalidate
Checks that a signature generated using ssh-keygen -Y sign has a
valid structure. This does not validate if a signature comes
from an authorized signer. When testing a signature, ssh-keygen
accepts a message on standard input and a signature namespace
using -n. A file containing the corresponding signature must
also be supplied using the -s flag. Successful testing of the
signature is signalled by ssh-keygen returning a zero exit
status.
-Y sign
Cryptographically sign a file or some data using a SSH key. When
signing, ssh-keygen accepts zero or more files to sign on the
command-line - if no files are specified then ssh-keygen will
sign data presented on standard input. Signatures are written to
the path of the input file with M-bM-^@M-^\.sigM-bM-^@M-^] appended, or to standard
output if the message to be signed was read from standard input.
The key used for signing is specified using the -f option and may
refer to either a private key, or a public key with the private
half available via ssh-agent(1). An additional signature
namespace, used to prevent signature confusion across different
domains of use (e.g. file signing vs email signing) must be
provided via the -n flag. Namespaces are arbitrary strings, and
may include: M-bM-^@M-^\fileM-bM-^@M-^] for file signing, M-bM-^@M-^\emailM-bM-^@M-^] for email signing.
For custom uses, it is recommended to use names following a
NAMESPACE@YOUR.DOMAIN pattern to generate unambiguous namespaces.
-Y verify
Request to verify a signature generated using ssh-keygen -Y sign
as described above. When verifying a signature, ssh-keygen
accepts a message on standard input and a signature namespace
using -n. A file containing the corresponding signature must
also be supplied using the -s flag, along with the identity of
the signer using -I and a list of allowed signers via the -f
flag. The format of the allowed signers file is documented in
the ALLOWED SIGNERS section below. A file containing revoked
keys can be passed using the -r flag. The revocation file may be
a KRL or a one-per-line list of public keys. Successful
verification by an authorized signer is signalled by ssh-keygen
returning a zero exit status.
-y This option will read a private OpenSSH format file and print an
OpenSSH public key to stdout.
-Z cipher
Specifies the cipher to use for encryption when writing an
OpenSSH-format private key file. The list of available ciphers
may be obtained using "ssh -Q cipher". The default is
M-bM-^@M-^\aes256-ctrM-bM-^@M-^].
-z serial_number
Specifies a serial number to be embedded in the certificate to
distinguish this certificate from others from the same CA. If
the serial_number is prefixed with a M-bM-^@M-^X+M-bM-^@M-^Y character, then the
serial number will be incremented for each certificate signed on
a single command-line. The default serial number is zero.
When generating a KRL, the -z flag is used to specify a KRL
version number.
MODULI GENERATION
ssh-keygen may be used to generate groups for the Diffie-Hellman Group
Exchange (DH-GEX) protocol. Generating these groups is a two-step
process: first, candidate primes are generated using a fast, but memory
intensive process. These candidate primes are then tested for
suitability (a CPU-intensive process).
Generation of primes is performed using the -M generate option. The
desired length of the primes may be specified by the -O bits option. For
example:
# ssh-keygen -M generate -O bits=2048 moduli-2048.candidates
By default, the search for primes begins at a random point in the desired
length range. This may be overridden using the -O start option, which
specifies a different start point (in hex).
Once a set of candidates have been generated, they must be screened for
suitability. This may be performed using the -M screen option. In this
mode ssh-keygen will read candidates from standard input (or a file
specified using the -f option). For example:
# ssh-keygen -M screen -f moduli-2048.candidates moduli-2048
By default, each candidate will be subjected to 100 primality tests.
This may be overridden using the -O prime-tests option. The DH generator
value will be chosen automatically for the prime under consideration. If
a specific generator is desired, it may be requested using the -O
generator option. Valid generator values are 2, 3, and 5.
Screened DH groups may be installed in /etc/moduli. It is important that
this file contains moduli of a range of bit lengths and that both ends of
a connection share common moduli.
A number of options are available for moduli generation and screening via
the -O flag:
lines=number
Exit after screening the specified number of lines while
performing DH candidate screening.
start-line=line-number
Start screening at the specified line number while performing DH
candidate screening.
checkpoint=filename
Write the last line processed to the specified file while
performing DH candidate screening. This will be used to skip
lines in the input file that have already been processed if the
job is restarted.
memory=mbytes
Specify the amount of memory to use (in megabytes) when
generating candidate moduli for DH-GEX.
start=hex-value
Specify start point (in hex) when generating candidate moduli for
DH-GEX.
generator=value
Specify desired generator (in decimal) when testing candidate
moduli for DH-GEX.
CERTIFICATES
ssh-keygen supports signing of keys to produce certificates that may be
used for user or host authentication. Certificates consist of a public
key, some identity information, zero or more principal (user or host)
names and a set of options that are signed by a Certification Authority
(CA) key. Clients or servers may then trust only the CA key and verify
its signature on a certificate rather than trusting many user/host keys.
Note that OpenSSH certificates are a different, and much simpler, format
to the X.509 certificates used in ssl(8).
ssh-keygen supports two types of certificates: user and host. User
certificates authenticate users to servers, whereas host certificates
authenticate server hosts to users. To generate a user certificate:
$ ssh-keygen -s /path/to/ca_key -I key_id /path/to/user_key.pub
The resultant certificate will be placed in /path/to/user_key-cert.pub.
A host certificate requires the -h option:
$ ssh-keygen -s /path/to/ca_key -I key_id -h /path/to/host_key.pub
The host certificate will be output to /path/to/host_key-cert.pub.
It is possible to sign using a CA key stored in a PKCS#11 token by
providing the token library using -D and identifying the CA key by
providing its public half as an argument to -s:
$ ssh-keygen -s ca_key.pub -D libpkcs11.so -I key_id user_key.pub
Similarly, it is possible for the CA key to be hosted in a ssh-agent(1).
This is indicated by the -U flag and, again, the CA key must be
identified by its public half.
$ ssh-keygen -Us ca_key.pub -I key_id user_key.pub
In all cases, key_id is a "key identifier" that is logged by the server
when the certificate is used for authentication.
Certificates may be limited to be valid for a set of principal
(user/host) names. By default, generated certificates are valid for all
users or hosts. To generate a certificate for a specified set of
principals:
$ ssh-keygen -s ca_key -I key_id -n user1,user2 user_key.pub
$ ssh-keygen -s ca_key -I key_id -h -n host.domain host_key.pub
Additional limitations on the validity and use of user certificates may
be specified through certificate options. A certificate option may
disable features of the SSH session, may be valid only when presented
from particular source addresses or may force the use of a specific
command.
The options that are valid for user certificates are:
clear Clear all enabled permissions. This is useful for clearing the
default set of permissions so permissions may be added
individually.
critical:name[=contents]
extension:name[=contents]
Includes an arbitrary certificate critical option or extension.
The specified name should include a domain suffix, e.g.
M-bM-^@M-^\name@example.comM-bM-^@M-^]. If contents is specified then it is included
as the contents of the extension/option encoded as a string,
otherwise the extension/option is created with no contents
(usually indicating a flag). Extensions may be ignored by a
client or server that does not recognise them, whereas unknown
critical options will cause the certificate to be refused.
force-command=command
Forces the execution of command instead of any shell or command
specified by the user when the certificate is used for
authentication.
no-agent-forwarding
Disable ssh-agent(1) forwarding (permitted by default).
no-port-forwarding
Disable port forwarding (permitted by default).
no-pty Disable PTY allocation (permitted by default).
no-user-rc
Disable execution of ~/.ssh/rc by sshd(8) (permitted by default).
no-x11-forwarding
Disable X11 forwarding (permitted by default).
permit-agent-forwarding
Allows ssh-agent(1) forwarding.
permit-port-forwarding
Allows port forwarding.
permit-pty
Allows PTY allocation.
permit-user-rc
Allows execution of ~/.ssh/rc by sshd(8).
permit-X11-forwarding
Allows X11 forwarding.
no-touch-required
Do not require signatures made using this key include
demonstration of user presence (e.g. by having the user touch the
authenticator). This option only makes sense for the FIDO
authenticator algorithms ecdsa-sk and ed25519-sk.
source-address=address_list
Restrict the source addresses from which the certificate is
considered valid. The address_list is a comma-separated list of
one or more address/netmask pairs in CIDR format.
verify-required
Require signatures made using this key indicate that the user was
first verified. This option only makes sense for the FIDO
authenticator algorithms ecdsa-sk and ed25519-sk. Currently PIN
authentication is the only supported verification method, but
other methods may be supported in the future.
At present, no standard options are valid for host keys.
Finally, certificates may be defined with a validity lifetime. The -V
option allows specification of certificate start and end times. A
certificate that is presented at a time outside this range will not be
considered valid. By default, certificates are valid from the UNIX Epoch
to the distant future.
For certificates to be used for user or host authentication, the CA
public key must be trusted by sshd(8) or ssh(1). Please refer to those
manual pages for details.
KEY REVOCATION LISTS
ssh-keygen is able to manage OpenSSH format Key Revocation Lists (KRLs).
These binary files specify keys or certificates to be revoked using a
compact format, taking as little as one bit per certificate if they are
being revoked by serial number.
KRLs may be generated using the -k flag. This option reads one or more
files from the command line and generates a new KRL. The files may
either contain a KRL specification (see below) or public keys, listed one
per line. Plain public keys are revoked by listing their hash or
contents in the KRL and certificates revoked by serial number or key ID
(if the serial is zero or not available).
Revoking keys using a KRL specification offers explicit control over the
types of record used to revoke keys and may be used to directly revoke
certificates by serial number or key ID without having the complete
original certificate on hand. A KRL specification consists of lines
containing one of the following directives followed by a colon and some
directive-specific information.
serial: serial_number[-serial_number]
Revokes a certificate with the specified serial number. Serial
numbers are 64-bit values, not including zero and may be
expressed in decimal, hex or octal. If two serial numbers are
specified separated by a hyphen, then the range of serial numbers
including and between each is revoked. The CA key must have been
specified on the ssh-keygen command line using the -s option.
id: key_id
Revokes a certificate with the specified key ID string. The CA
key must have been specified on the ssh-keygen command line using
the -s option.
key: public_key
Revokes the specified key. If a certificate is listed, then it
is revoked as a plain public key.
sha1: public_key
Revokes the specified key by including its SHA1 hash in the KRL.
sha256: public_key
Revokes the specified key by including its SHA256 hash in the
KRL. KRLs that revoke keys by SHA256 hash are not supported by
OpenSSH versions prior to 7.9.
hash: fingerprint
Revokes a key using a fingerprint hash, as obtained from a
sshd(8) authentication log message or the ssh-keygen -l flag.
Only SHA256 fingerprints are supported here and resultant KRLs
are not supported by OpenSSH versions prior to 7.9.
KRLs may be updated using the -u flag in addition to -k. When this
option is specified, keys listed via the command line are merged into the
KRL, adding to those already there.
It is also possible, given a KRL, to test whether it revokes a particular
key (or keys). The -Q flag will query an existing KRL, testing each key
specified on the command line. If any key listed on the command line has
been revoked (or an error encountered) then ssh-keygen will exit with a
non-zero exit status. A zero exit status will only be returned if no key
was revoked.
ALLOWED SIGNERS
When verifying signatures, ssh-keygen uses a simple list of identities
and keys to determine whether a signature comes from an authorized
source. This "allowed signers" file uses a format patterned after the
AUTHORIZED_KEYS FILE FORMAT described in sshd(8). Each line of the file
contains the following space-separated fields: principals, options,
keytype, base64-encoded key. Empty lines and lines starting with a M-bM-^@M-^X#M-bM-^@M-^Y
are ignored as comments.
The principals field is a pattern-list (see PATTERNS in ssh_config(5))
consisting of one or more comma-separated USER@DOMAIN identity patterns
that are accepted for signing. When verifying, the identity presented
via the -I option must match a principals pattern in order for the
corresponding key to be considered acceptable for verification.
The options (if present) consist of comma-separated option
specifications. No spaces are permitted, except within double quotes.
The following option specifications are supported (note that option
keywords are case-insensitive):
cert-authority
Indicates that this key is accepted as a certificate authority
(CA) and that certificates signed by this CA may be accepted for
verification.
namespaces="namespace-list"
Specifies a pattern-list of namespaces that are accepted for this
key. If this option is present, the signature namespace embedded
in the signature object and presented on the verification
command-line must match the specified list before the key will be
considered acceptable.
When verifying signatures made by certificates, the expected principal
name must match both the principals pattern in the allowed signers file
and the principals embedded in the certificate itself.
An example allowed signers file:
# Comments allowed at start of line
user1@example.com,user2@example.com ssh-rsa AAAAX1...
# A certificate authority, trusted for all principals in a domain.
*@example.com cert-authority ssh-ed25519 AAAB4...
# A key that is accepted only for file signing.
user2@example.com namespaces="file" ssh-ed25519 AAA41...
ENVIRONMENT
SSH_SK_PROVIDER
Specifies a path to a library that will be used when loading any
FIDO authenticator-hosted keys, overriding the default of using
the built-in USB HID support.
FILES
~/.ssh/id_dsa
~/.ssh/id_ecdsa
~/.ssh/id_ecdsa_sk
~/.ssh/id_ed25519
~/.ssh/id_ed25519_sk
~/.ssh/id_rsa
Contains the DSA, ECDSA, authenticator-hosted ECDSA, Ed25519,
authenticator-hosted Ed25519 or RSA authentication identity of
the user. This file should not be readable by anyone but the
user. It is possible to specify a passphrase when generating the
key; that passphrase will be used to encrypt the private part of
this file using 128-bit AES. This file is not automatically
accessed by ssh-keygen but it is offered as the default file for
the private key. ssh(1) will read this file when a login attempt
is made.
~/.ssh/id_dsa.pub
~/.ssh/id_ecdsa.pub
~/.ssh/id_ecdsa_sk.pub
~/.ssh/id_ed25519.pub
~/.ssh/id_ed25519_sk.pub
~/.ssh/id_rsa.pub
Contains the DSA, ECDSA, authenticator-hosted ECDSA, Ed25519,
authenticator-hosted Ed25519 or RSA public key for
authentication. The contents of this file should be added to
~/.ssh/authorized_keys on all machines where the user wishes to
log in using public key authentication. There is no need to keep
the contents of this file secret.
/etc/moduli
Contains Diffie-Hellman groups used for DH-GEX. The file format
is described in moduli(5).
SEE ALSO
ssh(1), ssh-add(1), ssh-agent(1), moduli(5), sshd(8)
The Secure Shell (SSH) Public Key File Format, RFC 4716, 2006.
AUTHORS
OpenSSH is a derivative of the original and free ssh 1.2.12 release by
Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo
de Raadt and Dug Song removed many bugs, re-added newer features and
created OpenSSH. Markus Friedl contributed the support for SSH protocol
versions 1.5 and 2.0.
-OpenBSD 6.8 November 27, 2020 OpenBSD 6.8
+OpenBSD 6.9 November 27, 2020 OpenBSD 6.9
diff --git a/ssh-keygen.c b/ssh-keygen.c
index cfb5f1151661..027c6db6bd4a 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,3715 +1,3716 @@
-/* $OpenBSD: ssh-keygen.c,v 1.427 2020/12/20 23:36:51 djm Exp $ */
+/* $OpenBSD: ssh-keygen.c,v 1.429 2021/04/03 06:18:41 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Identity and host key generation and maintenance.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#ifdef WITH_OPENSSL
#include <openssl/evp.h>
#include <openssl/pem.h>
#include "openbsd-compat/openssl-compat.h"
#endif
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#include <pwd.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <locale.h>
#include <time.h>
#include "xmalloc.h"
#include "sshkey.h"
#include "authfile.h"
#include "sshbuf.h"
#include "pathnames.h"
#include "log.h"
#include "misc.h"
#include "match.h"
#include "hostfile.h"
#include "dns.h"
#include "ssh.h"
#include "ssh2.h"
#include "ssherr.h"
#include "ssh-pkcs11.h"
#include "atomicio.h"
#include "krl.h"
#include "digest.h"
#include "utf8.h"
#include "authfd.h"
#include "sshsig.h"
#include "ssh-sk.h"
#include "sk-api.h" /* XXX for SSH_SK_USER_PRESENCE_REQD; remove */
#include "cipher.h"
#ifdef WITH_OPENSSL
# define DEFAULT_KEY_TYPE_NAME "rsa"
#else
# define DEFAULT_KEY_TYPE_NAME "ed25519"
#endif
/*
* Default number of bits in the RSA, DSA and ECDSA keys. These value can be
* overridden on the command line.
*
* These values, with the exception of DSA, provide security equivalent to at
* least 128 bits of security according to NIST Special Publication 800-57:
* Recommendation for Key Management Part 1 rev 4 section 5.6.1.
* For DSA it (and FIPS-186-4 section 4.2) specifies that the only size for
* which a 160bit hash is acceptable is 1kbit, and since ssh-dss specifies only
* SHA1 we limit the DSA key size 1k bits.
*/
#define DEFAULT_BITS 3072
#define DEFAULT_BITS_DSA 1024
#define DEFAULT_BITS_ECDSA 256
static int quiet = 0;
/* Flag indicating that we just want to see the key fingerprint */
static int print_fingerprint = 0;
static int print_bubblebabble = 0;
/* Hash algorithm to use for fingerprints. */
static int fingerprint_hash = SSH_FP_HASH_DEFAULT;
/* The identity file name, given on the command line or entered by the user. */
static char identity_file[PATH_MAX];
static int have_identity = 0;
/* This is set to the passphrase if given on the command line. */
static char *identity_passphrase = NULL;
/* This is set to the new passphrase if given on the command line. */
static char *identity_new_passphrase = NULL;
/* Key type when certifying */
static u_int cert_key_type = SSH2_CERT_TYPE_USER;
/* "key ID" of signed key */
static char *cert_key_id = NULL;
/* Comma-separated list of principal names for certifying keys */
static char *cert_principals = NULL;
/* Validity period for certificates */
static u_int64_t cert_valid_from = 0;
static u_int64_t cert_valid_to = ~0ULL;
/* Certificate options */
#define CERTOPT_X_FWD (1)
#define CERTOPT_AGENT_FWD (1<<1)
#define CERTOPT_PORT_FWD (1<<2)
#define CERTOPT_PTY (1<<3)
#define CERTOPT_USER_RC (1<<4)
#define CERTOPT_NO_REQUIRE_USER_PRESENCE (1<<5)
#define CERTOPT_DEFAULT (CERTOPT_X_FWD|CERTOPT_AGENT_FWD| \
CERTOPT_PORT_FWD|CERTOPT_PTY|CERTOPT_USER_RC)
static u_int32_t certflags_flags = CERTOPT_DEFAULT;
static char *certflags_command = NULL;
static char *certflags_src_addr = NULL;
/* Arbitrary extensions specified by user */
struct cert_ext {
char *key;
char *val;
int crit;
};
static struct cert_ext *cert_ext;
static size_t ncert_ext;
/* Conversion to/from various formats */
enum {
FMT_RFC4716,
FMT_PKCS8,
FMT_PEM
} convert_format = FMT_RFC4716;
static char *key_type_name = NULL;
/* Load key from this PKCS#11 provider */
static char *pkcs11provider = NULL;
/* FIDO/U2F provider to use */
static char *sk_provider = NULL;
/* Format for writing private keys */
static int private_key_format = SSHKEY_PRIVATE_OPENSSH;
/* Cipher for new-format private keys */
static char *openssh_format_cipher = NULL;
/* Number of KDF rounds to derive new format keys. */
static int rounds = 0;
/* argv0 */
extern char *__progname;
static char hostname[NI_MAXHOST];
#ifdef WITH_OPENSSL
/* moduli.c */
int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *);
int prime_test(FILE *, FILE *, u_int32_t, u_int32_t, char *, unsigned long,
unsigned long);
#endif
static void
type_bits_valid(int type, const char *name, u_int32_t *bitsp)
{
if (type == KEY_UNSPEC)
fatal("unknown key type %s", key_type_name);
if (*bitsp == 0) {
#ifdef WITH_OPENSSL
int nid;
switch(type) {
case KEY_DSA:
*bitsp = DEFAULT_BITS_DSA;
break;
case KEY_ECDSA:
if (name != NULL &&
(nid = sshkey_ecdsa_nid_from_name(name)) > 0)
*bitsp = sshkey_curve_nid_to_bits(nid);
if (*bitsp == 0)
*bitsp = DEFAULT_BITS_ECDSA;
break;
case KEY_RSA:
*bitsp = DEFAULT_BITS;
break;
}
#endif
}
#ifdef WITH_OPENSSL
switch (type) {
case KEY_DSA:
if (*bitsp != 1024)
fatal("Invalid DSA key length: must be 1024 bits");
break;
case KEY_RSA:
if (*bitsp < SSH_RSA_MINIMUM_MODULUS_SIZE)
fatal("Invalid RSA key length: minimum is %d bits",
SSH_RSA_MINIMUM_MODULUS_SIZE);
else if (*bitsp > OPENSSL_RSA_MAX_MODULUS_BITS)
fatal("Invalid RSA key length: maximum is %d bits",
OPENSSL_RSA_MAX_MODULUS_BITS);
break;
case KEY_ECDSA:
if (sshkey_ecdsa_bits_to_nid(*bitsp) == -1)
#ifdef OPENSSL_HAS_NISTP521
fatal("Invalid ECDSA key length: valid lengths are "
"256, 384 or 521 bits");
#else
fatal("Invalid ECDSA key length: valid lengths are "
"256 or 384 bits");
#endif
}
#endif
}
/*
* Checks whether a file exists and, if so, asks the user whether they wish
* to overwrite it.
* Returns nonzero if the file does not already exist or if the user agrees to
* overwrite, or zero otherwise.
*/
static int
confirm_overwrite(const char *filename)
{
char yesno[3];
struct stat st;
if (stat(filename, &st) != 0)
return 1;
printf("%s already exists.\n", filename);
printf("Overwrite (y/n)? ");
fflush(stdout);
if (fgets(yesno, sizeof(yesno), stdin) == NULL)
return 0;
if (yesno[0] != 'y' && yesno[0] != 'Y')
return 0;
return 1;
}
static void
ask_filename(struct passwd *pw, const char *prompt)
{
char buf[1024];
char *name = NULL;
if (key_type_name == NULL)
name = _PATH_SSH_CLIENT_ID_RSA;
else {
switch (sshkey_type_from_name(key_type_name)) {
case KEY_DSA_CERT:
case KEY_DSA:
name = _PATH_SSH_CLIENT_ID_DSA;
break;
#ifdef OPENSSL_HAS_ECC
case KEY_ECDSA_CERT:
case KEY_ECDSA:
name = _PATH_SSH_CLIENT_ID_ECDSA;
break;
case KEY_ECDSA_SK_CERT:
case KEY_ECDSA_SK:
name = _PATH_SSH_CLIENT_ID_ECDSA_SK;
break;
#endif
case KEY_RSA_CERT:
case KEY_RSA:
name = _PATH_SSH_CLIENT_ID_RSA;
break;
case KEY_ED25519:
case KEY_ED25519_CERT:
name = _PATH_SSH_CLIENT_ID_ED25519;
break;
case KEY_ED25519_SK:
case KEY_ED25519_SK_CERT:
name = _PATH_SSH_CLIENT_ID_ED25519_SK;
break;
case KEY_XMSS:
case KEY_XMSS_CERT:
name = _PATH_SSH_CLIENT_ID_XMSS;
break;
default:
fatal("bad key type");
}
}
snprintf(identity_file, sizeof(identity_file),
"%s/%s", pw->pw_dir, name);
printf("%s (%s): ", prompt, identity_file);
fflush(stdout);
if (fgets(buf, sizeof(buf), stdin) == NULL)
exit(1);
buf[strcspn(buf, "\n")] = '\0';
if (strcmp(buf, "") != 0)
strlcpy(identity_file, buf, sizeof(identity_file));
have_identity = 1;
}
static struct sshkey *
load_identity(const char *filename, char **commentp)
{
char *pass;
struct sshkey *prv;
int r;
if (commentp != NULL)
*commentp = NULL;
if ((r = sshkey_load_private(filename, "", &prv, commentp)) == 0)
return prv;
if (r != SSH_ERR_KEY_WRONG_PASSPHRASE)
fatal_r(r, "Load key \"%s\"", filename);
if (identity_passphrase)
pass = xstrdup(identity_passphrase);
else
pass = read_passphrase("Enter passphrase: ", RP_ALLOW_STDIN);
r = sshkey_load_private(filename, pass, &prv, commentp);
freezero(pass, strlen(pass));
if (r != 0)
fatal_r(r, "Load key \"%s\"", filename);
return prv;
}
#define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
#define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----"
#define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
#define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb
#ifdef WITH_OPENSSL
static void
do_convert_to_ssh2(struct passwd *pw, struct sshkey *k)
{
struct sshbuf *b;
char comment[61], *b64;
int r;
if ((b = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshkey_putb(k, b)) != 0)
fatal_fr(r, "put key");
if ((b64 = sshbuf_dtob64_string(b, 1)) == NULL)
fatal_f("sshbuf_dtob64_string failed");
/* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */
snprintf(comment, sizeof(comment),
"%u-bit %s, converted by %s@%s from OpenSSH",
sshkey_size(k), sshkey_type(k),
pw->pw_name, hostname);
sshkey_free(k);
sshbuf_free(b);
fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
fprintf(stdout, "Comment: \"%s\"\n%s", comment, b64);
fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
free(b64);
exit(0);
}
static void
do_convert_to_pkcs8(struct sshkey *k)
{
switch (sshkey_type_plain(k->type)) {
case KEY_RSA:
if (!PEM_write_RSA_PUBKEY(stdout, k->rsa))
fatal("PEM_write_RSA_PUBKEY failed");
break;
case KEY_DSA:
if (!PEM_write_DSA_PUBKEY(stdout, k->dsa))
fatal("PEM_write_DSA_PUBKEY failed");
break;
#ifdef OPENSSL_HAS_ECC
case KEY_ECDSA:
if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa))
fatal("PEM_write_EC_PUBKEY failed");
break;
#endif
default:
fatal_f("unsupported key type %s", sshkey_type(k));
}
exit(0);
}
static void
do_convert_to_pem(struct sshkey *k)
{
switch (sshkey_type_plain(k->type)) {
case KEY_RSA:
if (!PEM_write_RSAPublicKey(stdout, k->rsa))
fatal("PEM_write_RSAPublicKey failed");
break;
case KEY_DSA:
if (!PEM_write_DSA_PUBKEY(stdout, k->dsa))
fatal("PEM_write_DSA_PUBKEY failed");
break;
#ifdef OPENSSL_HAS_ECC
case KEY_ECDSA:
if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa))
fatal("PEM_write_EC_PUBKEY failed");
break;
#endif
default:
fatal_f("unsupported key type %s", sshkey_type(k));
}
exit(0);
}
static void
do_convert_to(struct passwd *pw)
{
struct sshkey *k;
struct stat st;
int r;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
if (stat(identity_file, &st) == -1)
fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
if ((r = sshkey_load_public(identity_file, &k, NULL)) != 0)
k = load_identity(identity_file, NULL);
switch (convert_format) {
case FMT_RFC4716:
do_convert_to_ssh2(pw, k);
break;
case FMT_PKCS8:
do_convert_to_pkcs8(k);
break;
case FMT_PEM:
do_convert_to_pem(k);
break;
default:
fatal_f("unknown key format %d", convert_format);
}
exit(0);
}
/*
* This is almost exactly the bignum1 encoding, but with 32 bit for length
* instead of 16.
*/
static void
buffer_get_bignum_bits(struct sshbuf *b, BIGNUM *value)
{
u_int bytes, bignum_bits;
int r;
if ((r = sshbuf_get_u32(b, &bignum_bits)) != 0)
fatal_fr(r, "parse");
bytes = (bignum_bits + 7) / 8;
if (sshbuf_len(b) < bytes)
fatal_f("input buffer too small: need %d have %zu",
bytes, sshbuf_len(b));
if (BN_bin2bn(sshbuf_ptr(b), bytes, value) == NULL)
fatal_f("BN_bin2bn failed");
if ((r = sshbuf_consume(b, bytes)) != 0)
fatal_fr(r, "consume");
}
static struct sshkey *
do_convert_private_ssh2(struct sshbuf *b)
{
struct sshkey *key = NULL;
char *type, *cipher;
u_char e1, e2, e3, *sig = NULL, data[] = "abcde12345";
int r, rlen, ktype;
u_int magic, i1, i2, i3, i4;
size_t slen;
u_long e;
BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL;
BIGNUM *dsa_pub_key = NULL, *dsa_priv_key = NULL;
BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
BIGNUM *rsa_p = NULL, *rsa_q = NULL, *rsa_iqmp = NULL;
if ((r = sshbuf_get_u32(b, &magic)) != 0)
fatal_fr(r, "parse magic");
if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
error("bad magic 0x%x != 0x%x", magic,
SSH_COM_PRIVATE_KEY_MAGIC);
return NULL;
}
if ((r = sshbuf_get_u32(b, &i1)) != 0 ||
(r = sshbuf_get_cstring(b, &type, NULL)) != 0 ||
(r = sshbuf_get_cstring(b, &cipher, NULL)) != 0 ||
(r = sshbuf_get_u32(b, &i2)) != 0 ||
(r = sshbuf_get_u32(b, &i3)) != 0 ||
(r = sshbuf_get_u32(b, &i4)) != 0)
fatal_fr(r, "parse");
debug("ignore (%d %d %d %d)", i1, i2, i3, i4);
if (strcmp(cipher, "none") != 0) {
error("unsupported cipher %s", cipher);
free(cipher);
free(type);
return NULL;
}
free(cipher);
if (strstr(type, "dsa")) {
ktype = KEY_DSA;
} else if (strstr(type, "rsa")) {
ktype = KEY_RSA;
} else {
free(type);
return NULL;
}
if ((key = sshkey_new(ktype)) == NULL)
fatal("sshkey_new failed");
free(type);
switch (key->type) {
case KEY_DSA:
if ((dsa_p = BN_new()) == NULL ||
(dsa_q = BN_new()) == NULL ||
(dsa_g = BN_new()) == NULL ||
(dsa_pub_key = BN_new()) == NULL ||
(dsa_priv_key = BN_new()) == NULL)
fatal_f("BN_new");
buffer_get_bignum_bits(b, dsa_p);
buffer_get_bignum_bits(b, dsa_g);
buffer_get_bignum_bits(b, dsa_q);
buffer_get_bignum_bits(b, dsa_pub_key);
buffer_get_bignum_bits(b, dsa_priv_key);
if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g))
fatal_f("DSA_set0_pqg failed");
dsa_p = dsa_q = dsa_g = NULL; /* transferred */
if (!DSA_set0_key(key->dsa, dsa_pub_key, dsa_priv_key))
fatal_f("DSA_set0_key failed");
dsa_pub_key = dsa_priv_key = NULL; /* transferred */
break;
case KEY_RSA:
if ((r = sshbuf_get_u8(b, &e1)) != 0 ||
(e1 < 30 && (r = sshbuf_get_u8(b, &e2)) != 0) ||
(e1 < 30 && (r = sshbuf_get_u8(b, &e3)) != 0))
fatal_fr(r, "parse RSA");
e = e1;
debug("e %lx", e);
if (e < 30) {
e <<= 8;
e += e2;
debug("e %lx", e);
e <<= 8;
e += e3;
debug("e %lx", e);
}
if ((rsa_e = BN_new()) == NULL)
fatal_f("BN_new");
if (!BN_set_word(rsa_e, e)) {
BN_clear_free(rsa_e);
sshkey_free(key);
return NULL;
}
if ((rsa_n = BN_new()) == NULL ||
(rsa_d = BN_new()) == NULL ||
(rsa_p = BN_new()) == NULL ||
(rsa_q = BN_new()) == NULL ||
(rsa_iqmp = BN_new()) == NULL)
fatal_f("BN_new");
buffer_get_bignum_bits(b, rsa_d);
buffer_get_bignum_bits(b, rsa_n);
buffer_get_bignum_bits(b, rsa_iqmp);
buffer_get_bignum_bits(b, rsa_q);
buffer_get_bignum_bits(b, rsa_p);
if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, rsa_d))
fatal_f("RSA_set0_key failed");
rsa_n = rsa_e = rsa_d = NULL; /* transferred */
if (!RSA_set0_factors(key->rsa, rsa_p, rsa_q))
fatal_f("RSA_set0_factors failed");
rsa_p = rsa_q = NULL; /* transferred */
if ((r = ssh_rsa_complete_crt_parameters(key, rsa_iqmp)) != 0)
fatal_fr(r, "generate RSA parameters");
BN_clear_free(rsa_iqmp);
break;
}
rlen = sshbuf_len(b);
if (rlen != 0)
error_f("remaining bytes in key blob %d", rlen);
/* try the key */
if (sshkey_sign(key, &sig, &slen, data, sizeof(data),
NULL, NULL, NULL, 0) != 0 ||
sshkey_verify(key, sig, slen, data, sizeof(data),
NULL, 0, NULL) != 0) {
sshkey_free(key);
free(sig);
return NULL;
}
free(sig);
return key;
}
static int
get_line(FILE *fp, char *line, size_t len)
{
int c;
size_t pos = 0;
line[0] = '\0';
while ((c = fgetc(fp)) != EOF) {
if (pos >= len - 1)
fatal("input line too long.");
switch (c) {
case '\r':
c = fgetc(fp);
if (c != EOF && c != '\n' && ungetc(c, fp) == EOF)
fatal("unget: %s", strerror(errno));
return pos;
case '\n':
return pos;
}
line[pos++] = c;
line[pos] = '\0';
}
/* We reached EOF */
return -1;
}
static void
do_convert_from_ssh2(struct passwd *pw, struct sshkey **k, int *private)
{
int r, blen, escaped = 0;
u_int len;
char line[1024];
struct sshbuf *buf;
char encoded[8096];
FILE *fp;
if ((buf = sshbuf_new()) == NULL)
fatal("sshbuf_new failed");
if ((fp = fopen(identity_file, "r")) == NULL)
fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
encoded[0] = '\0';
while ((blen = get_line(fp, line, sizeof(line))) != -1) {
if (blen > 0 && line[blen - 1] == '\\')
escaped++;
if (strncmp(line, "----", 4) == 0 ||
strstr(line, ": ") != NULL) {
if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
*private = 1;
if (strstr(line, " END ") != NULL) {
break;
}
/* fprintf(stderr, "ignore: %s", line); */
continue;
}
if (escaped) {
escaped--;
/* fprintf(stderr, "escaped: %s", line); */
continue;
}
strlcat(encoded, line, sizeof(encoded));
}
len = strlen(encoded);
if (((len % 4) == 3) &&
(encoded[len-1] == '=') &&
(encoded[len-2] == '=') &&
(encoded[len-3] == '='))
encoded[len-3] = '\0';
if ((r = sshbuf_b64tod(buf, encoded)) != 0)
fatal_fr(r, "base64 decode");
if (*private) {
if ((*k = do_convert_private_ssh2(buf)) == NULL)
fatal_f("private key conversion failed");
} else if ((r = sshkey_fromb(buf, k)) != 0)
fatal_fr(r, "parse key");
sshbuf_free(buf);
fclose(fp);
}
static void
do_convert_from_pkcs8(struct sshkey **k, int *private)
{
EVP_PKEY *pubkey;
FILE *fp;
if ((fp = fopen(identity_file, "r")) == NULL)
fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
if ((pubkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
fatal_f("%s is not a recognised public key format",
identity_file);
}
fclose(fp);
switch (EVP_PKEY_base_id(pubkey)) {
case EVP_PKEY_RSA:
if ((*k = sshkey_new(KEY_UNSPEC)) == NULL)
fatal("sshkey_new failed");
(*k)->type = KEY_RSA;
(*k)->rsa = EVP_PKEY_get1_RSA(pubkey);
break;
case EVP_PKEY_DSA:
if ((*k = sshkey_new(KEY_UNSPEC)) == NULL)
fatal("sshkey_new failed");
(*k)->type = KEY_DSA;
(*k)->dsa = EVP_PKEY_get1_DSA(pubkey);
break;
#ifdef OPENSSL_HAS_ECC
case EVP_PKEY_EC:
if ((*k = sshkey_new(KEY_UNSPEC)) == NULL)
fatal("sshkey_new failed");
(*k)->type = KEY_ECDSA;
(*k)->ecdsa = EVP_PKEY_get1_EC_KEY(pubkey);
(*k)->ecdsa_nid = sshkey_ecdsa_key_to_nid((*k)->ecdsa);
break;
#endif
default:
fatal_f("unsupported pubkey type %d",
EVP_PKEY_base_id(pubkey));
}
EVP_PKEY_free(pubkey);
return;
}
static void
do_convert_from_pem(struct sshkey **k, int *private)
{
FILE *fp;
RSA *rsa;
if ((fp = fopen(identity_file, "r")) == NULL)
fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
if ((rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL)) != NULL) {
if ((*k = sshkey_new(KEY_UNSPEC)) == NULL)
fatal("sshkey_new failed");
(*k)->type = KEY_RSA;
(*k)->rsa = rsa;
fclose(fp);
return;
}
fatal_f("unrecognised raw private key format");
}
static void
do_convert_from(struct passwd *pw)
{
struct sshkey *k = NULL;
int r, private = 0, ok = 0;
struct stat st;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
if (stat(identity_file, &st) == -1)
fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
switch (convert_format) {
case FMT_RFC4716:
do_convert_from_ssh2(pw, &k, &private);
break;
case FMT_PKCS8:
do_convert_from_pkcs8(&k, &private);
break;
case FMT_PEM:
do_convert_from_pem(&k, &private);
break;
default:
fatal_f("unknown key format %d", convert_format);
}
if (!private) {
if ((r = sshkey_write(k, stdout)) == 0)
ok = 1;
if (ok)
fprintf(stdout, "\n");
} else {
switch (k->type) {
case KEY_DSA:
ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL,
NULL, 0, NULL, NULL);
break;
#ifdef OPENSSL_HAS_ECC
case KEY_ECDSA:
ok = PEM_write_ECPrivateKey(stdout, k->ecdsa, NULL,
NULL, 0, NULL, NULL);
break;
#endif
case KEY_RSA:
ok = PEM_write_RSAPrivateKey(stdout, k->rsa, NULL,
NULL, 0, NULL, NULL);
break;
default:
fatal_f("unsupported key type %s", sshkey_type(k));
}
}
if (!ok)
fatal("key write failed");
sshkey_free(k);
exit(0);
}
#endif
static void
do_print_public(struct passwd *pw)
{
struct sshkey *prv;
struct stat st;
int r;
char *comment = NULL;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
if (stat(identity_file, &st) == -1)
fatal("%s: %s", identity_file, strerror(errno));
prv = load_identity(identity_file, &comment);
if ((r = sshkey_write(prv, stdout)) != 0)
fatal_fr(r, "write key");
if (comment != NULL && *comment != '\0')
fprintf(stdout, " %s", comment);
fprintf(stdout, "\n");
if (sshkey_is_sk(prv)) {
debug("sk_application: \"%s\", sk_flags 0x%02x",
prv->sk_application, prv->sk_flags);
}
sshkey_free(prv);
free(comment);
exit(0);
}
static void
do_download(struct passwd *pw)
{
#ifdef ENABLE_PKCS11
struct sshkey **keys = NULL;
int i, nkeys;
enum sshkey_fp_rep rep;
int fptype;
char *fp, *ra, **comments = NULL;
fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash;
rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT;
pkcs11_init(1);
nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys, &comments);
if (nkeys <= 0)
fatal("cannot read public key from pkcs11");
for (i = 0; i < nkeys; i++) {
if (print_fingerprint) {
fp = sshkey_fingerprint(keys[i], fptype, rep);
ra = sshkey_fingerprint(keys[i], fingerprint_hash,
SSH_FP_RANDOMART);
if (fp == NULL || ra == NULL)
fatal_f("sshkey_fingerprint fail");
printf("%u %s %s (PKCS11 key)\n", sshkey_size(keys[i]),
fp, sshkey_type(keys[i]));
if (log_level_get() >= SYSLOG_LEVEL_VERBOSE)
printf("%s\n", ra);
free(ra);
free(fp);
} else {
(void) sshkey_write(keys[i], stdout); /* XXX check */
fprintf(stdout, "%s%s\n",
*(comments[i]) == '\0' ? "" : " ", comments[i]);
}
free(comments[i]);
sshkey_free(keys[i]);
}
free(comments);
free(keys);
pkcs11_terminate();
exit(0);
#else
fatal("no pkcs11 support");
#endif /* ENABLE_PKCS11 */
}
static struct sshkey *
try_read_key(char **cpp)
{
struct sshkey *ret;
int r;
if ((ret = sshkey_new(KEY_UNSPEC)) == NULL)
fatal("sshkey_new failed");
if ((r = sshkey_read(ret, cpp)) == 0)
return ret;
/* Not a key */
sshkey_free(ret);
return NULL;
}
static void
fingerprint_one_key(const struct sshkey *public, const char *comment)
{
char *fp = NULL, *ra = NULL;
enum sshkey_fp_rep rep;
int fptype;
fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash;
rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT;
fp = sshkey_fingerprint(public, fptype, rep);
ra = sshkey_fingerprint(public, fingerprint_hash, SSH_FP_RANDOMART);
if (fp == NULL || ra == NULL)
fatal_f("sshkey_fingerprint failed");
mprintf("%u %s %s (%s)\n", sshkey_size(public), fp,
comment ? comment : "no comment", sshkey_type(public));
if (log_level_get() >= SYSLOG_LEVEL_VERBOSE)
printf("%s\n", ra);
free(ra);
free(fp);
}
static void
fingerprint_private(const char *path)
{
struct stat st;
char *comment = NULL;
struct sshkey *privkey = NULL, *pubkey = NULL;
int r;
if (stat(identity_file, &st) == -1)
fatal("%s: %s", path, strerror(errno));
if ((r = sshkey_load_public(path, &pubkey, &comment)) != 0)
debug_r(r, "load public \"%s\"", path);
if (pubkey == NULL || comment == NULL || *comment == '\0') {
free(comment);
if ((r = sshkey_load_private(path, NULL,
&privkey, &comment)) != 0)
debug_r(r, "load private \"%s\"", path);
}
if (pubkey == NULL && privkey == NULL)
fatal("%s is not a key file.", path);
fingerprint_one_key(pubkey == NULL ? privkey : pubkey, comment);
sshkey_free(pubkey);
sshkey_free(privkey);
free(comment);
}
static void
do_fingerprint(struct passwd *pw)
{
FILE *f;
struct sshkey *public = NULL;
char *comment = NULL, *cp, *ep, *line = NULL;
size_t linesize = 0;
int i, invalid = 1;
const char *path;
u_long lnum = 0;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
path = identity_file;
if (strcmp(identity_file, "-") == 0) {
f = stdin;
path = "(stdin)";
} else if ((f = fopen(path, "r")) == NULL)
fatal("%s: %s: %s", __progname, path, strerror(errno));
while (getline(&line, &linesize, f) != -1) {
lnum++;
cp = line;
cp[strcspn(cp, "\n")] = '\0';
/* Trim leading space and comments */
cp = line + strspn(line, " \t");
if (*cp == '#' || *cp == '\0')
continue;
/*
* Input may be plain keys, private keys, authorized_keys
* or known_hosts.
*/
/*
* Try private keys first. Assume a key is private if
* "SSH PRIVATE KEY" appears on the first line and we're
* not reading from stdin (XXX support private keys on stdin).
*/
if (lnum == 1 && strcmp(identity_file, "-") != 0 &&
strstr(cp, "PRIVATE KEY") != NULL) {
free(line);
fclose(f);
fingerprint_private(path);
exit(0);
}
/*
* If it's not a private key, then this must be prepared to
* accept a public key prefixed with a hostname or options.
* Try a bare key first, otherwise skip the leading stuff.
*/
if ((public = try_read_key(&cp)) == NULL) {
i = strtol(cp, &ep, 10);
if (i == 0 || ep == NULL ||
(*ep != ' ' && *ep != '\t')) {
int quoted = 0;
comment = cp;
for (; *cp && (quoted || (*cp != ' ' &&
*cp != '\t')); cp++) {
if (*cp == '\\' && cp[1] == '"')
cp++; /* Skip both */
else if (*cp == '"')
quoted = !quoted;
}
if (!*cp)
continue;
*cp++ = '\0';
}
}
/* Retry after parsing leading hostname/key options */
if (public == NULL && (public = try_read_key(&cp)) == NULL) {
debug("%s:%lu: not a public key", path, lnum);
continue;
}
/* Find trailing comment, if any */
for (; *cp == ' ' || *cp == '\t'; cp++)
;
if (*cp != '\0' && *cp != '#')
comment = cp;
fingerprint_one_key(public, comment);
sshkey_free(public);
invalid = 0; /* One good key in the file is sufficient */
}
fclose(f);
free(line);
if (invalid)
fatal("%s is not a public key file.", path);
exit(0);
}
static void
do_gen_all_hostkeys(struct passwd *pw)
{
struct {
char *key_type;
char *key_type_display;
char *path;
} key_types[] = {
#ifdef WITH_OPENSSL
{ "rsa", "RSA" ,_PATH_HOST_RSA_KEY_FILE },
{ "dsa", "DSA", _PATH_HOST_DSA_KEY_FILE },
#ifdef OPENSSL_HAS_ECC
{ "ecdsa", "ECDSA",_PATH_HOST_ECDSA_KEY_FILE },
#endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
{ "ed25519", "ED25519",_PATH_HOST_ED25519_KEY_FILE },
#ifdef WITH_XMSS
{ "xmss", "XMSS",_PATH_HOST_XMSS_KEY_FILE },
#endif /* WITH_XMSS */
{ NULL, NULL, NULL }
};
u_int32_t bits = 0;
int first = 0;
struct stat st;
struct sshkey *private, *public;
char comment[1024], *prv_tmp, *pub_tmp, *prv_file, *pub_file;
int i, type, fd, r;
for (i = 0; key_types[i].key_type; i++) {
public = private = NULL;
prv_tmp = pub_tmp = prv_file = pub_file = NULL;
xasprintf(&prv_file, "%s%s",
identity_file, key_types[i].path);
/* Check whether private key exists and is not zero-length */
if (stat(prv_file, &st) == 0) {
if (st.st_size != 0)
goto next;
} else if (errno != ENOENT) {
error("Could not stat %s: %s", key_types[i].path,
strerror(errno));
goto failnext;
}
/*
* Private key doesn't exist or is invalid; proceed with
* key generation.
*/
xasprintf(&prv_tmp, "%s%s.XXXXXXXXXX",
identity_file, key_types[i].path);
xasprintf(&pub_tmp, "%s%s.pub.XXXXXXXXXX",
identity_file, key_types[i].path);
xasprintf(&pub_file, "%s%s.pub",
identity_file, key_types[i].path);
if (first == 0) {
first = 1;
printf("%s: generating new host keys: ", __progname);
}
printf("%s ", key_types[i].key_type_display);
fflush(stdout);
type = sshkey_type_from_name(key_types[i].key_type);
if ((fd = mkstemp(prv_tmp)) == -1) {
error("Could not save your private key in %s: %s",
prv_tmp, strerror(errno));
goto failnext;
}
(void)close(fd); /* just using mkstemp() to reserve a name */
bits = 0;
type_bits_valid(type, NULL, &bits);
if ((r = sshkey_generate(type, bits, &private)) != 0) {
error_r(r, "sshkey_generate failed");
goto failnext;
}
if ((r = sshkey_from_private(private, &public)) != 0)
fatal_fr(r, "sshkey_from_private");
snprintf(comment, sizeof comment, "%s@%s", pw->pw_name,
hostname);
if ((r = sshkey_save_private(private, prv_tmp, "",
comment, private_key_format, openssh_format_cipher,
rounds)) != 0) {
error_r(r, "Saving key \"%s\" failed", prv_tmp);
goto failnext;
}
if ((fd = mkstemp(pub_tmp)) == -1) {
error("Could not save your public key in %s: %s",
pub_tmp, strerror(errno));
goto failnext;
}
(void)fchmod(fd, 0644);
(void)close(fd);
if ((r = sshkey_save_public(public, pub_tmp, comment)) != 0) {
error_r(r, "Unable to save public key to %s",
identity_file);
goto failnext;
}
/* Rename temporary files to their permanent locations. */
if (rename(pub_tmp, pub_file) != 0) {
error("Unable to move %s into position: %s",
pub_file, strerror(errno));
goto failnext;
}
if (rename(prv_tmp, prv_file) != 0) {
error("Unable to move %s into position: %s",
key_types[i].path, strerror(errno));
failnext:
first = 0;
goto next;
}
next:
sshkey_free(private);
sshkey_free(public);
free(prv_tmp);
free(pub_tmp);
free(prv_file);
free(pub_file);
}
if (first != 0)
printf("\n");
}
struct known_hosts_ctx {
const char *host; /* Hostname searched for in find/delete case */
FILE *out; /* Output file, stdout for find_hosts case */
int has_unhashed; /* When hashing, original had unhashed hosts */
int found_key; /* For find/delete, host was found */
int invalid; /* File contained invalid items; don't delete */
int hash_hosts; /* Hash hostnames as we go */
int find_host; /* Search for specific hostname */
int delete_host; /* Delete host from known_hosts */
};
static int
known_hosts_hash(struct hostkey_foreach_line *l, void *_ctx)
{
struct known_hosts_ctx *ctx = (struct known_hosts_ctx *)_ctx;
char *hashed, *cp, *hosts, *ohosts;
int has_wild = l->hosts && strcspn(l->hosts, "*?!") != strlen(l->hosts);
int was_hashed = l->hosts && l->hosts[0] == HASH_DELIM;
switch (l->status) {
case HKF_STATUS_OK:
case HKF_STATUS_MATCHED:
/*
* Don't hash hosts already already hashed, with wildcard
* characters or a CA/revocation marker.
*/
if (was_hashed || has_wild || l->marker != MRK_NONE) {
fprintf(ctx->out, "%s\n", l->line);
if (has_wild && !ctx->find_host) {
logit("%s:%lu: ignoring host name "
"with wildcard: %.64s", l->path,
l->linenum, l->hosts);
}
return 0;
}
/*
* Split any comma-separated hostnames from the host list,
* hash and store separately.
*/
ohosts = hosts = xstrdup(l->hosts);
while ((cp = strsep(&hosts, ",")) != NULL && *cp != '\0') {
lowercase(cp);
if ((hashed = host_hash(cp, NULL, 0)) == NULL)
fatal("hash_host failed");
fprintf(ctx->out, "%s %s\n", hashed, l->rawkey);
ctx->has_unhashed = 1;
}
free(ohosts);
return 0;
case HKF_STATUS_INVALID:
/* Retain invalid lines, but mark file as invalid. */
ctx->invalid = 1;
logit("%s:%lu: invalid line", l->path, l->linenum);
/* FALLTHROUGH */
default:
fprintf(ctx->out, "%s\n", l->line);
return 0;
}
/* NOTREACHED */
return -1;
}
static int
known_hosts_find_delete(struct hostkey_foreach_line *l, void *_ctx)
{
struct known_hosts_ctx *ctx = (struct known_hosts_ctx *)_ctx;
enum sshkey_fp_rep rep;
int fptype;
char *fp = NULL, *ra = NULL;
fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash;
rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT;
if (l->status == HKF_STATUS_MATCHED) {
if (ctx->delete_host) {
if (l->marker != MRK_NONE) {
/* Don't remove CA and revocation lines */
fprintf(ctx->out, "%s\n", l->line);
} else {
/*
* Hostname matches and has no CA/revoke
* marker, delete it by *not* writing the
* line to ctx->out.
*/
ctx->found_key = 1;
if (!quiet)
printf("# Host %s found: line %lu\n",
ctx->host, l->linenum);
}
return 0;
} else if (ctx->find_host) {
ctx->found_key = 1;
if (!quiet) {
printf("# Host %s found: line %lu %s\n",
ctx->host,
l->linenum, l->marker == MRK_CA ? "CA" :
(l->marker == MRK_REVOKE ? "REVOKED" : ""));
}
if (ctx->hash_hosts)
known_hosts_hash(l, ctx);
else if (print_fingerprint) {
fp = sshkey_fingerprint(l->key, fptype, rep);
ra = sshkey_fingerprint(l->key,
fingerprint_hash, SSH_FP_RANDOMART);
if (fp == NULL || ra == NULL)
fatal_f("sshkey_fingerprint failed");
mprintf("%s %s %s%s%s\n", ctx->host,
sshkey_type(l->key), fp,
l->comment[0] ? " " : "",
l->comment);
if (log_level_get() >= SYSLOG_LEVEL_VERBOSE)
printf("%s\n", ra);
free(ra);
free(fp);
} else
fprintf(ctx->out, "%s\n", l->line);
return 0;
}
} else if (ctx->delete_host) {
/* Retain non-matching hosts when deleting */
if (l->status == HKF_STATUS_INVALID) {
ctx->invalid = 1;
logit("%s:%lu: invalid line", l->path, l->linenum);
}
fprintf(ctx->out, "%s\n", l->line);
}
return 0;
}
static void
do_known_hosts(struct passwd *pw, const char *name, int find_host,
int delete_host, int hash_hosts)
{
char *cp, tmp[PATH_MAX], old[PATH_MAX];
int r, fd, oerrno, inplace = 0;
struct known_hosts_ctx ctx;
u_int foreach_options;
struct stat sb;
if (!have_identity) {
cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
if (strlcpy(identity_file, cp, sizeof(identity_file)) >=
sizeof(identity_file))
fatal("Specified known hosts path too long");
free(cp);
have_identity = 1;
}
if (stat(identity_file, &sb) != 0)
fatal("Cannot stat %s: %s", identity_file, strerror(errno));
memset(&ctx, 0, sizeof(ctx));
ctx.out = stdout;
ctx.host = name;
ctx.hash_hosts = hash_hosts;
ctx.find_host = find_host;
ctx.delete_host = delete_host;
/*
* Find hosts goes to stdout, hash and deletions happen in-place
* A corner case is ssh-keygen -HF foo, which should go to stdout
*/
if (!find_host && (hash_hosts || delete_host)) {
if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) ||
strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) ||
strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) ||
strlcat(old, ".old", sizeof(old)) >= sizeof(old))
fatal("known_hosts path too long");
umask(077);
if ((fd = mkstemp(tmp)) == -1)
fatal("mkstemp: %s", strerror(errno));
if ((ctx.out = fdopen(fd, "w")) == NULL) {
oerrno = errno;
unlink(tmp);
fatal("fdopen: %s", strerror(oerrno));
}
fchmod(fd, sb.st_mode & 0644);
inplace = 1;
}
/* XXX support identity_file == "-" for stdin */
foreach_options = find_host ? HKF_WANT_MATCH : 0;
foreach_options |= print_fingerprint ? HKF_WANT_PARSE_KEY : 0;
if ((r = hostkeys_foreach(identity_file, (find_host || !hash_hosts) ?
known_hosts_find_delete : known_hosts_hash, &ctx, name, NULL,
foreach_options, 0)) != 0) {
if (inplace)
unlink(tmp);
fatal_fr(r, "hostkeys_foreach");
}
if (inplace)
fclose(ctx.out);
if (ctx.invalid) {
error("%s is not a valid known_hosts file.", identity_file);
if (inplace) {
error("Not replacing existing known_hosts "
"file because of errors");
unlink(tmp);
}
exit(1);
} else if (delete_host && !ctx.found_key) {
logit("Host %s not found in %s", name, identity_file);
if (inplace)
unlink(tmp);
} else if (inplace) {
/* Backup existing file */
if (unlink(old) == -1 && errno != ENOENT)
fatal("unlink %.100s: %s", old, strerror(errno));
if (link(identity_file, old) == -1)
fatal("link %.100s to %.100s: %s", identity_file, old,
strerror(errno));
/* Move new one into place */
if (rename(tmp, identity_file) == -1) {
error("rename\"%s\" to \"%s\": %s", tmp, identity_file,
strerror(errno));
unlink(tmp);
unlink(old);
exit(1);
}
printf("%s updated.\n", identity_file);
printf("Original contents retained as %s\n", old);
if (ctx.has_unhashed) {
logit("WARNING: %s contains unhashed entries", old);
logit("Delete this file to ensure privacy "
"of hostnames");
}
}
exit (find_host && !ctx.found_key);
}
/*
* Perform changing a passphrase. The argument is the passwd structure
* for the current user.
*/
static void
do_change_passphrase(struct passwd *pw)
{
char *comment;
char *old_passphrase, *passphrase1, *passphrase2;
struct stat st;
struct sshkey *private;
int r;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
if (stat(identity_file, &st) == -1)
fatal("%s: %s", identity_file, strerror(errno));
/* Try to load the file with empty passphrase. */
r = sshkey_load_private(identity_file, "", &private, &comment);
if (r == SSH_ERR_KEY_WRONG_PASSPHRASE) {
if (identity_passphrase)
old_passphrase = xstrdup(identity_passphrase);
else
old_passphrase =
read_passphrase("Enter old passphrase: ",
RP_ALLOW_STDIN);
r = sshkey_load_private(identity_file, old_passphrase,
&private, &comment);
freezero(old_passphrase, strlen(old_passphrase));
if (r != 0)
goto badkey;
} else if (r != 0) {
badkey:
fatal_r(r, "Failed to load key %s", identity_file);
}
if (comment)
mprintf("Key has comment '%s'\n", comment);
/* Ask the new passphrase (twice). */
if (identity_new_passphrase) {
passphrase1 = xstrdup(identity_new_passphrase);
passphrase2 = NULL;
} else {
passphrase1 =
read_passphrase("Enter new passphrase (empty for no "
"passphrase): ", RP_ALLOW_STDIN);
passphrase2 = read_passphrase("Enter same passphrase again: ",
RP_ALLOW_STDIN);
/* Verify that they are the same. */
if (strcmp(passphrase1, passphrase2) != 0) {
explicit_bzero(passphrase1, strlen(passphrase1));
explicit_bzero(passphrase2, strlen(passphrase2));
free(passphrase1);
free(passphrase2);
printf("Pass phrases do not match. Try again.\n");
exit(1);
}
/* Destroy the other copy. */
freezero(passphrase2, strlen(passphrase2));
}
/* Save the file using the new passphrase. */
if ((r = sshkey_save_private(private, identity_file, passphrase1,
comment, private_key_format, openssh_format_cipher, rounds)) != 0) {
error_r(r, "Saving key \"%s\" failed", identity_file);
freezero(passphrase1, strlen(passphrase1));
sshkey_free(private);
free(comment);
exit(1);
}
/* Destroy the passphrase and the copy of the key in memory. */
freezero(passphrase1, strlen(passphrase1));
sshkey_free(private); /* Destroys contents */
free(comment);
printf("Your identification has been saved with the new passphrase.\n");
exit(0);
}
/*
* Print the SSHFP RR.
*/
static int
do_print_resource_record(struct passwd *pw, char *fname, char *hname,
int print_generic)
{
struct sshkey *public;
char *comment = NULL;
struct stat st;
int r;
if (fname == NULL)
fatal_f("no filename");
if (stat(fname, &st) == -1) {
if (errno == ENOENT)
return 0;
fatal("%s: %s", fname, strerror(errno));
}
if ((r = sshkey_load_public(fname, &public, &comment)) != 0)
fatal_r(r, "Failed to read v2 public key from \"%s\"", fname);
export_dns_rr(hname, public, stdout, print_generic);
sshkey_free(public);
free(comment);
return 1;
}
/*
* Change the comment of a private key file.
*/
static void
do_change_comment(struct passwd *pw, const char *identity_comment)
{
char new_comment[1024], *comment, *passphrase;
struct sshkey *private;
struct sshkey *public;
struct stat st;
int r;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
if (stat(identity_file, &st) == -1)
fatal("%s: %s", identity_file, strerror(errno));
if ((r = sshkey_load_private(identity_file, "",
&private, &comment)) == 0)
passphrase = xstrdup("");
else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE)
fatal_r(r, "Cannot load private key \"%s\"", identity_file);
else {
if (identity_passphrase)
passphrase = xstrdup(identity_passphrase);
else if (identity_new_passphrase)
passphrase = xstrdup(identity_new_passphrase);
else
passphrase = read_passphrase("Enter passphrase: ",
RP_ALLOW_STDIN);
/* Try to load using the passphrase. */
if ((r = sshkey_load_private(identity_file, passphrase,
&private, &comment)) != 0) {
freezero(passphrase, strlen(passphrase));
fatal_r(r, "Cannot load private key \"%s\"",
identity_file);
}
}
if (private->type != KEY_ED25519 && private->type != KEY_XMSS &&
private_key_format != SSHKEY_PRIVATE_OPENSSH) {
error("Comments are only supported for keys stored in "
"the new format (-o).");
explicit_bzero(passphrase, strlen(passphrase));
sshkey_free(private);
exit(1);
}
if (comment)
printf("Old comment: %s\n", comment);
else
printf("No existing comment\n");
if (identity_comment) {
strlcpy(new_comment, identity_comment, sizeof(new_comment));
} else {
printf("New comment: ");
fflush(stdout);
if (!fgets(new_comment, sizeof(new_comment), stdin)) {
explicit_bzero(passphrase, strlen(passphrase));
sshkey_free(private);
exit(1);
}
new_comment[strcspn(new_comment, "\n")] = '\0';
}
if (comment != NULL && strcmp(comment, new_comment) == 0) {
printf("No change to comment\n");
free(passphrase);
sshkey_free(private);
free(comment);
exit(0);
}
/* Save the file using the new passphrase. */
if ((r = sshkey_save_private(private, identity_file, passphrase,
new_comment, private_key_format, openssh_format_cipher,
rounds)) != 0) {
error_r(r, "Saving key \"%s\" failed", identity_file);
freezero(passphrase, strlen(passphrase));
sshkey_free(private);
free(comment);
exit(1);
}
freezero(passphrase, strlen(passphrase));
if ((r = sshkey_from_private(private, &public)) != 0)
fatal_fr(r, "sshkey_from_private");
sshkey_free(private);
strlcat(identity_file, ".pub", sizeof(identity_file));
if ((r = sshkey_save_public(public, identity_file, new_comment)) != 0)
fatal_r(r, "Unable to save public key to %s", identity_file);
sshkey_free(public);
free(comment);
if (strlen(new_comment) > 0)
printf("Comment '%s' applied\n", new_comment);
else
printf("Comment removed\n");
exit(0);
}
static void
cert_ext_add(const char *key, const char *value, int iscrit)
{
cert_ext = xreallocarray(cert_ext, ncert_ext + 1, sizeof(*cert_ext));
cert_ext[ncert_ext].key = xstrdup(key);
cert_ext[ncert_ext].val = value == NULL ? NULL : xstrdup(value);
cert_ext[ncert_ext].crit = iscrit;
ncert_ext++;
}
/* qsort(3) comparison function for certificate extensions */
static int
cert_ext_cmp(const void *_a, const void *_b)
{
const struct cert_ext *a = (const struct cert_ext *)_a;
const struct cert_ext *b = (const struct cert_ext *)_b;
int r;
if (a->crit != b->crit)
return (a->crit < b->crit) ? -1 : 1;
if ((r = strcmp(a->key, b->key)) != 0)
return r;
if ((a->val == NULL) != (b->val == NULL))
return (a->val == NULL) ? -1 : 1;
if (a->val != NULL && (r = strcmp(a->val, b->val)) != 0)
return r;
return 0;
}
#define OPTIONS_CRITICAL 1
#define OPTIONS_EXTENSIONS 2
static void
prepare_options_buf(struct sshbuf *c, int which)
{
struct sshbuf *b;
size_t i;
int r;
const struct cert_ext *ext;
if ((b = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
sshbuf_reset(c);
for (i = 0; i < ncert_ext; i++) {
ext = &cert_ext[i];
if ((ext->crit && (which & OPTIONS_EXTENSIONS)) ||
(!ext->crit && (which & OPTIONS_CRITICAL)))
continue;
if (ext->val == NULL) {
/* flag option */
debug3_f("%s", ext->key);
if ((r = sshbuf_put_cstring(c, ext->key)) != 0 ||
(r = sshbuf_put_string(c, NULL, 0)) != 0)
fatal_fr(r, "prepare flag");
} else {
/* key/value option */
debug3_f("%s=%s", ext->key, ext->val);
sshbuf_reset(b);
if ((r = sshbuf_put_cstring(c, ext->key)) != 0 ||
(r = sshbuf_put_cstring(b, ext->val)) != 0 ||
(r = sshbuf_put_stringb(c, b)) != 0)
fatal_fr(r, "prepare k/v");
}
}
sshbuf_free(b);
}
static void
finalise_cert_exts(void)
{
/* critical options */
if (certflags_command != NULL)
cert_ext_add("force-command", certflags_command, 1);
if (certflags_src_addr != NULL)
cert_ext_add("source-address", certflags_src_addr, 1);
/* extensions */
if ((certflags_flags & CERTOPT_X_FWD) != 0)
cert_ext_add("permit-X11-forwarding", NULL, 0);
if ((certflags_flags & CERTOPT_AGENT_FWD) != 0)
cert_ext_add("permit-agent-forwarding", NULL, 0);
if ((certflags_flags & CERTOPT_PORT_FWD) != 0)
cert_ext_add("permit-port-forwarding", NULL, 0);
if ((certflags_flags & CERTOPT_PTY) != 0)
cert_ext_add("permit-pty", NULL, 0);
if ((certflags_flags & CERTOPT_USER_RC) != 0)
cert_ext_add("permit-user-rc", NULL, 0);
if ((certflags_flags & CERTOPT_NO_REQUIRE_USER_PRESENCE) != 0)
cert_ext_add("no-touch-required", NULL, 0);
/* order lexically by key */
if (ncert_ext > 0)
qsort(cert_ext, ncert_ext, sizeof(*cert_ext), cert_ext_cmp);
}
static struct sshkey *
load_pkcs11_key(char *path)
{
#ifdef ENABLE_PKCS11
struct sshkey **keys = NULL, *public, *private = NULL;
int r, i, nkeys;
if ((r = sshkey_load_public(path, &public, NULL)) != 0)
fatal_r(r, "Couldn't load CA public key \"%s\"", path);
nkeys = pkcs11_add_provider(pkcs11provider, identity_passphrase,
&keys, NULL);
debug3_f("%d keys", nkeys);
if (nkeys <= 0)
fatal("cannot read public key from pkcs11");
for (i = 0; i < nkeys; i++) {
if (sshkey_equal_public(public, keys[i])) {
private = keys[i];
continue;
}
sshkey_free(keys[i]);
}
free(keys);
sshkey_free(public);
return private;
#else
fatal("no pkcs11 support");
#endif /* ENABLE_PKCS11 */
}
/* Signer for sshkey_certify_custom that uses the agent */
static int
agent_signer(struct sshkey *key, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen,
const char *alg, const char *provider, const char *pin,
u_int compat, void *ctx)
{
int *agent_fdp = (int *)ctx;
return ssh_agent_sign(*agent_fdp, key, sigp, lenp,
data, datalen, alg, compat);
}
static void
do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
unsigned long long cert_serial, int cert_serial_autoinc,
int argc, char **argv)
{
int r, i, found, agent_fd = -1;
u_int n;
struct sshkey *ca, *public;
char valid[64], *otmp, *tmp, *cp, *out, *comment;
char *ca_fp = NULL, **plist = NULL, *pin = NULL;
struct ssh_identitylist *agent_ids;
size_t j;
struct notifier_ctx *notifier = NULL;
#ifdef ENABLE_PKCS11
pkcs11_init(1);
#endif
tmp = tilde_expand_filename(ca_key_path, pw->pw_uid);
if (pkcs11provider != NULL) {
/* If a PKCS#11 token was specified then try to use it */
if ((ca = load_pkcs11_key(tmp)) == NULL)
fatal("No PKCS#11 key matching %s found", ca_key_path);
} else if (prefer_agent) {
/*
* Agent signature requested. Try to use agent after making
* sure the public key specified is actually present in the
* agent.
*/
if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0)
fatal_r(r, "Cannot load CA public key %s", tmp);
if ((r = ssh_get_authentication_socket(&agent_fd)) != 0)
fatal_r(r, "Cannot use public key for CA signature");
if ((r = ssh_fetch_identitylist(agent_fd, &agent_ids)) != 0)
fatal_r(r, "Retrieve agent key list");
found = 0;
for (j = 0; j < agent_ids->nkeys; j++) {
if (sshkey_equal(ca, agent_ids->keys[j])) {
found = 1;
break;
}
}
if (!found)
fatal("CA key %s not found in agent", tmp);
ssh_free_identitylist(agent_ids);
ca->flags |= SSHKEY_FLAG_EXT;
} else {
/* CA key is assumed to be a private key on the filesystem */
ca = load_identity(tmp, NULL);
if (sshkey_is_sk(ca) &&
(ca->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) {
if ((pin = read_passphrase("Enter PIN for CA key: ",
RP_ALLOW_STDIN)) == NULL)
fatal_f("couldn't read PIN");
}
}
free(tmp);
if (key_type_name != NULL) {
if (sshkey_type_from_name(key_type_name) != ca->type) {
fatal("CA key type %s doesn't match specified %s",
sshkey_ssh_name(ca), key_type_name);
}
} else if (ca->type == KEY_RSA) {
/* Default to a good signature algorithm */
key_type_name = "rsa-sha2-512";
}
ca_fp = sshkey_fingerprint(ca, fingerprint_hash, SSH_FP_DEFAULT);
finalise_cert_exts();
for (i = 0; i < argc; i++) {
/* Split list of principals */
n = 0;
if (cert_principals != NULL) {
otmp = tmp = xstrdup(cert_principals);
plist = NULL;
for (; (cp = strsep(&tmp, ",")) != NULL; n++) {
plist = xreallocarray(plist, n + 1, sizeof(*plist));
if (*(plist[n] = xstrdup(cp)) == '\0')
fatal("Empty principal name");
}
free(otmp);
}
if (n > SSHKEY_CERT_MAX_PRINCIPALS)
fatal("Too many certificate principals specified");
tmp = tilde_expand_filename(argv[i], pw->pw_uid);
if ((r = sshkey_load_public(tmp, &public, &comment)) != 0)
fatal_r(r, "load pubkey \"%s\"", tmp);
if (sshkey_is_cert(public))
fatal_f("key \"%s\" type %s cannot be certified",
tmp, sshkey_type(public));
/* Prepare certificate to sign */
if ((r = sshkey_to_certified(public)) != 0)
fatal_r(r, "Could not upgrade key %s to certificate", tmp);
public->cert->type = cert_key_type;
public->cert->serial = (u_int64_t)cert_serial;
public->cert->key_id = xstrdup(cert_key_id);
public->cert->nprincipals = n;
public->cert->principals = plist;
public->cert->valid_after = cert_valid_from;
public->cert->valid_before = cert_valid_to;
prepare_options_buf(public->cert->critical, OPTIONS_CRITICAL);
prepare_options_buf(public->cert->extensions,
OPTIONS_EXTENSIONS);
if ((r = sshkey_from_private(ca,
&public->cert->signature_key)) != 0)
fatal_r(r, "sshkey_from_private (ca key)");
if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) {
if ((r = sshkey_certify_custom(public, ca,
key_type_name, sk_provider, NULL, agent_signer,
&agent_fd)) != 0)
fatal_r(r, "Couldn't certify %s via agent", tmp);
} else {
if (sshkey_is_sk(ca) &&
(ca->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
notifier = notify_start(0,
"Confirm user presence for key %s %s",
sshkey_type(ca), ca_fp);
}
r = sshkey_certify(public, ca, key_type_name,
sk_provider, pin);
notify_complete(notifier, "User presence confirmed");
if (r != 0)
fatal_r(r, "Couldn't certify key %s", tmp);
}
if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0)
*cp = '\0';
xasprintf(&out, "%s-cert.pub", tmp);
free(tmp);
if ((r = sshkey_save_public(public, out, comment)) != 0) {
fatal_r(r, "Unable to save public key to %s",
identity_file);
}
if (!quiet) {
sshkey_format_cert_validity(public->cert,
valid, sizeof(valid));
logit("Signed %s key %s: id \"%s\" serial %llu%s%s "
"valid %s", sshkey_cert_type(public),
out, public->cert->key_id,
(unsigned long long)public->cert->serial,
cert_principals != NULL ? " for " : "",
cert_principals != NULL ? cert_principals : "",
valid);
}
sshkey_free(public);
free(out);
if (cert_serial_autoinc)
cert_serial++;
}
if (pin != NULL)
freezero(pin, strlen(pin));
free(ca_fp);
#ifdef ENABLE_PKCS11
pkcs11_terminate();
#endif
exit(0);
}
static u_int64_t
parse_relative_time(const char *s, time_t now)
{
int64_t mul, secs;
mul = *s == '-' ? -1 : 1;
if ((secs = convtime(s + 1)) == -1)
fatal("Invalid relative certificate time %s", s);
if (mul == -1 && secs > now)
fatal("Certificate time %s cannot be represented", s);
return now + (u_int64_t)(secs * mul);
}
static void
parse_cert_times(char *timespec)
{
char *from, *to;
time_t now = time(NULL);
int64_t secs;
/* +timespec relative to now */
if (*timespec == '+' && strchr(timespec, ':') == NULL) {
if ((secs = convtime(timespec + 1)) == -1)
fatal("Invalid relative certificate life %s", timespec);
cert_valid_to = now + secs;
/*
* Backdate certificate one minute to avoid problems on hosts
* with poorly-synchronised clocks.
*/
cert_valid_from = ((now - 59)/ 60) * 60;
return;
}
/*
* from:to, where
* from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | "always"
* to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | "forever"
*/
from = xstrdup(timespec);
to = strchr(from, ':');
if (to == NULL || from == to || *(to + 1) == '\0')
fatal("Invalid certificate life specification %s", timespec);
*to++ = '\0';
if (*from == '-' || *from == '+')
cert_valid_from = parse_relative_time(from, now);
else if (strcmp(from, "always") == 0)
cert_valid_from = 0;
else if (parse_absolute_time(from, &cert_valid_from) != 0)
fatal("Invalid from time \"%s\"", from);
if (*to == '-' || *to == '+')
cert_valid_to = parse_relative_time(to, now);
else if (strcmp(to, "forever") == 0)
cert_valid_to = ~(u_int64_t)0;
else if (parse_absolute_time(to, &cert_valid_to) != 0)
fatal("Invalid to time \"%s\"", to);
if (cert_valid_to <= cert_valid_from)
fatal("Empty certificate validity interval");
free(from);
}
static void
add_cert_option(char *opt)
{
char *val, *cp;
int iscrit = 0;
if (strcasecmp(opt, "clear") == 0)
certflags_flags = 0;
else if (strcasecmp(opt, "no-x11-forwarding") == 0)
certflags_flags &= ~CERTOPT_X_FWD;
else if (strcasecmp(opt, "permit-x11-forwarding") == 0)
certflags_flags |= CERTOPT_X_FWD;
else if (strcasecmp(opt, "no-agent-forwarding") == 0)
certflags_flags &= ~CERTOPT_AGENT_FWD;
else if (strcasecmp(opt, "permit-agent-forwarding") == 0)
certflags_flags |= CERTOPT_AGENT_FWD;
else if (strcasecmp(opt, "no-port-forwarding") == 0)
certflags_flags &= ~CERTOPT_PORT_FWD;
else if (strcasecmp(opt, "permit-port-forwarding") == 0)
certflags_flags |= CERTOPT_PORT_FWD;
else if (strcasecmp(opt, "no-pty") == 0)
certflags_flags &= ~CERTOPT_PTY;
else if (strcasecmp(opt, "permit-pty") == 0)
certflags_flags |= CERTOPT_PTY;
else if (strcasecmp(opt, "no-user-rc") == 0)
certflags_flags &= ~CERTOPT_USER_RC;
else if (strcasecmp(opt, "permit-user-rc") == 0)
certflags_flags |= CERTOPT_USER_RC;
else if (strcasecmp(opt, "touch-required") == 0)
certflags_flags &= ~CERTOPT_NO_REQUIRE_USER_PRESENCE;
else if (strcasecmp(opt, "no-touch-required") == 0)
certflags_flags |= CERTOPT_NO_REQUIRE_USER_PRESENCE;
else if (strncasecmp(opt, "force-command=", 14) == 0) {
val = opt + 14;
if (*val == '\0')
fatal("Empty force-command option");
if (certflags_command != NULL)
fatal("force-command already specified");
certflags_command = xstrdup(val);
} else if (strncasecmp(opt, "source-address=", 15) == 0) {
val = opt + 15;
if (*val == '\0')
fatal("Empty source-address option");
if (certflags_src_addr != NULL)
fatal("source-address already specified");
if (addr_match_cidr_list(NULL, val) != 0)
fatal("Invalid source-address list");
certflags_src_addr = xstrdup(val);
} else if (strncasecmp(opt, "extension:", 10) == 0 ||
- (iscrit = (strncasecmp(opt, "critical:", 9) == 0))) {
+ (iscrit = (strncasecmp(opt, "critical:", 9) == 0))) {
val = xstrdup(strchr(opt, ':') + 1);
if ((cp = strchr(val, '=')) != NULL)
*cp++ = '\0';
cert_ext_add(val, cp, iscrit);
free(val);
} else
fatal("Unsupported certificate option \"%s\"", opt);
}
static void
show_options(struct sshbuf *optbuf, int in_critical)
{
char *name, *arg, *hex;
struct sshbuf *options, *option = NULL;
int r;
if ((options = sshbuf_fromb(optbuf)) == NULL)
fatal_f("sshbuf_fromb failed");
while (sshbuf_len(options) != 0) {
sshbuf_free(option);
option = NULL;
if ((r = sshbuf_get_cstring(options, &name, NULL)) != 0 ||
(r = sshbuf_froms(options, &option)) != 0)
fatal_fr(r, "parse option");
printf(" %s", name);
if (!in_critical &&
(strcmp(name, "permit-X11-forwarding") == 0 ||
strcmp(name, "permit-agent-forwarding") == 0 ||
strcmp(name, "permit-port-forwarding") == 0 ||
strcmp(name, "permit-pty") == 0 ||
strcmp(name, "permit-user-rc") == 0 ||
strcmp(name, "no-touch-required") == 0)) {
printf("\n");
} else if (in_critical &&
(strcmp(name, "force-command") == 0 ||
strcmp(name, "source-address") == 0)) {
if ((r = sshbuf_get_cstring(option, &arg, NULL)) != 0)
fatal_fr(r, "parse critical");
printf(" %s\n", arg);
free(arg);
} else if (sshbuf_len(option) > 0) {
hex = sshbuf_dtob16(option);
printf(" UNKNOWN OPTION: %s (len %zu)\n",
hex, sshbuf_len(option));
sshbuf_reset(option);
free(hex);
} else
printf(" UNKNOWN FLAG OPTION\n");
free(name);
if (sshbuf_len(option) != 0)
fatal("Option corrupt: extra data at end");
}
sshbuf_free(option);
sshbuf_free(options);
}
static void
print_cert(struct sshkey *key)
{
char valid[64], *key_fp, *ca_fp;
u_int i;
key_fp = sshkey_fingerprint(key, fingerprint_hash, SSH_FP_DEFAULT);
ca_fp = sshkey_fingerprint(key->cert->signature_key,
fingerprint_hash, SSH_FP_DEFAULT);
if (key_fp == NULL || ca_fp == NULL)
fatal_f("sshkey_fingerprint fail");
sshkey_format_cert_validity(key->cert, valid, sizeof(valid));
printf(" Type: %s %s certificate\n", sshkey_ssh_name(key),
sshkey_cert_type(key));
printf(" Public key: %s %s\n", sshkey_type(key), key_fp);
printf(" Signing CA: %s %s (using %s)\n",
sshkey_type(key->cert->signature_key), ca_fp,
key->cert->signature_type);
printf(" Key ID: \"%s\"\n", key->cert->key_id);
printf(" Serial: %llu\n", (unsigned long long)key->cert->serial);
printf(" Valid: %s\n", valid);
printf(" Principals: ");
if (key->cert->nprincipals == 0)
printf("(none)\n");
else {
for (i = 0; i < key->cert->nprincipals; i++)
printf("\n %s",
key->cert->principals[i]);
printf("\n");
}
printf(" Critical Options: ");
if (sshbuf_len(key->cert->critical) == 0)
printf("(none)\n");
else {
printf("\n");
show_options(key->cert->critical, 1);
}
printf(" Extensions: ");
if (sshbuf_len(key->cert->extensions) == 0)
printf("(none)\n");
else {
printf("\n");
show_options(key->cert->extensions, 0);
}
}
static void
do_show_cert(struct passwd *pw)
{
struct sshkey *key = NULL;
struct stat st;
int r, is_stdin = 0, ok = 0;
FILE *f;
char *cp, *line = NULL;
const char *path;
size_t linesize = 0;
u_long lnum = 0;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
if (strcmp(identity_file, "-") != 0 && stat(identity_file, &st) == -1)
fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
path = identity_file;
if (strcmp(path, "-") == 0) {
f = stdin;
path = "(stdin)";
is_stdin = 1;
} else if ((f = fopen(identity_file, "r")) == NULL)
fatal("fopen %s: %s", identity_file, strerror(errno));
while (getline(&line, &linesize, f) != -1) {
lnum++;
sshkey_free(key);
key = NULL;
/* Trim leading space and comments */
cp = line + strspn(line, " \t");
if (*cp == '#' || *cp == '\0')
continue;
if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
fatal("sshkey_new");
if ((r = sshkey_read(key, &cp)) != 0) {
error_r(r, "%s:%lu: invalid key", path, lnum);
continue;
}
if (!sshkey_is_cert(key)) {
error("%s:%lu is not a certificate", path, lnum);
continue;
}
ok = 1;
if (!is_stdin && lnum == 1)
printf("%s:\n", path);
else
printf("%s:%lu:\n", path, lnum);
print_cert(key);
}
free(line);
sshkey_free(key);
fclose(f);
exit(ok ? 0 : 1);
}
static void
load_krl(const char *path, struct ssh_krl **krlp)
{
struct sshbuf *krlbuf;
int r;
if ((r = sshbuf_load_file(path, &krlbuf)) != 0)
fatal_r(r, "Unable to load KRL %s", path);
/* XXX check sigs */
if ((r = ssh_krl_from_blob(krlbuf, krlp, NULL, 0)) != 0 ||
*krlp == NULL)
fatal_r(r, "Invalid KRL file %s", path);
sshbuf_free(krlbuf);
}
static void
hash_to_blob(const char *cp, u_char **blobp, size_t *lenp,
const char *file, u_long lnum)
{
char *tmp;
size_t tlen;
struct sshbuf *b;
int r;
if (strncmp(cp, "SHA256:", 7) != 0)
fatal("%s:%lu: unsupported hash algorithm", file, lnum);
cp += 7;
/*
* OpenSSH base64 hashes omit trailing '='
* characters; put them back for decode.
*/
tlen = strlen(cp);
tmp = xmalloc(tlen + 4 + 1);
strlcpy(tmp, cp, tlen + 1);
while ((tlen % 4) != 0) {
tmp[tlen++] = '=';
tmp[tlen] = '\0';
}
if ((b = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_b64tod(b, tmp)) != 0)
fatal_r(r, "%s:%lu: decode hash failed", file, lnum);
free(tmp);
*lenp = sshbuf_len(b);
*blobp = xmalloc(*lenp);
memcpy(*blobp, sshbuf_ptr(b), *lenp);
sshbuf_free(b);
}
static void
update_krl_from_file(struct passwd *pw, const char *file, int wild_ca,
const struct sshkey *ca, struct ssh_krl *krl)
{
struct sshkey *key = NULL;
u_long lnum = 0;
char *path, *cp, *ep, *line = NULL;
u_char *blob = NULL;
size_t blen = 0, linesize = 0;
unsigned long long serial, serial2;
int i, was_explicit_key, was_sha1, was_sha256, was_hash, r;
FILE *krl_spec;
path = tilde_expand_filename(file, pw->pw_uid);
if (strcmp(path, "-") == 0) {
krl_spec = stdin;
free(path);
path = xstrdup("(standard input)");
} else if ((krl_spec = fopen(path, "r")) == NULL)
fatal("fopen %s: %s", path, strerror(errno));
if (!quiet)
printf("Revoking from %s\n", path);
while (getline(&line, &linesize, krl_spec) != -1) {
lnum++;
was_explicit_key = was_sha1 = was_sha256 = was_hash = 0;
cp = line + strspn(line, " \t");
/* Trim trailing space, comments and strip \n */
for (i = 0, r = -1; cp[i] != '\0'; i++) {
if (cp[i] == '#' || cp[i] == '\n') {
cp[i] = '\0';
break;
}
if (cp[i] == ' ' || cp[i] == '\t') {
/* Remember the start of a span of whitespace */
if (r == -1)
r = i;
} else
r = -1;
}
if (r != -1)
cp[r] = '\0';
if (*cp == '\0')
continue;
if (strncasecmp(cp, "serial:", 7) == 0) {
if (ca == NULL && !wild_ca) {
fatal("revoking certificates by serial number "
"requires specification of a CA key");
}
cp += 7;
cp = cp + strspn(cp, " \t");
errno = 0;
serial = strtoull(cp, &ep, 0);
if (*cp == '\0' || (*ep != '\0' && *ep != '-'))
fatal("%s:%lu: invalid serial \"%s\"",
path, lnum, cp);
if (errno == ERANGE && serial == ULLONG_MAX)
fatal("%s:%lu: serial out of range",
path, lnum);
serial2 = serial;
if (*ep == '-') {
cp = ep + 1;
errno = 0;
serial2 = strtoull(cp, &ep, 0);
if (*cp == '\0' || *ep != '\0')
fatal("%s:%lu: invalid serial \"%s\"",
path, lnum, cp);
if (errno == ERANGE && serial2 == ULLONG_MAX)
fatal("%s:%lu: serial out of range",
path, lnum);
if (serial2 <= serial)
fatal("%s:%lu: invalid serial range "
"%llu:%llu", path, lnum,
(unsigned long long)serial,
(unsigned long long)serial2);
}
if (ssh_krl_revoke_cert_by_serial_range(krl,
ca, serial, serial2) != 0) {
fatal_f("revoke serial failed");
}
} else if (strncasecmp(cp, "id:", 3) == 0) {
if (ca == NULL && !wild_ca) {
fatal("revoking certificates by key ID "
"requires specification of a CA key");
}
cp += 3;
cp = cp + strspn(cp, " \t");
if (ssh_krl_revoke_cert_by_key_id(krl, ca, cp) != 0)
fatal_f("revoke key ID failed");
} else if (strncasecmp(cp, "hash:", 5) == 0) {
cp += 5;
cp = cp + strspn(cp, " \t");
hash_to_blob(cp, &blob, &blen, file, lnum);
r = ssh_krl_revoke_key_sha256(krl, blob, blen);
if (r != 0)
fatal_fr(r, "revoke key failed");
} else {
if (strncasecmp(cp, "key:", 4) == 0) {
cp += 4;
cp = cp + strspn(cp, " \t");
was_explicit_key = 1;
} else if (strncasecmp(cp, "sha1:", 5) == 0) {
cp += 5;
cp = cp + strspn(cp, " \t");
was_sha1 = 1;
} else if (strncasecmp(cp, "sha256:", 7) == 0) {
cp += 7;
cp = cp + strspn(cp, " \t");
was_sha256 = 1;
/*
* Just try to process the line as a key.
* Parsing will fail if it isn't.
*/
}
if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
fatal("sshkey_new");
if ((r = sshkey_read(key, &cp)) != 0)
fatal_r(r, "%s:%lu: invalid key", path, lnum);
if (was_explicit_key)
r = ssh_krl_revoke_key_explicit(krl, key);
else if (was_sha1) {
if (sshkey_fingerprint_raw(key,
SSH_DIGEST_SHA1, &blob, &blen) != 0) {
fatal("%s:%lu: fingerprint failed",
file, lnum);
}
r = ssh_krl_revoke_key_sha1(krl, blob, blen);
} else if (was_sha256) {
if (sshkey_fingerprint_raw(key,
SSH_DIGEST_SHA256, &blob, &blen) != 0) {
fatal("%s:%lu: fingerprint failed",
file, lnum);
}
r = ssh_krl_revoke_key_sha256(krl, blob, blen);
} else
r = ssh_krl_revoke_key(krl, key);
if (r != 0)
fatal_fr(r, "revoke key failed");
freezero(blob, blen);
blob = NULL;
blen = 0;
sshkey_free(key);
}
}
if (strcmp(path, "-") != 0)
fclose(krl_spec);
free(line);
free(path);
}
static void
do_gen_krl(struct passwd *pw, int updating, const char *ca_key_path,
unsigned long long krl_version, const char *krl_comment,
int argc, char **argv)
{
struct ssh_krl *krl;
struct stat sb;
struct sshkey *ca = NULL;
int i, r, wild_ca = 0;
char *tmp;
struct sshbuf *kbuf;
if (*identity_file == '\0')
fatal("KRL generation requires an output file");
if (stat(identity_file, &sb) == -1) {
if (errno != ENOENT)
fatal("Cannot access KRL \"%s\": %s",
identity_file, strerror(errno));
if (updating)
fatal("KRL \"%s\" does not exist", identity_file);
}
if (ca_key_path != NULL) {
if (strcasecmp(ca_key_path, "none") == 0)
wild_ca = 1;
else {
tmp = tilde_expand_filename(ca_key_path, pw->pw_uid);
if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0)
fatal_r(r, "Cannot load CA public key %s", tmp);
free(tmp);
}
}
if (updating)
load_krl(identity_file, &krl);
else if ((krl = ssh_krl_init()) == NULL)
fatal("couldn't create KRL");
if (krl_version != 0)
ssh_krl_set_version(krl, krl_version);
if (krl_comment != NULL)
ssh_krl_set_comment(krl, krl_comment);
for (i = 0; i < argc; i++)
update_krl_from_file(pw, argv[i], wild_ca, ca, krl);
if ((kbuf = sshbuf_new()) == NULL)
fatal("sshbuf_new failed");
if (ssh_krl_to_blob(krl, kbuf, NULL, 0) != 0)
fatal("Couldn't generate KRL");
if ((r = sshbuf_write_file(identity_file, kbuf)) != 0)
fatal("write %s: %s", identity_file, strerror(errno));
sshbuf_free(kbuf);
ssh_krl_free(krl);
sshkey_free(ca);
}
static void
do_check_krl(struct passwd *pw, int print_krl, int argc, char **argv)
{
int i, r, ret = 0;
char *comment;
struct ssh_krl *krl;
struct sshkey *k;
if (*identity_file == '\0')
fatal("KRL checking requires an input file");
load_krl(identity_file, &krl);
if (print_krl)
krl_dump(krl, stdout);
for (i = 0; i < argc; i++) {
if ((r = sshkey_load_public(argv[i], &k, &comment)) != 0)
fatal_r(r, "Cannot load public key %s", argv[i]);
r = ssh_krl_check_key(krl, k);
printf("%s%s%s%s: %s\n", argv[i],
*comment ? " (" : "", comment, *comment ? ")" : "",
r == 0 ? "ok" : "REVOKED");
if (r != 0)
ret = 1;
sshkey_free(k);
free(comment);
}
ssh_krl_free(krl);
exit(ret);
}
static struct sshkey *
load_sign_key(const char *keypath, const struct sshkey *pubkey)
{
size_t i, slen, plen = strlen(keypath);
char *privpath = xstrdup(keypath);
const char *suffixes[] = { "-cert.pub", ".pub", NULL };
struct sshkey *ret = NULL, *privkey = NULL;
int r;
/*
* If passed a public key filename, then try to locate the corresponding
* private key. This lets us specify certificates on the command-line
* and have ssh-keygen find the appropriate private key.
*/
for (i = 0; suffixes[i]; i++) {
slen = strlen(suffixes[i]);
if (plen <= slen ||
strcmp(privpath + plen - slen, suffixes[i]) != 0)
continue;
privpath[plen - slen] = '\0';
debug_f("%s looks like a public key, using private key "
"path %s instead", keypath, privpath);
}
if ((privkey = load_identity(privpath, NULL)) == NULL) {
error("Couldn't load identity %s", keypath);
goto done;
}
if (!sshkey_equal_public(pubkey, privkey)) {
error("Public key %s doesn't match private %s",
keypath, privpath);
goto done;
}
if (sshkey_is_cert(pubkey) && !sshkey_is_cert(privkey)) {
/*
* Graft the certificate onto the private key to make
* it capable of signing.
*/
if ((r = sshkey_to_certified(privkey)) != 0) {
error_fr(r, "sshkey_to_certified");
goto done;
}
if ((r = sshkey_cert_copy(pubkey, privkey)) != 0) {
error_fr(r, "sshkey_cert_copy");
goto done;
}
}
/* success */
ret = privkey;
privkey = NULL;
done:
sshkey_free(privkey);
free(privpath);
return ret;
}
static int
sign_one(struct sshkey *signkey, const char *filename, int fd,
const char *sig_namespace, sshsig_signer *signer, void *signer_ctx)
{
struct sshbuf *sigbuf = NULL, *abuf = NULL;
int r = SSH_ERR_INTERNAL_ERROR, wfd = -1, oerrno;
char *wfile = NULL, *asig = NULL, *fp = NULL;
char *pin = NULL, *prompt = NULL;
if (!quiet) {
if (fd == STDIN_FILENO)
fprintf(stderr, "Signing data on standard input\n");
else
fprintf(stderr, "Signing file %s\n", filename);
}
if (signer == NULL && sshkey_is_sk(signkey)) {
if ((signkey->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) {
xasprintf(&prompt, "Enter PIN for %s key: ",
sshkey_type(signkey));
if ((pin = read_passphrase(prompt,
RP_ALLOW_STDIN)) == NULL)
fatal_f("couldn't read PIN");
}
if ((signkey->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
if ((fp = sshkey_fingerprint(signkey, fingerprint_hash,
SSH_FP_DEFAULT)) == NULL)
fatal_f("fingerprint failed");
fprintf(stderr, "Confirm user presence for key %s %s\n",
sshkey_type(signkey), fp);
free(fp);
}
}
if ((r = sshsig_sign_fd(signkey, NULL, sk_provider, pin,
fd, sig_namespace, &sigbuf, signer, signer_ctx)) != 0) {
error_r(r, "Signing %s failed", filename);
goto out;
}
if ((r = sshsig_armor(sigbuf, &abuf)) != 0) {
error_fr(r, "sshsig_armor");
goto out;
}
if ((asig = sshbuf_dup_string(abuf)) == NULL) {
error_f("buffer error");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (fd == STDIN_FILENO) {
fputs(asig, stdout);
fflush(stdout);
} else {
xasprintf(&wfile, "%s.sig", filename);
if (confirm_overwrite(wfile)) {
if ((wfd = open(wfile, O_WRONLY|O_CREAT|O_TRUNC,
0666)) == -1) {
oerrno = errno;
error("Cannot open %s: %s",
wfile, strerror(errno));
errno = oerrno;
r = SSH_ERR_SYSTEM_ERROR;
goto out;
}
if (atomicio(vwrite, wfd, asig,
strlen(asig)) != strlen(asig)) {
oerrno = errno;
error("Cannot write to %s: %s",
wfile, strerror(errno));
errno = oerrno;
r = SSH_ERR_SYSTEM_ERROR;
goto out;
}
if (!quiet) {
fprintf(stderr, "Write signature to %s\n",
wfile);
}
}
}
/* success */
r = 0;
out:
free(wfile);
free(prompt);
free(asig);
if (pin != NULL)
freezero(pin, strlen(pin));
sshbuf_free(abuf);
sshbuf_free(sigbuf);
if (wfd != -1)
close(wfd);
return r;
}
static int
sig_sign(const char *keypath, const char *sig_namespace, int argc, char **argv)
{
int i, fd = -1, r, ret = -1;
int agent_fd = -1;
struct sshkey *pubkey = NULL, *privkey = NULL, *signkey = NULL;
sshsig_signer *signer = NULL;
/* Check file arguments. */
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "-") != 0)
continue;
if (i > 0 || argc > 1)
fatal("Cannot sign mix of paths and standard input");
}
if ((r = sshkey_load_public(keypath, &pubkey, NULL)) != 0) {
error_r(r, "Couldn't load public key %s", keypath);
goto done;
}
if ((r = ssh_get_authentication_socket(&agent_fd)) != 0)
debug_r(r, "Couldn't get agent socket");
else {
if ((r = ssh_agent_has_key(agent_fd, pubkey)) == 0)
signer = agent_signer;
else
debug_r(r, "Couldn't find key in agent");
}
if (signer == NULL) {
/* Not using agent - try to load private key */
if ((privkey = load_sign_key(keypath, pubkey)) == NULL)
goto done;
signkey = privkey;
} else {
/* Will use key in agent */
signkey = pubkey;
}
if (argc == 0) {
if ((r = sign_one(signkey, "(stdin)", STDIN_FILENO,
sig_namespace, signer, &agent_fd)) != 0)
goto done;
} else {
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "-") == 0)
fd = STDIN_FILENO;
else if ((fd = open(argv[i], O_RDONLY)) == -1) {
error("Cannot open %s for signing: %s",
argv[i], strerror(errno));
goto done;
}
if ((r = sign_one(signkey, argv[i], fd, sig_namespace,
signer, &agent_fd)) != 0)
goto done;
if (fd != STDIN_FILENO)
close(fd);
fd = -1;
}
}
ret = 0;
done:
if (fd != -1 && fd != STDIN_FILENO)
close(fd);
sshkey_free(pubkey);
sshkey_free(privkey);
return ret;
}
static int
sig_verify(const char *signature, const char *sig_namespace,
const char *principal, const char *allowed_keys, const char *revoked_keys)
{
int r, ret = -1;
struct sshbuf *sigbuf = NULL, *abuf = NULL;
struct sshkey *sign_key = NULL;
char *fp = NULL;
struct sshkey_sig_details *sig_details = NULL;
memset(&sig_details, 0, sizeof(sig_details));
if ((r = sshbuf_load_file(signature, &abuf)) != 0) {
error_r(r, "Couldn't read signature file");
goto done;
}
if ((r = sshsig_dearmor(abuf, &sigbuf)) != 0) {
error_fr(r, "sshsig_armor");
goto done;
}
if ((r = sshsig_verify_fd(sigbuf, STDIN_FILENO, sig_namespace,
&sign_key, &sig_details)) != 0)
goto done; /* sshsig_verify() prints error */
if ((fp = sshkey_fingerprint(sign_key, fingerprint_hash,
SSH_FP_DEFAULT)) == NULL)
fatal_f("sshkey_fingerprint failed");
debug("Valid (unverified) signature from key %s", fp);
if (sig_details != NULL) {
debug2_f("signature details: counter = %u, flags = 0x%02x",
sig_details->sk_counter, sig_details->sk_flags);
}
free(fp);
fp = NULL;
if (revoked_keys != NULL) {
if ((r = sshkey_check_revoked(sign_key, revoked_keys)) != 0) {
debug3_fr(r, "sshkey_check_revoked");
goto done;
}
}
if (allowed_keys != NULL && (r = sshsig_check_allowed_keys(allowed_keys,
sign_key, principal, sig_namespace)) != 0) {
debug3_fr(r, "sshsig_check_allowed_keys");
goto done;
}
/* success */
ret = 0;
done:
if (!quiet) {
if (ret == 0) {
if ((fp = sshkey_fingerprint(sign_key, fingerprint_hash,
SSH_FP_DEFAULT)) == NULL)
fatal_f("sshkey_fingerprint failed");
if (principal == NULL) {
printf("Good \"%s\" signature with %s key %s\n",
- sig_namespace, sshkey_type(sign_key), fp);
+ sig_namespace, sshkey_type(sign_key), fp);
} else {
printf("Good \"%s\" signature for %s with %s key %s\n",
- sig_namespace, principal,
- sshkey_type(sign_key), fp);
+ sig_namespace, principal,
+ sshkey_type(sign_key), fp);
}
} else {
printf("Could not verify signature.\n");
}
}
sshbuf_free(sigbuf);
sshbuf_free(abuf);
sshkey_free(sign_key);
sshkey_sig_details_free(sig_details);
free(fp);
return ret;
}
static int
sig_find_principals(const char *signature, const char *allowed_keys) {
int r, ret = -1;
struct sshbuf *sigbuf = NULL, *abuf = NULL;
struct sshkey *sign_key = NULL;
char *principals = NULL, *cp, *tmp;
if ((r = sshbuf_load_file(signature, &abuf)) != 0) {
error_r(r, "Couldn't read signature file");
goto done;
}
if ((r = sshsig_dearmor(abuf, &sigbuf)) != 0) {
error_fr(r, "sshsig_armor");
goto done;
}
if ((r = sshsig_get_pubkey(sigbuf, &sign_key)) != 0) {
error_fr(r, "sshsig_get_pubkey");
goto done;
}
if ((r = sshsig_find_principals(allowed_keys, sign_key,
&principals)) != 0) {
error_fr(r, "sshsig_get_principal");
goto done;
}
ret = 0;
done:
if (ret == 0 ) {
/* Emit matching principals one per line */
tmp = principals;
while ((cp = strsep(&tmp, ",")) != NULL && *cp != '\0')
puts(cp);
} else {
fprintf(stderr, "No principal matched.\n");
}
sshbuf_free(sigbuf);
sshbuf_free(abuf);
sshkey_free(sign_key);
free(principals);
return ret;
}
static void
do_moduli_gen(const char *out_file, char **opts, size_t nopts)
{
#ifdef WITH_OPENSSL
/* Moduli generation/screening */
u_int32_t memory = 0;
BIGNUM *start = NULL;
int moduli_bits = 0;
FILE *out;
size_t i;
const char *errstr;
/* Parse options */
for (i = 0; i < nopts; i++) {
if (strncmp(opts[i], "memory=", 7) == 0) {
memory = (u_int32_t)strtonum(opts[i]+7, 1,
UINT_MAX, &errstr);
if (errstr) {
fatal("Memory limit is %s: %s",
errstr, opts[i]+7);
}
} else if (strncmp(opts[i], "start=", 6) == 0) {
/* XXX - also compare length against bits */
if (BN_hex2bn(&start, opts[i]+6) == 0)
fatal("Invalid start point.");
} else if (strncmp(opts[i], "bits=", 5) == 0) {
moduli_bits = (int)strtonum(opts[i]+5, 1,
INT_MAX, &errstr);
if (errstr) {
fatal("Invalid number: %s (%s)",
opts[i]+12, errstr);
}
} else {
fatal("Option \"%s\" is unsupported for moduli "
"generation", opts[i]);
}
}
if ((out = fopen(out_file, "w")) == NULL) {
fatal("Couldn't open modulus candidate file \"%s\": %s",
out_file, strerror(errno));
}
setvbuf(out, NULL, _IOLBF, 0);
if (moduli_bits == 0)
moduli_bits = DEFAULT_BITS;
if (gen_candidates(out, memory, moduli_bits, start) != 0)
fatal("modulus candidate generation failed");
#else /* WITH_OPENSSL */
fatal("Moduli generation is not supported");
#endif /* WITH_OPENSSL */
}
static void
do_moduli_screen(const char *out_file, char **opts, size_t nopts)
{
#ifdef WITH_OPENSSL
/* Moduli generation/screening */
char *checkpoint = NULL;
u_int32_t generator_wanted = 0;
unsigned long start_lineno = 0, lines_to_process = 0;
int prime_tests = 0;
FILE *out, *in = stdin;
size_t i;
const char *errstr;
/* Parse options */
for (i = 0; i < nopts; i++) {
if (strncmp(opts[i], "lines=", 6) == 0) {
lines_to_process = strtoul(opts[i]+6, NULL, 10);
} else if (strncmp(opts[i], "start-line=", 11) == 0) {
start_lineno = strtoul(opts[i]+11, NULL, 10);
} else if (strncmp(opts[i], "checkpoint=", 11) == 0) {
checkpoint = xstrdup(opts[i]+11);
} else if (strncmp(opts[i], "generator=", 10) == 0) {
generator_wanted = (u_int32_t)strtonum(
opts[i]+10, 1, UINT_MAX, &errstr);
if (errstr != NULL) {
fatal("Generator invalid: %s (%s)",
opts[i]+10, errstr);
}
} else if (strncmp(opts[i], "prime-tests=", 12) == 0) {
prime_tests = (int)strtonum(opts[i]+12, 1,
INT_MAX, &errstr);
if (errstr) {
fatal("Invalid number: %s (%s)",
opts[i]+12, errstr);
}
} else {
fatal("Option \"%s\" is unsupported for moduli "
"screening", opts[i]);
}
}
if (have_identity && strcmp(identity_file, "-") != 0) {
if ((in = fopen(identity_file, "r")) == NULL) {
fatal("Couldn't open modulus candidate "
"file \"%s\": %s", identity_file,
strerror(errno));
}
}
if ((out = fopen(out_file, "a")) == NULL) {
fatal("Couldn't open moduli file \"%s\": %s",
out_file, strerror(errno));
}
setvbuf(out, NULL, _IOLBF, 0);
if (prime_test(in, out, prime_tests == 0 ? 100 : prime_tests,
generator_wanted, checkpoint,
start_lineno, lines_to_process) != 0)
fatal("modulus screening failed");
#else /* WITH_OPENSSL */
fatal("Moduli screening is not supported");
#endif /* WITH_OPENSSL */
}
static char *
private_key_passphrase(void)
{
char *passphrase1, *passphrase2;
/* Ask for a passphrase (twice). */
if (identity_passphrase)
passphrase1 = xstrdup(identity_passphrase);
else if (identity_new_passphrase)
passphrase1 = xstrdup(identity_new_passphrase);
else {
passphrase_again:
passphrase1 =
read_passphrase("Enter passphrase (empty for no "
"passphrase): ", RP_ALLOW_STDIN);
passphrase2 = read_passphrase("Enter same passphrase again: ",
RP_ALLOW_STDIN);
if (strcmp(passphrase1, passphrase2) != 0) {
/*
* The passphrases do not match. Clear them and
* retry.
*/
freezero(passphrase1, strlen(passphrase1));
freezero(passphrase2, strlen(passphrase2));
printf("Passphrases do not match. Try again.\n");
goto passphrase_again;
}
/* Clear the other copy of the passphrase. */
freezero(passphrase2, strlen(passphrase2));
}
return passphrase1;
}
static const char *
skip_ssh_url_preamble(const char *s)
{
if (strncmp(s, "ssh://", 6) == 0)
return s + 6;
else if (strncmp(s, "ssh:", 4) == 0)
return s + 4;
return s;
}
static int
do_download_sk(const char *skprovider, const char *device)
{
struct sshkey **keys;
size_t nkeys, i;
int r, ret = -1;
char *fp, *pin = NULL, *pass = NULL, *path, *pubpath;
const char *ext;
if (skprovider == NULL)
fatal("Cannot download keys without provider");
pin = read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN);
if (!quiet) {
printf("You may need to touch your authenticator "
"to authorize key download.\n");
}
if ((r = sshsk_load_resident(skprovider, device, pin,
&keys, &nkeys)) != 0) {
if (pin != NULL)
freezero(pin, strlen(pin));
error_r(r, "Unable to load resident keys");
return -1;
}
if (nkeys == 0)
logit("No keys to download");
if (pin != NULL)
freezero(pin, strlen(pin));
for (i = 0; i < nkeys; i++) {
if (keys[i]->type != KEY_ECDSA_SK &&
keys[i]->type != KEY_ED25519_SK) {
error("Unsupported key type %s (%d)",
sshkey_type(keys[i]), keys[i]->type);
continue;
}
if ((fp = sshkey_fingerprint(keys[i],
fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
fatal_f("sshkey_fingerprint failed");
debug_f("key %zu: %s %s %s (flags 0x%02x)", i,
sshkey_type(keys[i]), fp, keys[i]->sk_application,
keys[i]->sk_flags);
ext = skip_ssh_url_preamble(keys[i]->sk_application);
xasprintf(&path, "id_%s_rk%s%s",
keys[i]->type == KEY_ECDSA_SK ? "ecdsa_sk" : "ed25519_sk",
*ext == '\0' ? "" : "_", ext);
/* If the file already exists, ask the user to confirm. */
if (!confirm_overwrite(path)) {
free(path);
break;
}
/* Save the key with the application string as the comment */
if (pass == NULL)
pass = private_key_passphrase();
if ((r = sshkey_save_private(keys[i], path, pass,
keys[i]->sk_application, private_key_format,
openssh_format_cipher, rounds)) != 0) {
error_r(r, "Saving key \"%s\" failed", path);
free(path);
break;
}
if (!quiet) {
printf("Saved %s key%s%s to %s\n",
sshkey_type(keys[i]),
*ext != '\0' ? " " : "",
*ext != '\0' ? keys[i]->sk_application : "",
path);
}
/* Save public key too */
xasprintf(&pubpath, "%s.pub", path);
free(path);
if ((r = sshkey_save_public(keys[i], pubpath,
keys[i]->sk_application)) != 0) {
error_r(r, "Saving public key \"%s\" failed", pubpath);
free(pubpath);
break;
}
free(pubpath);
}
if (i >= nkeys)
ret = 0; /* success */
if (pass != NULL)
freezero(pass, strlen(pass));
for (i = 0; i < nkeys; i++)
sshkey_free(keys[i]);
free(keys);
return ret;
}
static void
save_attestation(struct sshbuf *attest, const char *path)
{
mode_t omask;
int r;
if (path == NULL)
return; /* nothing to do */
if (attest == NULL || sshbuf_len(attest) == 0)
fatal("Enrollment did not return attestation data");
omask = umask(077);
r = sshbuf_write_file(path, attest);
umask(omask);
if (r != 0)
fatal_r(r, "Unable to write attestation data \"%s\"", path);
if (!quiet)
printf("Your FIDO attestation certificate has been saved in "
"%s\n", path);
}
static void
usage(void)
{
fprintf(stderr,
"usage: ssh-keygen [-q] [-a rounds] [-b bits] [-C comment] [-f output_keyfile]\n"
" [-m format] [-N new_passphrase] [-O option]\n"
" [-t dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa]\n"
" [-w provider] [-Z cipher]\n"
" ssh-keygen -p [-a rounds] [-f keyfile] [-m format] [-N new_passphrase]\n"
" [-P old_passphrase] [-Z cipher]\n"
" ssh-keygen -i [-f input_keyfile] [-m key_format]\n"
" ssh-keygen -e [-f input_keyfile] [-m key_format]\n"
" ssh-keygen -y [-f input_keyfile]\n"
" ssh-keygen -c [-a rounds] [-C comment] [-f keyfile] [-P passphrase]\n"
" ssh-keygen -l [-v] [-E fingerprint_hash] [-f input_keyfile]\n"
" ssh-keygen -B [-f input_keyfile]\n");
#ifdef ENABLE_PKCS11
fprintf(stderr,
" ssh-keygen -D pkcs11\n");
#endif
fprintf(stderr,
" ssh-keygen -F hostname [-lv] [-f known_hosts_file]\n"
" ssh-keygen -H [-f known_hosts_file]\n"
" ssh-keygen -K [-a rounds] [-w provider]\n"
" ssh-keygen -R hostname [-f known_hosts_file]\n"
" ssh-keygen -r hostname [-g] [-f input_keyfile]\n"
#ifdef WITH_OPENSSL
" ssh-keygen -M generate [-O option] output_file\n"
" ssh-keygen -M screen [-f input_file] [-O option] output_file\n"
#endif
" ssh-keygen -I certificate_identity -s ca_key [-hU] [-D pkcs11_provider]\n"
" [-n principals] [-O option] [-V validity_interval]\n"
" [-z serial_number] file ...\n"
" ssh-keygen -L [-f input_keyfile]\n"
" ssh-keygen -A [-a rounds] [-f prefix_path]\n"
" ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n"
" file ...\n"
" ssh-keygen -Q [-l] -f krl_file [file ...]\n"
" ssh-keygen -Y find-principals -s signature_file -f allowed_signers_file\n"
" ssh-keygen -Y check-novalidate -n namespace -s signature_file\n"
" ssh-keygen -Y sign -f key_file -n namespace file ...\n"
" ssh-keygen -Y verify -f allowed_signers_file -I signer_identity\n"
" -n namespace -s signature_file [-r revocation_file]\n");
exit(1);
}
/*
* Main program for key management.
*/
int
main(int argc, char **argv)
{
char comment[1024], *passphrase;
char *rr_hostname = NULL, *ep, *fp, *ra;
struct sshkey *private, *public;
struct passwd *pw;
int r, opt, type;
int change_passphrase = 0, change_comment = 0, show_cert = 0;
int find_host = 0, delete_host = 0, hash_hosts = 0;
int gen_all_hostkeys = 0, gen_krl = 0, update_krl = 0, check_krl = 0;
int prefer_agent = 0, convert_to = 0, convert_from = 0;
int print_public = 0, print_generic = 0, cert_serial_autoinc = 0;
int do_gen_candidates = 0, do_screen_candidates = 0, download_sk = 0;
unsigned long long cert_serial = 0;
char *identity_comment = NULL, *ca_key_path = NULL, **opts = NULL;
char *sk_application = NULL, *sk_device = NULL, *sk_user = NULL;
char *sk_attestation_path = NULL;
struct sshbuf *challenge = NULL, *attest = NULL;
size_t i, nopts = 0;
u_int32_t bits = 0;
uint8_t sk_flags = SSH_SK_USER_PRESENCE_REQD;
const char *errstr;
int log_level = SYSLOG_LEVEL_INFO;
char *sign_op = NULL;
extern int optind;
extern char *optarg;
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
sanitise_stdfd();
__progname = ssh_get_progname(argv[0]);
seed_rng();
log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
msetlocale();
/* we need this for the home * directory. */
pw = getpwuid(getuid());
if (!pw)
fatal("No user exists for uid %lu", (u_long)getuid());
+ pw = pwcopy(pw);
if (gethostname(hostname, sizeof(hostname)) == -1)
fatal("gethostname: %s", strerror(errno));
sk_provider = getenv("SSH_SK_PROVIDER");
/* Remaining characters: dGjJSTWx */
while ((opt = getopt(argc, argv, "ABHKLQUXceghiklopquvy"
"C:D:E:F:I:M:N:O:P:R:V:Y:Z:"
"a:b:f:g:m:n:r:s:t:w:z:")) != -1) {
switch (opt) {
case 'A':
gen_all_hostkeys = 1;
break;
case 'b':
bits = (u_int32_t)strtonum(optarg, 1, UINT32_MAX,
&errstr);
if (errstr)
fatal("Bits has bad value %s (%s)",
optarg, errstr);
break;
case 'E':
fingerprint_hash = ssh_digest_alg_by_name(optarg);
if (fingerprint_hash == -1)
fatal("Invalid hash algorithm \"%s\"", optarg);
break;
case 'F':
find_host = 1;
rr_hostname = optarg;
break;
case 'H':
hash_hosts = 1;
break;
case 'I':
cert_key_id = optarg;
break;
case 'R':
delete_host = 1;
rr_hostname = optarg;
break;
case 'L':
show_cert = 1;
break;
case 'l':
print_fingerprint = 1;
break;
case 'B':
print_bubblebabble = 1;
break;
case 'm':
if (strcasecmp(optarg, "RFC4716") == 0 ||
strcasecmp(optarg, "ssh2") == 0) {
convert_format = FMT_RFC4716;
break;
}
if (strcasecmp(optarg, "PKCS8") == 0) {
convert_format = FMT_PKCS8;
private_key_format = SSHKEY_PRIVATE_PKCS8;
break;
}
if (strcasecmp(optarg, "PEM") == 0) {
convert_format = FMT_PEM;
private_key_format = SSHKEY_PRIVATE_PEM;
break;
}
fatal("Unsupported conversion format \"%s\"", optarg);
case 'n':
cert_principals = optarg;
break;
case 'o':
/* no-op; new format is already the default */
break;
case 'p':
change_passphrase = 1;
break;
case 'c':
change_comment = 1;
break;
case 'f':
if (strlcpy(identity_file, optarg,
sizeof(identity_file)) >= sizeof(identity_file))
fatal("Identity filename too long");
have_identity = 1;
break;
case 'g':
print_generic = 1;
break;
case 'K':
download_sk = 1;
break;
case 'P':
identity_passphrase = optarg;
break;
case 'N':
identity_new_passphrase = optarg;
break;
case 'Q':
check_krl = 1;
break;
case 'O':
opts = xrecallocarray(opts, nopts, nopts + 1,
sizeof(*opts));
opts[nopts++] = xstrdup(optarg);
break;
case 'Z':
openssh_format_cipher = optarg;
if (cipher_by_name(openssh_format_cipher) == NULL)
fatal("Invalid OpenSSH-format cipher '%s'",
openssh_format_cipher);
break;
case 'C':
identity_comment = optarg;
break;
case 'q':
quiet = 1;
break;
case 'e':
/* export key */
convert_to = 1;
break;
case 'h':
cert_key_type = SSH2_CERT_TYPE_HOST;
certflags_flags = 0;
break;
case 'k':
gen_krl = 1;
break;
case 'i':
case 'X':
/* import key */
convert_from = 1;
break;
case 'y':
print_public = 1;
break;
case 's':
ca_key_path = optarg;
break;
case 't':
key_type_name = optarg;
break;
case 'D':
pkcs11provider = optarg;
break;
case 'U':
prefer_agent = 1;
break;
case 'u':
update_krl = 1;
break;
case 'v':
if (log_level == SYSLOG_LEVEL_INFO)
log_level = SYSLOG_LEVEL_DEBUG1;
else {
if (log_level >= SYSLOG_LEVEL_DEBUG1 &&
log_level < SYSLOG_LEVEL_DEBUG3)
log_level++;
}
break;
case 'r':
rr_hostname = optarg;
break;
case 'a':
rounds = (int)strtonum(optarg, 1, INT_MAX, &errstr);
if (errstr)
fatal("Invalid number: %s (%s)",
optarg, errstr);
break;
case 'V':
parse_cert_times(optarg);
break;
case 'Y':
sign_op = optarg;
break;
case 'w':
sk_provider = optarg;
break;
case 'z':
errno = 0;
if (*optarg == '+') {
cert_serial_autoinc = 1;
optarg++;
}
cert_serial = strtoull(optarg, &ep, 10);
if (*optarg < '0' || *optarg > '9' || *ep != '\0' ||
(errno == ERANGE && cert_serial == ULLONG_MAX))
fatal("Invalid serial number \"%s\"", optarg);
break;
case 'M':
if (strcmp(optarg, "generate") == 0)
do_gen_candidates = 1;
else if (strcmp(optarg, "screen") == 0)
do_screen_candidates = 1;
else
fatal("Unsupported moduli option %s", optarg);
break;
case '?':
default:
usage();
}
}
#ifdef ENABLE_SK_INTERNAL
if (sk_provider == NULL)
sk_provider = "internal";
#endif
/* reinit */
log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1);
argv += optind;
argc -= optind;
if (sign_op != NULL) {
if (strncmp(sign_op, "find-principals", 15) == 0) {
if (ca_key_path == NULL) {
error("Too few arguments for find-principals:"
- "missing signature file");
+ "missing signature file");
exit(1);
}
if (!have_identity) {
error("Too few arguments for find-principals:"
- "missing allowed keys file");
+ "missing allowed keys file");
exit(1);
}
return sig_find_principals(ca_key_path, identity_file);
} else if (strncmp(sign_op, "sign", 4) == 0) {
if (cert_principals == NULL ||
*cert_principals == '\0') {
error("Too few arguments for sign: "
"missing namespace");
exit(1);
}
if (!have_identity) {
error("Too few arguments for sign: "
"missing key");
exit(1);
}
return sig_sign(identity_file, cert_principals,
argc, argv);
} else if (strncmp(sign_op, "check-novalidate", 16) == 0) {
if (ca_key_path == NULL) {
error("Too few arguments for check-novalidate: "
- "missing signature file");
+ "missing signature file");
exit(1);
}
return sig_verify(ca_key_path, cert_principals,
NULL, NULL, NULL);
} else if (strncmp(sign_op, "verify", 6) == 0) {
if (cert_principals == NULL ||
*cert_principals == '\0') {
error("Too few arguments for verify: "
"missing namespace");
exit(1);
}
if (ca_key_path == NULL) {
error("Too few arguments for verify: "
"missing signature file");
exit(1);
}
if (!have_identity) {
error("Too few arguments for sign: "
"missing allowed keys file");
exit(1);
}
if (cert_key_id == NULL) {
error("Too few arguments for verify: "
"missing principal ID");
exit(1);
}
return sig_verify(ca_key_path, cert_principals,
cert_key_id, identity_file, rr_hostname);
}
error("Unsupported operation for -Y: \"%s\"", sign_op);
usage();
/* NOTREACHED */
}
if (ca_key_path != NULL) {
if (argc < 1 && !gen_krl) {
error("Too few arguments.");
usage();
}
} else if (argc > 0 && !gen_krl && !check_krl &&
!do_gen_candidates && !do_screen_candidates) {
error("Too many arguments.");
usage();
}
if (change_passphrase && change_comment) {
error("Can only have one of -p and -c.");
usage();
}
if (print_fingerprint && (delete_host || hash_hosts)) {
error("Cannot use -l with -H or -R.");
usage();
}
if (gen_krl) {
do_gen_krl(pw, update_krl, ca_key_path,
cert_serial, identity_comment, argc, argv);
return (0);
}
if (check_krl) {
do_check_krl(pw, print_fingerprint, argc, argv);
return (0);
}
if (ca_key_path != NULL) {
if (cert_key_id == NULL)
fatal("Must specify key id (-I) when certifying");
for (i = 0; i < nopts; i++)
add_cert_option(opts[i]);
do_ca_sign(pw, ca_key_path, prefer_agent,
cert_serial, cert_serial_autoinc, argc, argv);
}
if (show_cert)
do_show_cert(pw);
if (delete_host || hash_hosts || find_host) {
do_known_hosts(pw, rr_hostname, find_host,
delete_host, hash_hosts);
}
if (pkcs11provider != NULL)
do_download(pw);
if (download_sk) {
for (i = 0; i < nopts; i++) {
if (strncasecmp(opts[i], "device=", 7) == 0) {
sk_device = xstrdup(opts[i] + 7);
} else {
fatal("Option \"%s\" is unsupported for "
"FIDO authenticator download", opts[i]);
}
}
return do_download_sk(sk_provider, sk_device);
}
if (print_fingerprint || print_bubblebabble)
do_fingerprint(pw);
if (change_passphrase)
do_change_passphrase(pw);
if (change_comment)
do_change_comment(pw, identity_comment);
#ifdef WITH_OPENSSL
if (convert_to)
do_convert_to(pw);
if (convert_from)
do_convert_from(pw);
#else /* WITH_OPENSSL */
if (convert_to || convert_from)
fatal("key conversion disabled at compile time");
#endif /* WITH_OPENSSL */
if (print_public)
do_print_public(pw);
if (rr_hostname != NULL) {
unsigned int n = 0;
if (have_identity) {
n = do_print_resource_record(pw, identity_file,
rr_hostname, print_generic);
if (n == 0)
fatal("%s: %s", identity_file, strerror(errno));
exit(0);
} else {
n += do_print_resource_record(pw,
_PATH_HOST_RSA_KEY_FILE, rr_hostname,
print_generic);
n += do_print_resource_record(pw,
_PATH_HOST_DSA_KEY_FILE, rr_hostname,
print_generic);
n += do_print_resource_record(pw,
_PATH_HOST_ECDSA_KEY_FILE, rr_hostname,
print_generic);
n += do_print_resource_record(pw,
_PATH_HOST_ED25519_KEY_FILE, rr_hostname,
print_generic);
n += do_print_resource_record(pw,
_PATH_HOST_XMSS_KEY_FILE, rr_hostname,
print_generic);
if (n == 0)
fatal("no keys found.");
exit(0);
}
}
if (do_gen_candidates || do_screen_candidates) {
if (argc <= 0)
fatal("No output file specified");
else if (argc > 1)
fatal("Too many output files specified");
}
if (do_gen_candidates) {
do_moduli_gen(argv[0], opts, nopts);
return 0;
}
if (do_screen_candidates) {
do_moduli_screen(argv[0], opts, nopts);
return 0;
}
if (gen_all_hostkeys) {
do_gen_all_hostkeys(pw);
return (0);
}
if (key_type_name == NULL)
key_type_name = DEFAULT_KEY_TYPE_NAME;
type = sshkey_type_from_name(key_type_name);
type_bits_valid(type, key_type_name, &bits);
if (!quiet)
printf("Generating public/private %s key pair.\n",
key_type_name);
switch (type) {
case KEY_ECDSA_SK:
case KEY_ED25519_SK:
for (i = 0; i < nopts; i++) {
if (strcasecmp(opts[i], "no-touch-required") == 0) {
sk_flags &= ~SSH_SK_USER_PRESENCE_REQD;
} else if (strcasecmp(opts[i], "verify-required") == 0) {
sk_flags |= SSH_SK_USER_VERIFICATION_REQD;
} else if (strcasecmp(opts[i], "resident") == 0) {
sk_flags |= SSH_SK_RESIDENT_KEY;
} else if (strncasecmp(opts[i], "device=", 7) == 0) {
sk_device = xstrdup(opts[i] + 7);
} else if (strncasecmp(opts[i], "user=", 5) == 0) {
sk_user = xstrdup(opts[i] + 5);
} else if (strncasecmp(opts[i], "challenge=", 10) == 0) {
if ((r = sshbuf_load_file(opts[i] + 10,
&challenge)) != 0) {
fatal_r(r, "Unable to load FIDO "
"enrollment challenge \"%s\"",
opts[i] + 10);
}
} else if (strncasecmp(opts[i],
"write-attestation=", 18) == 0) {
sk_attestation_path = opts[i] + 18;
} else if (strncasecmp(opts[i],
"application=", 12) == 0) {
sk_application = xstrdup(opts[i] + 12);
if (strncmp(sk_application, "ssh:", 4) != 0) {
fatal("FIDO application string must "
"begin with \"ssh:\"");
}
} else {
fatal("Option \"%s\" is unsupported for "
"FIDO authenticator enrollment", opts[i]);
}
}
if (!quiet) {
printf("You may need to touch your authenticator "
"to authorize key generation.\n");
}
if ((attest = sshbuf_new()) == NULL)
fatal("sshbuf_new failed");
if ((sk_flags &
(SSH_SK_USER_VERIFICATION_REQD|SSH_SK_RESIDENT_KEY))) {
passphrase = read_passphrase("Enter PIN for "
"authenticator: ", RP_ALLOW_STDIN);
} else {
passphrase = NULL;
}
for (i = 0 ; ; i++) {
fflush(stdout);
r = sshsk_enroll(type, sk_provider, sk_device,
sk_application == NULL ? "ssh:" : sk_application,
sk_user, sk_flags, passphrase, challenge,
&private, attest);
if (r == 0)
break;
if (r != SSH_ERR_KEY_WRONG_PASSPHRASE)
fatal_r(r, "Key enrollment failed");
else if (passphrase != NULL) {
error("PIN incorrect");
freezero(passphrase, strlen(passphrase));
passphrase = NULL;
}
if (i >= 3)
fatal("Too many incorrect PINs");
passphrase = read_passphrase("Enter PIN for "
"authenticator: ", RP_ALLOW_STDIN);
if (!quiet) {
printf("You may need to touch your "
"authenticator (again) to authorize "
"key generation.\n");
}
}
if (passphrase != NULL) {
freezero(passphrase, strlen(passphrase));
passphrase = NULL;
}
break;
default:
if ((r = sshkey_generate(type, bits, &private)) != 0)
fatal("sshkey_generate failed");
break;
}
if ((r = sshkey_from_private(private, &public)) != 0)
fatal_r(r, "sshkey_from_private");
if (!have_identity)
ask_filename(pw, "Enter file in which to save the key");
/* Create ~/.ssh directory if it doesn't already exist. */
hostfile_create_user_ssh_dir(identity_file, !quiet);
/* If the file already exists, ask the user to confirm. */
if (!confirm_overwrite(identity_file))
exit(1);
/* Determine the passphrase for the private key */
passphrase = private_key_passphrase();
if (identity_comment) {
strlcpy(comment, identity_comment, sizeof(comment));
} else {
/* Create default comment field for the passphrase. */
snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
}
/* Save the key with the given passphrase and comment. */
if ((r = sshkey_save_private(private, identity_file, passphrase,
comment, private_key_format, openssh_format_cipher, rounds)) != 0) {
error_r(r, "Saving key \"%s\" failed", identity_file);
freezero(passphrase, strlen(passphrase));
exit(1);
}
freezero(passphrase, strlen(passphrase));
sshkey_free(private);
if (!quiet) {
printf("Your identification has been saved in %s\n",
identity_file);
}
strlcat(identity_file, ".pub", sizeof(identity_file));
if ((r = sshkey_save_public(public, identity_file, comment)) != 0)
fatal_r(r, "Unable to save public key to %s", identity_file);
if (!quiet) {
fp = sshkey_fingerprint(public, fingerprint_hash,
SSH_FP_DEFAULT);
ra = sshkey_fingerprint(public, fingerprint_hash,
SSH_FP_RANDOMART);
if (fp == NULL || ra == NULL)
fatal("sshkey_fingerprint failed");
printf("Your public key has been saved in %s\n",
identity_file);
printf("The key fingerprint is:\n");
printf("%s %s\n", fp, comment);
printf("The key's randomart image is:\n");
printf("%s\n", ra);
free(ra);
free(fp);
}
if (sk_attestation_path != NULL)
save_attestation(attest, sk_attestation_path);
sshbuf_free(attest);
sshkey_free(public);
exit(0);
}
diff --git a/ssh-keyscan.0 b/ssh-keyscan.0
index 1a5fefcbfc1d..e65b4259a9fa 100644
--- a/ssh-keyscan.0
+++ b/ssh-keyscan.0
@@ -1,96 +1,96 @@
SSH-KEYSCAN(1) General Commands Manual SSH-KEYSCAN(1)
NAME
ssh-keyscan M-bM-^@M-^S gather SSH public keys from servers
SYNOPSIS
ssh-keyscan [-46cDHv] [-f file] [-p port] [-T timeout] [-t type]
[host | addrlist namelist]
DESCRIPTION
ssh-keyscan is a utility for gathering the public SSH host keys of a
number of hosts. It was designed to aid in building and verifying
ssh_known_hosts files, the format of which is documented in sshd(8).
ssh-keyscan provides a minimal interface suitable for use by shell and
perl scripts.
ssh-keyscan uses non-blocking socket I/O to contact as many hosts as
possible in parallel, so it is very efficient. The keys from a domain of
1,000 hosts can be collected in tens of seconds, even when some of those
hosts are down or do not run sshd(8). For scanning, one does not need
login access to the machines that are being scanned, nor does the
scanning process involve any encryption.
The options are as follows:
-4 Force ssh-keyscan to use IPv4 addresses only.
-6 Force ssh-keyscan to use IPv6 addresses only.
-c Request certificates from target hosts instead of plain keys.
-D Print keys found as SSHFP DNS records. The default is to print
keys in a format usable as a ssh(1) known_hosts file.
-f file
Read hosts or M-bM-^@M-^\addrlist namelistM-bM-^@M-^] pairs from file, one per line.
If M-bM-^@M-^X-M-bM-^@M-^Y is supplied instead of a filename, ssh-keyscan will read
from the standard input. Input is expected in the format:
1.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4
-H Hash all hostnames and addresses in the output. Hashed names may
be used normally by ssh(1) and sshd(8), but they do not reveal
identifying information should the file's contents be disclosed.
-p port
Connect to port on the remote host.
-T timeout
Set the timeout for connection attempts. If timeout seconds have
elapsed since a connection was initiated to a host or since the
last time anything was read from that host, the connection is
closed and the host in question considered unavailable. The
default is 5 seconds.
-t type
Specify the type of the key to fetch from the scanned hosts. The
possible values are M-bM-^@M-^\dsaM-bM-^@M-^], M-bM-^@M-^\ecdsaM-bM-^@M-^], M-bM-^@M-^\ed25519M-bM-^@M-^], or M-bM-^@M-^\rsaM-bM-^@M-^].
Multiple values may be specified by separating them with commas.
The default is to fetch M-bM-^@M-^\rsaM-bM-^@M-^], M-bM-^@M-^\ecdsaM-bM-^@M-^], and M-bM-^@M-^\ed25519M-bM-^@M-^] keys.
-v Verbose mode: print debugging messages about progress.
If an ssh_known_hosts file is constructed using ssh-keyscan without
verifying the keys, users will be vulnerable to man in the middle
attacks. On the other hand, if the security model allows such a risk,
ssh-keyscan can help in the detection of tampered keyfiles or man in the
middle attacks which have begun after the ssh_known_hosts file was
created.
FILES
/etc/ssh/ssh_known_hosts
EXAMPLES
Print the RSA host key for machine hostname:
$ ssh-keyscan -t rsa hostname
Find all hosts from the file ssh_hosts which have new or different keys
from those in the sorted file ssh_known_hosts:
$ ssh-keyscan -t rsa,dsa,ecdsa,ed25519 -f ssh_hosts | \
sort -u - ssh_known_hosts | diff ssh_known_hosts -
SEE ALSO
ssh(1), sshd(8)
Using DNS to Securely Publish Secure Shell (SSH) Key Fingerprints, RFC
4255, 2006.
AUTHORS
David Mazieres <dm@lcs.mit.edu> wrote the initial version, and Wayne
Davison <wayned@users.sourceforge.net> added support for protocol version
2.
-OpenBSD 6.8 November 30, 2019 OpenBSD 6.8
+OpenBSD 6.9 November 30, 2019 OpenBSD 6.9
diff --git a/ssh-keysign.0 b/ssh-keysign.0
index b4ec3cc64a53..6d0c83997dd4 100644
--- a/ssh-keysign.0
+++ b/ssh-keysign.0
@@ -1,52 +1,52 @@
SSH-KEYSIGN(8) System Manager's Manual SSH-KEYSIGN(8)
NAME
ssh-keysign M-bM-^@M-^S OpenSSH helper for host-based authentication
SYNOPSIS
ssh-keysign
DESCRIPTION
ssh-keysign is used by ssh(1) to access the local host keys and generate
the digital signature required during host-based authentication.
ssh-keysign is disabled by default and can only be enabled in the global
client configuration file /etc/ssh/ssh_config by setting EnableSSHKeysign
to M-bM-^@M-^\yesM-bM-^@M-^].
ssh-keysign is not intended to be invoked by the user, but from ssh(1).
See ssh(1) and sshd(8) for more information about host-based
authentication.
FILES
/etc/ssh/ssh_config
Controls whether ssh-keysign is enabled.
/etc/ssh/ssh_host_dsa_key
/etc/ssh/ssh_host_ecdsa_key
/etc/ssh/ssh_host_ed25519_key
/etc/ssh/ssh_host_rsa_key
These files contain the private parts of the host keys used to
generate the digital signature. They should be owned by root,
readable only by root, and not accessible to others. Since they
are readable only by root, ssh-keysign must be set-uid root if
host-based authentication is used.
/etc/ssh/ssh_host_dsa_key-cert.pub
/etc/ssh/ssh_host_ecdsa_key-cert.pub
/etc/ssh/ssh_host_ed25519_key-cert.pub
/etc/ssh/ssh_host_rsa_key-cert.pub
If these files exist they are assumed to contain public
certificate information corresponding with the private keys
above.
SEE ALSO
ssh(1), ssh-keygen(1), ssh_config(5), sshd(8)
HISTORY
ssh-keysign first appeared in OpenBSD 3.2.
AUTHORS
Markus Friedl <markus@openbsd.org>
-OpenBSD 6.8 November 30, 2019 OpenBSD 6.8
+OpenBSD 6.9 November 30, 2019 OpenBSD 6.9
diff --git a/ssh-pkcs11-helper.0 b/ssh-pkcs11-helper.0
index 973b551a5b8d..0553465cf3be 100644
--- a/ssh-pkcs11-helper.0
+++ b/ssh-pkcs11-helper.0
@@ -1,35 +1,35 @@
SSH-PKCS11-HELPER(8) System Manager's Manual SSH-PKCS11-HELPER(8)
NAME
ssh-pkcs11-helper M-bM-^@M-^S OpenSSH helper for PKCS#11 support
SYNOPSIS
ssh-pkcs11-helper [-v]
DESCRIPTION
ssh-pkcs11-helper is used by ssh-agent(1) to access keys provided by a
PKCS#11 token.
ssh-pkcs11-helper is not intended to be invoked by the user, but from
ssh-agent(1).
A single option is supported:
-v Verbose mode. Causes ssh-pkcs11-helper to print debugging
messages about its progress. This is helpful in debugging
problems. Multiple -v options increase the verbosity. The
maximum is 3.
Note that ssh-agent(1) will automatically pass the -v flag to
ssh-pkcs11-helper when it has itself been placed in debug mode.
SEE ALSO
ssh(1), ssh-add(1), ssh-agent(1)
HISTORY
ssh-pkcs11-helper first appeared in OpenBSD 4.7.
AUTHORS
Markus Friedl <markus@openbsd.org>
-OpenBSD 6.8 November 30, 2019 OpenBSD 6.8
+OpenBSD 6.9 November 30, 2019 OpenBSD 6.9
diff --git a/ssh-sk-client.c b/ssh-sk-client.c
index 3102a2c99934..e932590094a2 100644
--- a/ssh-sk-client.c
+++ b/ssh-sk-client.c
@@ -1,448 +1,448 @@
-/* $OpenBSD: ssh-sk-client.c,v 1.8 2020/10/18 11:32:02 djm Exp $ */
+/* $OpenBSD: ssh-sk-client.c,v 1.9 2021/04/03 06:18:41 djm Exp $ */
/*
* Copyright (c) 2019 Google LLC
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <limits.h>
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "log.h"
#include "ssherr.h"
#include "sshbuf.h"
#include "sshkey.h"
#include "msg.h"
#include "digest.h"
#include "pathnames.h"
#include "ssh-sk.h"
#include "misc.h"
/* #define DEBUG_SK 1 */
static int
start_helper(int *fdp, pid_t *pidp, void (**osigchldp)(int))
{
void (*osigchld)(int);
int oerrno, pair[2];
pid_t pid;
char *helper, *verbosity = NULL;
*fdp = -1;
*pidp = 0;
*osigchldp = SIG_DFL;
helper = getenv("SSH_SK_HELPER");
if (helper == NULL || strlen(helper) == 0)
helper = _PATH_SSH_SK_HELPER;
if (access(helper, X_OK) != 0) {
oerrno = errno;
error_f("helper \"%s\" unusable: %s", helper, strerror(errno));
errno = oerrno;
return SSH_ERR_SYSTEM_ERROR;
}
#ifdef DEBUG_SK
verbosity = "-vvv";
#endif
/* Start helper */
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
error("socketpair: %s", strerror(errno));
return SSH_ERR_SYSTEM_ERROR;
}
osigchld = ssh_signal(SIGCHLD, SIG_DFL);
if ((pid = fork()) == -1) {
oerrno = errno;
error("fork: %s", strerror(errno));
close(pair[0]);
close(pair[1]);
ssh_signal(SIGCHLD, osigchld);
errno = oerrno;
return SSH_ERR_SYSTEM_ERROR;
}
if (pid == 0) {
if ((dup2(pair[1], STDIN_FILENO) == -1) ||
(dup2(pair[1], STDOUT_FILENO) == -1)) {
error_f("dup2: %s", strerror(errno));
_exit(1);
}
close(pair[0]);
close(pair[1]);
closefrom(STDERR_FILENO + 1);
debug_f("starting %s %s", helper,
verbosity == NULL ? "" : verbosity);
execlp(helper, helper, verbosity, (char *)NULL);
error_f("execlp: %s", strerror(errno));
_exit(1);
}
close(pair[1]);
/* success */
debug3_f("started pid=%ld", (long)pid);
*fdp = pair[0];
*pidp = pid;
*osigchldp = osigchld;
return 0;
}
static int
reap_helper(pid_t pid)
{
int status, oerrno;
debug3_f("pid=%ld", (long)pid);
errno = 0;
while (waitpid(pid, &status, 0) == -1) {
if (errno == EINTR) {
errno = 0;
continue;
}
oerrno = errno;
error_f("waitpid: %s", strerror(errno));
errno = oerrno;
return SSH_ERR_SYSTEM_ERROR;
}
if (!WIFEXITED(status)) {
error_f("helper exited abnormally");
return SSH_ERR_AGENT_FAILURE;
} else if (WEXITSTATUS(status) != 0) {
error_f("helper exited with non-zero exit status");
return SSH_ERR_AGENT_FAILURE;
}
return 0;
}
static int
client_converse(struct sshbuf *msg, struct sshbuf **respp, u_int type)
{
int oerrno, fd, r2, ll, r = SSH_ERR_INTERNAL_ERROR;
u_int rtype, rerr;
pid_t pid;
u_char version;
void (*osigchld)(int);
struct sshbuf *req = NULL, *resp = NULL;
*respp = NULL;
if ((r = start_helper(&fd, &pid, &osigchld)) != 0)
return r;
if ((req = sshbuf_new()) == NULL || (resp = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* Request preamble: type, log_on_stderr, log_level */
ll = log_level_get();
if ((r = sshbuf_put_u32(req, type)) != 0 ||
- (r = sshbuf_put_u8(req, log_is_on_stderr() != 0)) != 0 ||
- (r = sshbuf_put_u32(req, ll < 0 ? 0 : ll)) != 0 ||
- (r = sshbuf_putb(req, msg)) != 0) {
+ (r = sshbuf_put_u8(req, log_is_on_stderr() != 0)) != 0 ||
+ (r = sshbuf_put_u32(req, ll < 0 ? 0 : ll)) != 0 ||
+ (r = sshbuf_putb(req, msg)) != 0) {
error_fr(r, "compose");
goto out;
}
if ((r = ssh_msg_send(fd, SSH_SK_HELPER_VERSION, req)) != 0) {
error_fr(r, "send");
goto out;
}
if ((r = ssh_msg_recv(fd, resp)) != 0) {
error_fr(r, "receive");
goto out;
}
if ((r = sshbuf_get_u8(resp, &version)) != 0) {
error_fr(r, "parse version");
goto out;
}
if (version != SSH_SK_HELPER_VERSION) {
error_f("unsupported version: got %u, expected %u",
version, SSH_SK_HELPER_VERSION);
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((r = sshbuf_get_u32(resp, &rtype)) != 0) {
error_fr(r, "parse message type");
goto out;
}
if (rtype == SSH_SK_HELPER_ERROR) {
if ((r = sshbuf_get_u32(resp, &rerr)) != 0) {
error_fr(r, "parse");
goto out;
}
debug_f("helper returned error -%u", rerr);
/* OpenSSH error values are negative; encoded as -err on wire */
if (rerr == 0 || rerr >= INT_MAX)
r = SSH_ERR_INTERNAL_ERROR;
else
r = -(int)rerr;
goto out;
} else if (rtype != type) {
error_f("helper returned incorrect message type %u, "
"expecting %u", rtype, type);
r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
/* success */
r = 0;
out:
oerrno = errno;
close(fd);
if ((r2 = reap_helper(pid)) != 0) {
if (r == 0) {
r = r2;
oerrno = errno;
}
}
if (r == 0) {
*respp = resp;
resp = NULL;
}
sshbuf_free(req);
sshbuf_free(resp);
ssh_signal(SIGCHLD, osigchld);
errno = oerrno;
return r;
}
int
sshsk_sign(const char *provider, struct sshkey *key,
u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
u_int compat, const char *pin)
{
int oerrno, r = SSH_ERR_INTERNAL_ERROR;
char *fp = NULL;
struct sshbuf *kbuf = NULL, *req = NULL, *resp = NULL;
*sigp = NULL;
*lenp = 0;
#ifndef ENABLE_SK
return SSH_ERR_KEY_TYPE_UNKNOWN;
#endif
if ((kbuf = sshbuf_new()) == NULL ||
(req = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshkey_private_serialize(key, kbuf)) != 0) {
error_fr(r, "encode key");
goto out;
}
if ((r = sshbuf_put_stringb(req, kbuf)) != 0 ||
(r = sshbuf_put_cstring(req, provider)) != 0 ||
(r = sshbuf_put_string(req, data, datalen)) != 0 ||
(r = sshbuf_put_cstring(req, NULL)) != 0 || /* alg */
(r = sshbuf_put_u32(req, compat)) != 0 ||
(r = sshbuf_put_cstring(req, pin)) != 0) {
error_fr(r, "compose");
goto out;
}
if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
SSH_FP_DEFAULT)) == NULL) {
error_f("sshkey_fingerprint failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = client_converse(req, &resp, SSH_SK_HELPER_SIGN)) != 0)
goto out;
if ((r = sshbuf_get_string(resp, sigp, lenp)) != 0) {
error_fr(r, "parse signature");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (sshbuf_len(resp) != 0) {
error_f("trailing data in response");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* success */
r = 0;
out:
oerrno = errno;
if (r != 0) {
freezero(*sigp, *lenp);
*sigp = NULL;
*lenp = 0;
}
sshbuf_free(kbuf);
sshbuf_free(req);
sshbuf_free(resp);
errno = oerrno;
return r;
}
int
sshsk_enroll(int type, const char *provider_path, const char *device,
const char *application, const char *userid, uint8_t flags,
const char *pin, struct sshbuf *challenge_buf,
struct sshkey **keyp, struct sshbuf *attest)
{
int oerrno, r = SSH_ERR_INTERNAL_ERROR;
struct sshbuf *kbuf = NULL, *abuf = NULL, *req = NULL, *resp = NULL;
struct sshkey *key = NULL;
*keyp = NULL;
if (attest != NULL)
sshbuf_reset(attest);
#ifndef ENABLE_SK
return SSH_ERR_KEY_TYPE_UNKNOWN;
#endif
if (type < 0)
return SSH_ERR_INVALID_ARGUMENT;
if ((abuf = sshbuf_new()) == NULL ||
(kbuf = sshbuf_new()) == NULL ||
(req = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_put_u32(req, (u_int)type)) != 0 ||
(r = sshbuf_put_cstring(req, provider_path)) != 0 ||
(r = sshbuf_put_cstring(req, device)) != 0 ||
(r = sshbuf_put_cstring(req, application)) != 0 ||
(r = sshbuf_put_cstring(req, userid)) != 0 ||
(r = sshbuf_put_u8(req, flags)) != 0 ||
(r = sshbuf_put_cstring(req, pin)) != 0 ||
(r = sshbuf_put_stringb(req, challenge_buf)) != 0) {
error_fr(r, "compose");
goto out;
}
if ((r = client_converse(req, &resp, SSH_SK_HELPER_ENROLL)) != 0)
goto out;
if ((r = sshbuf_get_stringb(resp, kbuf)) != 0 ||
(r = sshbuf_get_stringb(resp, abuf)) != 0) {
error_fr(r, "parse");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (sshbuf_len(resp) != 0) {
error_f("trailing data in response");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((r = sshkey_private_deserialize(kbuf, &key)) != 0) {
error_fr(r, "encode");
goto out;
}
if (attest != NULL && (r = sshbuf_putb(attest, abuf)) != 0) {
error_fr(r, "encode attestation information");
goto out;
}
/* success */
r = 0;
*keyp = key;
key = NULL;
out:
oerrno = errno;
sshkey_free(key);
sshbuf_free(kbuf);
sshbuf_free(abuf);
sshbuf_free(req);
sshbuf_free(resp);
errno = oerrno;
return r;
}
int
sshsk_load_resident(const char *provider_path, const char *device,
const char *pin, struct sshkey ***keysp, size_t *nkeysp)
{
int oerrno, r = SSH_ERR_INTERNAL_ERROR;
struct sshbuf *kbuf = NULL, *req = NULL, *resp = NULL;
struct sshkey *key = NULL, **keys = NULL, **tmp;
size_t i, nkeys = 0;
*keysp = NULL;
*nkeysp = 0;
if ((resp = sshbuf_new()) == NULL ||
(kbuf = sshbuf_new()) == NULL ||
(req = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_put_cstring(req, provider_path)) != 0 ||
(r = sshbuf_put_cstring(req, device)) != 0 ||
(r = sshbuf_put_cstring(req, pin)) != 0) {
error_fr(r, "compose");
goto out;
}
if ((r = client_converse(req, &resp, SSH_SK_HELPER_LOAD_RESIDENT)) != 0)
goto out;
while (sshbuf_len(resp) != 0) {
/* key, comment */
if ((r = sshbuf_get_stringb(resp, kbuf)) != 0 ||
(r = sshbuf_get_cstring(resp, NULL, NULL)) != 0) {
error_fr(r, "parse signature");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((r = sshkey_private_deserialize(kbuf, &key)) != 0) {
error_fr(r, "decode key");
goto out;
}
if ((tmp = recallocarray(keys, nkeys, nkeys + 1,
sizeof(*keys))) == NULL) {
error_f("recallocarray keys failed");
goto out;
}
debug_f("keys[%zu]: %s %s", nkeys, sshkey_type(key),
key->sk_application);
keys = tmp;
keys[nkeys++] = key;
key = NULL;
}
/* success */
r = 0;
*keysp = keys;
*nkeysp = nkeys;
keys = NULL;
nkeys = 0;
out:
oerrno = errno;
for (i = 0; i < nkeys; i++)
sshkey_free(keys[i]);
free(keys);
sshkey_free(key);
sshbuf_free(kbuf);
sshbuf_free(req);
sshbuf_free(resp);
errno = oerrno;
return r;
}
diff --git a/ssh.0 b/ssh.0
index e69ce2fa0d3c..113fe49cda98 100644
--- a/ssh.0
+++ b/ssh.0
@@ -1,1004 +1,1004 @@
SSH(1) General Commands Manual SSH(1)
NAME
ssh M-bM-^@M-^S OpenSSH remote login client
SYNOPSIS
ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface] [-b bind_address]
[-c cipher_spec] [-D [bind_address:]port] [-E log_file]
[-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file]
[-J destination] [-L address] [-l login_name] [-m mac_spec]
[-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address]
[-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]] destination
[command]
DESCRIPTION
ssh (SSH client) is a program for logging into a remote machine and for
executing commands on a remote machine. It is intended to provide secure
encrypted communications between two untrusted hosts over an insecure
network. X11 connections, arbitrary TCP ports and UNIX-domain sockets
can also be forwarded over the secure channel.
ssh connects and logs into the specified destination, which may be
specified as either [user@]hostname or a URI of the form
ssh://[user@]hostname[:port]. The user must prove his/her identity to
the remote machine using one of several methods (see below).
If a command is specified, it is executed on the remote host instead of a
login shell.
The options are as follows:
-4 Forces ssh to use IPv4 addresses only.
-6 Forces ssh to use IPv6 addresses only.
-A Enables forwarding of connections from an authentication agent
such as ssh-agent(1). This can also be specified on a per-host
basis in a configuration file.
Agent forwarding should be enabled with caution. Users with the
ability to bypass file permissions on the remote host (for the
agent's UNIX-domain socket) can access the local agent through
the forwarded connection. An attacker cannot obtain key material
from the agent, however they can perform operations on the keys
that enable them to authenticate using the identities loaded into
the agent. A safer alternative may be to use a jump host (see
-J).
-a Disables forwarding of the authentication agent connection.
-B bind_interface
Bind to the address of bind_interface before attempting to
connect to the destination host. This is only useful on systems
with more than one address.
-b bind_address
Use bind_address on the local machine as the source address of
the connection. Only useful on systems with more than one
address.
-C Requests compression of all data (including stdin, stdout,
stderr, and data for forwarded X11, TCP and UNIX-domain
connections). The compression algorithm is the same used by
gzip(1). Compression is desirable on modem lines and other slow
connections, but will only slow down things on fast networks.
The default value can be set on a host-by-host basis in the
configuration files; see the Compression option.
-c cipher_spec
Selects the cipher specification for encrypting the session.
cipher_spec is a comma-separated list of ciphers listed in order
of preference. See the Ciphers keyword in ssh_config(5) for more
information.
-D [bind_address:]port
Specifies a local M-bM-^@M-^\dynamicM-bM-^@M-^] application-level port forwarding.
This works by allocating a socket to listen to port on the local
side, optionally bound to the specified bind_address. Whenever a
connection is made to this port, the connection is forwarded over
the secure channel, and the application protocol is then used to
determine where to connect to from the remote machine. Currently
the SOCKS4 and SOCKS5 protocols are supported, and ssh will act
as a SOCKS server. Only root can forward privileged ports.
Dynamic port forwardings can also be specified in the
configuration file.
IPv6 addresses can be specified by enclosing the address in
square brackets. Only the superuser can forward privileged
ports. By default, the local port is bound in accordance with
the GatewayPorts setting. However, an explicit bind_address may
be used to bind the connection to a specific address. The
bind_address of M-bM-^@M-^\localhostM-bM-^@M-^] indicates that the listening port be
bound for local use only, while an empty address or M-bM-^@M-^X*M-bM-^@M-^Y indicates
that the port should be available from all interfaces.
-E log_file
Append debug logs to log_file instead of standard error.
-e escape_char
Sets the escape character for sessions with a pty (default: M-bM-^@M-^X~M-bM-^@M-^Y).
The escape character is only recognized at the beginning of a
line. The escape character followed by a dot (M-bM-^@M-^X.M-bM-^@M-^Y) closes the
connection; followed by control-Z suspends the connection; and
followed by itself sends the escape character once. Setting the
character to M-bM-^@M-^\noneM-bM-^@M-^] disables any escapes and makes the session
fully transparent.
-F configfile
Specifies an alternative per-user configuration file. If a
configuration file is given on the command line, the system-wide
configuration file (/etc/ssh/ssh_config) will be ignored. The
default for the per-user configuration file is ~/.ssh/config. If
set to M-bM-^@M-^\noneM-bM-^@M-^], no configuration files will be read.
-f Requests ssh to go to background just before command execution.
This is useful if ssh is going to ask for passwords or
passphrases, but the user wants it in the background. This
implies -n. The recommended way to start X11 programs at a
remote site is with something like ssh -f host xterm.
If the ExitOnForwardFailure configuration option is set to M-bM-^@M-^\yesM-bM-^@M-^],
then a client started with -f will wait for all remote port
forwards to be successfully established before placing itself in
the background.
-G Causes ssh to print its configuration after evaluating Host and
Match blocks and exit.
-g Allows remote hosts to connect to local forwarded ports. If used
on a multiplexed connection, then this option must be specified
on the master process.
-I pkcs11
Specify the PKCS#11 shared library ssh should use to communicate
with a PKCS#11 token providing keys for user authentication.
-i identity_file
Selects a file from which the identity (private key) for public
key authentication is read. The default is ~/.ssh/id_dsa,
~/.ssh/id_ecdsa, ~/.ssh/id_ecdsa_sk, ~/.ssh/id_ed25519,
~/.ssh/id_ed25519_sk and ~/.ssh/id_rsa. Identity files may also
be specified on a per-host basis in the configuration file. It
is possible to have multiple -i options (and multiple identities
specified in configuration files). If no certificates have been
explicitly specified by the CertificateFile directive, ssh will
also try to load certificate information from the filename
obtained by appending -cert.pub to identity filenames.
-J destination
Connect to the target host by first making a ssh connection to
the jump host described by destination and then establishing a
TCP forwarding to the ultimate destination from there. Multiple
jump hops may be specified separated by comma characters. This
is a shortcut to specify a ProxyJump configuration directive.
Note that configuration directives supplied on the command-line
generally apply to the destination host and not any specified
jump hosts. Use ~/.ssh/config to specify configuration for jump
hosts.
-K Enables GSSAPI-based authentication and forwarding (delegation)
of GSSAPI credentials to the server.
-k Disables forwarding (delegation) of GSSAPI credentials to the
server.
-L [bind_address:]port:host:hostport
-L [bind_address:]port:remote_socket
-L local_socket:host:hostport
-L local_socket:remote_socket
Specifies that connections to the given TCP port or Unix socket
on the local (client) host are to be forwarded to the given host
and port, or Unix socket, on the remote side. This works by
allocating a socket to listen to either a TCP port on the local
side, optionally bound to the specified bind_address, or to a
Unix socket. Whenever a connection is made to the local port or
socket, the connection is forwarded over the secure channel, and
a connection is made to either host port hostport, or the Unix
socket remote_socket, from the remote machine.
Port forwardings can also be specified in the configuration file.
Only the superuser can forward privileged ports. IPv6 addresses
can be specified by enclosing the address in square brackets.
By default, the local port is bound in accordance with the
GatewayPorts setting. However, an explicit bind_address may be
used to bind the connection to a specific address. The
bind_address of M-bM-^@M-^\localhostM-bM-^@M-^] indicates that the listening port be
bound for local use only, while an empty address or M-bM-^@M-^X*M-bM-^@M-^Y indicates
that the port should be available from all interfaces.
-l login_name
Specifies the user to log in as on the remote machine. This also
may be specified on a per-host basis in the configuration file.
-M Places the ssh client into M-bM-^@M-^\masterM-bM-^@M-^] mode for connection sharing.
Multiple -M options places ssh into M-bM-^@M-^\masterM-bM-^@M-^] mode but with
confirmation required using ssh-askpass(1) before each operation
that changes the multiplexing state (e.g. opening a new session).
Refer to the description of ControlMaster in ssh_config(5) for
details.
-m mac_spec
A comma-separated list of MAC (message authentication code)
algorithms, specified in order of preference. See the MACs
keyword for more information.
-N Do not execute a remote command. This is useful for just
forwarding ports.
-n Redirects stdin from /dev/null (actually, prevents reading from
stdin). This must be used when ssh is run in the background. A
common trick is to use this to run X11 programs on a remote
machine. For example, ssh -n shadows.cs.hut.fi emacs & will
start an emacs on shadows.cs.hut.fi, and the X11 connection will
be automatically forwarded over an encrypted channel. The ssh
program will be put in the background. (This does not work if
ssh needs to ask for a password or passphrase; see also the -f
option.)
-O ctl_cmd
Control an active connection multiplexing master process. When
the -O option is specified, the ctl_cmd argument is interpreted
and passed to the master process. Valid commands are: M-bM-^@M-^\checkM-bM-^@M-^]
(check that the master process is running), M-bM-^@M-^\forwardM-bM-^@M-^] (request
forwardings without command execution), M-bM-^@M-^\cancelM-bM-^@M-^] (cancel
forwardings), M-bM-^@M-^\exitM-bM-^@M-^] (request the master to exit), and M-bM-^@M-^\stopM-bM-^@M-^]
(request the master to stop accepting further multiplexing
requests).
-o option
Can be used to give options in the format used in the
configuration file. This is useful for specifying options for
which there is no separate command-line flag. For full details
of the options listed below, and their possible values, see
ssh_config(5).
AddKeysToAgent
AddressFamily
BatchMode
BindAddress
CanonicalDomains
CanonicalizeFallbackLocal
CanonicalizeHostname
CanonicalizeMaxDots
CanonicalizePermittedCNAMEs
CASignatureAlgorithms
CertificateFile
ChallengeResponseAuthentication
CheckHostIP
Ciphers
ClearAllForwardings
Compression
ConnectionAttempts
ConnectTimeout
ControlMaster
ControlPath
ControlPersist
DynamicForward
EscapeChar
ExitOnForwardFailure
FingerprintHash
ForwardAgent
ForwardX11
ForwardX11Timeout
ForwardX11Trusted
GatewayPorts
GlobalKnownHostsFile
GSSAPIAuthentication
GSSAPIDelegateCredentials
HashKnownHosts
Host
HostbasedAcceptedAlgorithms
HostbasedAuthentication
HostKeyAlgorithms
HostKeyAlias
Hostname
IdentitiesOnly
IdentityAgent
IdentityFile
IPQoS
KbdInteractiveAuthentication
KbdInteractiveDevices
KexAlgorithms
KnownHostsCommand
LocalCommand
LocalForward
LogLevel
MACs
Match
NoHostAuthenticationForLocalhost
NumberOfPasswordPrompts
PasswordAuthentication
PermitLocalCommand
PermitRemoteOpen
PKCS11Provider
Port
PreferredAuthentications
ProxyCommand
ProxyJump
ProxyUseFdpass
PubkeyAcceptedAlgorithms
PubkeyAuthentication
RekeyLimit
RemoteCommand
RemoteForward
RequestTTY
SendEnv
ServerAliveInterval
ServerAliveCountMax
SetEnv
StreamLocalBindMask
StreamLocalBindUnlink
StrictHostKeyChecking
TCPKeepAlive
Tunnel
TunnelDevice
UpdateHostKeys
User
UserKnownHostsFile
VerifyHostKeyDNS
VisualHostKey
XAuthLocation
-p port
Port to connect to on the remote host. This can be specified on
a per-host basis in the configuration file.
-Q query_option
Queries ssh for the algorithms supported for the specified
version 2. The available features are: cipher (supported
symmetric ciphers), cipher-auth (supported symmetric ciphers that
support authenticated encryption), help (supported query terms
for use with the -Q flag), mac (supported message integrity
codes), kex (key exchange algorithms), key (key types), key-cert
(certificate key types), key-plain (non-certificate key types),
key-sig (all key types and signature algorithms),
protocol-version (supported SSH protocol versions), and sig
(supported signature algorithms). Alternatively, any keyword
from ssh_config(5) or sshd_config(5) that takes an algorithm list
may be used as an alias for the corresponding query_option.
-q Quiet mode. Causes most warning and diagnostic messages to be
suppressed.
-R [bind_address:]port:host:hostport
-R [bind_address:]port:local_socket
-R remote_socket:host:hostport
-R remote_socket:local_socket
-R [bind_address:]port
Specifies that connections to the given TCP port or Unix socket
on the remote (server) host are to be forwarded to the local
side.
This works by allocating a socket to listen to either a TCP port
or to a Unix socket on the remote side. Whenever a connection is
made to this port or Unix socket, the connection is forwarded
over the secure channel, and a connection is made from the local
machine to either an explicit destination specified by host port
hostport, or local_socket, or, if no explicit destination was
specified, ssh will act as a SOCKS 4/5 proxy and forward
connections to the destinations requested by the remote SOCKS
client.
Port forwardings can also be specified in the configuration file.
Privileged ports can be forwarded only when logging in as root on
the remote machine. IPv6 addresses can be specified by enclosing
the address in square brackets.
By default, TCP listening sockets on the server will be bound to
the loopback interface only. This may be overridden by
specifying a bind_address. An empty bind_address, or the address
M-bM-^@M-^X*M-bM-^@M-^Y, indicates that the remote socket should listen on all
interfaces. Specifying a remote bind_address will only succeed
if the server's GatewayPorts option is enabled (see
sshd_config(5)).
If the port argument is M-bM-^@M-^X0M-bM-^@M-^Y, the listen port will be dynamically
allocated on the server and reported to the client at run time.
When used together with -O forward the allocated port will be
printed to the standard output.
-S ctl_path
Specifies the location of a control socket for connection
sharing, or the string M-bM-^@M-^\noneM-bM-^@M-^] to disable connection sharing.
Refer to the description of ControlPath and ControlMaster in
ssh_config(5) for details.
-s May be used to request invocation of a subsystem on the remote
system. Subsystems facilitate the use of SSH as a secure
transport for other applications (e.g. sftp(1)). The subsystem
is specified as the remote command.
-T Disable pseudo-terminal allocation.
-t Force pseudo-terminal allocation. This can be used to execute
arbitrary screen-based programs on a remote machine, which can be
very useful, e.g. when implementing menu services. Multiple -t
options force tty allocation, even if ssh has no local tty.
-V Display the version number and exit.
-v Verbose mode. Causes ssh to print debugging messages about its
progress. This is helpful in debugging connection,
authentication, and configuration problems. Multiple -v options
increase the verbosity. The maximum is 3.
-W host:port
Requests that standard input and output on the client be
forwarded to host on port over the secure channel. Implies -N,
-T, ExitOnForwardFailure and ClearAllForwardings, though these
can be overridden in the configuration file or using -o command
line options.
-w local_tun[:remote_tun]
Requests tunnel device forwarding with the specified tun(4)
devices between the client (local_tun) and the server
(remote_tun).
The devices may be specified by numerical ID or the keyword
M-bM-^@M-^\anyM-bM-^@M-^], which uses the next available tunnel device. If
remote_tun is not specified, it defaults to M-bM-^@M-^\anyM-bM-^@M-^]. See also the
Tunnel and TunnelDevice directives in ssh_config(5).
If the Tunnel directive is unset, it will be set to the default
tunnel mode, which is M-bM-^@M-^\point-to-pointM-bM-^@M-^]. If a different Tunnel
forwarding mode it desired, then it should be specified before
-w.
-X Enables X11 forwarding. This can also be specified on a per-host
basis in a configuration file.
X11 forwarding should be enabled with caution. Users with the
ability to bypass file permissions on the remote host (for the
user's X authorization database) can access the local X11 display
through the forwarded connection. An attacker may then be able
to perform activities such as keystroke monitoring.
For this reason, X11 forwarding is subjected to X11 SECURITY
extension restrictions by default. Please refer to the ssh -Y
option and the ForwardX11Trusted directive in ssh_config(5) for
more information.
-x Disables X11 forwarding.
-Y Enables trusted X11 forwarding. Trusted X11 forwardings are not
subjected to the X11 SECURITY extension controls.
-y Send log information using the syslog(3) system module. By
default this information is sent to stderr.
ssh may additionally obtain configuration data from a per-user
configuration file and a system-wide configuration file. The file format
and configuration options are described in ssh_config(5).
AUTHENTICATION
The OpenSSH SSH client supports SSH protocol 2.
The methods available for authentication are: GSSAPI-based
authentication, host-based authentication, public key authentication,
challenge-response authentication, and password authentication.
Authentication methods are tried in the order specified above, though
PreferredAuthentications can be used to change the default order.
Host-based authentication works as follows: If the machine the user logs
in from is listed in /etc/hosts.equiv or /etc/shosts.equiv on the remote
machine, the user is non-root and the user names are the same on both
sides, or if the files ~/.rhosts or ~/.shosts exist in the user's home
directory on the remote machine and contain a line containing the name of
the client machine and the name of the user on that machine, the user is
considered for login. Additionally, the server must be able to verify
the client's host key (see the description of /etc/ssh/ssh_known_hosts
and ~/.ssh/known_hosts, below) for login to be permitted. This
authentication method closes security holes due to IP spoofing, DNS
spoofing, and routing spoofing. [Note to the administrator:
/etc/hosts.equiv, ~/.rhosts, and the rlogin/rsh protocol in general, are
inherently insecure and should be disabled if security is desired.]
Public key authentication works as follows: The scheme is based on
public-key cryptography, using cryptosystems where encryption and
decryption are done using separate keys, and it is unfeasible to derive
the decryption key from the encryption key. The idea is that each user
creates a public/private key pair for authentication purposes. The
server knows the public key, and only the user knows the private key.
ssh implements public key authentication protocol automatically, using
one of the DSA, ECDSA, Ed25519 or RSA algorithms. The HISTORY section of
ssl(8) contains a brief discussion of the DSA and RSA algorithms.
The file ~/.ssh/authorized_keys lists the public keys that are permitted
for logging in. When the user logs in, the ssh program tells the server
which key pair it would like to use for authentication. The client
proves that it has access to the private key and the server checks that
the corresponding public key is authorized to accept the account.
The server may inform the client of errors that prevented public key
authentication from succeeding after authentication completes using a
different method. These may be viewed by increasing the LogLevel to
DEBUG or higher (e.g. by using the -v flag).
The user creates his/her key pair by running ssh-keygen(1). This stores
the private key in ~/.ssh/id_dsa (DSA), ~/.ssh/id_ecdsa (ECDSA),
~/.ssh/id_ecdsa_sk (authenticator-hosted ECDSA), ~/.ssh/id_ed25519
(Ed25519), ~/.ssh/id_ed25519_sk (authenticator-hosted Ed25519), or
~/.ssh/id_rsa (RSA) and stores the public key in ~/.ssh/id_dsa.pub (DSA),
~/.ssh/id_ecdsa.pub (ECDSA), ~/.ssh/id_ecdsa_sk.pub (authenticator-hosted
ECDSA), ~/.ssh/id_ed25519.pub (Ed25519), ~/.ssh/id_ed25519_sk.pub
(authenticator-hosted Ed25519), or ~/.ssh/id_rsa.pub (RSA) in the user's
home directory. The user should then copy the public key to
~/.ssh/authorized_keys in his/her home directory on the remote machine.
The authorized_keys file corresponds to the conventional ~/.rhosts file,
and has one key per line, though the lines can be very long. After this,
the user can log in without giving the password.
A variation on public key authentication is available in the form of
certificate authentication: instead of a set of public/private keys,
signed certificates are used. This has the advantage that a single
trusted certification authority can be used in place of many
public/private keys. See the CERTIFICATES section of ssh-keygen(1) for
more information.
The most convenient way to use public key or certificate authentication
may be with an authentication agent. See ssh-agent(1) and (optionally)
the AddKeysToAgent directive in ssh_config(5) for more information.
Challenge-response authentication works as follows: The server sends an
arbitrary "challenge" text, and prompts for a response. Examples of
challenge-response authentication include BSD Authentication (see
login.conf(5)) and PAM (some non-OpenBSD systems).
Finally, if other authentication methods fail, ssh prompts the user for a
password. The password is sent to the remote host for checking; however,
since all communications are encrypted, the password cannot be seen by
someone listening on the network.
ssh automatically maintains and checks a database containing
identification for all hosts it has ever been used with. Host keys are
stored in ~/.ssh/known_hosts in the user's home directory. Additionally,
the file /etc/ssh/ssh_known_hosts is automatically checked for known
hosts. Any new hosts are automatically added to the user's file. If a
host's identification ever changes, ssh warns about this and disables
password authentication to prevent server spoofing or man-in-the-middle
attacks, which could otherwise be used to circumvent the encryption. The
StrictHostKeyChecking option can be used to control logins to machines
whose host key is not known or has changed.
When the user's identity has been accepted by the server, the server
either executes the given command in a non-interactive session or, if no
command has been specified, logs into the machine and gives the user a
normal shell as an interactive session. All communication with the
remote command or shell will be automatically encrypted.
If an interactive session is requested ssh by default will only request a
pseudo-terminal (pty) for interactive sessions when the client has one.
The flags -T and -t can be used to override this behaviour.
If a pseudo-terminal has been allocated the user may use the escape
characters noted below.
If no pseudo-terminal has been allocated, the session is transparent and
can be used to reliably transfer binary data. On most systems, setting
the escape character to M-bM-^@M-^\noneM-bM-^@M-^] will also make the session transparent
even if a tty is used.
The session terminates when the command or shell on the remote machine
exits and all X11 and TCP connections have been closed.
ESCAPE CHARACTERS
When a pseudo-terminal has been requested, ssh supports a number of
functions through the use of an escape character.
A single tilde character can be sent as ~~ or by following the tilde by a
character other than those described below. The escape character must
always follow a newline to be interpreted as special. The escape
character can be changed in configuration files using the EscapeChar
configuration directive or on the command line by the -e option.
The supported escapes (assuming the default M-bM-^@M-^X~M-bM-^@M-^Y) are:
~. Disconnect.
~^Z Background ssh.
~# List forwarded connections.
~& Background ssh at logout when waiting for forwarded connection /
X11 sessions to terminate.
~? Display a list of escape characters.
~B Send a BREAK to the remote system (only useful if the peer
supports it).
~C Open command line. Currently this allows the addition of port
forwardings using the -L, -R and -D options (see above). It also
allows the cancellation of existing port-forwardings with
-KL[bind_address:]port for local, -KR[bind_address:]port for
remote and -KD[bind_address:]port for dynamic port-forwardings.
!command allows the user to execute a local command if the
PermitLocalCommand option is enabled in ssh_config(5). Basic
help is available, using the -h option.
~R Request rekeying of the connection (only useful if the peer
supports it).
~V Decrease the verbosity (LogLevel) when errors are being written
to stderr.
~v Increase the verbosity (LogLevel) when errors are being written
to stderr.
TCP FORWARDING
Forwarding of arbitrary TCP connections over a secure channel can be
specified either on the command line or in a configuration file. One
possible application of TCP forwarding is a secure connection to a mail
server; another is going through firewalls.
In the example below, we look at encrypting communication for an IRC
client, even though the IRC server it connects to does not directly
support encrypted communication. This works as follows: the user
connects to the remote host using ssh, specifying the ports to be used to
forward the connection. After that it is possible to start the program
locally, and ssh will encrypt and forward the connection to the remote
server.
The following example tunnels an IRC session from the client to an IRC
server at M-bM-^@M-^\server.example.comM-bM-^@M-^], joining channel M-bM-^@M-^\#usersM-bM-^@M-^], nickname
M-bM-^@M-^\pinkyM-bM-^@M-^], using the standard IRC port, 6667:
$ ssh -f -L 6667:localhost:6667 server.example.com sleep 10
$ irc -c '#users' pinky IRC/127.0.0.1
The -f option backgrounds ssh and the remote command M-bM-^@M-^\sleep 10M-bM-^@M-^] is
specified to allow an amount of time (10 seconds, in the example) to
start the program which is going to use the tunnel. If no connections
are made within the time specified, ssh will exit.
X11 FORWARDING
If the ForwardX11 variable is set to M-bM-^@M-^\yesM-bM-^@M-^] (or see the description of the
-X, -x, and -Y options above) and the user is using X11 (the DISPLAY
environment variable is set), the connection to the X11 display is
automatically forwarded to the remote side in such a way that any X11
programs started from the shell (or command) will go through the
encrypted channel, and the connection to the real X server will be made
from the local machine. The user should not manually set DISPLAY.
Forwarding of X11 connections can be configured on the command line or in
configuration files.
The DISPLAY value set by ssh will point to the server machine, but with a
display number greater than zero. This is normal, and happens because
ssh creates a M-bM-^@M-^\proxyM-bM-^@M-^] X server on the server machine for forwarding the
connections over the encrypted channel.
ssh will also automatically set up Xauthority data on the server machine.
For this purpose, it will generate a random authorization cookie, store
it in Xauthority on the server, and verify that any forwarded connections
carry this cookie and replace it by the real cookie when the connection
is opened. The real authentication cookie is never sent to the server
machine (and no cookies are sent in the plain).
If the ForwardAgent variable is set to M-bM-^@M-^\yesM-bM-^@M-^] (or see the description of
the -A and -a options above) and the user is using an authentication
agent, the connection to the agent is automatically forwarded to the
remote side.
VERIFYING HOST KEYS
When connecting to a server for the first time, a fingerprint of the
server's public key is presented to the user (unless the option
StrictHostKeyChecking has been disabled). Fingerprints can be determined
using ssh-keygen(1):
$ ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key
If the fingerprint is already known, it can be matched and the key can be
accepted or rejected. If only legacy (MD5) fingerprints for the server
are available, the ssh-keygen(1) -E option may be used to downgrade the
fingerprint algorithm to match.
Because of the difficulty of comparing host keys just by looking at
fingerprint strings, there is also support to compare host keys visually,
using random art. By setting the VisualHostKey option to M-bM-^@M-^\yesM-bM-^@M-^], a small
ASCII graphic gets displayed on every login to a server, no matter if the
session itself is interactive or not. By learning the pattern a known
server produces, a user can easily find out that the host key has changed
when a completely different pattern is displayed. Because these patterns
are not unambiguous however, a pattern that looks similar to the pattern
remembered only gives a good probability that the host key is the same,
not guaranteed proof.
To get a listing of the fingerprints along with their random art for all
known hosts, the following command line can be used:
$ ssh-keygen -lv -f ~/.ssh/known_hosts
If the fingerprint is unknown, an alternative method of verification is
available: SSH fingerprints verified by DNS. An additional resource
record (RR), SSHFP, is added to a zonefile and the connecting client is
able to match the fingerprint with that of the key presented.
In this example, we are connecting a client to a server,
M-bM-^@M-^\host.example.comM-bM-^@M-^]. The SSHFP resource records should first be added to
the zonefile for host.example.com:
$ ssh-keygen -r host.example.com.
The output lines will have to be added to the zonefile. To check that
the zone is answering fingerprint queries:
$ dig -t SSHFP host.example.com
Finally the client connects:
$ ssh -o "VerifyHostKeyDNS ask" host.example.com
[...]
Matching host key fingerprint found in DNS.
Are you sure you want to continue connecting (yes/no)?
See the VerifyHostKeyDNS option in ssh_config(5) for more information.
SSH-BASED VIRTUAL PRIVATE NETWORKS
ssh contains support for Virtual Private Network (VPN) tunnelling using
the tun(4) network pseudo-device, allowing two networks to be joined
securely. The sshd_config(5) configuration option PermitTunnel controls
whether the server supports this, and at what level (layer 2 or 3
traffic).
The following example would connect client network 10.0.50.0/24 with
remote network 10.0.99.0/24 using a point-to-point connection from
10.1.1.1 to 10.1.1.2, provided that the SSH server running on the gateway
to the remote network, at 192.168.1.15, allows it.
On the client:
# ssh -f -w 0:1 192.168.1.15 true
# ifconfig tun0 10.1.1.1 10.1.1.2 netmask 255.255.255.252
# route add 10.0.99.0/24 10.1.1.2
On the server:
# ifconfig tun1 10.1.1.2 10.1.1.1 netmask 255.255.255.252
# route add 10.0.50.0/24 10.1.1.1
Client access may be more finely tuned via the /root/.ssh/authorized_keys
file (see below) and the PermitRootLogin server option. The following
entry would permit connections on tun(4) device 1 from user M-bM-^@M-^\janeM-bM-^@M-^] and on
tun device 2 from user M-bM-^@M-^\johnM-bM-^@M-^], if PermitRootLogin is set to
M-bM-^@M-^\forced-commands-onlyM-bM-^@M-^]:
tunnel="1",command="sh /etc/netstart tun1" ssh-rsa ... jane
tunnel="2",command="sh /etc/netstart tun2" ssh-rsa ... john
Since an SSH-based setup entails a fair amount of overhead, it may be
more suited to temporary setups, such as for wireless VPNs. More
permanent VPNs are better provided by tools such as ipsecctl(8) and
isakmpd(8).
ENVIRONMENT
ssh will normally set the following environment variables:
DISPLAY The DISPLAY variable indicates the location of the
X11 server. It is automatically set by ssh to
point to a value of the form M-bM-^@M-^\hostname:nM-bM-^@M-^], where
M-bM-^@M-^\hostnameM-bM-^@M-^] indicates the host where the shell runs,
and M-bM-^@M-^XnM-bM-^@M-^Y is an integer M-bM-^IM-% 1. ssh uses this special
value to forward X11 connections over the secure
channel. The user should normally not set DISPLAY
explicitly, as that will render the X11 connection
insecure (and will require the user to manually
copy any required authorization cookies).
HOME Set to the path of the user's home directory.
LOGNAME Synonym for USER; set for compatibility with
systems that use this variable.
MAIL Set to the path of the user's mailbox.
PATH Set to the default PATH, as specified when
compiling ssh.
SSH_ASKPASS If ssh needs a passphrase, it will read the
passphrase from the current terminal if it was run
from a terminal. If ssh does not have a terminal
associated with it but DISPLAY and SSH_ASKPASS are
set, it will execute the program specified by
SSH_ASKPASS and open an X11 window to read the
passphrase. This is particularly useful when
calling ssh from a .xsession or related script.
(Note that on some machines it may be necessary to
redirect the input from /dev/null to make this
work.)
SSH_ASKPASS_REQUIRE Allows further control over the use of an askpass
program. If this variable is set to M-bM-^@M-^\neverM-bM-^@M-^] then
ssh will never attempt to use one. If it is set to
M-bM-^@M-^\preferM-bM-^@M-^], then ssh will prefer to use the askpass
program instead of the TTY when requesting
passwords. Finally, if the variable is set to
M-bM-^@M-^\forceM-bM-^@M-^], then the askpass program will be used for
all passphrase input regardless of whether DISPLAY
is set.
SSH_AUTH_SOCK Identifies the path of a UNIX-domain socket used to
communicate with the agent.
SSH_CONNECTION Identifies the client and server ends of the
connection. The variable contains four space-
separated values: client IP address, client port
number, server IP address, and server port number.
SSH_ORIGINAL_COMMAND This variable contains the original command line if
a forced command is executed. It can be used to
extract the original arguments.
SSH_TTY This is set to the name of the tty (path to the
device) associated with the current shell or
command. If the current session has no tty, this
variable is not set.
SSH_TUNNEL Optionally set by sshd(8) to contain the interface
names assigned if tunnel forwarding was requested
by the client.
SSH_USER_AUTH Optionally set by sshd(8), this variable may
contain a pathname to a file that lists the
authentication methods successfully used when the
session was established, including any public keys
that were used.
TZ This variable is set to indicate the present time
zone if it was set when the daemon was started
(i.e. the daemon passes the value on to new
connections).
USER Set to the name of the user logging in.
Additionally, ssh reads ~/.ssh/environment, and adds lines of the format
M-bM-^@M-^\VARNAME=valueM-bM-^@M-^] to the environment if the file exists and users are
allowed to change their environment. For more information, see the
PermitUserEnvironment option in sshd_config(5).
FILES
~/.rhosts
This file is used for host-based authentication (see above). On
some machines this file may need to be world-readable if the
user's home directory is on an NFS partition, because sshd(8)
reads it as root. Additionally, this file must be owned by the
user, and must not have write permissions for anyone else. The
recommended permission for most machines is read/write for the
user, and not accessible by others.
~/.shosts
This file is used in exactly the same way as .rhosts, but allows
host-based authentication without permitting login with
rlogin/rsh.
~/.ssh/
This directory is the default location for all user-specific
configuration and authentication information. There is no
general requirement to keep the entire contents of this directory
secret, but the recommended permissions are read/write/execute
for the user, and not accessible by others.
~/.ssh/authorized_keys
Lists the public keys (DSA, ECDSA, Ed25519, RSA) that can be used
for logging in as this user. The format of this file is
described in the sshd(8) manual page. This file is not highly
sensitive, but the recommended permissions are read/write for the
user, and not accessible by others.
~/.ssh/config
This is the per-user configuration file. The file format and
configuration options are described in ssh_config(5). Because of
the potential for abuse, this file must have strict permissions:
read/write for the user, and not writable by others.
~/.ssh/environment
Contains additional definitions for environment variables; see
ENVIRONMENT, above.
~/.ssh/id_dsa
~/.ssh/id_ecdsa
~/.ssh/id_ecdsa_sk
~/.ssh/id_ed25519
~/.ssh/id_ed25519_sk
~/.ssh/id_rsa
Contains the private key for authentication. These files contain
sensitive data and should be readable by the user but not
accessible by others (read/write/execute). ssh will simply
ignore a private key file if it is accessible by others. It is
possible to specify a passphrase when generating the key which
will be used to encrypt the sensitive part of this file using
AES-128.
~/.ssh/id_dsa.pub
~/.ssh/id_ecdsa.pub
~/.ssh/id_ecdsa_sk.pub
~/.ssh/id_ed25519.pub
~/.ssh/id_ed25519_sk.pub
~/.ssh/id_rsa.pub
Contains the public key for authentication. These files are not
sensitive and can (but need not) be readable by anyone.
~/.ssh/known_hosts
Contains a list of host keys for all hosts the user has logged
into that are not already in the systemwide list of known host
keys. See sshd(8) for further details of the format of this
file.
~/.ssh/rc
Commands in this file are executed by ssh when the user logs in,
just before the user's shell (or command) is started. See the
sshd(8) manual page for more information.
/etc/hosts.equiv
This file is for host-based authentication (see above). It
should only be writable by root.
/etc/shosts.equiv
This file is used in exactly the same way as hosts.equiv, but
allows host-based authentication without permitting login with
rlogin/rsh.
/etc/ssh/ssh_config
Systemwide configuration file. The file format and configuration
options are described in ssh_config(5).
/etc/ssh/ssh_host_key
/etc/ssh/ssh_host_dsa_key
/etc/ssh/ssh_host_ecdsa_key
/etc/ssh/ssh_host_ed25519_key
/etc/ssh/ssh_host_rsa_key
These files contain the private parts of the host keys and are
used for host-based authentication.
/etc/ssh/ssh_known_hosts
Systemwide list of known host keys. This file should be prepared
by the system administrator to contain the public host keys of
all machines in the organization. It should be world-readable.
See sshd(8) for further details of the format of this file.
/etc/ssh/sshrc
Commands in this file are executed by ssh when the user logs in,
just before the user's shell (or command) is started. See the
sshd(8) manual page for more information.
EXIT STATUS
ssh exits with the exit status of the remote command or with 255 if an
error occurred.
SEE ALSO
scp(1), sftp(1), ssh-add(1), ssh-agent(1), ssh-keygen(1), ssh-keyscan(1),
tun(4), ssh_config(5), ssh-keysign(8), sshd(8)
STANDARDS
S. Lehtinen and C. Lonvick, The Secure Shell (SSH) Protocol Assigned
Numbers, RFC 4250, January 2006.
T. Ylonen and C. Lonvick, The Secure Shell (SSH) Protocol Architecture,
RFC 4251, January 2006.
T. Ylonen and C. Lonvick, The Secure Shell (SSH) Authentication Protocol,
RFC 4252, January 2006.
T. Ylonen and C. Lonvick, The Secure Shell (SSH) Transport Layer
Protocol, RFC 4253, January 2006.
T. Ylonen and C. Lonvick, The Secure Shell (SSH) Connection Protocol, RFC
4254, January 2006.
J. Schlyter and W. Griffin, Using DNS to Securely Publish Secure Shell
(SSH) Key Fingerprints, RFC 4255, January 2006.
F. Cusack and M. Forssen, Generic Message Exchange Authentication for the
Secure Shell Protocol (SSH), RFC 4256, January 2006.
J. Galbraith and P. Remaker, The Secure Shell (SSH) Session Channel Break
Extension, RFC 4335, January 2006.
M. Bellare, T. Kohno, and C. Namprempre, The Secure Shell (SSH) Transport
Layer Encryption Modes, RFC 4344, January 2006.
B. Harris, Improved Arcfour Modes for the Secure Shell (SSH) Transport
Layer Protocol, RFC 4345, January 2006.
M. Friedl, N. Provos, and W. Simpson, Diffie-Hellman Group Exchange for
the Secure Shell (SSH) Transport Layer Protocol, RFC 4419, March 2006.
J. Galbraith and R. Thayer, The Secure Shell (SSH) Public Key File
Format, RFC 4716, November 2006.
D. Stebila and J. Green, Elliptic Curve Algorithm Integration in the
Secure Shell Transport Layer, RFC 5656, December 2009.
A. Perrig and D. Song, Hash Visualization: a New Technique to improve
Real-World Security, 1999, International Workshop on Cryptographic
Techniques and E-Commerce (CrypTEC '99).
AUTHORS
OpenSSH is a derivative of the original and free ssh 1.2.12 release by
Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo
de Raadt and Dug Song removed many bugs, re-added newer features and
created OpenSSH. Markus Friedl contributed the support for SSH protocol
versions 1.5 and 2.0.
-OpenBSD 6.8 February 15, 2021 OpenBSD 6.8
+OpenBSD 6.9 February 15, 2021 OpenBSD 6.9
diff --git a/ssh.c b/ssh.c
index 53330da5aecd..35b6b517616e 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,2368 +1,2372 @@
-/* $OpenBSD: ssh.c,v 1.552 2021/02/23 00:05:31 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.553 2021/04/03 05:40:39 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Ssh client program. This program can be used to log into a remote machine.
* The software supports strong authentication, encryption, and forwarding
* of X11, TCP/IP, and authentication connections.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
* Copyright (c) 1999 Niels Provos. All rights reserved.
* Copyright (c) 2000, 2001, 2002, 2003 Markus Friedl. All rights reserved.
*
* Modified to work with SSLeay by Niels Provos <provos@citi.umich.edu>
* in Canada (German citizen).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <sys/resource.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <limits.h>
#include <locale.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef WITH_OPENSSL
#include <openssl/evp.h>
#include <openssl/err.h>
#endif
#include "openbsd-compat/openssl-compat.h"
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "ssh.h"
#include "ssh2.h"
#include "canohost.h"
#include "compat.h"
#include "cipher.h"
#include "packet.h"
#include "sshbuf.h"
#include "channels.h"
#include "sshkey.h"
#include "authfd.h"
#include "authfile.h"
#include "pathnames.h"
#include "dispatch.h"
#include "clientloop.h"
#include "log.h"
#include "misc.h"
#include "readconf.h"
#include "sshconnect.h"
#include "kex.h"
#include "mac.h"
#include "sshpty.h"
#include "match.h"
#include "msg.h"
#include "version.h"
#include "ssherr.h"
#include "myproposal.h"
#include "utf8.h"
#ifdef ENABLE_PKCS11
#include "ssh-pkcs11.h"
#endif
extern char *__progname;
/* Saves a copy of argv for setproctitle emulation */
#ifndef HAVE_SETPROCTITLE
static char **saved_av;
#endif
/* Flag indicating whether debug mode is on. May be set on the command line. */
int debug_flag = 0;
/* Flag indicating whether a tty should be requested */
int tty_flag = 0;
/* don't exec a shell */
int no_shell_flag = 0;
/*
* Flag indicating that nothing should be read from stdin. This can be set
* on the command line.
*/
int stdin_null_flag = 0;
/*
* Flag indicating that the current process should be backgrounded and
* a new mux-client launched in the foreground for ControlPersist.
*/
int need_controlpersist_detach = 0;
/* Copies of flags for ControlPersist foreground mux-client */
int ostdin_null_flag, ono_shell_flag, otty_flag, orequest_tty;
/*
* Flag indicating that ssh should fork after authentication. This is useful
* so that the passphrase can be entered manually, and then ssh goes to the
* background.
*/
int fork_after_authentication_flag = 0;
/*
* General data structure for command line options and options configurable
* in configuration files. See readconf.h.
*/
Options options;
/* optional user configfile */
char *config = NULL;
/*
* Name of the host we are connecting to. This is the name given on the
* command line, or the Hostname specified for the user-supplied name in a
* configuration file.
*/
char *host;
/*
* A config can specify a path to forward, overriding SSH_AUTH_SOCK. If this is
* not NULL, forward the socket at this path instead.
*/
char *forward_agent_sock_path = NULL;
/* socket address the host resolves to */
struct sockaddr_storage hostaddr;
/* Private host keys. */
Sensitive sensitive_data;
/* command to be executed */
struct sshbuf *command;
/* Should we execute a command or invoke a subsystem? */
int subsystem_flag = 0;
/* # of replies received for global requests */
static int forward_confirms_pending = -1;
/* mux.c */
extern int muxserver_sock;
extern u_int muxclient_command;
/* Prints a help message to the user. This function never returns. */
static void
usage(void)
{
fprintf(stderr,
"usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface]\n"
" [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]\n"
" [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11]\n"
" [-i identity_file] [-J [user@]host[:port]] [-L address]\n"
" [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n"
" [-Q query_option] [-R address] [-S ctl_path] [-W host:port]\n"
" [-w local_tun[:remote_tun]] destination [command]\n"
);
exit(255);
}
static int ssh_session2(struct ssh *, const struct ssh_conn_info *);
static void load_public_identity_files(const struct ssh_conn_info *);
static void main_sigchld_handler(int);
/* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */
static void
tilde_expand_paths(char **paths, u_int num_paths)
{
u_int i;
char *cp;
for (i = 0; i < num_paths; i++) {
cp = tilde_expand_filename(paths[i], getuid());
free(paths[i]);
paths[i] = cp;
}
}
/*
* Expands the set of percent_expand options used by the majority of keywords
* in the client that support percent expansion.
* Caller must free returned string.
*/
static char *
default_client_percent_expand(const char *str,
const struct ssh_conn_info *cinfo)
{
return percent_expand(str,
DEFAULT_CLIENT_PERCENT_EXPAND_ARGS(cinfo),
(char *)NULL);
}
/*
* Expands the set of percent_expand options used by the majority of keywords
* AND perform environment variable substitution.
* Caller must free returned string.
*/
static char *
default_client_percent_dollar_expand(const char *str,
const struct ssh_conn_info *cinfo)
{
char *ret;
ret = percent_dollar_expand(str,
DEFAULT_CLIENT_PERCENT_EXPAND_ARGS(cinfo),
(char *)NULL);
if (ret == NULL)
fatal("invalid environment variable expansion");
return ret;
}
/*
* Attempt to resolve a host name / port to a set of addresses and
* optionally return any CNAMEs encountered along the way.
* Returns NULL on failure.
* NB. this function must operate with a options having undefined members.
*/
static struct addrinfo *
resolve_host(const char *name, int port, int logerr, char *cname, size_t clen)
{
char strport[NI_MAXSERV];
struct addrinfo hints, *res;
int gaierr;
LogLevel loglevel = SYSLOG_LEVEL_DEBUG1;
if (port <= 0)
port = default_ssh_port();
if (cname != NULL)
*cname = '\0';
snprintf(strport, sizeof strport, "%d", port);
memset(&hints, 0, sizeof(hints));
hints.ai_family = options.address_family == -1 ?
AF_UNSPEC : options.address_family;
hints.ai_socktype = SOCK_STREAM;
if (cname != NULL)
hints.ai_flags = AI_CANONNAME;
if ((gaierr = getaddrinfo(name, strport, &hints, &res)) != 0) {
if (logerr || (gaierr != EAI_NONAME && gaierr != EAI_NODATA))
loglevel = SYSLOG_LEVEL_ERROR;
do_log2(loglevel, "%s: Could not resolve hostname %.100s: %s",
__progname, name, ssh_gai_strerror(gaierr));
return NULL;
}
if (cname != NULL && res->ai_canonname != NULL) {
if (strlcpy(cname, res->ai_canonname, clen) >= clen) {
error_f("host \"%s\" cname \"%s\" too long (max %lu)",
name, res->ai_canonname, (u_long)clen);
if (clen > 0)
*cname = '\0';
}
}
return res;
}
/* Returns non-zero if name can only be an address and not a hostname */
static int
is_addr_fast(const char *name)
{
return (strchr(name, '%') != NULL || strchr(name, ':') != NULL ||
strspn(name, "0123456789.") == strlen(name));
}
/* Returns non-zero if name represents a valid, single address */
static int
is_addr(const char *name)
{
char strport[NI_MAXSERV];
struct addrinfo hints, *res;
if (is_addr_fast(name))
return 1;
snprintf(strport, sizeof strport, "%u", default_ssh_port());
memset(&hints, 0, sizeof(hints));
hints.ai_family = options.address_family == -1 ?
AF_UNSPEC : options.address_family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV;
if (getaddrinfo(name, strport, &hints, &res) != 0)
return 0;
if (res == NULL || res->ai_next != NULL) {
freeaddrinfo(res);
return 0;
}
freeaddrinfo(res);
return 1;
}
/*
* Attempt to resolve a numeric host address / port to a single address.
* Returns a canonical address string.
* Returns NULL on failure.
* NB. this function must operate with a options having undefined members.
*/
static struct addrinfo *
resolve_addr(const char *name, int port, char *caddr, size_t clen)
{
char addr[NI_MAXHOST], strport[NI_MAXSERV];
struct addrinfo hints, *res;
int gaierr;
if (port <= 0)
port = default_ssh_port();
snprintf(strport, sizeof strport, "%u", port);
memset(&hints, 0, sizeof(hints));
hints.ai_family = options.address_family == -1 ?
AF_UNSPEC : options.address_family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV;
if ((gaierr = getaddrinfo(name, strport, &hints, &res)) != 0) {
debug2_f("could not resolve name %.100s as address: %s",
name, ssh_gai_strerror(gaierr));
return NULL;
}
if (res == NULL) {
debug_f("getaddrinfo %.100s returned no addresses", name);
return NULL;
}
if (res->ai_next != NULL) {
debug_f("getaddrinfo %.100s returned multiple addresses", name);
goto fail;
}
if ((gaierr = getnameinfo(res->ai_addr, res->ai_addrlen,
addr, sizeof(addr), NULL, 0, NI_NUMERICHOST)) != 0) {
debug_f("Could not format address for name %.100s: %s",
name, ssh_gai_strerror(gaierr));
goto fail;
}
if (strlcpy(caddr, addr, clen) >= clen) {
error_f("host \"%s\" addr \"%s\" too long (max %lu)",
name, addr, (u_long)clen);
if (clen > 0)
*caddr = '\0';
fail:
freeaddrinfo(res);
return NULL;
}
return res;
}
/*
* Check whether the cname is a permitted replacement for the hostname
* and perform the replacement if it is.
* NB. this function must operate with a options having undefined members.
*/
static int
check_follow_cname(int direct, char **namep, const char *cname)
{
int i;
struct allowed_cname *rule;
if (*cname == '\0' || options.num_permitted_cnames == 0 ||
strcmp(*namep, cname) == 0)
return 0;
if (options.canonicalize_hostname == SSH_CANONICALISE_NO)
return 0;
/*
* Don't attempt to canonicalize names that will be interpreted by
* a proxy or jump host unless the user specifically requests so.
*/
if (!direct &&
options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
return 0;
debug3_f("check \"%s\" CNAME \"%s\"", *namep, cname);
for (i = 0; i < options.num_permitted_cnames; i++) {
rule = options.permitted_cnames + i;
if (match_pattern_list(*namep, rule->source_list, 1) != 1 ||
match_pattern_list(cname, rule->target_list, 1) != 1)
continue;
verbose("Canonicalized DNS aliased hostname "
"\"%s\" => \"%s\"", *namep, cname);
free(*namep);
*namep = xstrdup(cname);
return 1;
}
return 0;
}
/*
* Attempt to resolve the supplied hostname after applying the user's
* canonicalization rules. Returns the address list for the host or NULL
* if no name was found after canonicalization.
* NB. this function must operate with a options having undefined members.
*/
static struct addrinfo *
resolve_canonicalize(char **hostp, int port)
{
int i, direct, ndots;
char *cp, *fullhost, newname[NI_MAXHOST];
struct addrinfo *addrs;
/*
* Attempt to canonicalise addresses, regardless of
* whether hostname canonicalisation was requested
*/
if ((addrs = resolve_addr(*hostp, port,
newname, sizeof(newname))) != NULL) {
debug2_f("hostname %.100s is address", *hostp);
if (strcasecmp(*hostp, newname) != 0) {
debug2_f("canonicalised address \"%s\" => \"%s\"",
*hostp, newname);
free(*hostp);
*hostp = xstrdup(newname);
}
return addrs;
}
/*
* If this looks like an address but didn't parse as one, it might
* be an address with an invalid interface scope. Skip further
* attempts at canonicalisation.
*/
if (is_addr_fast(*hostp)) {
debug_f("hostname %.100s is an unrecognised address", *hostp);
return NULL;
}
if (options.canonicalize_hostname == SSH_CANONICALISE_NO)
return NULL;
/*
* Don't attempt to canonicalize names that will be interpreted by
* a proxy unless the user specifically requests so.
*/
direct = option_clear_or_none(options.proxy_command) &&
options.jump_host == NULL;
if (!direct &&
options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
return NULL;
/* If domain name is anchored, then resolve it now */
if ((*hostp)[strlen(*hostp) - 1] == '.') {
debug3_f("name is fully qualified");
fullhost = xstrdup(*hostp);
if ((addrs = resolve_host(fullhost, port, 0,
newname, sizeof(newname))) != NULL)
goto found;
free(fullhost);
goto notfound;
}
/* Don't apply canonicalization to sufficiently-qualified hostnames */
ndots = 0;
for (cp = *hostp; *cp != '\0'; cp++) {
if (*cp == '.')
ndots++;
}
if (ndots > options.canonicalize_max_dots) {
debug3_f("not canonicalizing hostname \"%s\" (max dots %d)",
*hostp, options.canonicalize_max_dots);
return NULL;
}
/* Attempt each supplied suffix */
for (i = 0; i < options.num_canonical_domains; i++) {
xasprintf(&fullhost, "%s.%s.", *hostp,
options.canonical_domains[i]);
debug3_f("attempting \"%s\" => \"%s\"", *hostp, fullhost);
if ((addrs = resolve_host(fullhost, port, 0,
newname, sizeof(newname))) == NULL) {
free(fullhost);
continue;
}
found:
/* Remove trailing '.' */
fullhost[strlen(fullhost) - 1] = '\0';
/* Follow CNAME if requested */
if (!check_follow_cname(direct, &fullhost, newname)) {
debug("Canonicalized hostname \"%s\" => \"%s\"",
*hostp, fullhost);
}
free(*hostp);
*hostp = fullhost;
return addrs;
}
notfound:
if (!options.canonicalize_fallback_local)
fatal("%s: Could not resolve host \"%s\"", __progname, *hostp);
debug2_f("host %s not found in any suffix", *hostp);
return NULL;
}
/*
* Check the result of hostkey loading, ignoring some errors and
* fatal()ing for others.
*/
static void
check_load(int r, const char *path, const char *message)
{
switch (r) {
case 0:
break;
case SSH_ERR_INTERNAL_ERROR:
case SSH_ERR_ALLOC_FAIL:
fatal_r(r, "load %s \"%s\"", message, path);
case SSH_ERR_SYSTEM_ERROR:
/* Ignore missing files */
if (errno == ENOENT)
break;
/* FALLTHROUGH */
default:
error_r(r, "load %s \"%s\"", message, path);
break;
}
}
/*
* Read per-user configuration file. Ignore the system wide config
* file if the user specifies a config file on the command line.
*/
static void
process_config_files(const char *host_name, struct passwd *pw, int final_pass,
int *want_final_pass)
{
char buf[PATH_MAX];
int r;
if (config != NULL) {
if (strcasecmp(config, "none") != 0 &&
!read_config_file(config, pw, host, host_name, &options,
SSHCONF_USERCONF | (final_pass ? SSHCONF_FINAL : 0),
want_final_pass))
fatal("Can't open user config file %.100s: "
"%.100s", config, strerror(errno));
} else {
r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
_PATH_SSH_USER_CONFFILE);
if (r > 0 && (size_t)r < sizeof(buf))
(void)read_config_file(buf, pw, host, host_name,
&options, SSHCONF_CHECKPERM | SSHCONF_USERCONF |
(final_pass ? SSHCONF_FINAL : 0), want_final_pass);
/* Read systemwide configuration file after user config. */
(void)read_config_file(_PATH_HOST_CONFIG_FILE, pw,
host, host_name, &options,
final_pass ? SSHCONF_FINAL : 0, want_final_pass);
}
}
/* Rewrite the port number in an addrinfo list of addresses */
static void
set_addrinfo_port(struct addrinfo *addrs, int port)
{
struct addrinfo *addr;
for (addr = addrs; addr != NULL; addr = addr->ai_next) {
switch (addr->ai_family) {
case AF_INET:
((struct sockaddr_in *)addr->ai_addr)->
sin_port = htons(port);
break;
case AF_INET6:
((struct sockaddr_in6 *)addr->ai_addr)->
sin6_port = htons(port);
break;
}
}
}
static void
ssh_conn_info_free(struct ssh_conn_info *cinfo)
{
if (cinfo == NULL)
return;
free(cinfo->conn_hash_hex);
free(cinfo->shorthost);
free(cinfo->uidstr);
free(cinfo->keyalias);
free(cinfo->thishost);
free(cinfo->host_arg);
free(cinfo->portstr);
free(cinfo->remhost);
free(cinfo->remuser);
free(cinfo->homedir);
free(cinfo->locuser);
free(cinfo);
}
/*
* Main program for the ssh client.
*/
int
main(int ac, char **av)
{
struct ssh *ssh = NULL;
int i, r, opt, exit_status, use_syslog, direct, timeout_ms;
int was_addr, config_test = 0, opt_terminated = 0, want_final_pass = 0;
char *p, *cp, *line, *argv0, *logfile, *host_arg;
char cname[NI_MAXHOST], thishost[NI_MAXHOST];
struct stat st;
struct passwd *pw;
extern int optind, optreset;
extern char *optarg;
struct Forward fwd;
struct addrinfo *addrs = NULL;
size_t n, len;
u_int j;
struct ssh_conn_info *cinfo = NULL;
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
sanitise_stdfd();
__progname = ssh_get_progname(av[0]);
#ifndef HAVE_SETPROCTITLE
/* Prepare for later setproctitle emulation */
/* Save argv so it isn't clobbered by setproctitle() emulation */
saved_av = xcalloc(ac + 1, sizeof(*saved_av));
for (i = 0; i < ac; i++)
saved_av[i] = xstrdup(av[i]);
saved_av[i] = NULL;
compat_init_setproctitle(ac, av);
av = saved_av;
#endif
seed_rng();
/*
* Discard other fds that are hanging around. These can cause problem
* with backgrounded ssh processes started by ControlPersist.
*/
closefrom(STDERR_FILENO + 1);
/* Get user data. */
pw = getpwuid(getuid());
if (!pw) {
logit("No user exists for uid %lu", (u_long)getuid());
exit(255);
}
/* Take a copy of the returned structure. */
pw = pwcopy(pw);
/*
* Set our umask to something reasonable, as some files are created
* with the default umask. This will make them world-readable but
* writable only by the owner, which is ok for all files for which we
* don't set the modes explicitly.
*/
umask(022);
msetlocale();
/*
* Initialize option structure to indicate that no values have been
* set.
*/
initialize_options(&options);
/*
* Prepare main ssh transport/connection structures
*/
if ((ssh = ssh_alloc_session_state()) == NULL)
fatal("Couldn't allocate session state");
channel_init_channels(ssh);
/* Parse command-line arguments. */
host = NULL;
use_syslog = 0;
logfile = NULL;
argv0 = av[0];
again:
while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
"AB:CD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
switch (opt) {
case '1':
fatal("SSH protocol v.1 is no longer supported");
break;
case '2':
/* Ignored */
break;
case '4':
options.address_family = AF_INET;
break;
case '6':
options.address_family = AF_INET6;
break;
case 'n':
stdin_null_flag = 1;
break;
case 'f':
fork_after_authentication_flag = 1;
stdin_null_flag = 1;
break;
case 'x':
options.forward_x11 = 0;
break;
case 'X':
options.forward_x11 = 1;
break;
case 'y':
use_syslog = 1;
break;
case 'E':
logfile = optarg;
break;
case 'G':
config_test = 1;
break;
case 'Y':
options.forward_x11 = 1;
options.forward_x11_trusted = 1;
break;
case 'g':
options.fwd_opts.gateway_ports = 1;
break;
case 'O':
if (options.stdio_forward_host != NULL)
fatal("Cannot specify multiplexing "
"command with -W");
else if (muxclient_command != 0)
fatal("Multiplexing command already specified");
if (strcmp(optarg, "check") == 0)
muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK;
else if (strcmp(optarg, "forward") == 0)
muxclient_command = SSHMUX_COMMAND_FORWARD;
else if (strcmp(optarg, "exit") == 0)
muxclient_command = SSHMUX_COMMAND_TERMINATE;
else if (strcmp(optarg, "stop") == 0)
muxclient_command = SSHMUX_COMMAND_STOP;
else if (strcmp(optarg, "cancel") == 0)
muxclient_command = SSHMUX_COMMAND_CANCEL_FWD;
else if (strcmp(optarg, "proxy") == 0)
muxclient_command = SSHMUX_COMMAND_PROXY;
else
fatal("Invalid multiplex command.");
break;
case 'P': /* deprecated */
break;
case 'Q':
cp = NULL;
if (strcmp(optarg, "cipher") == 0 ||
strcasecmp(optarg, "Ciphers") == 0)
cp = cipher_alg_list('\n', 0);
else if (strcmp(optarg, "cipher-auth") == 0)
cp = cipher_alg_list('\n', 1);
else if (strcmp(optarg, "mac") == 0 ||
strcasecmp(optarg, "MACs") == 0)
cp = mac_alg_list('\n');
else if (strcmp(optarg, "kex") == 0 ||
strcasecmp(optarg, "KexAlgorithms") == 0)
cp = kex_alg_list('\n');
else if (strcmp(optarg, "key") == 0)
cp = sshkey_alg_list(0, 0, 0, '\n');
else if (strcmp(optarg, "key-cert") == 0)
cp = sshkey_alg_list(1, 0, 0, '\n');
else if (strcmp(optarg, "key-plain") == 0)
cp = sshkey_alg_list(0, 1, 0, '\n');
else if (strcmp(optarg, "key-sig") == 0 ||
strcasecmp(optarg, "PubkeyAcceptedKeyTypes") == 0 || /* deprecated name */
strcasecmp(optarg, "PubkeyAcceptedAlgorithms") == 0 ||
strcasecmp(optarg, "HostKeyAlgorithms") == 0 ||
strcasecmp(optarg, "HostbasedKeyTypes") == 0 || /* deprecated name */
strcasecmp(optarg, "HostbasedAcceptedKeyTypes") == 0 || /* deprecated name */
strcasecmp(optarg, "HostbasedAcceptedAlgorithms") == 0)
cp = sshkey_alg_list(0, 0, 1, '\n');
else if (strcmp(optarg, "sig") == 0)
cp = sshkey_alg_list(0, 1, 1, '\n');
else if (strcmp(optarg, "protocol-version") == 0)
cp = xstrdup("2");
else if (strcmp(optarg, "compression") == 0) {
cp = xstrdup(compression_alg_list(0));
len = strlen(cp);
for (n = 0; n < len; n++)
if (cp[n] == ',')
cp[n] = '\n';
} else if (strcmp(optarg, "help") == 0) {
cp = xstrdup(
"cipher\ncipher-auth\ncompression\nkex\n"
"key\nkey-cert\nkey-plain\nkey-sig\nmac\n"
"protocol-version\nsig");
}
if (cp == NULL)
fatal("Unsupported query \"%s\"", optarg);
printf("%s\n", cp);
free(cp);
exit(0);
break;
case 'a':
options.forward_agent = 0;
break;
case 'A':
options.forward_agent = 1;
break;
case 'k':
options.gss_deleg_creds = 0;
break;
case 'K':
options.gss_authentication = 1;
options.gss_deleg_creds = 1;
break;
case 'i':
p = tilde_expand_filename(optarg, getuid());
if (stat(p, &st) == -1)
fprintf(stderr, "Warning: Identity file %s "
"not accessible: %s.\n", p,
strerror(errno));
else
add_identity_file(&options, NULL, p, 1);
free(p);
break;
case 'I':
#ifdef ENABLE_PKCS11
free(options.pkcs11_provider);
options.pkcs11_provider = xstrdup(optarg);
#else
fprintf(stderr, "no support for PKCS#11.\n");
#endif
break;
case 'J':
if (options.jump_host != NULL) {
fatal("Only a single -J option is permitted "
"(use commas to separate multiple "
"jump hops)");
}
if (options.proxy_command != NULL)
fatal("Cannot specify -J with ProxyCommand");
if (parse_jump(optarg, &options, 1) == -1)
fatal("Invalid -J argument");
options.proxy_command = xstrdup("none");
break;
case 't':
if (options.request_tty == REQUEST_TTY_YES)
options.request_tty = REQUEST_TTY_FORCE;
else
options.request_tty = REQUEST_TTY_YES;
break;
case 'v':
if (debug_flag == 0) {
debug_flag = 1;
options.log_level = SYSLOG_LEVEL_DEBUG1;
} else {
if (options.log_level < SYSLOG_LEVEL_DEBUG3) {
debug_flag++;
options.log_level++;
}
}
break;
case 'V':
fprintf(stderr, "%s, %s\n",
SSH_RELEASE, SSH_OPENSSL_VERSION);
if (opt == 'V')
exit(0);
break;
case 'w':
if (options.tun_open == -1)
options.tun_open = SSH_TUNMODE_DEFAULT;
options.tun_local = a2tun(optarg, &options.tun_remote);
if (options.tun_local == SSH_TUNID_ERR) {
fprintf(stderr,
"Bad tun device '%s'\n", optarg);
exit(255);
}
break;
case 'W':
if (options.stdio_forward_host != NULL)
fatal("stdio forward already specified");
if (muxclient_command != 0)
fatal("Cannot specify stdio forward with -O");
if (parse_forward(&fwd, optarg, 1, 0)) {
options.stdio_forward_host = fwd.listen_host;
options.stdio_forward_port = fwd.listen_port;
free(fwd.connect_host);
} else {
fprintf(stderr,
"Bad stdio forwarding specification '%s'\n",
optarg);
exit(255);
}
options.request_tty = REQUEST_TTY_NO;
no_shell_flag = 1;
break;
case 'q':
options.log_level = SYSLOG_LEVEL_QUIET;
break;
case 'e':
if (optarg[0] == '^' && optarg[2] == 0 &&
(u_char) optarg[1] >= 64 &&
(u_char) optarg[1] < 128)
options.escape_char = (u_char) optarg[1] & 31;
else if (strlen(optarg) == 1)
options.escape_char = (u_char) optarg[0];
else if (strcmp(optarg, "none") == 0)
options.escape_char = SSH_ESCAPECHAR_NONE;
else {
fprintf(stderr, "Bad escape character '%s'.\n",
optarg);
exit(255);
}
break;
case 'c':
if (!ciphers_valid(*optarg == '+' || *optarg == '^' ?
optarg + 1 : optarg)) {
fprintf(stderr, "Unknown cipher type '%s'\n",
optarg);
exit(255);
}
free(options.ciphers);
options.ciphers = xstrdup(optarg);
break;
case 'm':
if (mac_valid(optarg)) {
free(options.macs);
options.macs = xstrdup(optarg);
} else {
fprintf(stderr, "Unknown mac type '%s'\n",
optarg);
exit(255);
}
break;
case 'M':
if (options.control_master == SSHCTL_MASTER_YES)
options.control_master = SSHCTL_MASTER_ASK;
else
options.control_master = SSHCTL_MASTER_YES;
break;
case 'p':
if (options.port == -1) {
options.port = a2port(optarg);
if (options.port <= 0) {
fprintf(stderr, "Bad port '%s'\n",
optarg);
exit(255);
}
}
break;
case 'l':
if (options.user == NULL)
options.user = optarg;
break;
case 'L':
if (parse_forward(&fwd, optarg, 0, 0))
add_local_forward(&options, &fwd);
else {
fprintf(stderr,
"Bad local forwarding specification '%s'\n",
optarg);
exit(255);
}
break;
case 'R':
if (parse_forward(&fwd, optarg, 0, 1) ||
parse_forward(&fwd, optarg, 1, 1)) {
add_remote_forward(&options, &fwd);
} else {
fprintf(stderr,
"Bad remote forwarding specification "
"'%s'\n", optarg);
exit(255);
}
break;
case 'D':
if (parse_forward(&fwd, optarg, 1, 0)) {
add_local_forward(&options, &fwd);
} else {
fprintf(stderr,
"Bad dynamic forwarding specification "
"'%s'\n", optarg);
exit(255);
}
break;
case 'C':
#ifdef WITH_ZLIB
options.compression = 1;
#else
error("Compression not supported, disabling.");
#endif
break;
case 'N':
no_shell_flag = 1;
options.request_tty = REQUEST_TTY_NO;
break;
case 'T':
options.request_tty = REQUEST_TTY_NO;
break;
case 'o':
line = xstrdup(optarg);
if (process_config_line(&options, pw,
host ? host : "", host ? host : "", line,
"command-line", 0, NULL, SSHCONF_USERCONF) != 0)
exit(255);
free(line);
break;
case 's':
subsystem_flag = 1;
break;
case 'S':
free(options.control_path);
options.control_path = xstrdup(optarg);
break;
case 'b':
options.bind_address = optarg;
break;
case 'B':
options.bind_interface = optarg;
break;
case 'F':
config = optarg;
break;
default:
usage();
}
}
if (optind > 1 && strcmp(av[optind - 1], "--") == 0)
opt_terminated = 1;
ac -= optind;
av += optind;
if (ac > 0 && !host) {
int tport;
char *tuser;
switch (parse_ssh_uri(*av, &tuser, &host, &tport)) {
case -1:
usage();
break;
case 0:
if (options.user == NULL) {
options.user = tuser;
tuser = NULL;
}
free(tuser);
if (options.port == -1 && tport != -1)
options.port = tport;
break;
default:
p = xstrdup(*av);
cp = strrchr(p, '@');
if (cp != NULL) {
if (cp == p)
usage();
if (options.user == NULL) {
options.user = p;
p = NULL;
}
*cp++ = '\0';
host = xstrdup(cp);
free(p);
} else
host = p;
break;
}
if (ac > 1 && !opt_terminated) {
optind = optreset = 1;
goto again;
}
ac--, av++;
}
/* Check that we got a host name. */
if (!host)
usage();
host_arg = xstrdup(host);
/* Initialize the command to execute on remote host. */
if ((command = sshbuf_new()) == NULL)
fatal("sshbuf_new failed");
/*
* Save the command to execute on the remote host in a buffer. There
* is no limit on the length of the command, except by the maximum
* packet size. Also sets the tty flag if there is no command.
*/
if (!ac) {
/* No command specified - execute shell on a tty. */
if (subsystem_flag) {
fprintf(stderr,
"You must specify a subsystem to invoke.\n");
usage();
}
} else {
/* A command has been specified. Store it into the buffer. */
for (i = 0; i < ac; i++) {
if ((r = sshbuf_putf(command, "%s%s",
i ? " " : "", av[i])) != 0)
fatal_fr(r, "buffer error");
}
}
/*
* Initialize "log" output. Since we are the client all output
* goes to stderr unless otherwise specified by -y or -E.
*/
if (use_syslog && logfile != NULL)
fatal("Can't specify both -y and -E");
if (logfile != NULL)
log_redirect_stderr_to(logfile);
log_init(argv0,
options.log_level == SYSLOG_LEVEL_NOT_SET ?
SYSLOG_LEVEL_INFO : options.log_level,
options.log_facility == SYSLOG_FACILITY_NOT_SET ?
SYSLOG_FACILITY_USER : options.log_facility,
!use_syslog);
if (debug_flag)
logit("%s, %s", SSH_RELEASE, SSH_OPENSSL_VERSION);
/* Parse the configuration files */
process_config_files(host_arg, pw, 0, &want_final_pass);
if (want_final_pass)
debug("configuration requests final Match pass");
/* Hostname canonicalisation needs a few options filled. */
fill_default_options_for_canonicalization(&options);
/* If the user has replaced the hostname then take it into use now */
if (options.hostname != NULL) {
/* NB. Please keep in sync with readconf.c:match_cfg_line() */
cp = percent_expand(options.hostname,
"h", host, (char *)NULL);
free(host);
host = cp;
free(options.hostname);
options.hostname = xstrdup(host);
}
/* Don't lowercase addresses, they will be explicitly canonicalised */
if ((was_addr = is_addr(host)) == 0)
lowercase(host);
/*
* Try to canonicalize if requested by configuration or the
* hostname is an address.
*/
if (options.canonicalize_hostname != SSH_CANONICALISE_NO || was_addr)
addrs = resolve_canonicalize(&host, options.port);
/*
* If CanonicalizePermittedCNAMEs have been specified but
* other canonicalization did not happen (by not being requested
* or by failing with fallback) then the hostname may still be changed
* as a result of CNAME following.
*
* Try to resolve the bare hostname name using the system resolver's
* usual search rules and then apply the CNAME follow rules.
*
* Skip the lookup if a ProxyCommand is being used unless the user
* has specifically requested canonicalisation for this case via
* CanonicalizeHostname=always
*/
direct = option_clear_or_none(options.proxy_command) &&
options.jump_host == NULL;
if (addrs == NULL && options.num_permitted_cnames != 0 && (direct ||
options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) {
if ((addrs = resolve_host(host, options.port,
direct, cname, sizeof(cname))) == NULL) {
/* Don't fatal proxied host names not in the DNS */
if (direct)
cleanup_exit(255); /* logged in resolve_host */
} else
check_follow_cname(direct, &host, cname);
}
/*
* If canonicalisation is enabled then re-parse the configuration
* files as new stanzas may match.
*/
if (options.canonicalize_hostname != 0 && !want_final_pass) {
debug("hostname canonicalisation enabled, "
"will re-parse configuration");
want_final_pass = 1;
}
if (want_final_pass) {
debug("re-parsing configuration");
free(options.hostname);
options.hostname = xstrdup(host);
process_config_files(host_arg, pw, 1, NULL);
/*
* Address resolution happens early with canonicalisation
* enabled and the port number may have changed since, so
* reset it in address list
*/
if (addrs != NULL && options.port > 0)
set_addrinfo_port(addrs, options.port);
}
/* Fill configuration defaults. */
if (fill_default_options(&options) != 0)
cleanup_exit(255);
if (options.user == NULL)
options.user = xstrdup(pw->pw_name);
/*
* If ProxyJump option specified, then construct a ProxyCommand now.
*/
if (options.jump_host != NULL) {
char port_s[8];
const char *jumpuser = options.jump_user, *sshbin = argv0;
int port = options.port, jumpport = options.jump_port;
if (port <= 0)
port = default_ssh_port();
if (jumpport <= 0)
jumpport = default_ssh_port();
if (jumpuser == NULL)
jumpuser = options.user;
if (strcmp(options.jump_host, host) == 0 && port == jumpport &&
strcmp(options.user, jumpuser) == 0)
fatal("jumphost loop via %s", options.jump_host);
/*
* Try to use SSH indicated by argv[0], but fall back to
* "ssh" if it appears unavailable.
*/
if (strchr(argv0, '/') != NULL && access(argv0, X_OK) != 0)
sshbin = "ssh";
/* Consistency check */
if (options.proxy_command != NULL)
fatal("inconsistent options: ProxyCommand+ProxyJump");
/* Never use FD passing for ProxyJump */
options.proxy_use_fdpass = 0;
snprintf(port_s, sizeof(port_s), "%d", options.jump_port);
xasprintf(&options.proxy_command,
"%s%s%s%s%s%s%s%s%s%s%.*s -W '[%%h]:%%p' %s",
sshbin,
/* Optional "-l user" argument if jump_user set */
options.jump_user == NULL ? "" : " -l ",
options.jump_user == NULL ? "" : options.jump_user,
/* Optional "-p port" argument if jump_port set */
options.jump_port <= 0 ? "" : " -p ",
options.jump_port <= 0 ? "" : port_s,
/* Optional additional jump hosts ",..." */
options.jump_extra == NULL ? "" : " -J ",
options.jump_extra == NULL ? "" : options.jump_extra,
/* Optional "-F" argumment if -F specified */
config == NULL ? "" : " -F ",
config == NULL ? "" : config,
/* Optional "-v" arguments if -v set */
debug_flag ? " -" : "",
debug_flag, "vvv",
/* Mandatory hostname */
options.jump_host);
debug("Setting implicit ProxyCommand from ProxyJump: %s",
options.proxy_command);
}
if (options.port == 0)
options.port = default_ssh_port();
channel_set_af(ssh, options.address_family);
/* Tidy and check options */
if (options.host_key_alias != NULL)
lowercase(options.host_key_alias);
if (options.proxy_command != NULL &&
strcmp(options.proxy_command, "-") == 0 &&
options.proxy_use_fdpass)
fatal("ProxyCommand=- and ProxyUseFDPass are incompatible");
if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK) {
if (options.control_persist && options.control_path != NULL) {
debug("UpdateHostKeys=ask is incompatible with "
"ControlPersist; disabling");
options.update_hostkeys = 0;
} else if (sshbuf_len(command) != 0 ||
options.remote_command != NULL ||
options.request_tty == REQUEST_TTY_NO) {
debug("UpdateHostKeys=ask is incompatible with "
"remote command execution; disabling");
options.update_hostkeys = 0;
} else if (options.log_level < SYSLOG_LEVEL_INFO) {
/* no point logging anything; user won't see it */
options.update_hostkeys = 0;
}
}
if (options.connection_attempts <= 0)
fatal("Invalid number of ConnectionAttempts");
if (sshbuf_len(command) != 0 && options.remote_command != NULL)
fatal("Cannot execute command-line and remote command.");
/* Cannot fork to background if no command. */
if (fork_after_authentication_flag && sshbuf_len(command) == 0 &&
options.remote_command == NULL && !no_shell_flag)
fatal("Cannot fork into background without a command "
"to execute.");
/* reinit */
log_init(argv0, options.log_level, options.log_facility, !use_syslog);
for (j = 0; j < options.num_log_verbose; j++)
log_verbose_add(options.log_verbose[j]);
if (options.request_tty == REQUEST_TTY_YES ||
options.request_tty == REQUEST_TTY_FORCE)
tty_flag = 1;
/* Allocate a tty by default if no command specified. */
if (sshbuf_len(command) == 0 && options.remote_command == NULL)
tty_flag = options.request_tty != REQUEST_TTY_NO;
/* Force no tty */
if (options.request_tty == REQUEST_TTY_NO ||
(muxclient_command && muxclient_command != SSHMUX_COMMAND_PROXY))
tty_flag = 0;
/* Do not allocate a tty if stdin is not a tty. */
if ((!isatty(fileno(stdin)) || stdin_null_flag) &&
options.request_tty != REQUEST_TTY_FORCE) {
if (tty_flag)
logit("Pseudo-terminal will not be allocated because "
"stdin is not a terminal.");
tty_flag = 0;
}
/* Set up strings used to percent_expand() arguments */
cinfo = xcalloc(1, sizeof(*cinfo));
if (gethostname(thishost, sizeof(thishost)) == -1)
fatal("gethostname: %s", strerror(errno));
cinfo->thishost = xstrdup(thishost);
thishost[strcspn(thishost, ".")] = '\0';
cinfo->shorthost = xstrdup(thishost);
xasprintf(&cinfo->portstr, "%d", options.port);
xasprintf(&cinfo->uidstr, "%llu",
(unsigned long long)pw->pw_uid);
cinfo->keyalias = xstrdup(options.host_key_alias ?
options.host_key_alias : host_arg);
cinfo->conn_hash_hex = ssh_connection_hash(cinfo->thishost, host,
cinfo->portstr, options.user);
cinfo->host_arg = xstrdup(host_arg);
cinfo->remhost = xstrdup(host);
cinfo->remuser = xstrdup(options.user);
cinfo->homedir = xstrdup(pw->pw_dir);
cinfo->locuser = xstrdup(pw->pw_name);
/*
* Expand tokens in arguments. NB. LocalCommand is expanded later,
* after port-forwarding is set up, so it may pick up any local
* tunnel interface name allocated.
*/
if (options.remote_command != NULL) {
debug3("expanding RemoteCommand: %s", options.remote_command);
cp = options.remote_command;
options.remote_command = default_client_percent_expand(cp,
cinfo);
debug3("expanded RemoteCommand: %s", options.remote_command);
free(cp);
if ((r = sshbuf_put(command, options.remote_command,
strlen(options.remote_command))) != 0)
fatal_fr(r, "buffer error");
}
if (options.control_path != NULL) {
cp = tilde_expand_filename(options.control_path, getuid());
free(options.control_path);
options.control_path = default_client_percent_dollar_expand(cp,
cinfo);
free(cp);
}
if (options.identity_agent != NULL) {
p = tilde_expand_filename(options.identity_agent, getuid());
cp = default_client_percent_dollar_expand(p, cinfo);
free(p);
free(options.identity_agent);
options.identity_agent = cp;
}
if (options.forward_agent_sock_path != NULL) {
p = tilde_expand_filename(options.forward_agent_sock_path,
getuid());
cp = default_client_percent_dollar_expand(p, cinfo);
free(p);
free(options.forward_agent_sock_path);
options.forward_agent_sock_path = cp;
if (stat(options.forward_agent_sock_path, &st) != 0) {
error("Cannot forward agent socket path \"%s\": %s",
options.forward_agent_sock_path, strerror(errno));
if (options.exit_on_forward_failure)
cleanup_exit(255);
}
}
if (options.num_system_hostfiles > 0 &&
strcasecmp(options.system_hostfiles[0], "none") == 0) {
if (options.num_system_hostfiles > 1)
fatal("Invalid GlobalKnownHostsFiles: \"none\" "
"appears with other entries");
free(options.system_hostfiles[0]);
options.system_hostfiles[0] = NULL;
options.num_system_hostfiles = 0;
}
if (options.num_user_hostfiles > 0 &&
strcasecmp(options.user_hostfiles[0], "none") == 0) {
if (options.num_user_hostfiles > 1)
fatal("Invalid UserKnownHostsFiles: \"none\" "
"appears with other entries");
free(options.user_hostfiles[0]);
options.user_hostfiles[0] = NULL;
options.num_user_hostfiles = 0;
}
for (j = 0; j < options.num_user_hostfiles; j++) {
if (options.user_hostfiles[j] == NULL)
continue;
cp = tilde_expand_filename(options.user_hostfiles[j], getuid());
p = default_client_percent_dollar_expand(cp, cinfo);
if (strcmp(options.user_hostfiles[j], p) != 0)
debug3("expanded UserKnownHostsFile '%s' -> "
"'%s'", options.user_hostfiles[j], p);
free(options.user_hostfiles[j]);
free(cp);
options.user_hostfiles[j] = p;
}
for (i = 0; i < options.num_local_forwards; i++) {
if (options.local_forwards[i].listen_path != NULL) {
cp = options.local_forwards[i].listen_path;
p = options.local_forwards[i].listen_path =
default_client_percent_expand(cp, cinfo);
if (strcmp(cp, p) != 0)
debug3("expanded LocalForward listen path "
"'%s' -> '%s'", cp, p);
free(cp);
}
if (options.local_forwards[i].connect_path != NULL) {
cp = options.local_forwards[i].connect_path;
p = options.local_forwards[i].connect_path =
default_client_percent_expand(cp, cinfo);
if (strcmp(cp, p) != 0)
debug3("expanded LocalForward connect path "
"'%s' -> '%s'", cp, p);
free(cp);
}
}
for (i = 0; i < options.num_remote_forwards; i++) {
if (options.remote_forwards[i].listen_path != NULL) {
cp = options.remote_forwards[i].listen_path;
p = options.remote_forwards[i].listen_path =
default_client_percent_expand(cp, cinfo);
if (strcmp(cp, p) != 0)
debug3("expanded RemoteForward listen path "
"'%s' -> '%s'", cp, p);
free(cp);
}
if (options.remote_forwards[i].connect_path != NULL) {
cp = options.remote_forwards[i].connect_path;
p = options.remote_forwards[i].connect_path =
default_client_percent_expand(cp, cinfo);
if (strcmp(cp, p) != 0)
debug3("expanded RemoteForward connect path "
"'%s' -> '%s'", cp, p);
free(cp);
}
}
if (config_test) {
dump_client_config(&options, host);
exit(0);
}
/* Expand SecurityKeyProvider if it refers to an environment variable */
if (options.sk_provider != NULL && *options.sk_provider == '$' &&
strlen(options.sk_provider) > 1) {
if ((cp = getenv(options.sk_provider + 1)) == NULL) {
debug("Authenticator provider %s did not resolve; "
"disabling", options.sk_provider);
free(options.sk_provider);
options.sk_provider = NULL;
} else {
debug2("resolved SecurityKeyProvider %s => %s",
options.sk_provider, cp);
free(options.sk_provider);
options.sk_provider = xstrdup(cp);
}
}
if (muxclient_command != 0 && options.control_path == NULL)
fatal("No ControlPath specified for \"-O\" command");
if (options.control_path != NULL) {
int sock;
if ((sock = muxclient(options.control_path)) >= 0) {
ssh_packet_set_connection(ssh, sock, sock);
ssh_packet_set_mux(ssh);
goto skip_connect;
}
}
/*
* If hostname canonicalisation was not enabled, then we may not
* have yet resolved the hostname. Do so now.
*/
if (addrs == NULL && options.proxy_command == NULL) {
debug2("resolving \"%s\" port %d", host, options.port);
if ((addrs = resolve_host(host, options.port, 1,
cname, sizeof(cname))) == NULL)
cleanup_exit(255); /* resolve_host logs the error */
}
if (options.connection_timeout >= INT_MAX/1000)
timeout_ms = INT_MAX;
else
timeout_ms = options.connection_timeout * 1000;
/* Open a connection to the remote host. */
if (ssh_connect(ssh, host, host_arg, addrs, &hostaddr, options.port,
options.connection_attempts,
&timeout_ms, options.tcp_keep_alive) != 0)
- exit(255);
+ exit(255);
if (addrs != NULL)
freeaddrinfo(addrs);
ssh_packet_set_timeout(ssh, options.server_alive_interval,
options.server_alive_count_max);
if (timeout_ms > 0)
debug3("timeout: %d ms remain after connect", timeout_ms);
/*
* If we successfully made the connection and we have hostbased auth
* enabled, load the public keys so we can later use the ssh-keysign
* helper to sign challenges.
*/
sensitive_data.nkeys = 0;
sensitive_data.keys = NULL;
if (options.hostbased_authentication) {
sensitive_data.nkeys = 10;
sensitive_data.keys = xcalloc(sensitive_data.nkeys,
sizeof(struct sshkey));
/* XXX check errors? */
#define L_PUBKEY(p,o) do { \
if ((o) >= sensitive_data.nkeys) \
fatal_f("pubkey out of array bounds"); \
check_load(sshkey_load_public(p, &(sensitive_data.keys[o]), NULL), \
p, "pubkey"); \
} while (0)
#define L_CERT(p,o) do { \
if ((o) >= sensitive_data.nkeys) \
fatal_f("cert out of array bounds"); \
check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), p, "cert"); \
} while (0)
if (options.hostbased_authentication == 1) {
L_CERT(_PATH_HOST_ECDSA_KEY_FILE, 0);
L_CERT(_PATH_HOST_ED25519_KEY_FILE, 1);
L_CERT(_PATH_HOST_RSA_KEY_FILE, 2);
L_CERT(_PATH_HOST_DSA_KEY_FILE, 3);
L_PUBKEY(_PATH_HOST_ECDSA_KEY_FILE, 4);
L_PUBKEY(_PATH_HOST_ED25519_KEY_FILE, 5);
L_PUBKEY(_PATH_HOST_RSA_KEY_FILE, 6);
L_PUBKEY(_PATH_HOST_DSA_KEY_FILE, 7);
L_CERT(_PATH_HOST_XMSS_KEY_FILE, 8);
L_PUBKEY(_PATH_HOST_XMSS_KEY_FILE, 9);
}
}
/* load options.identity_files */
load_public_identity_files(cinfo);
/* optionally set the SSH_AUTHSOCKET_ENV_NAME variable */
if (options.identity_agent &&
strcmp(options.identity_agent, SSH_AUTHSOCKET_ENV_NAME) != 0) {
if (strcmp(options.identity_agent, "none") == 0) {
unsetenv(SSH_AUTHSOCKET_ENV_NAME);
} else {
cp = options.identity_agent;
/* legacy (limited) format */
if (cp[0] == '$' && cp[1] != '{') {
if (!valid_env_name(cp + 1)) {
fatal("Invalid IdentityAgent "
"environment variable name %s", cp);
}
if ((p = getenv(cp + 1)) == NULL)
unsetenv(SSH_AUTHSOCKET_ENV_NAME);
else
setenv(SSH_AUTHSOCKET_ENV_NAME, p, 1);
} else {
/* identity_agent specifies a path directly */
setenv(SSH_AUTHSOCKET_ENV_NAME, cp, 1);
}
}
}
if (options.forward_agent && options.forward_agent_sock_path != NULL) {
cp = options.forward_agent_sock_path;
if (cp[0] == '$') {
if (!valid_env_name(cp + 1)) {
fatal("Invalid ForwardAgent environment variable name %s", cp);
}
if ((p = getenv(cp + 1)) != NULL)
forward_agent_sock_path = p;
else
options.forward_agent = 0;
free(cp);
} else {
forward_agent_sock_path = cp;
}
}
/* Expand ~ in known host file names. */
tilde_expand_paths(options.system_hostfiles,
options.num_system_hostfiles);
tilde_expand_paths(options.user_hostfiles, options.num_user_hostfiles);
ssh_signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */
ssh_signal(SIGCHLD, main_sigchld_handler);
/* Log into the remote system. Never returns if the login fails. */
ssh_login(ssh, &sensitive_data, host, (struct sockaddr *)&hostaddr,
options.port, pw, timeout_ms, cinfo);
if (ssh_packet_connection_is_on_socket(ssh)) {
verbose("Authenticated to %s ([%s]:%d).", host,
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
} else {
verbose("Authenticated to %s (via proxy).", host);
}
/* We no longer need the private host keys. Clear them now. */
if (sensitive_data.nkeys != 0) {
for (i = 0; i < sensitive_data.nkeys; i++) {
if (sensitive_data.keys[i] != NULL) {
/* Destroys contents safely */
debug3("clear hostkey %d", i);
sshkey_free(sensitive_data.keys[i]);
sensitive_data.keys[i] = NULL;
}
}
free(sensitive_data.keys);
}
for (i = 0; i < options.num_identity_files; i++) {
free(options.identity_files[i]);
options.identity_files[i] = NULL;
if (options.identity_keys[i]) {
sshkey_free(options.identity_keys[i]);
options.identity_keys[i] = NULL;
}
}
for (i = 0; i < options.num_certificate_files; i++) {
free(options.certificate_files[i]);
options.certificate_files[i] = NULL;
}
+#ifdef ENABLE_PKCS11
+ (void)pkcs11_del_provider(options.pkcs11_provider);
+#endif
+
skip_connect:
exit_status = ssh_session2(ssh, cinfo);
ssh_conn_info_free(cinfo);
ssh_packet_close(ssh);
if (options.control_path != NULL && muxserver_sock != -1)
unlink(options.control_path);
/* Kill ProxyCommand if it is running. */
ssh_kill_proxy_command();
return exit_status;
}
static void
control_persist_detach(void)
{
pid_t pid;
debug_f("backgrounding master process");
/*
* master (current process) into the background, and make the
* foreground process a client of the backgrounded master.
*/
switch ((pid = fork())) {
case -1:
fatal_f("fork: %s", strerror(errno));
case 0:
/* Child: master process continues mainloop */
break;
default:
/* Parent: set up mux client to connect to backgrounded master */
debug2_f("background process is %ld", (long)pid);
stdin_null_flag = ostdin_null_flag;
options.request_tty = orequest_tty;
tty_flag = otty_flag;
close(muxserver_sock);
muxserver_sock = -1;
options.control_master = SSHCTL_MASTER_NO;
muxclient(options.control_path);
/* muxclient() doesn't return on success. */
fatal("Failed to connect to new control master");
}
if (stdfd_devnull(1, 1, !(log_is_on_stderr() && debug_flag)) == -1)
error_f("stdfd_devnull failed");
daemon(1, 1);
setproctitle("%s [mux]", options.control_path);
}
/* Do fork() after authentication. Used by "ssh -f" */
static void
fork_postauth(void)
{
if (need_controlpersist_detach)
control_persist_detach();
debug("forking to background");
fork_after_authentication_flag = 0;
if (daemon(1, 1) == -1)
fatal("daemon() failed: %.200s", strerror(errno));
if (stdfd_devnull(1, 1, !(log_is_on_stderr() && debug_flag)) == -1)
error_f("stdfd_devnull failed");
}
static void
forwarding_success(void)
{
if (forward_confirms_pending == -1)
return;
if (--forward_confirms_pending == 0) {
debug_f("all expected forwarding replies received");
if (fork_after_authentication_flag)
fork_postauth();
} else {
debug2_f("%d expected forwarding replies remaining",
forward_confirms_pending);
}
}
/* Callback for remote forward global requests */
static void
ssh_confirm_remote_forward(struct ssh *ssh, int type, u_int32_t seq, void *ctxt)
{
struct Forward *rfwd = (struct Forward *)ctxt;
u_int port;
int r;
/* XXX verbose() on failure? */
debug("remote forward %s for: listen %s%s%d, connect %s:%d",
type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
rfwd->listen_path ? rfwd->listen_path :
rfwd->listen_host ? rfwd->listen_host : "",
(rfwd->listen_path || rfwd->listen_host) ? ":" : "",
rfwd->listen_port, rfwd->connect_path ? rfwd->connect_path :
rfwd->connect_host, rfwd->connect_port);
if (rfwd->listen_path == NULL && rfwd->listen_port == 0) {
if (type == SSH2_MSG_REQUEST_SUCCESS) {
if ((r = sshpkt_get_u32(ssh, &port)) != 0)
fatal_fr(r, "parse packet");
if (port > 65535) {
error("Invalid allocated port %u for remote "
"forward to %s:%d", port,
rfwd->connect_host, rfwd->connect_port);
/* Ensure failure processing runs below */
type = SSH2_MSG_REQUEST_FAILURE;
channel_update_permission(ssh,
rfwd->handle, -1);
} else {
rfwd->allocated_port = (int)port;
logit("Allocated port %u for remote "
"forward to %s:%d",
rfwd->allocated_port, rfwd->connect_host,
rfwd->connect_port);
channel_update_permission(ssh,
rfwd->handle, rfwd->allocated_port);
}
} else {
channel_update_permission(ssh, rfwd->handle, -1);
}
}
if (type == SSH2_MSG_REQUEST_FAILURE) {
if (options.exit_on_forward_failure) {
if (rfwd->listen_path != NULL)
fatal("Error: remote port forwarding failed "
"for listen path %s", rfwd->listen_path);
else
fatal("Error: remote port forwarding failed "
"for listen port %d", rfwd->listen_port);
} else {
if (rfwd->listen_path != NULL)
logit("Warning: remote port forwarding failed "
"for listen path %s", rfwd->listen_path);
else
logit("Warning: remote port forwarding failed "
"for listen port %d", rfwd->listen_port);
}
}
forwarding_success();
}
static void
client_cleanup_stdio_fwd(struct ssh *ssh, int id, void *arg)
{
debug("stdio forwarding: done");
cleanup_exit(0);
}
static void
ssh_stdio_confirm(struct ssh *ssh, int id, int success, void *arg)
{
if (!success)
fatal("stdio forwarding failed");
}
static void
ssh_tun_confirm(struct ssh *ssh, int id, int success, void *arg)
{
if (!success) {
error("Tunnel forwarding failed");
if (options.exit_on_forward_failure)
cleanup_exit(255);
}
debug_f("tunnel forward established, id=%d", id);
forwarding_success();
}
static void
ssh_init_stdio_forwarding(struct ssh *ssh)
{
Channel *c;
int in, out;
if (options.stdio_forward_host == NULL)
return;
debug3_f("%s:%d", options.stdio_forward_host,
options.stdio_forward_port);
if ((in = dup(STDIN_FILENO)) == -1 ||
(out = dup(STDOUT_FILENO)) == -1)
fatal("channel_connect_stdio_fwd: dup() in/out failed");
if ((c = channel_connect_stdio_fwd(ssh, options.stdio_forward_host,
options.stdio_forward_port, in, out)) == NULL)
fatal_f("channel_connect_stdio_fwd failed");
channel_register_cleanup(ssh, c->self, client_cleanup_stdio_fwd, 0);
channel_register_open_confirm(ssh, c->self, ssh_stdio_confirm, NULL);
}
static void
ssh_init_forward_permissions(struct ssh *ssh, const char *what, char **opens,
u_int num_opens)
{
u_int i;
int port;
char *addr, *arg, *oarg, ch;
int where = FORWARD_LOCAL;
channel_clear_permission(ssh, FORWARD_ADM, where);
if (num_opens == 0)
return; /* permit any */
/* handle keywords: "any" / "none" */
if (num_opens == 1 && strcmp(opens[0], "any") == 0)
return;
if (num_opens == 1 && strcmp(opens[0], "none") == 0) {
channel_disable_admin(ssh, where);
return;
}
/* Otherwise treat it as a list of permitted host:port */
for (i = 0; i < num_opens; i++) {
oarg = arg = xstrdup(opens[i]);
ch = '\0';
addr = hpdelim2(&arg, &ch);
if (addr == NULL || ch == '/')
fatal_f("missing host in %s", what);
addr = cleanhostname(addr);
if (arg == NULL || ((port = permitopen_port(arg)) < 0))
fatal_f("bad port number in %s", what);
/* Send it to channels layer */
channel_add_permission(ssh, FORWARD_ADM,
where, addr, port);
free(oarg);
}
}
static void
ssh_init_forwarding(struct ssh *ssh, char **ifname)
{
int success = 0;
int i;
ssh_init_forward_permissions(ssh, "permitremoteopen",
options.permitted_remote_opens,
options.num_permitted_remote_opens);
if (options.exit_on_forward_failure)
forward_confirms_pending = 0; /* track pending requests */
/* Initiate local TCP/IP port forwardings. */
for (i = 0; i < options.num_local_forwards; i++) {
debug("Local connections to %.200s:%d forwarded to remote "
"address %.200s:%d",
(options.local_forwards[i].listen_path != NULL) ?
options.local_forwards[i].listen_path :
(options.local_forwards[i].listen_host == NULL) ?
(options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") :
options.local_forwards[i].listen_host,
options.local_forwards[i].listen_port,
(options.local_forwards[i].connect_path != NULL) ?
options.local_forwards[i].connect_path :
options.local_forwards[i].connect_host,
options.local_forwards[i].connect_port);
success += channel_setup_local_fwd_listener(ssh,
&options.local_forwards[i], &options.fwd_opts);
}
if (i > 0 && success != i && options.exit_on_forward_failure)
fatal("Could not request local forwarding.");
if (i > 0 && success == 0)
error("Could not request local forwarding.");
/* Initiate remote TCP/IP port forwardings. */
for (i = 0; i < options.num_remote_forwards; i++) {
debug("Remote connections from %.200s:%d forwarded to "
"local address %.200s:%d",
(options.remote_forwards[i].listen_path != NULL) ?
options.remote_forwards[i].listen_path :
(options.remote_forwards[i].listen_host == NULL) ?
"LOCALHOST" : options.remote_forwards[i].listen_host,
options.remote_forwards[i].listen_port,
(options.remote_forwards[i].connect_path != NULL) ?
options.remote_forwards[i].connect_path :
options.remote_forwards[i].connect_host,
options.remote_forwards[i].connect_port);
if ((options.remote_forwards[i].handle =
channel_request_remote_forwarding(ssh,
&options.remote_forwards[i])) >= 0) {
client_register_global_confirm(
ssh_confirm_remote_forward,
&options.remote_forwards[i]);
forward_confirms_pending++;
} else if (options.exit_on_forward_failure)
fatal("Could not request remote forwarding.");
else
logit("Warning: Could not request remote forwarding.");
}
/* Initiate tunnel forwarding. */
if (options.tun_open != SSH_TUNMODE_NO) {
if ((*ifname = client_request_tun_fwd(ssh,
options.tun_open, options.tun_local,
options.tun_remote, ssh_tun_confirm, NULL)) != NULL)
forward_confirms_pending++;
else if (options.exit_on_forward_failure)
fatal("Could not request tunnel forwarding.");
else
error("Could not request tunnel forwarding.");
}
if (forward_confirms_pending > 0) {
debug_f("expecting replies for %d forwards",
forward_confirms_pending);
}
}
static void
check_agent_present(void)
{
int r;
if (options.forward_agent) {
/* Clear agent forwarding if we don't have an agent. */
if ((r = ssh_get_authentication_socket(NULL)) != 0) {
options.forward_agent = 0;
if (r != SSH_ERR_AGENT_NOT_PRESENT)
debug_r(r, "ssh_get_authentication_socket");
}
}
}
static void
ssh_session2_setup(struct ssh *ssh, int id, int success, void *arg)
{
extern char **environ;
const char *display;
int r, interactive = tty_flag;
char *proto = NULL, *data = NULL;
if (!success)
return; /* No need for error message, channels code sens one */
display = getenv("DISPLAY");
if (display == NULL && options.forward_x11)
debug("X11 forwarding requested but DISPLAY not set");
if (options.forward_x11 && client_x11_get_proto(ssh, display,
options.xauth_location, options.forward_x11_trusted,
options.forward_x11_timeout, &proto, &data) == 0) {
/* Request forwarding with authentication spoofing. */
debug("Requesting X11 forwarding with authentication "
"spoofing.");
x11_request_forwarding_with_spoofing(ssh, id, display, proto,
data, 1);
client_expect_confirm(ssh, id, "X11 forwarding", CONFIRM_WARN);
/* XXX exit_on_forward_failure */
interactive = 1;
}
check_agent_present();
if (options.forward_agent) {
debug("Requesting authentication agent forwarding.");
channel_request_start(ssh, id, "auth-agent-req@openssh.com", 0);
if ((r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send packet");
}
/* Tell the packet module whether this is an interactive session. */
ssh_packet_set_interactive(ssh, interactive,
options.ip_qos_interactive, options.ip_qos_bulk);
client_session2_setup(ssh, id, tty_flag, subsystem_flag, getenv("TERM"),
NULL, fileno(stdin), command, environ);
}
/* open new channel for a session */
static int
ssh_session2_open(struct ssh *ssh)
{
Channel *c;
int window, packetmax, in, out, err;
if (stdin_null_flag) {
in = open(_PATH_DEVNULL, O_RDONLY);
} else {
in = dup(STDIN_FILENO);
}
out = dup(STDOUT_FILENO);
err = dup(STDERR_FILENO);
if (in == -1 || out == -1 || err == -1)
fatal("dup() in/out/err failed");
/* enable nonblocking unless tty */
if (!isatty(in))
set_nonblock(in);
if (!isatty(out))
set_nonblock(out);
if (!isatty(err))
set_nonblock(err);
window = CHAN_SES_WINDOW_DEFAULT;
packetmax = CHAN_SES_PACKET_DEFAULT;
if (tty_flag) {
window >>= 1;
packetmax >>= 1;
}
c = channel_new(ssh,
"session", SSH_CHANNEL_OPENING, in, out, err,
window, packetmax, CHAN_EXTENDED_WRITE,
"client-session", /*nonblock*/0);
debug3_f("channel_new: %d", c->self);
channel_send_open(ssh, c->self);
if (!no_shell_flag)
channel_register_open_confirm(ssh, c->self,
ssh_session2_setup, NULL);
return c->self;
}
static int
ssh_session2(struct ssh *ssh, const struct ssh_conn_info *cinfo)
{
int r, id = -1;
char *cp, *tun_fwd_ifname = NULL;
/* XXX should be pre-session */
if (!options.control_persist)
ssh_init_stdio_forwarding(ssh);
ssh_init_forwarding(ssh, &tun_fwd_ifname);
if (options.local_command != NULL) {
debug3("expanding LocalCommand: %s", options.local_command);
cp = options.local_command;
options.local_command = percent_expand(cp,
DEFAULT_CLIENT_PERCENT_EXPAND_ARGS(cinfo),
"T", tun_fwd_ifname == NULL ? "NONE" : tun_fwd_ifname,
(char *)NULL);
debug3("expanded LocalCommand: %s", options.local_command);
free(cp);
}
/* Start listening for multiplex clients */
if (!ssh_packet_get_mux(ssh))
muxserver_listen(ssh);
/*
* If we are in control persist mode and have a working mux listen
* socket, then prepare to background ourselves and have a foreground
* client attach as a control client.
* NB. we must save copies of the flags that we override for
* the backgrounding, since we defer attachment of the client until
* after the connection is fully established (in particular,
* async rfwd replies have been received for ExitOnForwardFailure).
*/
if (options.control_persist && muxserver_sock != -1) {
ostdin_null_flag = stdin_null_flag;
ono_shell_flag = no_shell_flag;
orequest_tty = options.request_tty;
otty_flag = tty_flag;
stdin_null_flag = 1;
no_shell_flag = 1;
tty_flag = 0;
if (!fork_after_authentication_flag)
need_controlpersist_detach = 1;
fork_after_authentication_flag = 1;
}
/*
* ControlPersist mux listen socket setup failed, attempt the
* stdio forward setup that we skipped earlier.
*/
if (options.control_persist && muxserver_sock == -1)
ssh_init_stdio_forwarding(ssh);
if (!no_shell_flag)
id = ssh_session2_open(ssh);
else {
ssh_packet_set_interactive(ssh,
options.control_master == SSHCTL_MASTER_NO,
options.ip_qos_interactive, options.ip_qos_bulk);
}
/* If we don't expect to open a new session, then disallow it */
if (options.control_master == SSHCTL_MASTER_NO &&
(ssh->compat & SSH_NEW_OPENSSH)) {
debug("Requesting no-more-sessions@openssh.com");
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh,
"no-more-sessions@openssh.com")) != 0 ||
(r = sshpkt_put_u8(ssh, 0)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send packet");
}
/* Execute a local command */
if (options.local_command != NULL &&
options.permit_local_command)
ssh_local_cmd(options.local_command);
/*
* stdout is now owned by the session channel; clobber it here
* so future channel closes are propagated to the local fd.
* NB. this can only happen after LocalCommand has completed,
* as it may want to write to stdout.
*/
if (!need_controlpersist_detach && stdfd_devnull(0, 1, 0) == -1)
error_f("stdfd_devnull failed");
/*
* If requested and we are not interested in replies to remote
* forwarding requests, then let ssh continue in the background.
*/
if (fork_after_authentication_flag) {
if (options.exit_on_forward_failure &&
options.num_remote_forwards > 0) {
debug("deferring postauth fork until remote forward "
"confirmation received");
} else
fork_postauth();
}
return client_loop(ssh, tty_flag, tty_flag ?
options.escape_char : SSH_ESCAPECHAR_NONE, id);
}
/* Loads all IdentityFile and CertificateFile keys */
static void
load_public_identity_files(const struct ssh_conn_info *cinfo)
{
char *filename, *cp;
struct sshkey *public;
int i;
u_int n_ids, n_certs;
char *identity_files[SSH_MAX_IDENTITY_FILES];
struct sshkey *identity_keys[SSH_MAX_IDENTITY_FILES];
int identity_file_userprovided[SSH_MAX_IDENTITY_FILES];
char *certificate_files[SSH_MAX_CERTIFICATE_FILES];
struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES];
int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES];
#ifdef ENABLE_PKCS11
struct sshkey **keys = NULL;
char **comments = NULL;
int nkeys;
#endif /* PKCS11 */
n_ids = n_certs = 0;
memset(identity_files, 0, sizeof(identity_files));
memset(identity_keys, 0, sizeof(identity_keys));
memset(identity_file_userprovided, 0,
sizeof(identity_file_userprovided));
memset(certificate_files, 0, sizeof(certificate_files));
memset(certificates, 0, sizeof(certificates));
memset(certificate_file_userprovided, 0,
sizeof(certificate_file_userprovided));
#ifdef ENABLE_PKCS11
if (options.pkcs11_provider != NULL &&
options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
(pkcs11_init(!options.batch_mode) == 0) &&
(nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL,
&keys, &comments)) > 0) {
for (i = 0; i < nkeys; i++) {
if (n_ids >= SSH_MAX_IDENTITY_FILES) {
sshkey_free(keys[i]);
free(comments[i]);
continue;
}
identity_keys[n_ids] = keys[i];
identity_files[n_ids] = comments[i]; /* transferred */
n_ids++;
}
free(keys);
free(comments);
}
#endif /* ENABLE_PKCS11 */
for (i = 0; i < options.num_identity_files; i++) {
if (n_ids >= SSH_MAX_IDENTITY_FILES ||
strcasecmp(options.identity_files[i], "none") == 0) {
free(options.identity_files[i]);
options.identity_files[i] = NULL;
continue;
}
cp = tilde_expand_filename(options.identity_files[i], getuid());
filename = default_client_percent_dollar_expand(cp, cinfo);
free(cp);
check_load(sshkey_load_public(filename, &public, NULL),
filename, "pubkey");
debug("identity file %s type %d", filename,
public ? public->type : -1);
free(options.identity_files[i]);
identity_files[n_ids] = filename;
identity_keys[n_ids] = public;
identity_file_userprovided[n_ids] =
options.identity_file_userprovided[i];
if (++n_ids >= SSH_MAX_IDENTITY_FILES)
continue;
/*
* If no certificates have been explicitly listed then try
* to add the default certificate variant too.
*/
if (options.num_certificate_files != 0)
continue;
xasprintf(&cp, "%s-cert", filename);
check_load(sshkey_load_public(cp, &public, NULL),
filename, "pubkey");
debug("identity file %s type %d", cp,
public ? public->type : -1);
if (public == NULL) {
free(cp);
continue;
}
if (!sshkey_is_cert(public)) {
debug_f("key %s type %s is not a certificate",
cp, sshkey_type(public));
sshkey_free(public);
free(cp);
continue;
}
/* NB. leave filename pointing to private key */
identity_files[n_ids] = xstrdup(filename);
identity_keys[n_ids] = public;
identity_file_userprovided[n_ids] =
options.identity_file_userprovided[i];
n_ids++;
}
if (options.num_certificate_files > SSH_MAX_CERTIFICATE_FILES)
fatal_f("too many certificates");
for (i = 0; i < options.num_certificate_files; i++) {
cp = tilde_expand_filename(options.certificate_files[i],
getuid());
filename = default_client_percent_dollar_expand(cp, cinfo);
free(cp);
check_load(sshkey_load_public(filename, &public, NULL),
filename, "certificate");
debug("certificate file %s type %d", filename,
public ? public->type : -1);
free(options.certificate_files[i]);
options.certificate_files[i] = NULL;
if (public == NULL) {
free(filename);
continue;
}
if (!sshkey_is_cert(public)) {
debug_f("key %s type %s is not a certificate",
filename, sshkey_type(public));
sshkey_free(public);
free(filename);
continue;
}
certificate_files[n_certs] = filename;
certificates[n_certs] = public;
certificate_file_userprovided[n_certs] =
options.certificate_file_userprovided[i];
++n_certs;
}
options.num_identity_files = n_ids;
memcpy(options.identity_files, identity_files, sizeof(identity_files));
memcpy(options.identity_keys, identity_keys, sizeof(identity_keys));
memcpy(options.identity_file_userprovided,
identity_file_userprovided, sizeof(identity_file_userprovided));
options.num_certificate_files = n_certs;
memcpy(options.certificate_files,
certificate_files, sizeof(certificate_files));
memcpy(options.certificates, certificates, sizeof(certificates));
memcpy(options.certificate_file_userprovided,
certificate_file_userprovided,
sizeof(certificate_file_userprovided));
}
static void
main_sigchld_handler(int sig)
{
int save_errno = errno;
pid_t pid;
int status;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
(pid == -1 && errno == EINTR))
;
errno = save_errno;
}
diff --git a/ssh_api.c b/ssh_api.c
index bceff0f0c5ae..d3c6617616bd 100644
--- a/ssh_api.c
+++ b/ssh_api.c
@@ -1,570 +1,570 @@
-/* $OpenBSD: ssh_api.c,v 1.26 2021/01/27 10:05:28 djm Exp $ */
+/* $OpenBSD: ssh_api.c,v 1.27 2021/04/03 06:18:41 djm Exp $ */
/*
* Copyright (c) 2012 Markus Friedl. All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include "ssh_api.h"
#include "compat.h"
#include "log.h"
#include "authfile.h"
#include "sshkey.h"
#include "misc.h"
#include "ssh2.h"
#include "version.h"
#include "myproposal.h"
#include "ssherr.h"
#include "sshbuf.h"
#include "openbsd-compat/openssl-compat.h"
#include <string.h>
int _ssh_exchange_banner(struct ssh *);
int _ssh_send_banner(struct ssh *, struct sshbuf *);
int _ssh_read_banner(struct ssh *, struct sshbuf *);
int _ssh_order_hostkeyalgs(struct ssh *);
int _ssh_verify_host_key(struct sshkey *, struct ssh *);
struct sshkey *_ssh_host_public_key(int, int, struct ssh *);
struct sshkey *_ssh_host_private_key(int, int, struct ssh *);
int _ssh_host_key_sign(struct ssh *, struct sshkey *, struct sshkey *,
u_char **, size_t *, const u_char *, size_t, const char *);
/*
* stubs for the server side implementation of kex.
* disable privsep so our stubs will never be called.
*/
int use_privsep = 0;
int mm_sshkey_sign(struct sshkey *, u_char **, u_int *,
const u_char *, u_int, const char *, const char *, const char *, u_int);
#ifdef WITH_OPENSSL
DH *mm_choose_dh(int, int, int);
#endif
int
mm_sshkey_sign(struct sshkey *key, u_char **sigp, u_int *lenp,
const u_char *data, u_int datalen, const char *alg,
const char *sk_provider, const char *sk_pin, u_int compat)
{
return (-1);
}
#ifdef WITH_OPENSSL
DH *
mm_choose_dh(int min, int nbits, int max)
{
return (NULL);
}
#endif
/* API */
int
ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params)
{
- char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
+ char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
struct ssh *ssh;
char **proposal;
static int called;
int r;
if (!called) {
seed_rng();
called = 1;
}
if ((ssh = ssh_packet_set_connection(NULL, -1, -1)) == NULL)
return SSH_ERR_ALLOC_FAIL;
if (is_server)
ssh_packet_set_server(ssh);
/* Initialize key exchange */
proposal = kex_params ? kex_params->proposal : myproposal;
if ((r = kex_ready(ssh, proposal)) != 0) {
ssh_free(ssh);
return r;
}
ssh->kex->server = is_server;
if (is_server) {
#ifdef WITH_OPENSSL
ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server;
ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server;
ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_server;
ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_server;
ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_server;
ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
# ifdef OPENSSL_HAS_ECC
ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
# endif
#endif /* WITH_OPENSSL */
ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_server;
ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server;
ssh->kex->load_host_public_key=&_ssh_host_public_key;
ssh->kex->load_host_private_key=&_ssh_host_private_key;
ssh->kex->sign=&_ssh_host_key_sign;
} else {
#ifdef WITH_OPENSSL
ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_client;
ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_client;
ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_client;
ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_client;
ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_client;
ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
# ifdef OPENSSL_HAS_ECC
ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client;
# endif
#endif /* WITH_OPENSSL */
ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client;
ssh->kex->verify_host_key =&_ssh_verify_host_key;
}
*sshp = ssh;
return 0;
}
void
ssh_free(struct ssh *ssh)
{
struct key_entry *k;
if (ssh == NULL)
return;
/*
* we've only created the public keys variants in case we
* are a acting as a server.
*/
while ((k = TAILQ_FIRST(&ssh->public_keys)) != NULL) {
TAILQ_REMOVE(&ssh->public_keys, k, next);
if (ssh->kex && ssh->kex->server)
sshkey_free(k->key);
free(k);
}
while ((k = TAILQ_FIRST(&ssh->private_keys)) != NULL) {
TAILQ_REMOVE(&ssh->private_keys, k, next);
free(k);
}
ssh_packet_close(ssh);
free(ssh);
}
void
ssh_set_app_data(struct ssh *ssh, void *app_data)
{
ssh->app_data = app_data;
}
void *
ssh_get_app_data(struct ssh *ssh)
{
return ssh->app_data;
}
/* Returns < 0 on error, 0 otherwise */
int
ssh_add_hostkey(struct ssh *ssh, struct sshkey *key)
{
struct sshkey *pubkey = NULL;
struct key_entry *k = NULL, *k_prv = NULL;
int r;
if (ssh->kex->server) {
if ((r = sshkey_from_private(key, &pubkey)) != 0)
return r;
if ((k = malloc(sizeof(*k))) == NULL ||
(k_prv = malloc(sizeof(*k_prv))) == NULL) {
free(k);
sshkey_free(pubkey);
return SSH_ERR_ALLOC_FAIL;
}
k_prv->key = key;
TAILQ_INSERT_TAIL(&ssh->private_keys, k_prv, next);
/* add the public key, too */
k->key = pubkey;
TAILQ_INSERT_TAIL(&ssh->public_keys, k, next);
r = 0;
} else {
if ((k = malloc(sizeof(*k))) == NULL)
return SSH_ERR_ALLOC_FAIL;
k->key = key;
TAILQ_INSERT_TAIL(&ssh->public_keys, k, next);
r = 0;
}
return r;
}
int
ssh_set_verify_host_key_callback(struct ssh *ssh,
int (*cb)(struct sshkey *, struct ssh *))
{
if (cb == NULL || ssh->kex == NULL)
return SSH_ERR_INVALID_ARGUMENT;
ssh->kex->verify_host_key = cb;
return 0;
}
int
ssh_input_append(struct ssh *ssh, const u_char *data, size_t len)
{
return sshbuf_put(ssh_packet_get_input(ssh), data, len);
}
int
ssh_packet_next(struct ssh *ssh, u_char *typep)
{
int r;
u_int32_t seqnr;
u_char type;
/*
* Try to read a packet. Return SSH_MSG_NONE if no packet or not
* enough data.
*/
*typep = SSH_MSG_NONE;
if (sshbuf_len(ssh->kex->client_version) == 0 ||
sshbuf_len(ssh->kex->server_version) == 0)
return _ssh_exchange_banner(ssh);
/*
* If we enough data and a dispatch function then
* call the function and get the next packet.
* Otherwise return the packet type to the caller so it
* can decide how to go on.
*
* We will only call the dispatch function for:
* 20-29 Algorithm negotiation
* 30-49 Key exchange method specific (numbers can be reused for
* different authentication methods)
*/
for (;;) {
if ((r = ssh_packet_read_poll2(ssh, &type, &seqnr)) != 0)
return r;
if (type > 0 && type < DISPATCH_MAX &&
type >= SSH2_MSG_KEXINIT && type <= SSH2_MSG_TRANSPORT_MAX &&
ssh->dispatch[type] != NULL) {
if ((r = (*ssh->dispatch[type])(type, seqnr, ssh)) != 0)
return r;
} else {
*typep = type;
return 0;
}
}
}
const u_char *
ssh_packet_payload(struct ssh *ssh, size_t *lenp)
{
return sshpkt_ptr(ssh, lenp);
}
int
ssh_packet_put(struct ssh *ssh, int type, const u_char *data, size_t len)
{
int r;
if ((r = sshpkt_start(ssh, type)) != 0 ||
(r = sshpkt_put(ssh, data, len)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
return r;
return 0;
}
const u_char *
ssh_output_ptr(struct ssh *ssh, size_t *len)
{
struct sshbuf *output = ssh_packet_get_output(ssh);
*len = sshbuf_len(output);
return sshbuf_ptr(output);
}
int
ssh_output_consume(struct ssh *ssh, size_t len)
{
return sshbuf_consume(ssh_packet_get_output(ssh), len);
}
int
ssh_output_space(struct ssh *ssh, size_t len)
{
return (0 == sshbuf_check_reserve(ssh_packet_get_output(ssh), len));
}
int
ssh_input_space(struct ssh *ssh, size_t len)
{
return (0 == sshbuf_check_reserve(ssh_packet_get_input(ssh), len));
}
/* Read other side's version identification. */
int
_ssh_read_banner(struct ssh *ssh, struct sshbuf *banner)
{
struct sshbuf *input = ssh_packet_get_input(ssh);
const char *mismatch = "Protocol mismatch.\r\n";
const u_char *s = sshbuf_ptr(input);
u_char c;
char *cp = NULL, *remote_version = NULL;
int r = 0, remote_major, remote_minor, expect_nl;
size_t n, j;
for (j = n = 0;;) {
sshbuf_reset(banner);
expect_nl = 0;
for (;;) {
if (j >= sshbuf_len(input))
return 0; /* insufficient data in input buf */
c = s[j++];
if (c == '\r') {
expect_nl = 1;
continue;
}
if (c == '\n')
break;
if (expect_nl)
goto bad;
if ((r = sshbuf_put_u8(banner, c)) != 0)
return r;
if (sshbuf_len(banner) > SSH_MAX_BANNER_LEN)
goto bad;
}
if (sshbuf_len(banner) >= 4 &&
memcmp(sshbuf_ptr(banner), "SSH-", 4) == 0)
break;
debug_f("%.*s", (int)sshbuf_len(banner),
sshbuf_ptr(banner));
/* Accept lines before banner only on client */
if (ssh->kex->server || ++n > SSH_MAX_PRE_BANNER_LINES) {
bad:
if ((r = sshbuf_put(ssh_packet_get_output(ssh),
- mismatch, strlen(mismatch))) != 0)
+ mismatch, strlen(mismatch))) != 0)
return r;
return SSH_ERR_NO_PROTOCOL_VERSION;
}
}
if ((r = sshbuf_consume(input, j)) != 0)
return r;
/* XXX remote version must be the same size as banner for sscanf */
if ((cp = sshbuf_dup_string(banner)) == NULL ||
(remote_version = calloc(1, sshbuf_len(banner))) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/*
* Check that the versions match. In future this might accept
* several versions and set appropriate flags to handle them.
*/
if (sscanf(cp, "SSH-%d.%d-%[^\n]\n",
&remote_major, &remote_minor, remote_version) != 3) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
debug("Remote protocol version %d.%d, remote software version %.100s",
remote_major, remote_minor, remote_version);
compat_banner(ssh, remote_version);
if (remote_major == 1 && remote_minor == 99) {
remote_major = 2;
remote_minor = 0;
}
if (remote_major != 2)
r = SSH_ERR_PROTOCOL_MISMATCH;
debug("Remote version string %.100s", cp);
out:
free(cp);
free(remote_version);
return r;
}
/* Send our own protocol version identification. */
int
_ssh_send_banner(struct ssh *ssh, struct sshbuf *banner)
{
char *cp;
int r;
if ((r = sshbuf_putf(banner, "SSH-2.0-%.100s\r\n", SSH_VERSION)) != 0)
return r;
if ((r = sshbuf_putb(ssh_packet_get_output(ssh), banner)) != 0)
return r;
/* Remove trailing \r\n */
if ((r = sshbuf_consume_end(banner, 2)) != 0)
return r;
if ((cp = sshbuf_dup_string(banner)) == NULL)
return SSH_ERR_ALLOC_FAIL;
debug("Local version string %.100s", cp);
free(cp);
return 0;
}
int
_ssh_exchange_banner(struct ssh *ssh)
{
struct kex *kex = ssh->kex;
int r;
/*
* if _ssh_read_banner() cannot parse a full version string
* it will return NULL and we end up calling it again.
*/
r = 0;
if (kex->server) {
if (sshbuf_len(ssh->kex->server_version) == 0)
r = _ssh_send_banner(ssh, ssh->kex->server_version);
if (r == 0 &&
sshbuf_len(ssh->kex->server_version) != 0 &&
sshbuf_len(ssh->kex->client_version) == 0)
r = _ssh_read_banner(ssh, ssh->kex->client_version);
} else {
if (sshbuf_len(ssh->kex->server_version) == 0)
r = _ssh_read_banner(ssh, ssh->kex->server_version);
if (r == 0 &&
sshbuf_len(ssh->kex->server_version) != 0 &&
sshbuf_len(ssh->kex->client_version) == 0)
r = _ssh_send_banner(ssh, ssh->kex->client_version);
}
if (r != 0)
return r;
/* start initial kex as soon as we have exchanged the banners */
if (sshbuf_len(ssh->kex->server_version) != 0 &&
sshbuf_len(ssh->kex->client_version) != 0) {
if ((r = _ssh_order_hostkeyalgs(ssh)) != 0 ||
(r = kex_send_kexinit(ssh)) != 0)
return r;
}
return 0;
}
struct sshkey *
_ssh_host_public_key(int type, int nid, struct ssh *ssh)
{
struct key_entry *k;
debug3_f("need %d", type);
TAILQ_FOREACH(k, &ssh->public_keys, next) {
debug3_f("check %s", sshkey_type(k->key));
if (k->key->type == type &&
(type != KEY_ECDSA || k->key->ecdsa_nid == nid))
return (k->key);
}
return (NULL);
}
struct sshkey *
_ssh_host_private_key(int type, int nid, struct ssh *ssh)
{
struct key_entry *k;
debug3_f("need %d", type);
TAILQ_FOREACH(k, &ssh->private_keys, next) {
debug3_f("check %s", sshkey_type(k->key));
if (k->key->type == type &&
(type != KEY_ECDSA || k->key->ecdsa_nid == nid))
return (k->key);
}
return (NULL);
}
int
_ssh_verify_host_key(struct sshkey *hostkey, struct ssh *ssh)
{
struct key_entry *k;
debug3_f("need %s", sshkey_type(hostkey));
TAILQ_FOREACH(k, &ssh->public_keys, next) {
debug3_f("check %s", sshkey_type(k->key));
if (sshkey_equal_public(hostkey, k->key))
return (0); /* ok */
}
return (-1); /* failed */
}
/* offer hostkey algorithms in kexinit depending on registered keys */
int
_ssh_order_hostkeyalgs(struct ssh *ssh)
{
struct key_entry *k;
char *orig, *avail, *oavail = NULL, *alg, *replace = NULL;
char **proposal;
size_t maxlen;
int ktype, r;
/* XXX we de-serialize ssh->kex->my, modify it, and change it */
if ((r = kex_buf2prop(ssh->kex->my, NULL, &proposal)) != 0)
return r;
orig = proposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
if ((oavail = avail = strdup(orig)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
maxlen = strlen(avail) + 1;
if ((replace = calloc(1, maxlen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
*replace = '\0';
while ((alg = strsep(&avail, ",")) && *alg != '\0') {
if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC)
continue;
TAILQ_FOREACH(k, &ssh->public_keys, next) {
if (k->key->type == ktype ||
(sshkey_is_cert(k->key) && k->key->type ==
sshkey_type_plain(ktype))) {
if (*replace != '\0')
strlcat(replace, ",", maxlen);
strlcat(replace, alg, maxlen);
break;
}
}
}
if (*replace != '\0') {
debug2_f("orig/%d %s", ssh->kex->server, orig);
debug2_f("replace/%d %s", ssh->kex->server, replace);
free(orig);
proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = replace;
replace = NULL; /* owned by proposal */
r = kex_prop2buf(ssh->kex->my, proposal);
}
out:
free(oavail);
free(replace);
kex_prop_free(proposal);
return r;
}
int
_ssh_host_key_sign(struct ssh *ssh, struct sshkey *privkey,
struct sshkey *pubkey, u_char **signature, size_t *slen,
const u_char *data, size_t dlen, const char *alg)
{
return sshkey_sign(privkey, signature, slen, data, dlen,
alg, NULL, NULL, ssh->compat);
}
diff --git a/ssh_config.0 b/ssh_config.0
index 38af944c1b1a..837ac74e36b1 100644
--- a/ssh_config.0
+++ b/ssh_config.0
@@ -1,1267 +1,1268 @@
SSH_CONFIG(5) File Formats Manual SSH_CONFIG(5)
NAME
ssh_config M-bM-^@M-^S OpenSSH client configuration file
DESCRIPTION
ssh(1) obtains configuration data from the following sources in the
following order:
1. command-line options
2. user's configuration file (~/.ssh/config)
3. system-wide configuration file (/etc/ssh/ssh_config)
For each parameter, the first obtained value will be used. The
configuration files contain sections separated by Host specifications,
and that section is only applied for hosts that match one of the patterns
given in the specification. The matched host name is usually the one
given on the command line (see the CanonicalizeHostname option for
exceptions).
Since the first obtained value for each parameter is used, more host-
specific declarations should be given near the beginning of the file, and
general defaults at the end.
The file contains keyword-argument pairs, one per line. Lines starting
with M-bM-^@M-^X#M-bM-^@M-^Y and empty lines are interpreted as comments. Arguments may
optionally be enclosed in double quotes (") in order to represent
arguments containing spaces. Configuration options may be separated by
whitespace or optional whitespace and exactly one M-bM-^@M-^X=M-bM-^@M-^Y; the latter format
is useful to avoid the need to quote whitespace when specifying
configuration options using the ssh, scp, and sftp -o option.
The possible keywords and their meanings are as follows (note that
keywords are case-insensitive and arguments are case-sensitive):
Host Restricts the following declarations (up to the next Host or
Match keyword) to be only for those hosts that match one of the
patterns given after the keyword. If more than one pattern is
provided, they should be separated by whitespace. A single M-bM-^@M-^X*M-bM-^@M-^Y
as a pattern can be used to provide global defaults for all
hosts. The host is usually the hostname argument given on the
command line (see the CanonicalizeHostname keyword for
exceptions).
A pattern entry may be negated by prefixing it with an
exclamation mark (M-bM-^@M-^X!M-bM-^@M-^Y). If a negated entry is matched, then the
Host entry is ignored, regardless of whether any other patterns
on the line match. Negated matches are therefore useful to
provide exceptions for wildcard matches.
See PATTERNS for more information on patterns.
Match Restricts the following declarations (up to the next Host or
Match keyword) to be used only when the conditions following the
Match keyword are satisfied. Match conditions are specified
using one or more criteria or the single token all which always
matches. The available criteria keywords are: canonical, final,
exec, host, originalhost, user, and localuser. The all criteria
must appear alone or immediately after canonical or final. Other
criteria may be combined arbitrarily. All criteria but all,
canonical, and final require an argument. Criteria may be
negated by prepending an exclamation mark (M-bM-^@M-^X!M-bM-^@M-^Y).
The canonical keyword matches only when the configuration file is
being re-parsed after hostname canonicalization (see the
CanonicalizeHostname option). This may be useful to specify
conditions that work with canonical host names only.
The final keyword requests that the configuration be re-parsed
(regardless of whether CanonicalizeHostname is enabled), and
matches only during this final pass. If CanonicalizeHostname is
enabled, then canonical and final match during the same pass.
The exec keyword executes the specified command under the user's
shell. If the command returns a zero exit status then the
condition is considered true. Commands containing whitespace
characters must be quoted. Arguments to exec accept the tokens
described in the TOKENS section.
The other keywords' criteria must be single entries or comma-
separated lists and may use the wildcard and negation operators
described in the PATTERNS section. The criteria for the host
keyword are matched against the target hostname, after any
substitution by the Hostname or CanonicalizeHostname options.
The originalhost keyword matches against the hostname as it was
specified on the command-line. The user keyword matches against
the target username on the remote host. The localuser keyword
matches against the name of the local user running ssh(1) (this
keyword may be useful in system-wide ssh_config files).
AddKeysToAgent
Specifies whether keys should be automatically added to a running
ssh-agent(1). If this option is set to yes and a key is loaded
from a file, the key and its passphrase are added to the agent
with the default lifetime, as if by ssh-add(1). If this option
is set to ask, ssh(1) will require confirmation using the
SSH_ASKPASS program before adding a key (see ssh-add(1) for
details). If this option is set to confirm, each use of the key
must be confirmed, as if the -c option was specified to
ssh-add(1). If this option is set to no, no keys are added to
the agent. Alternately, this option may be specified as a time
interval using the format described in the TIME FORMATS section
of sshd_config(5) to specify the key's lifetime in ssh-agent(1),
after which it will automatically be removed. The argument must
be no (the default), yes, confirm (optionally followed by a time
interval), ask or a time interval.
AddressFamily
Specifies which address family to use when connecting. Valid
arguments are any (the default), inet (use IPv4 only), or inet6
(use IPv6 only).
BatchMode
If set to yes, user interaction such as password prompts and host
key confirmation requests will be disabled. This option is
useful in scripts and other batch jobs where no user is present
to interact with ssh(1). The argument must be yes or no (the
default).
BindAddress
Use the specified address on the local machine as the source
address of the connection. Only useful on systems with more than
one address.
BindInterface
Use the address of the specified interface on the local machine
as the source address of the connection.
CanonicalDomains
When CanonicalizeHostname is enabled, this option specifies the
list of domain suffixes in which to search for the specified
destination host.
CanonicalizeFallbackLocal
Specifies whether to fail with an error when hostname
canonicalization fails. The default, yes, will attempt to look
up the unqualified hostname using the system resolver's search
rules. A value of no will cause ssh(1) to fail instantly if
CanonicalizeHostname is enabled and the target hostname cannot be
found in any of the domains specified by CanonicalDomains.
CanonicalizeHostname
Controls whether explicit hostname canonicalization is performed.
The default, no, is not to perform any name rewriting and let the
system resolver handle all hostname lookups. If set to yes then,
for connections that do not use a ProxyCommand or ProxyJump,
ssh(1) will attempt to canonicalize the hostname specified on the
command line using the CanonicalDomains suffixes and
CanonicalizePermittedCNAMEs rules. If CanonicalizeHostname is
set to always, then canonicalization is applied to proxied
connections too.
If this option is enabled, then the configuration files are
processed again using the new target name to pick up any new
configuration in matching Host and Match stanzas.
CanonicalizeMaxDots
Specifies the maximum number of dot characters in a hostname
before canonicalization is disabled. The default, 1, allows a
single dot (i.e. hostname.subdomain).
CanonicalizePermittedCNAMEs
Specifies rules to determine whether CNAMEs should be followed
when canonicalizing hostnames. The rules consist of one or more
arguments of source_domain_list:target_domain_list, where
source_domain_list is a pattern-list of domains that may follow
CNAMEs in canonicalization, and target_domain_list is a pattern-
list of domains that they may resolve to.
For example, "*.a.example.com:*.b.example.com,*.c.example.com"
will allow hostnames matching "*.a.example.com" to be
canonicalized to names in the "*.b.example.com" or
"*.c.example.com" domains.
CASignatureAlgorithms
Specifies which algorithms are allowed for signing of
certificates by certificate authorities (CAs). The default is:
- ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,
- ecdsa-sha2-nistp521,rsa-sha2-512,rsa-sha2-256,ssh-rsa
+ ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
+ sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com,
+ rsa-sha2-512,rsa-sha2-256
ssh(1) will not accept host certificates signed using algorithms
other than those specified.
CertificateFile
Specifies a file from which the user's certificate is read. A
corresponding private key must be provided separately in order to
use this certificate either from an IdentityFile directive or -i
flag to ssh(1), via ssh-agent(1), or via a PKCS11Provider or
SecurityKeyProvider.
Arguments to CertificateFile may use the tilde syntax to refer to
a user's home directory, the tokens described in the TOKENS
section and environment variables as described in the ENVIRONMENT
VARIABLES section.
It is possible to have multiple certificate files specified in
configuration files; these certificates will be tried in
sequence. Multiple CertificateFile directives will add to the
list of certificates used for authentication.
ChallengeResponseAuthentication
Specifies whether to use challenge-response authentication. The
argument to this keyword must be yes (the default) or no.
CheckHostIP
If set to yes ssh(1) will additionally check the host IP address
in the known_hosts file. This allows it to detect if a host key
changed due to DNS spoofing and will add addresses of destination
hosts to ~/.ssh/known_hosts in the process, regardless of the
setting of StrictHostKeyChecking. If the option is set to no
(the default), the check will not be executed.
Ciphers
Specifies the ciphers allowed and their order of preference.
Multiple ciphers must be comma-separated. If the specified list
begins with a M-bM-^@M-^X+M-bM-^@M-^Y character, then the specified ciphers will be
appended to the default set instead of replacing them. If the
specified list begins with a M-bM-^@M-^X-M-bM-^@M-^Y character, then the specified
ciphers (including wildcards) will be removed from the default
set instead of replacing them. If the specified list begins with
a M-bM-^@M-^X^M-bM-^@M-^Y character, then the specified ciphers will be placed at the
head of the default set.
The supported ciphers are:
3des-cbc
aes128-cbc
aes192-cbc
aes256-cbc
aes128-ctr
aes192-ctr
aes256-ctr
aes128-gcm@openssh.com
aes256-gcm@openssh.com
chacha20-poly1305@openssh.com
The default is:
chacha20-poly1305@openssh.com,
aes128-ctr,aes192-ctr,aes256-ctr,
aes128-gcm@openssh.com,aes256-gcm@openssh.com
The list of available ciphers may also be obtained using "ssh -Q
cipher".
ClearAllForwardings
Specifies that all local, remote, and dynamic port forwardings
specified in the configuration files or on the command line be
cleared. This option is primarily useful when used from the
ssh(1) command line to clear port forwardings set in
configuration files, and is automatically set by scp(1) and
sftp(1). The argument must be yes or no (the default).
Compression
Specifies whether to use compression. The argument must be yes
or no (the default).
ConnectionAttempts
Specifies the number of tries (one per second) to make before
exiting. The argument must be an integer. This may be useful in
scripts if the connection sometimes fails. The default is 1.
ConnectTimeout
Specifies the timeout (in seconds) used when connecting to the
SSH server, instead of using the default system TCP timeout.
This timeout is applied both to establishing the connection and
to performing the initial SSH protocol handshake and key
exchange.
ControlMaster
Enables the sharing of multiple sessions over a single network
connection. When set to yes, ssh(1) will listen for connections
on a control socket specified using the ControlPath argument.
Additional sessions can connect to this socket using the same
ControlPath with ControlMaster set to no (the default). These
sessions will try to reuse the master instance's network
connection rather than initiating new ones, but will fall back to
connecting normally if the control socket does not exist, or is
not listening.
Setting this to ask will cause ssh(1) to listen for control
connections, but require confirmation using ssh-askpass(1). If
the ControlPath cannot be opened, ssh(1) will continue without
connecting to a master instance.
X11 and ssh-agent(1) forwarding is supported over these
multiplexed connections, however the display and agent forwarded
will be the one belonging to the master connection i.e. it is not
possible to forward multiple displays or agents.
Two additional options allow for opportunistic multiplexing: try
to use a master connection but fall back to creating a new one if
one does not already exist. These options are: auto and autoask.
The latter requires confirmation like the ask option.
ControlPath
Specify the path to the control socket used for connection
sharing as described in the ControlMaster section above or the
string none to disable connection sharing. Arguments to
ControlPath may use the tilde syntax to refer to a user's home
directory, the tokens described in the TOKENS section and
environment variables as described in the ENVIRONMENT VARIABLES
section. It is recommended that any ControlPath used for
opportunistic connection sharing include at least %h, %p, and %r
(or alternatively %C) and be placed in a directory that is not
writable by other users. This ensures that shared connections
are uniquely identified.
ControlPersist
When used in conjunction with ControlMaster, specifies that the
master connection should remain open in the background (waiting
for future client connections) after the initial client
connection has been closed. If set to no (the default), then the
master connection will not be placed into the background, and
will close as soon as the initial client connection is closed.
If set to yes or 0, then the master connection will remain in the
background indefinitely (until killed or closed via a mechanism
such as the "ssh -O exit"). If set to a time in seconds, or a
time in any of the formats documented in sshd_config(5), then the
backgrounded master connection will automatically terminate after
it has remained idle (with no client connections) for the
specified time.
DynamicForward
Specifies that a TCP port on the local machine be forwarded over
the secure channel, and the application protocol is then used to
determine where to connect to from the remote machine.
The argument must be [bind_address:]port. IPv6 addresses can be
specified by enclosing addresses in square brackets. By default,
the local port is bound in accordance with the GatewayPorts
setting. However, an explicit bind_address may be used to bind
the connection to a specific address. The bind_address of
localhost indicates that the listening port be bound for local
use only, while an empty address or M-bM-^@M-^X*M-bM-^@M-^Y indicates that the port
should be available from all interfaces.
Currently the SOCKS4 and SOCKS5 protocols are supported, and
ssh(1) will act as a SOCKS server. Multiple forwardings may be
specified, and additional forwardings can be given on the command
line. Only the superuser can forward privileged ports.
EnableSSHKeysign
Setting this option to yes in the global client configuration
file /etc/ssh/ssh_config enables the use of the helper program
ssh-keysign(8) during HostbasedAuthentication. The argument must
be yes or no (the default). This option should be placed in the
non-hostspecific section. See ssh-keysign(8) for more
information.
EscapeChar
Sets the escape character (default: M-bM-^@M-^X~M-bM-^@M-^Y). The escape character
can also be set on the command line. The argument should be a
single character, M-bM-^@M-^X^M-bM-^@M-^Y followed by a letter, or none to disable
the escape character entirely (making the connection transparent
for binary data).
ExitOnForwardFailure
Specifies whether ssh(1) should terminate the connection if it
cannot set up all requested dynamic, tunnel, local, and remote
port forwardings, (e.g. if either end is unable to bind and
listen on a specified port). Note that ExitOnForwardFailure does
not apply to connections made over port forwardings and will not,
for example, cause ssh(1) to exit if TCP connections to the
ultimate forwarding destination fail. The argument must be yes
or no (the default).
FingerprintHash
Specifies the hash algorithm used when displaying key
fingerprints. Valid options are: md5 and sha256 (the default).
ForwardAgent
Specifies whether the connection to the authentication agent (if
any) will be forwarded to the remote machine. The argument may
be yes, no (the default), an explicit path to an agent socket or
the name of an environment variable (beginning with M-bM-^@M-^X$M-bM-^@M-^Y) in which
to find the path.
Agent forwarding should be enabled with caution. Users with the
ability to bypass file permissions on the remote host (for the
agent's Unix-domain socket) can access the local agent through
the forwarded connection. An attacker cannot obtain key material
from the agent, however they can perform operations on the keys
that enable them to authenticate using the identities loaded into
the agent.
ForwardX11
Specifies whether X11 connections will be automatically
redirected over the secure channel and DISPLAY set. The argument
must be yes or no (the default).
X11 forwarding should be enabled with caution. Users with the
ability to bypass file permissions on the remote host (for the
user's X11 authorization database) can access the local X11
display through the forwarded connection. An attacker may then
be able to perform activities such as keystroke monitoring if the
ForwardX11Trusted option is also enabled.
ForwardX11Timeout
Specify a timeout for untrusted X11 forwarding using the format
described in the TIME FORMATS section of sshd_config(5). X11
connections received by ssh(1) after this time will be refused.
Setting ForwardX11Timeout to zero will disable the timeout and
permit X11 forwarding for the life of the connection. The
default is to disable untrusted X11 forwarding after twenty
minutes has elapsed.
ForwardX11Trusted
If this option is set to yes, remote X11 clients will have full
access to the original X11 display.
If this option is set to no (the default), remote X11 clients
will be considered untrusted and prevented from stealing or
tampering with data belonging to trusted X11 clients.
Furthermore, the xauth(1) token used for the session will be set
to expire after 20 minutes. Remote clients will be refused
access after this time.
See the X11 SECURITY extension specification for full details on
the restrictions imposed on untrusted clients.
GatewayPorts
Specifies whether remote hosts are allowed to connect to local
forwarded ports. By default, ssh(1) binds local port forwardings
to the loopback address. This prevents other remote hosts from
connecting to forwarded ports. GatewayPorts can be used to
specify that ssh should bind local port forwardings to the
wildcard address, thus allowing remote hosts to connect to
forwarded ports. The argument must be yes or no (the default).
GlobalKnownHostsFile
Specifies one or more files to use for the global host key
database, separated by whitespace. The default is
/etc/ssh/ssh_known_hosts, /etc/ssh/ssh_known_hosts2.
GSSAPIAuthentication
Specifies whether user authentication based on GSSAPI is allowed.
The default is no.
GSSAPIDelegateCredentials
Forward (delegate) credentials to the server. The default is no.
HashKnownHosts
Indicates that ssh(1) should hash host names and addresses when
they are added to ~/.ssh/known_hosts. These hashed names may be
used normally by ssh(1) and sshd(8), but they do not visually
reveal identifying information if the file's contents are
disclosed. The default is no. Note that existing names and
addresses in known hosts files will not be converted
automatically, but may be manually hashed using ssh-keygen(1).
HostbasedAcceptedAlgorithms
Specifies the signature algorithms that will be used for
hostbased authentication as a comma-separated list of patterns.
Alternately if the specified list begins with a M-bM-^@M-^X+M-bM-^@M-^Y character,
then the specified signature algorithms will be appended to the
default set instead of replacing them. If the specified list
begins with a M-bM-^@M-^X-M-bM-^@M-^Y character, then the specified signature
algorithms (including wildcards) will be removed from the default
set instead of replacing them. If the specified list begins with
a M-bM-^@M-^X^M-bM-^@M-^Y character, then the specified signature algorithms will be
placed at the head of the default set. The default for this
option is:
ssh-ed25519-cert-v01@openssh.com,
ecdsa-sha2-nistp256-cert-v01@openssh.com,
ecdsa-sha2-nistp384-cert-v01@openssh.com,
ecdsa-sha2-nistp521-cert-v01@openssh.com,
sk-ssh-ed25519-cert-v01@openssh.com,
sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
rsa-sha2-512-cert-v01@openssh.com,
rsa-sha2-256-cert-v01@openssh.com,
ssh-rsa-cert-v01@openssh.com,
ssh-ed25519,
ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
sk-ssh-ed25519@openssh.com,
sk-ecdsa-sha2-nistp256@openssh.com,
rsa-sha2-512,rsa-sha2-256,ssh-rsa
The -Q option of ssh(1) may be used to list supported signature
algorithms. This was formerly named HostbasedKeyTypes.
HostbasedAuthentication
Specifies whether to try rhosts based authentication with public
key authentication. The argument must be yes or no (the
default).
HostKeyAlgorithms
Specifies the host key signature algorithms that the client wants
to use in order of preference. Alternately if the specified list
begins with a M-bM-^@M-^X+M-bM-^@M-^Y character, then the specified signature
algorithms will be appended to the default set instead of
replacing them. If the specified list begins with a M-bM-^@M-^X-M-bM-^@M-^Y
character, then the specified signature algorithms (including
wildcards) will be removed from the default set instead of
replacing them. If the specified list begins with a M-bM-^@M-^X^M-bM-^@M-^Y
character, then the specified signature algorithms will be placed
at the head of the default set. The default for this option is:
ssh-ed25519-cert-v01@openssh.com,
ecdsa-sha2-nistp256-cert-v01@openssh.com,
ecdsa-sha2-nistp384-cert-v01@openssh.com,
ecdsa-sha2-nistp521-cert-v01@openssh.com,
sk-ssh-ed25519-cert-v01@openssh.com,
sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
rsa-sha2-512-cert-v01@openssh.com,
rsa-sha2-256-cert-v01@openssh.com,
ssh-rsa-cert-v01@openssh.com,
ssh-ed25519,
ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
sk-ecdsa-sha2-nistp256@openssh.com,
sk-ssh-ed25519@openssh.com,
rsa-sha2-512,rsa-sha2-256,ssh-rsa
If hostkeys are known for the destination host then this default
is modified to prefer their algorithms.
The list of available signature algorithms may also be obtained
using "ssh -Q HostKeyAlgorithms".
HostKeyAlias
Specifies an alias that should be used instead of the real host
name when looking up or saving the host key in the host key
database files and when validating host certificates. This
option is useful for tunneling SSH connections or for multiple
servers running on a single host.
Hostname
Specifies the real host name to log into. This can be used to
specify nicknames or abbreviations for hosts. Arguments to
Hostname accept the tokens described in the TOKENS section.
Numeric IP addresses are also permitted (both on the command line
and in Hostname specifications). The default is the name given
on the command line.
IdentitiesOnly
Specifies that ssh(1) should only use the configured
authentication identity and certificate files (either the default
files, or those explicitly configured in the ssh_config files or
passed on the ssh(1) command-line), even if ssh-agent(1) or a
PKCS11Provider or SecurityKeyProvider offers more identities.
The argument to this keyword must be yes or no (the default).
This option is intended for situations where ssh-agent offers
many different identities.
IdentityAgent
Specifies the UNIX-domain socket used to communicate with the
authentication agent.
This option overrides the SSH_AUTH_SOCK environment variable and
can be used to select a specific agent. Setting the socket name
to none disables the use of an authentication agent. If the
string "SSH_AUTH_SOCK" is specified, the location of the socket
will be read from the SSH_AUTH_SOCK environment variable.
Otherwise if the specified value begins with a M-bM-^@M-^X$M-bM-^@M-^Y character,
then it will be treated as an environment variable containing the
location of the socket.
Arguments to IdentityAgent may use the tilde syntax to refer to a
user's home directory, the tokens described in the TOKENS section
and environment variables as described in the ENVIRONMENT
VARIABLES section.
IdentityFile
Specifies a file from which the user's DSA, ECDSA, authenticator-
hosted ECDSA, Ed25519, authenticator-hosted Ed25519 or RSA
authentication identity is read. The default is ~/.ssh/id_dsa,
~/.ssh/id_ecdsa, ~/.ssh/id_ecdsa_sk, ~/.ssh/id_ed25519,
~/.ssh/id_ed25519_sk and ~/.ssh/id_rsa. Additionally, any
identities represented by the authentication agent will be used
for authentication unless IdentitiesOnly is set. If no
certificates have been explicitly specified by CertificateFile,
ssh(1) will try to load certificate information from the filename
obtained by appending -cert.pub to the path of a specified
IdentityFile.
Arguments to IdentityFile may use the tilde syntax to refer to a
user's home directory or the tokens described in the TOKENS
section.
It is possible to have multiple identity files specified in
configuration files; all these identities will be tried in
sequence. Multiple IdentityFile directives will add to the list
of identities tried (this behaviour differs from that of other
configuration directives).
IdentityFile may be used in conjunction with IdentitiesOnly to
select which identities in an agent are offered during
authentication. IdentityFile may also be used in conjunction
with CertificateFile in order to provide any certificate also
needed for authentication with the identity.
IgnoreUnknown
Specifies a pattern-list of unknown options to be ignored if they
are encountered in configuration parsing. This may be used to
suppress errors if ssh_config contains options that are
unrecognised by ssh(1). It is recommended that IgnoreUnknown be
listed early in the configuration file as it will not be applied
to unknown options that appear before it.
Include
Include the specified configuration file(s). Multiple pathnames
may be specified and each pathname may contain glob(7) wildcards
and, for user configurations, shell-like M-bM-^@M-^X~M-bM-^@M-^Y references to user
home directories. Wildcards will be expanded and processed in
lexical order. Files without absolute paths are assumed to be in
~/.ssh if included in a user configuration file or /etc/ssh if
included from the system configuration file. Include directive
may appear inside a Match or Host block to perform conditional
inclusion.
IPQoS Specifies the IPv4 type-of-service or DSCP class for connections.
Accepted values are af11, af12, af13, af21, af22, af23, af31,
af32, af33, af41, af42, af43, cs0, cs1, cs2, cs3, cs4, cs5, cs6,
cs7, ef, le, lowdelay, throughput, reliability, a numeric value,
or none to use the operating system default. This option may
take one or two arguments, separated by whitespace. If one
argument is specified, it is used as the packet class
unconditionally. If two values are specified, the first is
automatically selected for interactive sessions and the second
for non-interactive sessions. The default is af21 (Low-Latency
Data) for interactive sessions and cs1 (Lower Effort) for non-
interactive sessions.
KbdInteractiveAuthentication
Specifies whether to use keyboard-interactive authentication.
The argument to this keyword must be yes (the default) or no.
KbdInteractiveDevices
Specifies the list of methods to use in keyboard-interactive
authentication. Multiple method names must be comma-separated.
The default is to use the server specified list. The methods
available vary depending on what the server supports. For an
OpenSSH server, it may be zero or more of: bsdauth and pam.
KexAlgorithms
Specifies the available KEX (Key Exchange) algorithms. Multiple
algorithms must be comma-separated. If the specified list begins
with a M-bM-^@M-^X+M-bM-^@M-^Y character, then the specified methods will be appended
to the default set instead of replacing them. If the specified
list begins with a M-bM-^@M-^X-M-bM-^@M-^Y character, then the specified methods
(including wildcards) will be removed from the default set
instead of replacing them. If the specified list begins with a
M-bM-^@M-^X^M-bM-^@M-^Y character, then the specified methods will be placed at the
head of the default set. The default is:
curve25519-sha256,curve25519-sha256@libssh.org,
ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,
diffie-hellman-group-exchange-sha256,
diffie-hellman-group16-sha512,
diffie-hellman-group18-sha512,
diffie-hellman-group14-sha256
The list of available key exchange algorithms may also be
obtained using "ssh -Q kex".
KnownHostsCommand
Specifies a command to use to obtain a list of host keys, in
addition to those listed in UserKnownHostsFile and
GlobalKnownHostsFile. This command is executed after the files
have been read. It may write host key lines to standard output
in identical format to the usual files (described in the
VERIFYING HOST KEYS section in ssh(1)). Arguments to
KnownHostsCommand accept the tokens described in the TOKENS
section. The command may be invoked multiple times per
connection: once when preparing the preference list of host key
algorithms to use, again to obtain the host key for the requested
host name and, if CheckHostIP is enabled, one more time to obtain
the host key matching the server's address. If the command exits
abnormally or returns a non-zero exit status then the connection
is terminated.
LocalCommand
Specifies a command to execute on the local machine after
successfully connecting to the server. The command string
extends to the end of the line, and is executed with the user's
shell. Arguments to LocalCommand accept the tokens described in
the TOKENS section.
The command is run synchronously and does not have access to the
session of the ssh(1) that spawned it. It should not be used for
interactive commands.
This directive is ignored unless PermitLocalCommand has been
enabled.
LocalForward
Specifies that a TCP port on the local machine be forwarded over
the secure channel to the specified host and port from the remote
machine. The first argument specifies the listener and may be
[bind_address:]port or a Unix domain socket path. The second
argument is the destination and may be host:hostport or a Unix
domain socket path if the remote host supports it.
IPv6 addresses can be specified by enclosing addresses in square
brackets. Multiple forwardings may be specified, and additional
forwardings can be given on the command line. Only the superuser
can forward privileged ports. By default, the local port is
bound in accordance with the GatewayPorts setting. However, an
explicit bind_address may be used to bind the connection to a
specific address. The bind_address of localhost indicates that
the listening port be bound for local use only, while an empty
address or M-bM-^@M-^X*M-bM-^@M-^Y indicates that the port should be available from
all interfaces. Unix domain socket paths may use the tokens
described in the TOKENS section and environment variables as
described in the ENVIRONMENT VARIABLES section.
LogLevel
Gives the verbosity level that is used when logging messages from
ssh(1). The possible values are: QUIET, FATAL, ERROR, INFO,
VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3. The default is INFO.
DEBUG and DEBUG1 are equivalent. DEBUG2 and DEBUG3 each specify
higher levels of verbose output.
LogVerbose
Specify one or more overrides to LogLevel. An override consists
of a pattern lists that matches the source file, function and
line number to force detailed logging for. For example, an
override pattern of:
kex.c:*:1000,*:kex_exchange_identification():*,packet.c:*
would enable detailed logging for line 1000 of kex.c, everything
in the kex_exchange_identification() function, and all code in
the packet.c file. This option is intended for debugging and no
overrides are enabled by default.
MACs Specifies the MAC (message authentication code) algorithms in
order of preference. The MAC algorithm is used for data
integrity protection. Multiple algorithms must be comma-
separated. If the specified list begins with a M-bM-^@M-^X+M-bM-^@M-^Y character,
then the specified algorithms will be appended to the default set
instead of replacing them. If the specified list begins with a
M-bM-^@M-^X-M-bM-^@M-^Y character, then the specified algorithms (including
wildcards) will be removed from the default set instead of
replacing them. If the specified list begins with a M-bM-^@M-^X^M-bM-^@M-^Y
character, then the specified algorithms will be placed at the
head of the default set.
The algorithms that contain "-etm" calculate the MAC after
encryption (encrypt-then-mac). These are considered safer and
their use recommended.
The default is:
umac-64-etm@openssh.com,umac-128-etm@openssh.com,
hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,
hmac-sha1-etm@openssh.com,
umac-64@openssh.com,umac-128@openssh.com,
hmac-sha2-256,hmac-sha2-512,hmac-sha1
The list of available MAC algorithms may also be obtained using
"ssh -Q mac".
NoHostAuthenticationForLocalhost
Disable host authentication for localhost (loopback addresses).
The argument to this keyword must be yes or no (the default).
NumberOfPasswordPrompts
Specifies the number of password prompts before giving up. The
argument to this keyword must be an integer. The default is 3.
PasswordAuthentication
Specifies whether to use password authentication. The argument
to this keyword must be yes (the default) or no.
PermitLocalCommand
Allow local command execution via the LocalCommand option or
using the !command escape sequence in ssh(1). The argument must
be yes or no (the default).
PermitRemoteOpen
Specifies the destinations to which remote TCP port forwarding is
permitted when RemoteForward is used as a SOCKS proxy. The
forwarding specification must be one of the following forms:
PermitRemoteOpen host:port
PermitRemoteOpen IPv4_addr:port
PermitRemoteOpen [IPv6_addr]:port
Multiple forwards may be specified by separating them with
whitespace. An argument of any can be used to remove all
restrictions and permit any forwarding requests. An argument of
none can be used to prohibit all forwarding requests. The
wildcard M-bM-^@M-^X*M-bM-^@M-^Y can be used for host or port to allow all hosts or
ports respectively. Otherwise, no pattern matching or address
lookups are performed on supplied names.
PKCS11Provider
Specifies which PKCS#11 provider to use or none to indicate that
no provider should be used (the default). The argument to this
keyword is a path to the PKCS#11 shared library ssh(1) should use
to communicate with a PKCS#11 token providing keys for user
authentication.
Port Specifies the port number to connect on the remote host. The
default is 22.
PreferredAuthentications
Specifies the order in which the client should try authentication
methods. This allows a client to prefer one method (e.g.
keyboard-interactive) over another method (e.g. password). The
default is:
gssapi-with-mic,hostbased,publickey,
keyboard-interactive,password
ProxyCommand
Specifies the command to use to connect to the server. The
command string extends to the end of the line, and is executed
using the user's shell M-bM-^@M-^XexecM-bM-^@M-^Y directive to avoid a lingering
shell process.
Arguments to ProxyCommand accept the tokens described in the
TOKENS section. The command can be basically anything, and
should read from its standard input and write to its standard
output. It should eventually connect an sshd(8) server running
on some machine, or execute sshd -i somewhere. Host key
management will be done using the Hostname of the host being
connected (defaulting to the name typed by the user). Setting
the command to none disables this option entirely. Note that
CheckHostIP is not available for connects with a proxy command.
This directive is useful in conjunction with nc(1) and its proxy
support. For example, the following directive would connect via
an HTTP proxy at 192.0.2.0:
ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p
ProxyJump
Specifies one or more jump proxies as either [user@]host[:port]
or an ssh URI. Multiple proxies may be separated by comma
characters and will be visited sequentially. Setting this option
will cause ssh(1) to connect to the target host by first making a
ssh(1) connection to the specified ProxyJump host and then
establishing a TCP forwarding to the ultimate target from there.
Setting the host to none disables this option entirely.
Note that this option will compete with the ProxyCommand option -
whichever is specified first will prevent later instances of the
other from taking effect.
Note also that the configuration for the destination host (either
supplied via the command-line or the configuration file) is not
generally applied to jump hosts. ~/.ssh/config should be used if
specific configuration is required for jump hosts.
ProxyUseFdpass
Specifies that ProxyCommand will pass a connected file descriptor
back to ssh(1) instead of continuing to execute and pass data.
The default is no.
PubkeyAcceptedAlgorithms
Specifies the signature algorithms that will be used for public
key authentication as a comma-separated list of patterns. If the
specified list begins with a M-bM-^@M-^X+M-bM-^@M-^Y character, then the algorithms
after it will be appended to the default instead of replacing it.
If the specified list begins with a M-bM-^@M-^X-M-bM-^@M-^Y character, then the
specified algorithms (including wildcards) will be removed from
the default set instead of replacing them. If the specified list
begins with a M-bM-^@M-^X^M-bM-^@M-^Y character, then the specified algorithms will
be placed at the head of the default set. The default for this
option is:
ssh-ed25519-cert-v01@openssh.com,
ecdsa-sha2-nistp256-cert-v01@openssh.com,
ecdsa-sha2-nistp384-cert-v01@openssh.com,
ecdsa-sha2-nistp521-cert-v01@openssh.com,
sk-ssh-ed25519-cert-v01@openssh.com,
sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
rsa-sha2-512-cert-v01@openssh.com,
rsa-sha2-256-cert-v01@openssh.com,
ssh-rsa-cert-v01@openssh.com,
ssh-ed25519,
ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
sk-ssh-ed25519@openssh.com,
sk-ecdsa-sha2-nistp256@openssh.com,
rsa-sha2-512,rsa-sha2-256,ssh-rsa
The list of available signature algorithms may also be obtained
using "ssh -Q PubkeyAcceptedAlgorithms".
PubkeyAuthentication
Specifies whether to try public key authentication. The argument
to this keyword must be yes (the default) or no.
RekeyLimit
Specifies the maximum amount of data that may be transmitted
before the session key is renegotiated, optionally followed by a
maximum amount of time that may pass before the session key is
renegotiated. The first argument is specified in bytes and may
have a suffix of M-bM-^@M-^XKM-bM-^@M-^Y, M-bM-^@M-^XMM-bM-^@M-^Y, or M-bM-^@M-^XGM-bM-^@M-^Y to indicate Kilobytes,
Megabytes, or Gigabytes, respectively. The default is between
M-bM-^@M-^X1GM-bM-^@M-^Y and M-bM-^@M-^X4GM-bM-^@M-^Y, depending on the cipher. The optional second
value is specified in seconds and may use any of the units
documented in the TIME FORMATS section of sshd_config(5). The
default value for RekeyLimit is default none, which means that
rekeying is performed after the cipher's default amount of data
has been sent or received and no time based rekeying is done.
RemoteCommand
Specifies a command to execute on the remote machine after
successfully connecting to the server. The command string
extends to the end of the line, and is executed with the user's
shell. Arguments to RemoteCommand accept the tokens described in
the TOKENS section.
RemoteForward
Specifies that a TCP port on the remote machine be forwarded over
the secure channel. The remote port may either be forwarded to a
specified host and port from the local machine, or may act as a
SOCKS 4/5 proxy that allows a remote client to connect to
arbitrary destinations from the local machine. The first
argument is the listening specification and may be
[bind_address:]port or, if the remote host supports it, a Unix
domain socket path. If forwarding to a specific destination then
the second argument must be host:hostport or a Unix domain socket
path, otherwise if no destination argument is specified then the
remote forwarding will be established as a SOCKS proxy. When
acting as a SOCKS proxy the destination of the connection can be
restricted by PermitRemoteOpen.
IPv6 addresses can be specified by enclosing addresses in square
brackets. Multiple forwardings may be specified, and additional
forwardings can be given on the command line. Privileged ports
can be forwarded only when logging in as root on the remote
machine. Unix domain socket paths may use the tokens described
in the TOKENS section and environment variables as described in
the ENVIRONMENT VARIABLES section.
If the port argument is 0, the listen port will be dynamically
allocated on the server and reported to the client at run time.
If the bind_address is not specified, the default is to only bind
to loopback addresses. If the bind_address is M-bM-^@M-^X*M-bM-^@M-^Y or an empty
string, then the forwarding is requested to listen on all
interfaces. Specifying a remote bind_address will only succeed
if the server's GatewayPorts option is enabled (see
sshd_config(5)).
RequestTTY
Specifies whether to request a pseudo-tty for the session. The
argument may be one of: no (never request a TTY), yes (always
request a TTY when standard input is a TTY), force (always
request a TTY) or auto (request a TTY when opening a login
session). This option mirrors the -t and -T flags for ssh(1).
RevokedHostKeys
Specifies revoked host public keys. Keys listed in this file
will be refused for host authentication. Note that if this file
does not exist or is not readable, then host authentication will
be refused for all hosts. Keys may be specified as a text file,
listing one public key per line, or as an OpenSSH Key Revocation
List (KRL) as generated by ssh-keygen(1). For more information
on KRLs, see the KEY REVOCATION LISTS section in ssh-keygen(1).
SecurityKeyProvider
Specifies a path to a library that will be used when loading any
FIDO authenticator-hosted keys, overriding the default of using
the built-in USB HID support.
If the specified value begins with a M-bM-^@M-^X$M-bM-^@M-^Y character, then it will
be treated as an environment variable containing the path to the
library.
SendEnv
Specifies what variables from the local environ(7) should be sent
to the server. The server must also support it, and the server
must be configured to accept these environment variables. Note
that the TERM environment variable is always sent whenever a
pseudo-terminal is requested as it is required by the protocol.
Refer to AcceptEnv in sshd_config(5) for how to configure the
server. Variables are specified by name, which may contain
wildcard characters. Multiple environment variables may be
separated by whitespace or spread across multiple SendEnv
directives.
See PATTERNS for more information on patterns.
It is possible to clear previously set SendEnv variable names by
prefixing patterns with -. The default is not to send any
environment variables.
ServerAliveCountMax
Sets the number of server alive messages (see below) which may be
sent without ssh(1) receiving any messages back from the server.
If this threshold is reached while server alive messages are
being sent, ssh will disconnect from the server, terminating the
session. It is important to note that the use of server alive
messages is very different from TCPKeepAlive (below). The server
alive messages are sent through the encrypted channel and
therefore will not be spoofable. The TCP keepalive option
enabled by TCPKeepAlive is spoofable. The server alive mechanism
is valuable when the client or server depend on knowing when a
connection has become unresponsive.
The default value is 3. If, for example, ServerAliveInterval
(see below) is set to 15 and ServerAliveCountMax is left at the
default, if the server becomes unresponsive, ssh will disconnect
after approximately 45 seconds.
ServerAliveInterval
Sets a timeout interval in seconds after which if no data has
been received from the server, ssh(1) will send a message through
the encrypted channel to request a response from the server. The
default is 0, indicating that these messages will not be sent to
the server.
SetEnv Directly specify one or more environment variables and their
contents to be sent to the server. Similarly to SendEnv, the
server must be prepared to accept the environment variable.
StreamLocalBindMask
Sets the octal file creation mode mask (umask) used when creating
a Unix-domain socket file for local or remote port forwarding.
This option is only used for port forwarding to a Unix-domain
socket file.
The default value is 0177, which creates a Unix-domain socket
file that is readable and writable only by the owner. Note that
not all operating systems honor the file mode on Unix-domain
socket files.
StreamLocalBindUnlink
Specifies whether to remove an existing Unix-domain socket file
for local or remote port forwarding before creating a new one.
If the socket file already exists and StreamLocalBindUnlink is
not enabled, ssh will be unable to forward the port to the Unix-
domain socket file. This option is only used for port forwarding
to a Unix-domain socket file.
The argument must be yes or no (the default).
StrictHostKeyChecking
If this flag is set to yes, ssh(1) will never automatically add
host keys to the ~/.ssh/known_hosts file, and refuses to connect
to hosts whose host key has changed. This provides maximum
protection against man-in-the-middle (MITM) attacks, though it
can be annoying when the /etc/ssh/ssh_known_hosts file is poorly
maintained or when connections to new hosts are frequently made.
This option forces the user to manually add all new hosts.
If this flag is set to M-bM-^@M-^\accept-newM-bM-^@M-^] then ssh will automatically
add new host keys to the user known hosts files, but will not
permit connections to hosts with changed host keys. If this flag
is set to M-bM-^@M-^\noM-bM-^@M-^] or M-bM-^@M-^\offM-bM-^@M-^], ssh will automatically add new host keys
to the user known hosts files and allow connections to hosts with
changed hostkeys to proceed, subject to some restrictions. If
this flag is set to ask (the default), new host keys will be
added to the user known host files only after the user has
confirmed that is what they really want to do, and ssh will
refuse to connect to hosts whose host key has changed. The host
keys of known hosts will be verified automatically in all cases.
SyslogFacility
Gives the facility code that is used when logging messages from
ssh(1). The possible values are: DAEMON, USER, AUTH, LOCAL0,
LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The
default is USER.
TCPKeepAlive
Specifies whether the system should send TCP keepalive messages
to the other side. If they are sent, death of the connection or
crash of one of the machines will be properly noticed. However,
this means that connections will die if the route is down
temporarily, and some people find it annoying.
The default is yes (to send TCP keepalive messages), and the
client will notice if the network goes down or the remote host
dies. This is important in scripts, and many users want it too.
To disable TCP keepalive messages, the value should be set to no.
See also ServerAliveInterval for protocol-level keepalives.
Tunnel Request tun(4) device forwarding between the client and the
server. The argument must be yes, point-to-point (layer 3),
ethernet (layer 2), or no (the default). Specifying yes requests
the default tunnel mode, which is point-to-point.
TunnelDevice
Specifies the tun(4) devices to open on the client (local_tun)
and the server (remote_tun).
The argument must be local_tun[:remote_tun]. The devices may be
specified by numerical ID or the keyword any, which uses the next
available tunnel device. If remote_tun is not specified, it
defaults to any. The default is any:any.
UpdateHostKeys
Specifies whether ssh(1) should accept notifications of
additional hostkeys from the server sent after authentication has
completed and add them to UserKnownHostsFile. The argument must
be yes, no or ask. This option allows learning alternate
hostkeys for a server and supports graceful key rotation by
allowing a server to send replacement public keys before old ones
are removed.
Additional hostkeys are only accepted if the key used to
authenticate the host was already trusted or explicitly accepted
by the user, the host was authenticated via UserKnownHostsFile
(i.e. not GlobalKnownHostsFile) and the host was authenticated
using a plain key and not a certificate.
UpdateHostKeys is enabled by default if the user has not
overridden the default UserKnownHostsFile setting and has not
enabled VerifyHostKeyDNS, otherwise UpdateHostKeys will be set to
no.
If UpdateHostKeys is set to ask, then the user is asked to
confirm the modifications to the known_hosts file. Confirmation
is currently incompatible with ControlPersist, and will be
disabled if it is enabled.
Presently, only sshd(8) from OpenSSH 6.8 and greater support the
"hostkeys@openssh.com" protocol extension used to inform the
client of all the server's hostkeys.
User Specifies the user to log in as. This can be useful when a
different user name is used on different machines. This saves
the trouble of having to remember to give the user name on the
command line.
UserKnownHostsFile
Specifies one or more files to use for the user host key
database, separated by whitespace. Each filename may use tilde
notation to refer to the user's home directory, the tokens
described in the TOKENS section and environment variables as
described in the ENVIRONMENT VARIABLES section. The default is
~/.ssh/known_hosts, ~/.ssh/known_hosts2.
VerifyHostKeyDNS
Specifies whether to verify the remote key using DNS and SSHFP
resource records. If this option is set to yes, the client will
implicitly trust keys that match a secure fingerprint from DNS.
Insecure fingerprints will be handled as if this option was set
to ask. If this option is set to ask, information on fingerprint
match will be displayed, but the user will still need to confirm
new host keys according to the StrictHostKeyChecking option. The
default is no.
See also VERIFYING HOST KEYS in ssh(1).
VisualHostKey
If this flag is set to yes, an ASCII art representation of the
remote host key fingerprint is printed in addition to the
fingerprint string at login and for unknown host keys. If this
flag is set to no (the default), no fingerprint strings are
printed at login and only the fingerprint string will be printed
for unknown host keys.
XAuthLocation
Specifies the full pathname of the xauth(1) program. The default
is /usr/X11R6/bin/xauth.
PATTERNS
A pattern consists of zero or more non-whitespace characters, M-bM-^@M-^X*M-bM-^@M-^Y (a
wildcard that matches zero or more characters), or M-bM-^@M-^X?M-bM-^@M-^Y (a wildcard that
matches exactly one character). For example, to specify a set of
declarations for any host in the ".co.uk" set of domains, the following
pattern could be used:
Host *.co.uk
The following pattern would match any host in the 192.168.0.[0-9] network
range:
Host 192.168.0.?
A pattern-list is a comma-separated list of patterns. Patterns within
pattern-lists may be negated by preceding them with an exclamation mark
(M-bM-^@M-^X!M-bM-^@M-^Y). For example, to allow a key to be used from anywhere within an
organization except from the "dialup" pool, the following entry (in
authorized_keys) could be used:
from="!*.dialup.example.com,*.example.com"
Note that a negated match will never produce a positive result by itself.
For example, attempting to match "host3" against the following pattern-
list will fail:
from="!host1,!host2"
The solution here is to include a term that will yield a positive match,
such as a wildcard:
from="!host1,!host2,*"
TOKENS
Arguments to some keywords can make use of tokens, which are expanded at
runtime:
%% A literal M-bM-^@M-^X%M-bM-^@M-^Y.
%C Hash of %l%h%p%r.
%d Local user's home directory.
%f The fingerprint of the server's host key.
%H The known_hosts hostname or address that is being searched
for.
%h The remote hostname.
%I A string describing the reason for a KnownHostsCommand
execution: either ADDRESS when looking up a host by address
(only when CheckHostIP is enabled), HOSTNAME when searching
by hostname, or ORDER when preparing the host key algorithm
preference list to use for the destination host.
%i The local user ID.
%K The base64 encoded host key.
- %k The host key alias if specified, otherwise the orignal remote
- hostname given on the command line.
+ %k The host key alias if specified, otherwise the original
+ remote hostname given on the command line.
%L The local hostname.
%l The local hostname, including the domain name.
%n The original remote hostname, as given on the command line.
%p The remote port.
%r The remote username.
%T The local tun(4) or tap(4) network interface assigned if
tunnel forwarding was requested, or "NONE" otherwise.
%t The type of the server host key, e.g. ssh-ed25519
%u The local username.
CertificateFile, ControlPath, IdentityAgent, IdentityFile,
KnownHostsCommand, LocalForward, Match exec, RemoteCommand,
RemoteForward, and UserKnownHostsFile accept the tokens %%, %C, %d, %h,
%i, %k, %L, %l, %n, %p, %r, and %u.
KnownHostsCommand additionally accepts the tokens %f, %H, %I, %K and %t.
Hostname accepts the tokens %% and %h.
LocalCommand accepts all tokens.
ProxyCommand accepts the tokens %%, %h, %n, %p, and %r.
ENVIRONMENT VARIABLES
Arguments to some keywords can be expanded at runtime from environment
variables on the client by enclosing them in ${}, for example
${HOME}/.ssh would refer to the user's .ssh directory. If a specified
environment variable does not exist then an error will be returned and
the setting for that keyword will be ignored.
- The keywords CertificateFile, ControlPath, IdentityAgent, IdentityFile
+ The keywords CertificateFile, ControlPath, IdentityAgent, IdentityFile,
KnownHostsCommand, and UserKnownHostsFile support environment variables.
The keywords LocalForward and RemoteForward support environment variables
only for Unix domain socket paths.
FILES
~/.ssh/config
This is the per-user configuration file. The format of this file
is described above. This file is used by the SSH client.
Because of the potential for abuse, this file must have strict
permissions: read/write for the user, and not writable by others.
/etc/ssh/ssh_config
Systemwide configuration file. This file provides defaults for
those values that are not specified in the user's configuration
file, and for those users who do not have a configuration file.
This file must be world-readable.
SEE ALSO
ssh(1)
AUTHORS
OpenSSH is a derivative of the original and free ssh 1.2.12 release by
Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo
de Raadt and Dug Song removed many bugs, re-added newer features and
created OpenSSH. Markus Friedl contributed the support for SSH protocol
versions 1.5 and 2.0.
-OpenBSD 6.8 February 28, 2021 OpenBSD 6.8
+OpenBSD 6.9 April 4, 2021 OpenBSD 6.9
diff --git a/ssh_config.5 b/ssh_config.5
index f81191890547..37a55e234b27 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -1,2085 +1,2086 @@
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
.\" All rights reserved
.\"
.\" As far as I am concerned, the code I have written for this software
.\" can be used freely for any purpose. Any derived versions of this
.\" software must be clearly marked as such, and if the derived work is
.\" incompatible with the protocol description in the RFC file, it must be
.\" called by a name other than "ssh" or "Secure Shell".
.\"
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.\" $OpenBSD: ssh_config.5,v 1.349 2021/02/28 22:56:30 dtucker Exp $
-.Dd $Mdocdate: February 28 2021 $
+.\" $OpenBSD: ssh_config.5,v 1.353 2021/04/04 11:36:56 jmc Exp $
+.Dd $Mdocdate: April 4 2021 $
.Dt SSH_CONFIG 5
.Os
.Sh NAME
.Nm ssh_config
.Nd OpenSSH client configuration file
.Sh DESCRIPTION
.Xr ssh 1
obtains configuration data from the following sources in
the following order:
.Pp
.Bl -enum -offset indent -compact
.It
command-line options
.It
user's configuration file
.Pq Pa ~/.ssh/config
.It
system-wide configuration file
.Pq Pa /etc/ssh/ssh_config
.El
.Pp
For each parameter, the first obtained value
will be used.
The configuration files contain sections separated by
.Cm Host
specifications, and that section is only applied for hosts that
match one of the patterns given in the specification.
The matched host name is usually the one given on the command line
(see the
.Cm CanonicalizeHostname
option for exceptions).
.Pp
Since the first obtained value for each parameter is used, more
host-specific declarations should be given near the beginning of the
file, and general defaults at the end.
.Pp
The file contains keyword-argument pairs, one per line.
Lines starting with
.Ql #
and empty lines are interpreted as comments.
Arguments may optionally be enclosed in double quotes
.Pq \&"
in order to represent arguments containing spaces.
Configuration options may be separated by whitespace or
optional whitespace and exactly one
.Ql = ;
the latter format is useful to avoid the need to quote whitespace
when specifying configuration options using the
.Nm ssh ,
.Nm scp ,
and
.Nm sftp
.Fl o
option.
.Pp
The possible
keywords and their meanings are as follows (note that
keywords are case-insensitive and arguments are case-sensitive):
.Bl -tag -width Ds
.It Cm Host
Restricts the following declarations (up to the next
.Cm Host
or
.Cm Match
keyword) to be only for those hosts that match one of the patterns
given after the keyword.
If more than one pattern is provided, they should be separated by whitespace.
A single
.Ql *
as a pattern can be used to provide global
defaults for all hosts.
The host is usually the
.Ar hostname
argument given on the command line
(see the
.Cm CanonicalizeHostname
keyword for exceptions).
.Pp
A pattern entry may be negated by prefixing it with an exclamation mark
.Pq Sq !\& .
If a negated entry is matched, then the
.Cm Host
entry is ignored, regardless of whether any other patterns on the line
match.
Negated matches are therefore useful to provide exceptions for wildcard
matches.
.Pp
See
.Sx PATTERNS
for more information on patterns.
.It Cm Match
Restricts the following declarations (up to the next
.Cm Host
or
.Cm Match
keyword) to be used only when the conditions following the
.Cm Match
keyword are satisfied.
Match conditions are specified using one or more criteria
or the single token
.Cm all
which always matches.
The available criteria keywords are:
.Cm canonical ,
.Cm final ,
.Cm exec ,
.Cm host ,
.Cm originalhost ,
.Cm user ,
and
.Cm localuser .
The
.Cm all
criteria must appear alone or immediately after
.Cm canonical
or
.Cm final .
Other criteria may be combined arbitrarily.
All criteria but
.Cm all ,
.Cm canonical ,
and
.Cm final
require an argument.
Criteria may be negated by prepending an exclamation mark
.Pq Sq !\& .
.Pp
The
.Cm canonical
keyword matches only when the configuration file is being re-parsed
after hostname canonicalization (see the
.Cm CanonicalizeHostname
option).
This may be useful to specify conditions that work with canonical host
names only.
.Pp
The
.Cm final
keyword requests that the configuration be re-parsed (regardless of whether
.Cm CanonicalizeHostname
is enabled), and matches only during this final pass.
If
.Cm CanonicalizeHostname
is enabled, then
.Cm canonical
and
.Cm final
match during the same pass.
.Pp
The
.Cm exec
keyword executes the specified command under the user's shell.
If the command returns a zero exit status then the condition is considered true.
Commands containing whitespace characters must be quoted.
Arguments to
.Cm exec
accept the tokens described in the
.Sx TOKENS
section.
.Pp
The other keywords' criteria must be single entries or comma-separated
lists and may use the wildcard and negation operators described in the
.Sx PATTERNS
section.
The criteria for the
.Cm host
keyword are matched against the target hostname, after any substitution
by the
.Cm Hostname
or
.Cm CanonicalizeHostname
options.
The
.Cm originalhost
keyword matches against the hostname as it was specified on the command-line.
The
.Cm user
keyword matches against the target username on the remote host.
The
.Cm localuser
keyword matches against the name of the local user running
.Xr ssh 1
(this keyword may be useful in system-wide
.Nm
files).
.It Cm AddKeysToAgent
Specifies whether keys should be automatically added to a running
.Xr ssh-agent 1 .
If this option is set to
.Cm yes
and a key is loaded from a file, the key and its passphrase are added to
the agent with the default lifetime, as if by
.Xr ssh-add 1 .
If this option is set to
.Cm ask ,
.Xr ssh 1
will require confirmation using the
.Ev SSH_ASKPASS
program before adding a key (see
.Xr ssh-add 1
for details).
If this option is set to
.Cm confirm ,
each use of the key must be confirmed, as if the
.Fl c
option was specified to
.Xr ssh-add 1 .
If this option is set to
.Cm no ,
no keys are added to the agent.
Alternately, this option may be specified as a time interval
using the format described in the
.Sx TIME FORMATS
section of
.Xr sshd_config 5
to specify the key's lifetime in
.Xr ssh-agent 1 ,
after which it will automatically be removed.
The argument must be
.Cm no
(the default),
.Cm yes ,
.Cm confirm
(optionally followed by a time interval),
.Cm ask
or a time interval.
.It Cm AddressFamily
Specifies which address family to use when connecting.
Valid arguments are
.Cm any
(the default),
.Cm inet
(use IPv4 only), or
.Cm inet6
(use IPv6 only).
.It Cm BatchMode
If set to
.Cm yes ,
user interaction such as password prompts and host key confirmation requests
will be disabled.
This option is useful in scripts and other batch jobs where no user
is present to interact with
.Xr ssh 1 .
The argument must be
.Cm yes
or
.Cm no
(the default).
.It Cm BindAddress
Use the specified address on the local machine as the source address of
the connection.
Only useful on systems with more than one address.
.It Cm BindInterface
Use the address of the specified interface on the local machine as the
source address of the connection.
.It Cm CanonicalDomains
When
.Cm CanonicalizeHostname
is enabled, this option specifies the list of domain suffixes in which to
search for the specified destination host.
.It Cm CanonicalizeFallbackLocal
Specifies whether to fail with an error when hostname canonicalization fails.
The default,
.Cm yes ,
will attempt to look up the unqualified hostname using the system resolver's
search rules.
A value of
.Cm no
will cause
.Xr ssh 1
to fail instantly if
.Cm CanonicalizeHostname
is enabled and the target hostname cannot be found in any of the domains
specified by
.Cm CanonicalDomains .
.It Cm CanonicalizeHostname
Controls whether explicit hostname canonicalization is performed.
The default,
.Cm no ,
is not to perform any name rewriting and let the system resolver handle all
hostname lookups.
If set to
.Cm yes
then, for connections that do not use a
.Cm ProxyCommand
or
.Cm ProxyJump ,
.Xr ssh 1
will attempt to canonicalize the hostname specified on the command line
using the
.Cm CanonicalDomains
suffixes and
.Cm CanonicalizePermittedCNAMEs
rules.
If
.Cm CanonicalizeHostname
is set to
.Cm always ,
then canonicalization is applied to proxied connections too.
.Pp
If this option is enabled, then the configuration files are processed
again using the new target name to pick up any new configuration in matching
.Cm Host
and
.Cm Match
stanzas.
.It Cm CanonicalizeMaxDots
Specifies the maximum number of dot characters in a hostname before
canonicalization is disabled.
The default, 1,
allows a single dot (i.e. hostname.subdomain).
.It Cm CanonicalizePermittedCNAMEs
Specifies rules to determine whether CNAMEs should be followed when
canonicalizing hostnames.
The rules consist of one or more arguments of
.Ar source_domain_list : Ns Ar target_domain_list ,
where
.Ar source_domain_list
is a pattern-list of domains that may follow CNAMEs in canonicalization,
and
.Ar target_domain_list
is a pattern-list of domains that they may resolve to.
.Pp
For example,
.Qq *.a.example.com:*.b.example.com,*.c.example.com
will allow hostnames matching
.Qq *.a.example.com
to be canonicalized to names in the
.Qq *.b.example.com
or
.Qq *.c.example.com
domains.
.It Cm CASignatureAlgorithms
Specifies which algorithms are allowed for signing of certificates
by certificate authorities (CAs).
The default is:
.Bd -literal -offset indent
-ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,
-ecdsa-sha2-nistp521,rsa-sha2-512,rsa-sha2-256,ssh-rsa
+ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
+sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com,
+rsa-sha2-512,rsa-sha2-256
.Ed
.Pp
.Xr ssh 1
will not accept host certificates signed using algorithms other than those
specified.
.It Cm CertificateFile
Specifies a file from which the user's certificate is read.
A corresponding private key must be provided separately in order
to use this certificate either
from an
.Cm IdentityFile
directive or
.Fl i
flag to
.Xr ssh 1 ,
via
.Xr ssh-agent 1 ,
or via a
.Cm PKCS11Provider
or
.Cm SecurityKeyProvider .
.Pp
Arguments to
.Cm CertificateFile
may use the tilde syntax to refer to a user's home directory,
the tokens described in the
.Sx TOKENS
section and environment variables as described in the
.Sx ENVIRONMENT VARIABLES
section.
.Pp
It is possible to have multiple certificate files specified in
configuration files; these certificates will be tried in sequence.
Multiple
.Cm CertificateFile
directives will add to the list of certificates used for
authentication.
.It Cm ChallengeResponseAuthentication
Specifies whether to use challenge-response authentication.
The argument to this keyword must be
.Cm yes
(the default)
or
.Cm no .
.It Cm CheckHostIP
If set to
.Cm yes
.Xr ssh 1
will additionally check the host IP address in the
.Pa known_hosts
file.
This allows it to detect if a host key changed due to DNS spoofing
and will add addresses of destination hosts to
.Pa ~/.ssh/known_hosts
in the process, regardless of the setting of
.Cm StrictHostKeyChecking .
If the option is set to
.Cm no
(the default),
the check will not be executed.
.It Cm Ciphers
Specifies the ciphers allowed and their order of preference.
Multiple ciphers must be comma-separated.
If the specified list begins with a
.Sq +
character, then the specified ciphers will be appended to the default set
instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified ciphers (including wildcards) will be removed
from the default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified ciphers will be placed at the head of the
default set.
.Pp
The supported ciphers are:
.Bd -literal -offset indent
3des-cbc
aes128-cbc
aes192-cbc
aes256-cbc
aes128-ctr
aes192-ctr
aes256-ctr
aes128-gcm@openssh.com
aes256-gcm@openssh.com
chacha20-poly1305@openssh.com
.Ed
.Pp
The default is:
.Bd -literal -offset indent
chacha20-poly1305@openssh.com,
aes128-ctr,aes192-ctr,aes256-ctr,
aes128-gcm@openssh.com,aes256-gcm@openssh.com
.Ed
.Pp
The list of available ciphers may also be obtained using
.Qq ssh -Q cipher .
.It Cm ClearAllForwardings
Specifies that all local, remote, and dynamic port forwardings
specified in the configuration files or on the command line be
cleared.
This option is primarily useful when used from the
.Xr ssh 1
command line to clear port forwardings set in
configuration files, and is automatically set by
.Xr scp 1
and
.Xr sftp 1 .
The argument must be
.Cm yes
or
.Cm no
(the default).
.It Cm Compression
Specifies whether to use compression.
The argument must be
.Cm yes
or
.Cm no
(the default).
.It Cm ConnectionAttempts
Specifies the number of tries (one per second) to make before exiting.
The argument must be an integer.
This may be useful in scripts if the connection sometimes fails.
The default is 1.
.It Cm ConnectTimeout
Specifies the timeout (in seconds) used when connecting to the
SSH server, instead of using the default system TCP timeout.
This timeout is applied both to establishing the connection and to performing
the initial SSH protocol handshake and key exchange.
.It Cm ControlMaster
Enables the sharing of multiple sessions over a single network connection.
When set to
.Cm yes ,
.Xr ssh 1
will listen for connections on a control socket specified using the
.Cm ControlPath
argument.
Additional sessions can connect to this socket using the same
.Cm ControlPath
with
.Cm ControlMaster
set to
.Cm no
(the default).
These sessions will try to reuse the master instance's network connection
rather than initiating new ones, but will fall back to connecting normally
if the control socket does not exist, or is not listening.
.Pp
Setting this to
.Cm ask
will cause
.Xr ssh 1
to listen for control connections, but require confirmation using
.Xr ssh-askpass 1 .
If the
.Cm ControlPath
cannot be opened,
.Xr ssh 1
will continue without connecting to a master instance.
.Pp
X11 and
.Xr ssh-agent 1
forwarding is supported over these multiplexed connections, however the
display and agent forwarded will be the one belonging to the master
connection i.e. it is not possible to forward multiple displays or agents.
.Pp
Two additional options allow for opportunistic multiplexing: try to use a
master connection but fall back to creating a new one if one does not already
exist.
These options are:
.Cm auto
and
.Cm autoask .
The latter requires confirmation like the
.Cm ask
option.
.It Cm ControlPath
Specify the path to the control socket used for connection sharing as described
in the
.Cm ControlMaster
section above or the string
.Cm none
to disable connection sharing.
Arguments to
.Cm ControlPath
may use the tilde syntax to refer to a user's home directory,
the tokens described in the
.Sx TOKENS
section and environment variables as described in the
.Sx ENVIRONMENT VARIABLES
section.
It is recommended that any
.Cm ControlPath
used for opportunistic connection sharing include
at least %h, %p, and %r (or alternatively %C) and be placed in a directory
that is not writable by other users.
This ensures that shared connections are uniquely identified.
.It Cm ControlPersist
When used in conjunction with
.Cm ControlMaster ,
specifies that the master connection should remain open
in the background (waiting for future client connections)
after the initial client connection has been closed.
If set to
.Cm no
(the default),
then the master connection will not be placed into the background,
and will close as soon as the initial client connection is closed.
If set to
.Cm yes
or 0,
then the master connection will remain in the background indefinitely
(until killed or closed via a mechanism such as the
.Qq ssh -O exit ) .
If set to a time in seconds, or a time in any of the formats documented in
.Xr sshd_config 5 ,
then the backgrounded master connection will automatically terminate
after it has remained idle (with no client connections) for the
specified time.
.It Cm DynamicForward
Specifies that a TCP port on the local machine be forwarded
over the secure channel, and the application
protocol is then used to determine where to connect to from the
remote machine.
.Pp
The argument must be
.Sm off
.Oo Ar bind_address : Oc Ar port .
.Sm on
IPv6 addresses can be specified by enclosing addresses in square brackets.
By default, the local port is bound in accordance with the
.Cm GatewayPorts
setting.
However, an explicit
.Ar bind_address
may be used to bind the connection to a specific address.
The
.Ar bind_address
of
.Cm localhost
indicates that the listening port be bound for local use only, while an
empty address or
.Sq *
indicates that the port should be available from all interfaces.
.Pp
Currently the SOCKS4 and SOCKS5 protocols are supported, and
.Xr ssh 1
will act as a SOCKS server.
Multiple forwardings may be specified, and
additional forwardings can be given on the command line.
Only the superuser can forward privileged ports.
.It Cm EnableSSHKeysign
Setting this option to
.Cm yes
in the global client configuration file
.Pa /etc/ssh/ssh_config
enables the use of the helper program
.Xr ssh-keysign 8
during
.Cm HostbasedAuthentication .
The argument must be
.Cm yes
or
.Cm no
(the default).
This option should be placed in the non-hostspecific section.
See
.Xr ssh-keysign 8
for more information.
.It Cm EscapeChar
Sets the escape character (default:
.Ql ~ ) .
The escape character can also
be set on the command line.
The argument should be a single character,
.Ql ^
followed by a letter, or
.Cm none
to disable the escape
character entirely (making the connection transparent for binary
data).
.It Cm ExitOnForwardFailure
Specifies whether
.Xr ssh 1
should terminate the connection if it cannot set up all requested
dynamic, tunnel, local, and remote port forwardings, (e.g.\&
if either end is unable to bind and listen on a specified port).
Note that
.Cm ExitOnForwardFailure
does not apply to connections made over port forwardings and will not,
for example, cause
.Xr ssh 1
to exit if TCP connections to the ultimate forwarding destination fail.
The argument must be
.Cm yes
or
.Cm no
(the default).
.It Cm FingerprintHash
Specifies the hash algorithm used when displaying key fingerprints.
Valid options are:
.Cm md5
and
.Cm sha256
(the default).
.It Cm ForwardAgent
Specifies whether the connection to the authentication agent (if any)
will be forwarded to the remote machine.
The argument may be
.Cm yes ,
.Cm no
(the default),
an explicit path to an agent socket or the name of an environment variable
(beginning with
.Sq $ )
in which to find the path.
.Pp
Agent forwarding should be enabled with caution.
Users with the ability to bypass file permissions on the remote host
(for the agent's Unix-domain socket)
can access the local agent through the forwarded connection.
An attacker cannot obtain key material from the agent,
however they can perform operations on the keys that enable them to
authenticate using the identities loaded into the agent.
.It Cm ForwardX11
Specifies whether X11 connections will be automatically redirected
over the secure channel and
.Ev DISPLAY
set.
The argument must be
.Cm yes
or
.Cm no
(the default).
.Pp
X11 forwarding should be enabled with caution.
Users with the ability to bypass file permissions on the remote host
(for the user's X11 authorization database)
can access the local X11 display through the forwarded connection.
An attacker may then be able to perform activities such as keystroke monitoring
if the
.Cm ForwardX11Trusted
option is also enabled.
.It Cm ForwardX11Timeout
Specify a timeout for untrusted X11 forwarding
using the format described in the
.Sx TIME FORMATS
section of
.Xr sshd_config 5 .
X11 connections received by
.Xr ssh 1
after this time will be refused.
Setting
.Cm ForwardX11Timeout
to zero will disable the timeout and permit X11 forwarding for the life
of the connection.
The default is to disable untrusted X11 forwarding after twenty minutes has
elapsed.
.It Cm ForwardX11Trusted
If this option is set to
.Cm yes ,
remote X11 clients will have full access to the original X11 display.
.Pp
If this option is set to
.Cm no
(the default),
remote X11 clients will be considered untrusted and prevented
from stealing or tampering with data belonging to trusted X11
clients.
Furthermore, the
.Xr xauth 1
token used for the session will be set to expire after 20 minutes.
Remote clients will be refused access after this time.
.Pp
See the X11 SECURITY extension specification for full details on
the restrictions imposed on untrusted clients.
.It Cm GatewayPorts
Specifies whether remote hosts are allowed to connect to local
forwarded ports.
By default,
.Xr ssh 1
binds local port forwardings to the loopback address.
This prevents other remote hosts from connecting to forwarded ports.
.Cm GatewayPorts
can be used to specify that ssh
should bind local port forwardings to the wildcard address,
thus allowing remote hosts to connect to forwarded ports.
The argument must be
.Cm yes
or
.Cm no
(the default).
.It Cm GlobalKnownHostsFile
Specifies one or more files to use for the global
host key database, separated by whitespace.
The default is
.Pa /etc/ssh/ssh_known_hosts ,
.Pa /etc/ssh/ssh_known_hosts2 .
.It Cm GSSAPIAuthentication
Specifies whether user authentication based on GSSAPI is allowed.
The default is
.Cm no .
.It Cm GSSAPIDelegateCredentials
Forward (delegate) credentials to the server.
The default is
.Cm no .
.It Cm HashKnownHosts
Indicates that
.Xr ssh 1
should hash host names and addresses when they are added to
.Pa ~/.ssh/known_hosts .
These hashed names may be used normally by
.Xr ssh 1
and
.Xr sshd 8 ,
but they do not visually reveal identifying information if the
file's contents are disclosed.
The default is
.Cm no .
Note that existing names and addresses in known hosts files
will not be converted automatically,
but may be manually hashed using
.Xr ssh-keygen 1 .
.It Cm HostbasedAcceptedAlgorithms
Specifies the signature algorithms that will be used for hostbased
authentication as a comma-separated list of patterns.
Alternately if the specified list begins with a
.Sq +
character, then the specified signature algorithms will be appended
to the default set instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified signature algorithms (including wildcards)
will be removed from the default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified signature algorithms will be placed
at the head of the default set.
The default for this option is:
.Bd -literal -offset 3n
ssh-ed25519-cert-v01@openssh.com,
ecdsa-sha2-nistp256-cert-v01@openssh.com,
ecdsa-sha2-nistp384-cert-v01@openssh.com,
ecdsa-sha2-nistp521-cert-v01@openssh.com,
sk-ssh-ed25519-cert-v01@openssh.com,
sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
rsa-sha2-512-cert-v01@openssh.com,
rsa-sha2-256-cert-v01@openssh.com,
ssh-rsa-cert-v01@openssh.com,
ssh-ed25519,
ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
sk-ssh-ed25519@openssh.com,
sk-ecdsa-sha2-nistp256@openssh.com,
rsa-sha2-512,rsa-sha2-256,ssh-rsa
.Ed
.Pp
The
.Fl Q
option of
.Xr ssh 1
may be used to list supported signature algorithms.
This was formerly named HostbasedKeyTypes.
.It Cm HostbasedAuthentication
Specifies whether to try rhosts based authentication with public key
authentication.
The argument must be
.Cm yes
or
.Cm no
(the default).
.It Cm HostKeyAlgorithms
Specifies the host key signature algorithms
that the client wants to use in order of preference.
Alternately if the specified list begins with a
.Sq +
character, then the specified signature algorithms will be appended to
the default set instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified signature algorithms (including wildcards)
will be removed from the default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified signature algorithms will be placed
at the head of the default set.
The default for this option is:
.Bd -literal -offset 3n
ssh-ed25519-cert-v01@openssh.com,
ecdsa-sha2-nistp256-cert-v01@openssh.com,
ecdsa-sha2-nistp384-cert-v01@openssh.com,
ecdsa-sha2-nistp521-cert-v01@openssh.com,
sk-ssh-ed25519-cert-v01@openssh.com,
sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
rsa-sha2-512-cert-v01@openssh.com,
rsa-sha2-256-cert-v01@openssh.com,
ssh-rsa-cert-v01@openssh.com,
ssh-ed25519,
ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
sk-ecdsa-sha2-nistp256@openssh.com,
sk-ssh-ed25519@openssh.com,
rsa-sha2-512,rsa-sha2-256,ssh-rsa
.Ed
.Pp
If hostkeys are known for the destination host then this default is modified
to prefer their algorithms.
.Pp
The list of available signature algorithms may also be obtained using
.Qq ssh -Q HostKeyAlgorithms .
.It Cm HostKeyAlias
Specifies an alias that should be used instead of the
real host name when looking up or saving the host key
in the host key database files and when validating host certificates.
This option is useful for tunneling SSH connections
or for multiple servers running on a single host.
.It Cm Hostname
Specifies the real host name to log into.
This can be used to specify nicknames or abbreviations for hosts.
Arguments to
.Cm Hostname
accept the tokens described in the
.Sx TOKENS
section.
Numeric IP addresses are also permitted (both on the command line and in
.Cm Hostname
specifications).
The default is the name given on the command line.
.It Cm IdentitiesOnly
Specifies that
.Xr ssh 1
should only use the configured authentication identity and certificate files
(either the default files, or those explicitly configured in the
.Nm
files
or passed on the
.Xr ssh 1
command-line),
even if
.Xr ssh-agent 1
or a
.Cm PKCS11Provider
or
.Cm SecurityKeyProvider
offers more identities.
The argument to this keyword must be
.Cm yes
or
.Cm no
(the default).
This option is intended for situations where ssh-agent
offers many different identities.
.It Cm IdentityAgent
Specifies the
.Ux Ns -domain
socket used to communicate with the authentication agent.
.Pp
This option overrides the
.Ev SSH_AUTH_SOCK
environment variable and can be used to select a specific agent.
Setting the socket name to
.Cm none
disables the use of an authentication agent.
If the string
.Qq SSH_AUTH_SOCK
is specified, the location of the socket will be read from the
.Ev SSH_AUTH_SOCK
environment variable.
Otherwise if the specified value begins with a
.Sq $
character, then it will be treated as an environment variable containing
the location of the socket.
.Pp
Arguments to
.Cm IdentityAgent
may use the tilde syntax to refer to a user's home directory,
the tokens described in the
.Sx TOKENS
section and environment variables as described in the
.Sx ENVIRONMENT VARIABLES
section.
.It Cm IdentityFile
Specifies a file from which the user's DSA, ECDSA, authenticator-hosted ECDSA,
Ed25519, authenticator-hosted Ed25519 or RSA authentication identity is read.
The default is
.Pa ~/.ssh/id_dsa ,
.Pa ~/.ssh/id_ecdsa ,
.Pa ~/.ssh/id_ecdsa_sk ,
.Pa ~/.ssh/id_ed25519 ,
.Pa ~/.ssh/id_ed25519_sk
and
.Pa ~/.ssh/id_rsa .
Additionally, any identities represented by the authentication agent
will be used for authentication unless
.Cm IdentitiesOnly
is set.
If no certificates have been explicitly specified by
.Cm CertificateFile ,
.Xr ssh 1
will try to load certificate information from the filename obtained by
appending
.Pa -cert.pub
to the path of a specified
.Cm IdentityFile .
.Pp
Arguments to
.Cm IdentityFile
may use the tilde syntax to refer to a user's home directory
or the tokens described in the
.Sx TOKENS
section.
.Pp
It is possible to have
multiple identity files specified in configuration files; all these
identities will be tried in sequence.
Multiple
.Cm IdentityFile
directives will add to the list of identities tried (this behaviour
differs from that of other configuration directives).
.Pp
.Cm IdentityFile
may be used in conjunction with
.Cm IdentitiesOnly
to select which identities in an agent are offered during authentication.
.Cm IdentityFile
may also be used in conjunction with
.Cm CertificateFile
in order to provide any certificate also needed for authentication with
the identity.
.It Cm IgnoreUnknown
Specifies a pattern-list of unknown options to be ignored if they are
encountered in configuration parsing.
This may be used to suppress errors if
.Nm
contains options that are unrecognised by
.Xr ssh 1 .
It is recommended that
.Cm IgnoreUnknown
be listed early in the configuration file as it will not be applied
to unknown options that appear before it.
.It Cm Include
Include the specified configuration file(s).
Multiple pathnames may be specified and each pathname may contain
.Xr glob 7
wildcards and, for user configurations, shell-like
.Sq ~
references to user home directories.
Wildcards will be expanded and processed in lexical order.
Files without absolute paths are assumed to be in
.Pa ~/.ssh
if included in a user configuration file or
.Pa /etc/ssh
if included from the system configuration file.
.Cm Include
directive may appear inside a
.Cm Match
or
.Cm Host
block
to perform conditional inclusion.
.It Cm IPQoS
Specifies the IPv4 type-of-service or DSCP class for connections.
Accepted values are
.Cm af11 ,
.Cm af12 ,
.Cm af13 ,
.Cm af21 ,
.Cm af22 ,
.Cm af23 ,
.Cm af31 ,
.Cm af32 ,
.Cm af33 ,
.Cm af41 ,
.Cm af42 ,
.Cm af43 ,
.Cm cs0 ,
.Cm cs1 ,
.Cm cs2 ,
.Cm cs3 ,
.Cm cs4 ,
.Cm cs5 ,
.Cm cs6 ,
.Cm cs7 ,
.Cm ef ,
.Cm le ,
.Cm lowdelay ,
.Cm throughput ,
.Cm reliability ,
a numeric value, or
.Cm none
to use the operating system default.
This option may take one or two arguments, separated by whitespace.
If one argument is specified, it is used as the packet class unconditionally.
If two values are specified, the first is automatically selected for
interactive sessions and the second for non-interactive sessions.
The default is
.Cm af21
(Low-Latency Data)
for interactive sessions and
.Cm cs1
(Lower Effort)
for non-interactive sessions.
.It Cm KbdInteractiveAuthentication
Specifies whether to use keyboard-interactive authentication.
The argument to this keyword must be
.Cm yes
(the default)
or
.Cm no .
.It Cm KbdInteractiveDevices
Specifies the list of methods to use in keyboard-interactive authentication.
Multiple method names must be comma-separated.
The default is to use the server specified list.
The methods available vary depending on what the server supports.
For an OpenSSH server,
it may be zero or more of:
.Cm bsdauth
and
.Cm pam .
.It Cm KexAlgorithms
Specifies the available KEX (Key Exchange) algorithms.
Multiple algorithms must be comma-separated.
If the specified list begins with a
.Sq +
character, then the specified methods will be appended to the default set
instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified methods (including wildcards) will be removed
from the default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified methods will be placed at the head of the
default set.
The default is:
.Bd -literal -offset indent
curve25519-sha256,curve25519-sha256@libssh.org,
ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,
diffie-hellman-group-exchange-sha256,
diffie-hellman-group16-sha512,
diffie-hellman-group18-sha512,
diffie-hellman-group14-sha256
.Ed
.Pp
The list of available key exchange algorithms may also be obtained using
.Qq ssh -Q kex .
.It Cm KnownHostsCommand
Specifies a command to use to obtain a list of host keys, in addition to
those listed in
.Cm UserKnownHostsFile
and
.Cm GlobalKnownHostsFile .
This command is executed after the files have been read.
It may write host key lines to standard output in identical format to the
usual files (described in the
.Sx VERIFYING HOST KEYS
section in
.Xr ssh 1 ) .
Arguments to
.Cm KnownHostsCommand
accept the tokens described in the
.Sx TOKENS
section.
The command may be invoked multiple times per connection: once when preparing
the preference list of host key algorithms to use, again to obtain the
host key for the requested host name and, if
.Cm CheckHostIP
is enabled, one more time to obtain the host key matching the server's
address.
If the command exits abnormally or returns a non-zero exit status then the
connection is terminated.
.It Cm LocalCommand
Specifies a command to execute on the local machine after successfully
connecting to the server.
The command string extends to the end of the line, and is executed with
the user's shell.
Arguments to
.Cm LocalCommand
accept the tokens described in the
.Sx TOKENS
section.
.Pp
The command is run synchronously and does not have access to the
session of the
.Xr ssh 1
that spawned it.
It should not be used for interactive commands.
.Pp
This directive is ignored unless
.Cm PermitLocalCommand
has been enabled.
.It Cm LocalForward
Specifies that a TCP port on the local machine be forwarded over
the secure channel to the specified host and port from the remote machine.
The first argument specifies the listener and may be
.Sm off
.Oo Ar bind_address : Oc Ar port
.Sm on
or a Unix domain socket path.
The second argument is the destination and may be
.Ar host : Ns Ar hostport
or a Unix domain socket path if the remote host supports it.
.Pp
IPv6 addresses can be specified by enclosing addresses in square brackets.
Multiple forwardings may be specified, and additional forwardings can be
given on the command line.
Only the superuser can forward privileged ports.
By default, the local port is bound in accordance with the
.Cm GatewayPorts
setting.
However, an explicit
.Ar bind_address
may be used to bind the connection to a specific address.
The
.Ar bind_address
of
.Cm localhost
indicates that the listening port be bound for local use only, while an
empty address or
.Sq *
indicates that the port should be available from all interfaces.
Unix domain socket paths may use the tokens described in the
.Sx TOKENS
section and environment variables as described in the
.Sx ENVIRONMENT VARIABLES
section.
.It Cm LogLevel
Gives the verbosity level that is used when logging messages from
.Xr ssh 1 .
The possible values are:
QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3.
The default is INFO.
DEBUG and DEBUG1 are equivalent.
DEBUG2 and DEBUG3 each specify higher levels of verbose output.
.It Cm LogVerbose
Specify one or more overrides to LogLevel.
An override consists of a pattern lists that matches the source file, function
and line number to force detailed logging for.
For example, an override pattern of:
.Bd -literal -offset indent
kex.c:*:1000,*:kex_exchange_identification():*,packet.c:*
.Ed
.Pp
would enable detailed logging for line 1000 of
.Pa kex.c ,
everything in the
.Fn kex_exchange_identification
function, and all code in the
.Pa packet.c
file.
This option is intended for debugging and no overrides are enabled by default.
.It Cm MACs
Specifies the MAC (message authentication code) algorithms
in order of preference.
The MAC algorithm is used for data integrity protection.
Multiple algorithms must be comma-separated.
If the specified list begins with a
.Sq +
character, then the specified algorithms will be appended to the default set
instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified algorithms (including wildcards) will be removed
from the default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified algorithms will be placed at the head of the
default set.
.Pp
The algorithms that contain
.Qq -etm
calculate the MAC after encryption (encrypt-then-mac).
These are considered safer and their use recommended.
.Pp
The default is:
.Bd -literal -offset indent
umac-64-etm@openssh.com,umac-128-etm@openssh.com,
hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,
hmac-sha1-etm@openssh.com,
umac-64@openssh.com,umac-128@openssh.com,
hmac-sha2-256,hmac-sha2-512,hmac-sha1
.Ed
.Pp
The list of available MAC algorithms may also be obtained using
.Qq ssh -Q mac .
.It Cm NoHostAuthenticationForLocalhost
Disable host authentication for localhost (loopback addresses).
The argument to this keyword must be
.Cm yes
or
.Cm no
(the default).
.It Cm NumberOfPasswordPrompts
Specifies the number of password prompts before giving up.
The argument to this keyword must be an integer.
The default is 3.
.It Cm PasswordAuthentication
Specifies whether to use password authentication.
The argument to this keyword must be
.Cm yes
(the default)
or
.Cm no .
.It Cm PermitLocalCommand
Allow local command execution via the
.Ic LocalCommand
option or using the
.Ic !\& Ns Ar command
escape sequence in
.Xr ssh 1 .
The argument must be
.Cm yes
or
.Cm no
(the default).
.It Cm PermitRemoteOpen
Specifies the destinations to which remote TCP port forwarding is permitted when
.Cm RemoteForward
is used as a SOCKS proxy.
The forwarding specification must be one of the following forms:
.Pp
.Bl -item -offset indent -compact
.It
.Cm PermitRemoteOpen
.Sm off
.Ar host : port
.Sm on
.It
.Cm PermitRemoteOpen
.Sm off
.Ar IPv4_addr : port
.Sm on
.It
.Cm PermitRemoteOpen
.Sm off
.Ar \&[ IPv6_addr \&] : port
.Sm on
.El
.Pp
Multiple forwards may be specified by separating them with whitespace.
An argument of
.Cm any
can be used to remove all restrictions and permit any forwarding requests.
An argument of
.Cm none
can be used to prohibit all forwarding requests.
The wildcard
.Sq *
can be used for host or port to allow all hosts or ports respectively.
Otherwise, no pattern matching or address lookups are performed on supplied
names.
.It Cm PKCS11Provider
Specifies which PKCS#11 provider to use or
.Cm none
to indicate that no provider should be used (the default).
The argument to this keyword is a path to the PKCS#11 shared library
.Xr ssh 1
should use to communicate with a PKCS#11 token providing keys for user
authentication.
.It Cm Port
Specifies the port number to connect on the remote host.
The default is 22.
.It Cm PreferredAuthentications
Specifies the order in which the client should try authentication methods.
This allows a client to prefer one method (e.g.\&
.Cm keyboard-interactive )
over another method (e.g.\&
.Cm password ) .
The default is:
.Bd -literal -offset indent
gssapi-with-mic,hostbased,publickey,
keyboard-interactive,password
.Ed
.It Cm ProxyCommand
Specifies the command to use to connect to the server.
The command
string extends to the end of the line, and is executed
using the user's shell
.Ql exec
directive to avoid a lingering shell process.
.Pp
Arguments to
.Cm ProxyCommand
accept the tokens described in the
.Sx TOKENS
section.
The command can be basically anything,
and should read from its standard input and write to its standard output.
It should eventually connect an
.Xr sshd 8
server running on some machine, or execute
.Ic sshd -i
somewhere.
Host key management will be done using the
.Cm Hostname
of the host being connected (defaulting to the name typed by the user).
Setting the command to
.Cm none
disables this option entirely.
Note that
.Cm CheckHostIP
is not available for connects with a proxy command.
.Pp
This directive is useful in conjunction with
.Xr nc 1
and its proxy support.
For example, the following directive would connect via an HTTP proxy at
192.0.2.0:
.Bd -literal -offset 3n
ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p
.Ed
.It Cm ProxyJump
Specifies one or more jump proxies as either
.Xo
.Sm off
.Op Ar user No @
.Ar host
.Op : Ns Ar port
.Sm on
or an ssh URI
.Xc .
Multiple proxies may be separated by comma characters and will be visited
sequentially.
Setting this option will cause
.Xr ssh 1
to connect to the target host by first making a
.Xr ssh 1
connection to the specified
.Cm ProxyJump
host and then establishing a
TCP forwarding to the ultimate target from there.
Setting the host to
.Cm none
disables this option entirely.
.Pp
Note that this option will compete with the
.Cm ProxyCommand
option - whichever is specified first will prevent later instances of the
other from taking effect.
.Pp
Note also that the configuration for the destination host (either supplied
via the command-line or the configuration file) is not generally applied
to jump hosts.
.Pa ~/.ssh/config
should be used if specific configuration is required for jump hosts.
.It Cm ProxyUseFdpass
Specifies that
.Cm ProxyCommand
will pass a connected file descriptor back to
.Xr ssh 1
instead of continuing to execute and pass data.
The default is
.Cm no .
.It Cm PubkeyAcceptedAlgorithms
Specifies the signature algorithms that will be used for public key
authentication as a comma-separated list of patterns.
If the specified list begins with a
.Sq +
character, then the algorithms after it will be appended to the default
instead of replacing it.
If the specified list begins with a
.Sq -
character, then the specified algorithms (including wildcards) will be removed
from the default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified algorithms will be placed at the head of the
default set.
The default for this option is:
.Bd -literal -offset 3n
ssh-ed25519-cert-v01@openssh.com,
ecdsa-sha2-nistp256-cert-v01@openssh.com,
ecdsa-sha2-nistp384-cert-v01@openssh.com,
ecdsa-sha2-nistp521-cert-v01@openssh.com,
sk-ssh-ed25519-cert-v01@openssh.com,
sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
rsa-sha2-512-cert-v01@openssh.com,
rsa-sha2-256-cert-v01@openssh.com,
ssh-rsa-cert-v01@openssh.com,
ssh-ed25519,
ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
sk-ssh-ed25519@openssh.com,
sk-ecdsa-sha2-nistp256@openssh.com,
rsa-sha2-512,rsa-sha2-256,ssh-rsa
.Ed
.Pp
The list of available signature algorithms may also be obtained using
.Qq ssh -Q PubkeyAcceptedAlgorithms .
.It Cm PubkeyAuthentication
Specifies whether to try public key authentication.
The argument to this keyword must be
.Cm yes
(the default)
or
.Cm no .
.It Cm RekeyLimit
Specifies the maximum amount of data that may be transmitted before the
session key is renegotiated, optionally followed by a maximum amount of
time that may pass before the session key is renegotiated.
The first argument is specified in bytes and may have a suffix of
.Sq K ,
.Sq M ,
or
.Sq G
to indicate Kilobytes, Megabytes, or Gigabytes, respectively.
The default is between
.Sq 1G
and
.Sq 4G ,
depending on the cipher.
The optional second value is specified in seconds and may use any of the
units documented in the TIME FORMATS section of
.Xr sshd_config 5 .
The default value for
.Cm RekeyLimit
is
.Cm default none ,
which means that rekeying is performed after the cipher's default amount
of data has been sent or received and no time based rekeying is done.
.It Cm RemoteCommand
Specifies a command to execute on the remote machine after successfully
connecting to the server.
The command string extends to the end of the line, and is executed with
the user's shell.
Arguments to
.Cm RemoteCommand
accept the tokens described in the
.Sx TOKENS
section.
.It Cm RemoteForward
Specifies that a TCP port on the remote machine be forwarded over
the secure channel.
The remote port may either be forwarded to a specified host and port
from the local machine, or may act as a SOCKS 4/5 proxy that allows a remote
client to connect to arbitrary destinations from the local machine.
The first argument is the listening specification and may be
.Sm off
.Oo Ar bind_address : Oc Ar port
.Sm on
or, if the remote host supports it, a Unix domain socket path.
If forwarding to a specific destination then the second argument must be
.Ar host : Ns Ar hostport
or a Unix domain socket path,
otherwise if no destination argument is specified then the remote forwarding
will be established as a SOCKS proxy.
When acting as a SOCKS proxy the destination of the connection can be
restricted by
.Cm PermitRemoteOpen .
.Pp
IPv6 addresses can be specified by enclosing addresses in square brackets.
Multiple forwardings may be specified, and additional
forwardings can be given on the command line.
Privileged ports can be forwarded only when
logging in as root on the remote machine.
Unix domain socket paths may use the tokens described in the
.Sx TOKENS
section and environment variables as described in the
.Sx ENVIRONMENT VARIABLES
section.
.Pp
If the
.Ar port
argument is 0,
the listen port will be dynamically allocated on the server and reported
to the client at run time.
.Pp
If the
.Ar bind_address
is not specified, the default is to only bind to loopback addresses.
If the
.Ar bind_address
is
.Ql *
or an empty string, then the forwarding is requested to listen on all
interfaces.
Specifying a remote
.Ar bind_address
will only succeed if the server's
.Cm GatewayPorts
option is enabled (see
.Xr sshd_config 5 ) .
.It Cm RequestTTY
Specifies whether to request a pseudo-tty for the session.
The argument may be one of:
.Cm no
(never request a TTY),
.Cm yes
(always request a TTY when standard input is a TTY),
.Cm force
(always request a TTY) or
.Cm auto
(request a TTY when opening a login session).
This option mirrors the
.Fl t
and
.Fl T
flags for
.Xr ssh 1 .
.It Cm RevokedHostKeys
Specifies revoked host public keys.
Keys listed in this file will be refused for host authentication.
Note that if this file does not exist or is not readable,
then host authentication will be refused for all hosts.
Keys may be specified as a text file, listing one public key per line, or as
an OpenSSH Key Revocation List (KRL) as generated by
.Xr ssh-keygen 1 .
For more information on KRLs, see the KEY REVOCATION LISTS section in
.Xr ssh-keygen 1 .
.It Cm SecurityKeyProvider
Specifies a path to a library that will be used when loading any
FIDO authenticator-hosted keys, overriding the default of using
the built-in USB HID support.
.Pp
If the specified value begins with a
.Sq $
character, then it will be treated as an environment variable containing
the path to the library.
.It Cm SendEnv
Specifies what variables from the local
.Xr environ 7
should be sent to the server.
The server must also support it, and the server must be configured to
accept these environment variables.
Note that the
.Ev TERM
environment variable is always sent whenever a
pseudo-terminal is requested as it is required by the protocol.
Refer to
.Cm AcceptEnv
in
.Xr sshd_config 5
for how to configure the server.
Variables are specified by name, which may contain wildcard characters.
Multiple environment variables may be separated by whitespace or spread
across multiple
.Cm SendEnv
directives.
.Pp
See
.Sx PATTERNS
for more information on patterns.
.Pp
It is possible to clear previously set
.Cm SendEnv
variable names by prefixing patterns with
.Pa - .
The default is not to send any environment variables.
.It Cm ServerAliveCountMax
Sets the number of server alive messages (see below) which may be
sent without
.Xr ssh 1
receiving any messages back from the server.
If this threshold is reached while server alive messages are being sent,
ssh will disconnect from the server, terminating the session.
It is important to note that the use of server alive messages is very
different from
.Cm TCPKeepAlive
(below).
The server alive messages are sent through the encrypted channel
and therefore will not be spoofable.
The TCP keepalive option enabled by
.Cm TCPKeepAlive
is spoofable.
The server alive mechanism is valuable when the client or
server depend on knowing when a connection has become unresponsive.
.Pp
The default value is 3.
If, for example,
.Cm ServerAliveInterval
(see below) is set to 15 and
.Cm ServerAliveCountMax
is left at the default, if the server becomes unresponsive,
ssh will disconnect after approximately 45 seconds.
.It Cm ServerAliveInterval
Sets a timeout interval in seconds after which if no data has been received
from the server,
.Xr ssh 1
will send a message through the encrypted
channel to request a response from the server.
The default
is 0, indicating that these messages will not be sent to the server.
.It Cm SetEnv
Directly specify one or more environment variables and their contents to
be sent to the server.
Similarly to
.Cm SendEnv ,
the server must be prepared to accept the environment variable.
.It Cm StreamLocalBindMask
Sets the octal file creation mode mask
.Pq umask
used when creating a Unix-domain socket file for local or remote
port forwarding.
This option is only used for port forwarding to a Unix-domain socket file.
.Pp
The default value is 0177, which creates a Unix-domain socket file that is
readable and writable only by the owner.
Note that not all operating systems honor the file mode on Unix-domain
socket files.
.It Cm StreamLocalBindUnlink
Specifies whether to remove an existing Unix-domain socket file for local
or remote port forwarding before creating a new one.
If the socket file already exists and
.Cm StreamLocalBindUnlink
is not enabled,
.Nm ssh
will be unable to forward the port to the Unix-domain socket file.
This option is only used for port forwarding to a Unix-domain socket file.
.Pp
The argument must be
.Cm yes
or
.Cm no
(the default).
.It Cm StrictHostKeyChecking
If this flag is set to
.Cm yes ,
.Xr ssh 1
will never automatically add host keys to the
.Pa ~/.ssh/known_hosts
file, and refuses to connect to hosts whose host key has changed.
This provides maximum protection against man-in-the-middle (MITM) attacks,
though it can be annoying when the
.Pa /etc/ssh/ssh_known_hosts
file is poorly maintained or when connections to new hosts are
frequently made.
This option forces the user to manually
add all new hosts.
.Pp
If this flag is set to
.Dq accept-new
then ssh will automatically add new host keys to the user
known hosts files, but will not permit connections to hosts with
changed host keys.
If this flag is set to
.Dq no
or
.Dq off ,
ssh will automatically add new host keys to the user known hosts files
and allow connections to hosts with changed hostkeys to proceed,
subject to some restrictions.
If this flag is set to
.Cm ask
(the default),
new host keys
will be added to the user known host files only after the user
has confirmed that is what they really want to do, and
ssh will refuse to connect to hosts whose host key has changed.
The host keys of
known hosts will be verified automatically in all cases.
.It Cm SyslogFacility
Gives the facility code that is used when logging messages from
.Xr ssh 1 .
The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2,
LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
The default is USER.
.It Cm TCPKeepAlive
Specifies whether the system should send TCP keepalive messages to the
other side.
If they are sent, death of the connection or crash of one
of the machines will be properly noticed.
However, this means that
connections will die if the route is down temporarily, and some people
find it annoying.
.Pp
The default is
.Cm yes
(to send TCP keepalive messages), and the client will notice
if the network goes down or the remote host dies.
This is important in scripts, and many users want it too.
.Pp
To disable TCP keepalive messages, the value should be set to
.Cm no .
See also
.Cm ServerAliveInterval
for protocol-level keepalives.
.It Cm Tunnel
Request
.Xr tun 4
device forwarding between the client and the server.
The argument must be
.Cm yes ,
.Cm point-to-point
(layer 3),
.Cm ethernet
(layer 2),
or
.Cm no
(the default).
Specifying
.Cm yes
requests the default tunnel mode, which is
.Cm point-to-point .
.It Cm TunnelDevice
Specifies the
.Xr tun 4
devices to open on the client
.Pq Ar local_tun
and the server
.Pq Ar remote_tun .
.Pp
The argument must be
.Sm off
.Ar local_tun Op : Ar remote_tun .
.Sm on
The devices may be specified by numerical ID or the keyword
.Cm any ,
which uses the next available tunnel device.
If
.Ar remote_tun
is not specified, it defaults to
.Cm any .
The default is
.Cm any:any .
.It Cm UpdateHostKeys
Specifies whether
.Xr ssh 1
should accept notifications of additional hostkeys from the server sent
after authentication has completed and add them to
.Cm UserKnownHostsFile .
The argument must be
.Cm yes ,
.Cm no
or
.Cm ask .
This option allows learning alternate hostkeys for a server
and supports graceful key rotation by allowing a server to send replacement
public keys before old ones are removed.
.Pp
Additional hostkeys are only accepted if the key used to authenticate the
host was already trusted or explicitly accepted by the user, the host was
authenticated via
.Cm UserKnownHostsFile
(i.e. not
.Cm GlobalKnownHostsFile )
and the host was authenticated using a plain key and not a certificate.
.Pp
.Cm UpdateHostKeys
is enabled by default if the user has not overridden the default
.Cm UserKnownHostsFile
setting and has not enabled
.Cm VerifyHostKeyDNS ,
otherwise
.Cm UpdateHostKeys
will be set to
.Cm no .
.Pp
If
.Cm UpdateHostKeys
is set to
.Cm ask ,
then the user is asked to confirm the modifications to the known_hosts file.
Confirmation is currently incompatible with
.Cm ControlPersist ,
and will be disabled if it is enabled.
.Pp
Presently, only
.Xr sshd 8
from OpenSSH 6.8 and greater support the
.Qq hostkeys@openssh.com
protocol extension used to inform the client of all the server's hostkeys.
.It Cm User
Specifies the user to log in as.
This can be useful when a different user name is used on different machines.
This saves the trouble of
having to remember to give the user name on the command line.
.It Cm UserKnownHostsFile
Specifies one or more files to use for the user
host key database, separated by whitespace.
Each filename may use tilde notation to refer to the user's home directory,
the tokens described in the
.Sx TOKENS
section and environment variables as described in the
.Sx ENVIRONMENT VARIABLES
section.
The default is
.Pa ~/.ssh/known_hosts ,
.Pa ~/.ssh/known_hosts2 .
.It Cm VerifyHostKeyDNS
Specifies whether to verify the remote key using DNS and SSHFP resource
records.
If this option is set to
.Cm yes ,
the client will implicitly trust keys that match a secure fingerprint
from DNS.
Insecure fingerprints will be handled as if this option was set to
.Cm ask .
If this option is set to
.Cm ask ,
information on fingerprint match will be displayed, but the user will still
need to confirm new host keys according to the
.Cm StrictHostKeyChecking
option.
The default is
.Cm no .
.Pp
See also
.Sx VERIFYING HOST KEYS
in
.Xr ssh 1 .
.It Cm VisualHostKey
If this flag is set to
.Cm yes ,
an ASCII art representation of the remote host key fingerprint is
printed in addition to the fingerprint string at login and
for unknown host keys.
If this flag is set to
.Cm no
(the default),
no fingerprint strings are printed at login and
only the fingerprint string will be printed for unknown host keys.
.It Cm XAuthLocation
Specifies the full pathname of the
.Xr xauth 1
program.
The default is
.Pa /usr/X11R6/bin/xauth .
.El
.Sh PATTERNS
A
.Em pattern
consists of zero or more non-whitespace characters,
.Sq *
(a wildcard that matches zero or more characters),
or
.Sq ?\&
(a wildcard that matches exactly one character).
For example, to specify a set of declarations for any host in the
.Qq .co.uk
set of domains,
the following pattern could be used:
.Pp
.Dl Host *.co.uk
.Pp
The following pattern
would match any host in the 192.168.0.[0-9] network range:
.Pp
.Dl Host 192.168.0.?
.Pp
A
.Em pattern-list
is a comma-separated list of patterns.
Patterns within pattern-lists may be negated
by preceding them with an exclamation mark
.Pq Sq !\& .
For example,
to allow a key to be used from anywhere within an organization
except from the
.Qq dialup
pool,
the following entry (in authorized_keys) could be used:
.Pp
.Dl from=\&"!*.dialup.example.com,*.example.com\&"
.Pp
Note that a negated match will never produce a positive result by itself.
For example, attempting to match
.Qq host3
against the following pattern-list will fail:
.Pp
.Dl from=\&"!host1,!host2\&"
.Pp
The solution here is to include a term that will yield a positive match,
such as a wildcard:
.Pp
.Dl from=\&"!host1,!host2,*\&"
.Sh TOKENS
Arguments to some keywords can make use of tokens,
which are expanded at runtime:
.Pp
.Bl -tag -width XXXX -offset indent -compact
.It %%
A literal
.Sq % .
.It \&%C
Hash of %l%h%p%r.
.It %d
Local user's home directory.
.It %f
The fingerprint of the server's host key.
.It %H
The
.Pa known_hosts
hostname or address that is being searched for.
.It %h
The remote hostname.
.It \%%I
A string describing the reason for a
.Cm KnownHostsCommand
execution: either
.Cm ADDRESS
when looking up a host by address (only when
.Cm CheckHostIP
is enabled),
.Cm HOSTNAME
when searching by hostname, or
.Cm ORDER
when preparing the host key algorithm preference list to use for the
destination host.
.It %i
The local user ID.
.It %K
The base64 encoded host key.
.It %k
-The host key alias if specified, otherwise the orignal remote hostname given
+The host key alias if specified, otherwise the original remote hostname given
on the command line.
.It %L
The local hostname.
.It %l
The local hostname, including the domain name.
.It %n
The original remote hostname, as given on the command line.
.It %p
The remote port.
.It %r
The remote username.
.It \&%T
The local
.Xr tun 4
or
.Xr tap 4
network interface assigned if
tunnel forwarding was requested, or
.Qq NONE
otherwise.
.It %t
The type of the server host key, e.g.
.Cm ssh-ed25519
.It %u
The local username.
.El
.Pp
.Cm CertificateFile ,
.Cm ControlPath ,
.Cm IdentityAgent ,
.Cm IdentityFile ,
.Cm KnownHostsCommand ,
.Cm LocalForward ,
.Cm Match exec ,
.Cm RemoteCommand ,
.Cm RemoteForward ,
and
.Cm UserKnownHostsFile
accept the tokens %%, %C, %d, %h, %i, %k, %L, %l, %n, %p, %r, and %u.
.Pp
.Cm KnownHostsCommand
additionally accepts the tokens %f, %H, %I, %K and %t.
.Pp
.Cm Hostname
accepts the tokens %% and %h.
.Pp
.Cm LocalCommand
accepts all tokens.
.Pp
.Cm ProxyCommand
accepts the tokens %%, %h, %n, %p, and %r.
.Sh ENVIRONMENT VARIABLES
Arguments to some keywords can be expanded at runtime from environment
variables on the client by enclosing them in
.Ic ${} ,
for example
.Ic ${HOME}/.ssh
would refer to the user's .ssh directory.
If a specified environment variable does not exist then an error will be
returned and the setting for that keyword will be ignored.
.Pp
The keywords
.Cm CertificateFile ,
.Cm ControlPath ,
.Cm IdentityAgent ,
-.Cm IdentityFile
+.Cm IdentityFile ,
.Cm KnownHostsCommand ,
and
.Cm UserKnownHostsFile
support environment variables.
The keywords
.Cm LocalForward
and
.Cm RemoteForward
support environment variables only for Unix domain socket paths.
.Sh FILES
.Bl -tag -width Ds
.It Pa ~/.ssh/config
This is the per-user configuration file.
The format of this file is described above.
This file is used by the SSH client.
Because of the potential for abuse, this file must have strict permissions:
read/write for the user, and not writable by others.
.It Pa /etc/ssh/ssh_config
Systemwide configuration file.
This file provides defaults for those
values that are not specified in the user's configuration file, and
for those users who do not have a configuration file.
This file must be world-readable.
.El
.Sh SEE ALSO
.Xr ssh 1
.Sh AUTHORS
.An -nosplit
OpenSSH is a derivative of the original and free
ssh 1.2.12 release by
.An Tatu Ylonen .
.An Aaron Campbell , Bob Beck , Markus Friedl ,
.An Niels Provos , Theo de Raadt
and
.An Dug Song
removed many bugs, re-added newer features and
created OpenSSH.
.An Markus Friedl
contributed the support for SSH protocol versions 1.5 and 2.0.
diff --git a/sshconnect.c b/sshconnect.c
index 74f9e76702f0..47f0b1c93abf 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,1713 +1,1715 @@
-/* $OpenBSD: sshconnect.c,v 1.350 2021/01/26 00:49:30 djm Exp $ */
+/* $OpenBSD: sshconnect.c,v 1.352 2021/04/03 06:18:41 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Code to connect to a remote host, and to perform the client side of the
* login (authentication) dialog.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/socket.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <netdb.h>
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#include <pwd.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_IFADDRS_H
# include <ifaddrs.h>
#endif
#include "xmalloc.h"
#include "hostfile.h"
#include "ssh.h"
#include "sshbuf.h"
#include "packet.h"
#include "compat.h"
#include "sshkey.h"
#include "sshconnect.h"
#include "log.h"
#include "misc.h"
#include "readconf.h"
#include "atomicio.h"
#include "dns.h"
#include "monitor_fdpass.h"
#include "ssh2.h"
#include "version.h"
#include "authfile.h"
#include "ssherr.h"
#include "authfd.h"
#include "kex.h"
struct sshkey *previous_host_key = NULL;
static int matching_host_key_dns = 0;
static pid_t proxy_command_pid = 0;
/* import */
extern int debug_flag;
extern Options options;
extern char *__progname;
static int show_other_keys(struct hostkeys *, struct sshkey *);
static void warn_changed_key(struct sshkey *);
/* Expand a proxy command */
static char *
expand_proxy_command(const char *proxy_command, const char *user,
const char *host, const char *host_arg, int port)
{
char *tmp, *ret, strport[NI_MAXSERV];
const char *keyalias = options.host_key_alias ?
- options.host_key_alias : host_arg;
+ options.host_key_alias : host_arg;
snprintf(strport, sizeof strport, "%d", port);
xasprintf(&tmp, "exec %s", proxy_command);
ret = percent_expand(tmp,
"h", host,
"k", keyalias,
"n", host_arg,
"p", strport,
"r", options.user,
(char *)NULL);
free(tmp);
return ret;
}
/*
* Connect to the given ssh server using a proxy command that passes a
* a connected fd back to us.
*/
static int
ssh_proxy_fdpass_connect(struct ssh *ssh, const char *host,
const char *host_arg, u_short port, const char *proxy_command)
{
char *command_string;
int sp[2], sock;
pid_t pid;
char *shell;
if ((shell = getenv("SHELL")) == NULL)
shell = _PATH_BSHELL;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == -1)
fatal("Could not create socketpair to communicate with "
"proxy dialer: %.100s", strerror(errno));
command_string = expand_proxy_command(proxy_command, options.user,
host, host_arg, port);
debug("Executing proxy dialer command: %.500s", command_string);
/* Fork and execute the proxy command. */
if ((pid = fork()) == 0) {
char *argv[10];
close(sp[1]);
/* Redirect stdin and stdout. */
if (sp[0] != 0) {
if (dup2(sp[0], 0) == -1)
perror("dup2 stdin");
}
if (sp[0] != 1) {
if (dup2(sp[0], 1) == -1)
perror("dup2 stdout");
}
if (sp[0] >= 2)
close(sp[0]);
/*
* Stderr is left for non-ControlPersist connections is so
* error messages may be printed on the user's terminal.
*/
if (!debug_flag && options.control_path != NULL &&
options.control_persist && stdfd_devnull(0, 0, 1) == -1)
error_f("stdfd_devnull failed");
argv[0] = shell;
argv[1] = "-c";
argv[2] = command_string;
argv[3] = NULL;
/*
* Execute the proxy command.
* Note that we gave up any extra privileges above.
*/
execv(argv[0], argv);
perror(argv[0]);
exit(1);
}
/* Parent. */
if (pid == -1)
fatal("fork failed: %.100s", strerror(errno));
close(sp[0]);
free(command_string);
if ((sock = mm_receive_fd(sp[1])) == -1)
fatal("proxy dialer did not pass back a connection");
close(sp[1]);
while (waitpid(pid, NULL, 0) == -1)
if (errno != EINTR)
fatal("Couldn't wait for child: %s", strerror(errno));
/* Set the connection file descriptors. */
if (ssh_packet_set_connection(ssh, sock, sock) == NULL)
return -1; /* ssh_packet_set_connection logs error */
return 0;
}
/*
* Connect to the given ssh server using a proxy command.
*/
static int
ssh_proxy_connect(struct ssh *ssh, const char *host, const char *host_arg,
u_short port, const char *proxy_command)
{
char *command_string;
int pin[2], pout[2];
pid_t pid;
char *shell;
if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
shell = _PATH_BSHELL;
/* Create pipes for communicating with the proxy. */
if (pipe(pin) == -1 || pipe(pout) == -1)
fatal("Could not create pipes to communicate with the proxy: %.100s",
strerror(errno));
command_string = expand_proxy_command(proxy_command, options.user,
host, host_arg, port);
debug("Executing proxy command: %.500s", command_string);
/* Fork and execute the proxy command. */
if ((pid = fork()) == 0) {
char *argv[10];
/* Redirect stdin and stdout. */
close(pin[1]);
if (pin[0] != 0) {
if (dup2(pin[0], 0) == -1)
perror("dup2 stdin");
close(pin[0]);
}
close(pout[0]);
if (dup2(pout[1], 1) == -1)
perror("dup2 stdout");
/* Cannot be 1 because pin allocated two descriptors. */
close(pout[1]);
/*
* Stderr is left for non-ControlPersist connections is so
* error messages may be printed on the user's terminal.
*/
if (!debug_flag && options.control_path != NULL &&
options.control_persist && stdfd_devnull(0, 0, 1) == -1)
error_f("stdfd_devnull failed");
argv[0] = shell;
argv[1] = "-c";
argv[2] = command_string;
argv[3] = NULL;
- /* Execute the proxy command. Note that we gave up any
- extra privileges above. */
+ /*
+ * Execute the proxy command. Note that we gave up any
+ * extra privileges above.
+ */
ssh_signal(SIGPIPE, SIG_DFL);
execv(argv[0], argv);
perror(argv[0]);
exit(1);
}
/* Parent. */
if (pid == -1)
fatal("fork failed: %.100s", strerror(errno));
else
proxy_command_pid = pid; /* save pid to clean up later */
/* Close child side of the descriptors. */
close(pin[0]);
close(pout[1]);
/* Free the command name. */
free(command_string);
/* Set the connection file descriptors. */
if (ssh_packet_set_connection(ssh, pout[0], pin[1]) == NULL)
return -1; /* ssh_packet_set_connection logs error */
return 0;
}
void
ssh_kill_proxy_command(void)
{
/*
* Send SIGHUP to proxy command if used. We don't wait() in
* case it hangs and instead rely on init to reap the child
*/
if (proxy_command_pid > 1)
kill(proxy_command_pid, SIGHUP);
}
#ifdef HAVE_IFADDRS_H
/*
* Search a interface address list (returned from getifaddrs(3)) for an
* address that matches the desired address family on the specified interface.
* Returns 0 and fills in *resultp and *rlenp on success. Returns -1 on failure.
*/
static int
check_ifaddrs(const char *ifname, int af, const struct ifaddrs *ifaddrs,
struct sockaddr_storage *resultp, socklen_t *rlenp)
{
struct sockaddr_in6 *sa6;
struct sockaddr_in *sa;
struct in6_addr *v6addr;
const struct ifaddrs *ifa;
int allow_local;
/*
* Prefer addresses that are not loopback or linklocal, but use them
* if nothing else matches.
*/
for (allow_local = 0; allow_local < 2; allow_local++) {
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL ||
(ifa->ifa_flags & IFF_UP) == 0 ||
ifa->ifa_addr->sa_family != af ||
strcmp(ifa->ifa_name, options.bind_interface) != 0)
continue;
switch (ifa->ifa_addr->sa_family) {
case AF_INET:
sa = (struct sockaddr_in *)ifa->ifa_addr;
if (!allow_local && sa->sin_addr.s_addr ==
htonl(INADDR_LOOPBACK))
continue;
if (*rlenp < sizeof(struct sockaddr_in)) {
error_f("v4 addr doesn't fit");
return -1;
}
*rlenp = sizeof(struct sockaddr_in);
memcpy(resultp, sa, *rlenp);
return 0;
case AF_INET6:
sa6 = (struct sockaddr_in6 *)ifa->ifa_addr;
v6addr = &sa6->sin6_addr;
if (!allow_local &&
(IN6_IS_ADDR_LINKLOCAL(v6addr) ||
IN6_IS_ADDR_LOOPBACK(v6addr)))
continue;
if (*rlenp < sizeof(struct sockaddr_in6)) {
error_f("v6 addr doesn't fit");
return -1;
}
*rlenp = sizeof(struct sockaddr_in6);
memcpy(resultp, sa6, *rlenp);
return 0;
}
}
}
return -1;
}
#endif
/*
* Creates a socket for use as the ssh connection.
*/
static int
ssh_create_socket(struct addrinfo *ai)
{
int sock, r;
struct sockaddr_storage bindaddr;
socklen_t bindaddrlen = 0;
struct addrinfo hints, *res = NULL;
#ifdef HAVE_IFADDRS_H
struct ifaddrs *ifaddrs = NULL;
#endif
char ntop[NI_MAXHOST];
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sock == -1) {
error("socket: %s", strerror(errno));
return -1;
}
fcntl(sock, F_SETFD, FD_CLOEXEC);
/* Use interactive QOS (if specified) until authentication completed */
if (options.ip_qos_interactive != INT_MAX)
set_sock_tos(sock, options.ip_qos_interactive);
/* Bind the socket to an alternative local IP address */
if (options.bind_address == NULL && options.bind_interface == NULL)
return sock;
if (options.bind_address != NULL) {
memset(&hints, 0, sizeof(hints));
hints.ai_family = ai->ai_family;
hints.ai_socktype = ai->ai_socktype;
hints.ai_protocol = ai->ai_protocol;
hints.ai_flags = AI_PASSIVE;
if ((r = getaddrinfo(options.bind_address, NULL,
&hints, &res)) != 0) {
error("getaddrinfo: %s: %s", options.bind_address,
ssh_gai_strerror(r));
goto fail;
}
if (res == NULL) {
error("getaddrinfo: no addrs");
goto fail;
}
memcpy(&bindaddr, res->ai_addr, res->ai_addrlen);
bindaddrlen = res->ai_addrlen;
} else if (options.bind_interface != NULL) {
#ifdef HAVE_IFADDRS_H
if ((r = getifaddrs(&ifaddrs)) != 0) {
error("getifaddrs: %s: %s", options.bind_interface,
- strerror(errno));
+ strerror(errno));
goto fail;
}
bindaddrlen = sizeof(bindaddr);
if (check_ifaddrs(options.bind_interface, ai->ai_family,
ifaddrs, &bindaddr, &bindaddrlen) != 0) {
logit("getifaddrs: %s: no suitable addresses",
- options.bind_interface);
+ options.bind_interface);
goto fail;
}
#else
error("BindInterface not supported on this platform.");
#endif
}
if ((r = getnameinfo((struct sockaddr *)&bindaddr, bindaddrlen,
ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST)) != 0) {
error_f("getnameinfo failed: %s", ssh_gai_strerror(r));
goto fail;
}
if (bind(sock, (struct sockaddr *)&bindaddr, bindaddrlen) != 0) {
error("bind %s: %s", ntop, strerror(errno));
goto fail;
}
debug_f("bound to %s", ntop);
/* success */
goto out;
fail:
close(sock);
sock = -1;
out:
if (res != NULL)
freeaddrinfo(res);
#ifdef HAVE_IFADDRS_H
if (ifaddrs != NULL)
freeifaddrs(ifaddrs);
#endif
return sock;
}
/*
* Opens a TCP/IP connection to the remote server on the given host.
* The address of the remote host will be returned in hostaddr.
* If port is 0, the default port will be used.
* Connection_attempts specifies the maximum number of tries (one per
* second). If proxy_command is non-NULL, it specifies the command (with %h
* and %p substituted for host and port, respectively) to use to contact
* the daemon.
*/
static int
ssh_connect_direct(struct ssh *ssh, const char *host, struct addrinfo *aitop,
struct sockaddr_storage *hostaddr, u_short port, int connection_attempts,
int *timeout_ms, int want_keepalive)
{
int on = 1, saved_timeout_ms = *timeout_ms;
int oerrno, sock = -1, attempt;
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
struct addrinfo *ai;
debug3_f("entering");
memset(ntop, 0, sizeof(ntop));
memset(strport, 0, sizeof(strport));
for (attempt = 0; attempt < connection_attempts; attempt++) {
if (attempt > 0) {
/* Sleep a moment before retrying. */
sleep(1);
debug("Trying again...");
}
/*
* Loop through addresses for this host, and try each one in
* sequence until the connection succeeds.
*/
for (ai = aitop; ai; ai = ai->ai_next) {
if (ai->ai_family != AF_INET &&
ai->ai_family != AF_INET6) {
errno = EAFNOSUPPORT;
continue;
}
if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
ntop, sizeof(ntop), strport, sizeof(strport),
NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
oerrno = errno;
error_f("getnameinfo failed");
errno = oerrno;
continue;
}
debug("Connecting to %.200s [%.100s] port %s.",
host, ntop, strport);
/* Create a socket for connecting. */
sock = ssh_create_socket(ai);
if (sock < 0) {
/* Any error is already output */
errno = 0;
continue;
}
*timeout_ms = saved_timeout_ms;
if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen,
timeout_ms) >= 0) {
/* Successful connection. */
memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
break;
} else {
oerrno = errno;
debug("connect to address %s port %s: %s",
ntop, strport, strerror(errno));
close(sock);
sock = -1;
errno = oerrno;
}
}
if (sock != -1)
break; /* Successful connection. */
}
/* Return failure if we didn't get a successful connection. */
if (sock == -1) {
error("ssh: connect to host %s port %s: %s",
host, strport, errno == 0 ? "failure" : strerror(errno));
return -1;
}
debug("Connection established.");
/* Set SO_KEEPALIVE if requested. */
if (want_keepalive &&
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
sizeof(on)) == -1)
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
/* Set the connection. */
if (ssh_packet_set_connection(ssh, sock, sock) == NULL)
return -1; /* ssh_packet_set_connection logs error */
return 0;
}
int
ssh_connect(struct ssh *ssh, const char *host, const char *host_arg,
struct addrinfo *addrs, struct sockaddr_storage *hostaddr, u_short port,
int connection_attempts, int *timeout_ms, int want_keepalive)
{
int in, out;
if (options.proxy_command == NULL) {
return ssh_connect_direct(ssh, host, addrs, hostaddr, port,
connection_attempts, timeout_ms, want_keepalive);
} else if (strcmp(options.proxy_command, "-") == 0) {
if ((in = dup(STDIN_FILENO)) == -1 ||
(out = dup(STDOUT_FILENO)) == -1) {
if (in >= 0)
close(in);
error_f("dup() in/out failed");
return -1; /* ssh_packet_set_connection logs error */
}
if ((ssh_packet_set_connection(ssh, in, out)) == NULL)
return -1; /* ssh_packet_set_connection logs error */
return 0;
} else if (options.proxy_use_fdpass) {
return ssh_proxy_fdpass_connect(ssh, host, host_arg, port,
options.proxy_command);
}
return ssh_proxy_connect(ssh, host, host_arg, port,
options.proxy_command);
}
/* defaults to 'no' */
static int
confirm(const char *prompt, const char *fingerprint)
{
const char *msg, *again = "Please type 'yes' or 'no': ";
const char *again_fp = "Please type 'yes', 'no' or the fingerprint: ";
char *p, *cp;
int ret = -1;
if (options.batch_mode)
return 0;
for (msg = prompt;;msg = fingerprint ? again_fp : again) {
cp = p = read_passphrase(msg, RP_ECHO);
if (p == NULL)
return 0;
p += strspn(p, " \t"); /* skip leading whitespace */
p[strcspn(p, " \t\n")] = '\0'; /* remove trailing whitespace */
if (p[0] == '\0' || strcasecmp(p, "no") == 0)
ret = 0;
else if (strcasecmp(p, "yes") == 0 || (fingerprint != NULL &&
strcmp(p, fingerprint) == 0))
ret = 1;
free(cp);
if (ret != -1)
return ret;
}
}
static int
sockaddr_is_local(struct sockaddr *hostaddr)
{
switch (hostaddr->sa_family) {
case AF_INET:
return (ntohl(((struct sockaddr_in *)hostaddr)->
sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
case AF_INET6:
return IN6_IS_ADDR_LOOPBACK(
&(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
default:
return 0;
}
}
/*
* Prepare the hostname and ip address strings that are used to lookup
* host keys in known_hosts files. These may have a port number appended.
*/
void
get_hostfile_hostname_ipaddr(char *hostname, struct sockaddr *hostaddr,
u_short port, char **hostfile_hostname, char **hostfile_ipaddr)
{
char ntop[NI_MAXHOST];
socklen_t addrlen;
switch (hostaddr == NULL ? -1 : hostaddr->sa_family) {
case -1:
addrlen = 0;
break;
case AF_INET:
addrlen = sizeof(struct sockaddr_in);
break;
case AF_INET6:
addrlen = sizeof(struct sockaddr_in6);
break;
default:
addrlen = sizeof(struct sockaddr);
break;
}
/*
* We don't have the remote ip-address for connections
* using a proxy command
*/
if (hostfile_ipaddr != NULL) {
if (options.proxy_command == NULL) {
if (getnameinfo(hostaddr, addrlen,
ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0)
fatal_f("getnameinfo failed");
*hostfile_ipaddr = put_host_port(ntop, port);
} else {
*hostfile_ipaddr = xstrdup("<no hostip for proxy "
"command>");
}
}
/*
* Allow the user to record the key under a different name or
* differentiate a non-standard port. This is useful for ssh
* tunneling over forwarded connections or if you run multiple
* sshd's on different ports on the same machine.
*/
if (hostfile_hostname != NULL) {
if (options.host_key_alias != NULL) {
*hostfile_hostname = xstrdup(options.host_key_alias);
debug("using hostkeyalias: %s", *hostfile_hostname);
} else {
*hostfile_hostname = put_host_port(hostname, port);
}
}
}
/* returns non-zero if path appears in hostfiles, or 0 if not. */
static int
path_in_hostfiles(const char *path, char **hostfiles, u_int num_hostfiles)
{
u_int i;
for (i = 0; i < num_hostfiles; i++) {
if (strcmp(path, hostfiles[i]) == 0)
return 1;
}
return 0;
}
struct find_by_key_ctx {
const char *host, *ip;
const struct sshkey *key;
char **names;
u_int nnames;
};
/* Try to replace home directory prefix (per $HOME) with a ~/ sequence */
static char *
try_tilde_unexpand(const char *path)
{
char *home, *ret = NULL;
size_t l;
if (*path != '/')
return xstrdup(path);
if ((home = getenv("HOME")) == NULL || (l = strlen(home)) == 0)
return xstrdup(path);
if (strncmp(path, home, l) != 0)
return xstrdup(path);
/*
* ensure we have matched on a path boundary: either the $HOME that
* we just compared ends with a '/' or the next character of the path
* must be a '/'.
*/
if (home[l - 1] != '/' && path[l] != '/')
return xstrdup(path);
if (path[l] == '/')
l++;
xasprintf(&ret, "~/%s", path + l);
return ret;
}
static int
hostkeys_find_by_key_cb(struct hostkey_foreach_line *l, void *_ctx)
{
struct find_by_key_ctx *ctx = (struct find_by_key_ctx *)_ctx;
char *path;
/* we are looking for keys with names that *do not* match */
if ((l->match & HKF_MATCH_HOST) != 0)
return 0;
/* not interested in marker lines */
if (l->marker != MRK_NONE)
return 0;
/* we are only interested in exact key matches */
if (l->key == NULL || !sshkey_equal(ctx->key, l->key))
return 0;
path = try_tilde_unexpand(l->path);
debug_f("found matching key in %s:%lu", path, l->linenum);
ctx->names = xrecallocarray(ctx->names,
ctx->nnames, ctx->nnames + 1, sizeof(*ctx->names));
xasprintf(&ctx->names[ctx->nnames], "%s:%lu: %s", path, l->linenum,
strncmp(l->hosts, HASH_MAGIC, strlen(HASH_MAGIC)) == 0 ?
"[hashed name]" : l->hosts);
ctx->nnames++;
free(path);
return 0;
}
static int
hostkeys_find_by_key_hostfile(const char *file, const char *which,
struct find_by_key_ctx *ctx)
{
int r;
debug3_f("trying %s hostfile \"%s\"", which, file);
if ((r = hostkeys_foreach(file, hostkeys_find_by_key_cb, ctx,
ctx->host, ctx->ip, HKF_WANT_PARSE_KEY, 0)) != 0) {
if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) {
debug_f("hostkeys file %s does not exist", file);
return 0;
}
error_fr(r, "hostkeys_foreach failed for %s", file);
return r;
}
return 0;
}
/*
* Find 'key' in known hosts file(s) that do not match host/ip.
* Used to display also-known-as information for previously-unseen hostkeys.
*/
static void
hostkeys_find_by_key(const char *host, const char *ip, const struct sshkey *key,
char **user_hostfiles, u_int num_user_hostfiles,
char **system_hostfiles, u_int num_system_hostfiles,
char ***names, u_int *nnames)
{
struct find_by_key_ctx ctx = {0, 0, 0, 0, 0};
u_int i;
*names = NULL;
*nnames = 0;
if (key == NULL || sshkey_is_cert(key))
return;
ctx.host = host;
ctx.ip = ip;
ctx.key = key;
for (i = 0; i < num_user_hostfiles; i++) {
if (hostkeys_find_by_key_hostfile(user_hostfiles[i],
"user", &ctx) != 0)
goto fail;
}
for (i = 0; i < num_system_hostfiles; i++) {
if (hostkeys_find_by_key_hostfile(system_hostfiles[i],
"system", &ctx) != 0)
goto fail;
}
/* success */
*names = ctx.names;
*nnames = ctx.nnames;
ctx.names = NULL;
ctx.nnames = 0;
return;
fail:
for (i = 0; i < ctx.nnames; i++)
free(ctx.names[i]);
free(ctx.names);
}
#define MAX_OTHER_NAMES 8 /* Maximum number of names to list */
static char *
other_hostkeys_message(const char *host, const char *ip,
const struct sshkey *key,
char **user_hostfiles, u_int num_user_hostfiles,
char **system_hostfiles, u_int num_system_hostfiles)
{
char *ret = NULL, **othernames = NULL;
u_int i, n, num_othernames = 0;
hostkeys_find_by_key(host, ip, key,
user_hostfiles, num_user_hostfiles,
system_hostfiles, num_system_hostfiles,
&othernames, &num_othernames);
if (num_othernames == 0)
return xstrdup("This key is not known by any other names");
xasprintf(&ret, "This host key is known by the following other "
"names/addresses:");
n = num_othernames;
if (n > MAX_OTHER_NAMES)
n = MAX_OTHER_NAMES;
for (i = 0; i < n; i++) {
xextendf(&ret, "\n", " %s", othernames[i]);
}
if (n < num_othernames) {
- xextendf(&ret, "\n", " (%d additional names ommitted)",
+ xextendf(&ret, "\n", " (%d additional names omitted)",
num_othernames - n);
}
for (i = 0; i < num_othernames; i++)
free(othernames[i]);
free(othernames);
return ret;
}
void
load_hostkeys_command(struct hostkeys *hostkeys, const char *command_template,
const char *invocation, const struct ssh_conn_info *cinfo,
const struct sshkey *host_key, const char *hostfile_hostname)
{
int r, i, ac = 0;
char *key_fp = NULL, *keytext = NULL, *tmp;
char *command = NULL, *tag = NULL, **av = NULL;
FILE *f = NULL;
pid_t pid;
void (*osigchld)(int);
xasprintf(&tag, "KnownHostsCommand-%s", invocation);
if (host_key != NULL) {
if ((key_fp = sshkey_fingerprint(host_key,
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
fatal_f("sshkey_fingerprint failed");
if ((r = sshkey_to_base64(host_key, &keytext)) != 0)
fatal_fr(r, "sshkey_to_base64 failed");
}
/*
* NB. all returns later this function should go via "out" to
* ensure the original SIGCHLD handler is restored properly.
*/
osigchld = ssh_signal(SIGCHLD, SIG_DFL);
/* Turn the command into an argument vector */
if (argv_split(command_template, &ac, &av) != 0) {
error("%s \"%s\" contains invalid quotes", tag,
- command_template);
+ command_template);
goto out;
}
if (ac == 0) {
error("%s \"%s\" yielded no arguments", tag,
command_template);
goto out;
}
for (i = 1; i < ac; i++) {
tmp = percent_dollar_expand(av[i],
DEFAULT_CLIENT_PERCENT_EXPAND_ARGS(cinfo),
"H", hostfile_hostname,
"I", invocation,
"t", host_key == NULL ? "NONE" : sshkey_ssh_name(host_key),
"f", key_fp == NULL ? "NONE" : key_fp,
"K", keytext == NULL ? "NONE" : keytext,
(char *)NULL);
if (tmp == NULL)
fatal_f("percent_expand failed");
free(av[i]);
av[i] = tmp;
}
/* Prepare a printable command for logs, etc. */
command = argv_assemble(ac, av);
if ((pid = subprocess(tag, command, ac, av, &f,
SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_UNSAFE_PATH|
SSH_SUBPROCESS_PRESERVE_ENV, NULL, NULL, NULL)) == 0)
goto out;
load_hostkeys_file(hostkeys, hostfile_hostname, tag, f, 1);
if (exited_cleanly(pid, tag, command, 0) != 0)
fatal("KnownHostsCommand failed");
out:
if (f != NULL)
fclose(f);
ssh_signal(SIGCHLD, osigchld);
for (i = 0; i < ac; i++)
free(av[i]);
free(av);
free(tag);
free(command);
free(key_fp);
free(keytext);
}
/*
* check whether the supplied host key is valid, return -1 if the key
* is not valid. user_hostfile[0] will not be updated if 'readonly' is true.
*/
#define RDRW 0
#define RDONLY 1
#define ROQUIET 2
static int
check_host_key(char *hostname, const struct ssh_conn_info *cinfo,
struct sockaddr *hostaddr, u_short port,
struct sshkey *host_key, int readonly, int clobber_port,
char **user_hostfiles, u_int num_user_hostfiles,
char **system_hostfiles, u_int num_system_hostfiles,
const char *hostfile_command)
{
HostStatus host_status = -1, ip_status = -1;
struct sshkey *raw_key = NULL;
char *ip = NULL, *host = NULL;
char hostline[1000], *hostp, *fp, *ra;
char msg[1024];
const char *type, *fail_reason;
const struct hostkey_entry *host_found = NULL, *ip_found = NULL;
int len, cancelled_forwarding = 0, confirmed;
int local = sockaddr_is_local(hostaddr);
int r, want_cert = sshkey_is_cert(host_key), host_ip_differ = 0;
int hostkey_trusted = 0; /* Known or explicitly accepted by user */
struct hostkeys *host_hostkeys, *ip_hostkeys;
u_int i;
/*
* Force accepting of the host key for loopback/localhost. The
* problem is that if the home directory is NFS-mounted to multiple
* machines, localhost will refer to a different machine in each of
* them, and the user will get bogus HOST_CHANGED warnings. This
* essentially disables host authentication for localhost; however,
* this is probably not a real problem.
*/
if (options.no_host_authentication_for_localhost == 1 && local &&
options.host_key_alias == NULL) {
debug("Forcing accepting of host key for "
"loopback/localhost.");
options.update_hostkeys = 0;
return 0;
}
/*
* Prepare the hostname and address strings used for hostkey lookup.
* In some cases, these will have a port number appended.
*/
get_hostfile_hostname_ipaddr(hostname, hostaddr,
clobber_port ? 0 : port, &host, &ip);
/*
* Turn off check_host_ip if the connection is to localhost, via proxy
* command or if we don't have a hostname to compare with
*/
if (options.check_host_ip && (local ||
strcmp(hostname, ip) == 0 || options.proxy_command != NULL))
options.check_host_ip = 0;
host_hostkeys = init_hostkeys();
for (i = 0; i < num_user_hostfiles; i++)
load_hostkeys(host_hostkeys, host, user_hostfiles[i], 0);
for (i = 0; i < num_system_hostfiles; i++)
load_hostkeys(host_hostkeys, host, system_hostfiles[i], 0);
if (hostfile_command != NULL && !clobber_port) {
load_hostkeys_command(host_hostkeys, hostfile_command,
"HOSTNAME", cinfo, host_key, host);
}
ip_hostkeys = NULL;
if (!want_cert && options.check_host_ip) {
ip_hostkeys = init_hostkeys();
for (i = 0; i < num_user_hostfiles; i++)
load_hostkeys(ip_hostkeys, ip, user_hostfiles[i], 0);
for (i = 0; i < num_system_hostfiles; i++)
load_hostkeys(ip_hostkeys, ip, system_hostfiles[i], 0);
if (hostfile_command != NULL && !clobber_port) {
load_hostkeys_command(ip_hostkeys, hostfile_command,
"ADDRESS", cinfo, host_key, ip);
}
}
retry:
/* Reload these as they may have changed on cert->key downgrade */
want_cert = sshkey_is_cert(host_key);
type = sshkey_type(host_key);
/*
* Check if the host key is present in the user's list of known
* hosts or in the systemwide list.
*/
host_status = check_key_in_hostkeys(host_hostkeys, host_key,
&host_found);
/*
* If there are no hostfiles, or if the hostkey was found via
* KnownHostsCommand, then don't try to touch the disk.
*/
if (!readonly && (num_user_hostfiles == 0 ||
(host_found != NULL && host_found->note != 0)))
readonly = RDONLY;
/*
* Also perform check for the ip address, skip the check if we are
* localhost, looking for a certificate, or the hostname was an ip
* address to begin with.
*/
if (!want_cert && ip_hostkeys != NULL) {
ip_status = check_key_in_hostkeys(ip_hostkeys, host_key,
&ip_found);
if (host_status == HOST_CHANGED &&
(ip_status != HOST_CHANGED ||
(ip_found != NULL &&
!sshkey_equal(ip_found->key, host_found->key))))
host_ip_differ = 1;
} else
ip_status = host_status;
switch (host_status) {
case HOST_OK:
/* The host is known and the key matches. */
debug("Host '%.200s' is known and matches the %s host %s.",
host, type, want_cert ? "certificate" : "key");
debug("Found %s in %s:%lu", want_cert ? "CA key" : "key",
host_found->file, host_found->line);
if (want_cert) {
if (sshkey_cert_check_host(host_key,
options.host_key_alias == NULL ?
hostname : options.host_key_alias, 0,
options.ca_sign_algorithms, &fail_reason) != 0) {
error("%s", fail_reason);
goto fail;
}
/*
* Do not attempt hostkey update if a certificate was
* successfully matched.
*/
if (options.update_hostkeys != 0) {
options.update_hostkeys = 0;
debug3_f("certificate host key in use; "
"disabling UpdateHostkeys");
}
}
/* Turn off UpdateHostkeys if key was in system known_hosts */
if (options.update_hostkeys != 0 &&
(path_in_hostfiles(host_found->file,
system_hostfiles, num_system_hostfiles) ||
(ip_status == HOST_OK && ip_found != NULL &&
path_in_hostfiles(ip_found->file,
system_hostfiles, num_system_hostfiles)))) {
options.update_hostkeys = 0;
debug3_f("host key found in GlobalKnownHostsFile; "
"disabling UpdateHostkeys");
}
if (options.update_hostkeys != 0 && host_found->note) {
options.update_hostkeys = 0;
debug3_f("host key found via KnownHostsCommand; "
"disabling UpdateHostkeys");
}
if (options.check_host_ip && ip_status == HOST_NEW) {
if (readonly || want_cert)
logit("%s host key for IP address "
"'%.128s' not in list of known hosts.",
type, ip);
else if (!add_host_to_hostfile(user_hostfiles[0], ip,
host_key, options.hash_known_hosts))
logit("Failed to add the %s host key for IP "
"address '%.128s' to the list of known "
"hosts (%.500s).", type, ip,
user_hostfiles[0]);
else
logit("Warning: Permanently added the %s host "
"key for IP address '%.128s' to the list "
"of known hosts.", type, ip);
} else if (options.visual_host_key) {
fp = sshkey_fingerprint(host_key,
options.fingerprint_hash, SSH_FP_DEFAULT);
ra = sshkey_fingerprint(host_key,
options.fingerprint_hash, SSH_FP_RANDOMART);
if (fp == NULL || ra == NULL)
fatal_f("sshkey_fingerprint failed");
logit("Host key fingerprint is %s\n%s", fp, ra);
free(ra);
free(fp);
}
hostkey_trusted = 1;
break;
case HOST_NEW:
if (options.host_key_alias == NULL && port != 0 &&
port != SSH_DEFAULT_PORT && !clobber_port) {
debug("checking without port identifier");
if (check_host_key(hostname, cinfo, hostaddr, 0,
host_key, ROQUIET, 1,
user_hostfiles, num_user_hostfiles,
system_hostfiles, num_system_hostfiles,
hostfile_command) == 0) {
debug("found matching key w/out port");
break;
}
}
if (readonly || want_cert)
goto fail;
/* The host is new. */
if (options.strict_host_key_checking ==
SSH_STRICT_HOSTKEY_YES) {
/*
* User has requested strict host key checking. We
* will not add the host key automatically. The only
* alternative left is to abort.
*/
error("No %s host key is known for %.200s and you "
"have requested strict checking.", type, host);
goto fail;
} else if (options.strict_host_key_checking ==
SSH_STRICT_HOSTKEY_ASK) {
char *msg1 = NULL, *msg2 = NULL;
xasprintf(&msg1, "The authenticity of host "
"'%.200s (%s)' can't be established", host, ip);
if (show_other_keys(host_hostkeys, host_key)) {
xextendf(&msg1, "\n", "but keys of different "
"type are already known for this host.");
} else
xextendf(&msg1, "", ".");
fp = sshkey_fingerprint(host_key,
options.fingerprint_hash, SSH_FP_DEFAULT);
ra = sshkey_fingerprint(host_key,
options.fingerprint_hash, SSH_FP_RANDOMART);
if (fp == NULL || ra == NULL)
fatal_f("sshkey_fingerprint failed");
xextendf(&msg1, "\n", "%s key fingerprint is %s.",
type, fp);
if (options.visual_host_key)
xextendf(&msg1, "\n", "%s", ra);
if (options.verify_host_key_dns) {
xextendf(&msg1, "\n",
"%s host key fingerprint found in DNS.",
matching_host_key_dns ?
"Matching" : "No matching");
}
/* msg2 informs for other names matching this key */
if ((msg2 = other_hostkeys_message(host, ip, host_key,
user_hostfiles, num_user_hostfiles,
system_hostfiles, num_system_hostfiles)) != NULL)
xextendf(&msg1, "\n", "%s", msg2);
xextendf(&msg1, "\n",
"Are you sure you want to continue connecting "
"(yes/no/[fingerprint])? ");
confirmed = confirm(msg1, fp);
free(ra);
free(fp);
free(msg1);
free(msg2);
if (!confirmed)
goto fail;
hostkey_trusted = 1; /* user explicitly confirmed */
}
/*
* If in "new" or "off" strict mode, add the key automatically
* to the local known_hosts file.
*/
if (options.check_host_ip && ip_status == HOST_NEW) {
snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
hostp = hostline;
if (options.hash_known_hosts) {
/* Add hash of host and IP separately */
r = add_host_to_hostfile(user_hostfiles[0],
host, host_key, options.hash_known_hosts) &&
add_host_to_hostfile(user_hostfiles[0], ip,
host_key, options.hash_known_hosts);
} else {
/* Add unhashed "host,ip" */
r = add_host_to_hostfile(user_hostfiles[0],
hostline, host_key,
options.hash_known_hosts);
}
} else {
r = add_host_to_hostfile(user_hostfiles[0], host,
host_key, options.hash_known_hosts);
hostp = host;
}
if (!r)
logit("Failed to add the host to the list of known "
"hosts (%.500s).", user_hostfiles[0]);
else
logit("Warning: Permanently added '%.200s' (%s) to the "
"list of known hosts.", hostp, type);
break;
case HOST_REVOKED:
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: REVOKED HOST KEY DETECTED! @");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("The %s host key for %s is marked as revoked.", type, host);
error("This could mean that a stolen key is being used to");
error("impersonate this host.");
/*
* If strict host key checking is in use, the user will have
* to edit the key manually and we can only abort.
*/
if (options.strict_host_key_checking !=
SSH_STRICT_HOSTKEY_OFF) {
error("%s host key for %.200s was revoked and you have "
"requested strict checking.", type, host);
goto fail;
}
goto continue_unsafe;
case HOST_CHANGED:
if (want_cert) {
/*
* This is only a debug() since it is valid to have
* CAs with wildcard DNS matches that don't match
* all hosts that one might visit.
*/
debug("Host certificate authority does not "
"match %s in %s:%lu", CA_MARKER,
host_found->file, host_found->line);
goto fail;
}
if (readonly == ROQUIET)
goto fail;
if (options.check_host_ip && host_ip_differ) {
char *key_msg;
if (ip_status == HOST_NEW)
key_msg = "is unknown";
else if (ip_status == HOST_OK)
key_msg = "is unchanged";
else
key_msg = "has a different value";
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("The %s host key for %s has changed,", type, host);
error("and the key for the corresponding IP address %s", ip);
error("%s. This could either mean that", key_msg);
error("DNS SPOOFING is happening or the IP address for the host");
error("and its host key have changed at the same time.");
if (ip_status != HOST_NEW)
error("Offending key for IP in %s:%lu",
ip_found->file, ip_found->line);
}
/* The host key has changed. */
warn_changed_key(host_key);
error("Add correct host key in %.100s to get rid of this message.",
user_hostfiles[0]);
error("Offending %s key in %s:%lu",
sshkey_type(host_found->key),
host_found->file, host_found->line);
/*
* If strict host key checking is in use, the user will have
* to edit the key manually and we can only abort.
*/
if (options.strict_host_key_checking !=
SSH_STRICT_HOSTKEY_OFF) {
error("Host key for %.200s has changed and you have "
"requested strict checking.", host);
goto fail;
}
continue_unsafe:
/*
* If strict host key checking has not been requested, allow
* the connection but without MITM-able authentication or
* forwarding.
*/
if (options.password_authentication) {
error("Password authentication is disabled to avoid "
"man-in-the-middle attacks.");
options.password_authentication = 0;
cancelled_forwarding = 1;
}
if (options.kbd_interactive_authentication) {
error("Keyboard-interactive authentication is disabled"
" to avoid man-in-the-middle attacks.");
options.kbd_interactive_authentication = 0;
options.challenge_response_authentication = 0;
cancelled_forwarding = 1;
}
if (options.challenge_response_authentication) {
error("Challenge/response authentication is disabled"
" to avoid man-in-the-middle attacks.");
options.challenge_response_authentication = 0;
cancelled_forwarding = 1;
}
if (options.forward_agent) {
error("Agent forwarding is disabled to avoid "
"man-in-the-middle attacks.");
options.forward_agent = 0;
cancelled_forwarding = 1;
}
if (options.forward_x11) {
error("X11 forwarding is disabled to avoid "
"man-in-the-middle attacks.");
options.forward_x11 = 0;
cancelled_forwarding = 1;
}
if (options.num_local_forwards > 0 ||
options.num_remote_forwards > 0) {
error("Port forwarding is disabled to avoid "
"man-in-the-middle attacks.");
options.num_local_forwards =
options.num_remote_forwards = 0;
cancelled_forwarding = 1;
}
if (options.tun_open != SSH_TUNMODE_NO) {
error("Tunnel forwarding is disabled to avoid "
"man-in-the-middle attacks.");
options.tun_open = SSH_TUNMODE_NO;
cancelled_forwarding = 1;
}
if (options.update_hostkeys != 0) {
error("UpdateHostkeys is disabled because the host "
"key is not trusted.");
options.update_hostkeys = 0;
}
if (options.exit_on_forward_failure && cancelled_forwarding)
fatal("Error: forwarding disabled due to host key "
"check failure");
/*
* XXX Should permit the user to change to use the new id.
* This could be done by converting the host key to an
* identifying sentence, tell that the host identifies itself
* by that sentence, and ask the user if he/she wishes to
* accept the authentication.
*/
break;
case HOST_FOUND:
fatal("internal error");
break;
}
if (options.check_host_ip && host_status != HOST_CHANGED &&
ip_status == HOST_CHANGED) {
snprintf(msg, sizeof(msg),
"Warning: the %s host key for '%.200s' "
"differs from the key for the IP address '%.128s'"
"\nOffending key for IP in %s:%lu",
type, host, ip, ip_found->file, ip_found->line);
if (host_status == HOST_OK) {
len = strlen(msg);
snprintf(msg + len, sizeof(msg) - len,
"\nMatching host key in %s:%lu",
host_found->file, host_found->line);
}
if (options.strict_host_key_checking ==
SSH_STRICT_HOSTKEY_ASK) {
strlcat(msg, "\nAre you sure you want "
"to continue connecting (yes/no)? ", sizeof(msg));
if (!confirm(msg, NULL))
goto fail;
} else if (options.strict_host_key_checking !=
SSH_STRICT_HOSTKEY_OFF) {
logit("%s", msg);
error("Exiting, you have requested strict checking.");
goto fail;
} else {
logit("%s", msg);
}
}
if (!hostkey_trusted && options.update_hostkeys) {
debug_f("hostkey not known or explicitly trusted: "
"disabling UpdateHostkeys");
options.update_hostkeys = 0;
}
free(ip);
free(host);
if (host_hostkeys != NULL)
free_hostkeys(host_hostkeys);
if (ip_hostkeys != NULL)
free_hostkeys(ip_hostkeys);
return 0;
fail:
if (want_cert && host_status != HOST_REVOKED) {
/*
* No matching certificate. Downgrade cert to raw key and
* search normally.
*/
debug("No matching CA found. Retry with plain key");
if ((r = sshkey_from_private(host_key, &raw_key)) != 0)
fatal_fr(r, "decode key");
if ((r = sshkey_drop_cert(raw_key)) != 0)
fatal_r(r, "Couldn't drop certificate");
host_key = raw_key;
goto retry;
}
sshkey_free(raw_key);
free(ip);
free(host);
if (host_hostkeys != NULL)
free_hostkeys(host_hostkeys);
if (ip_hostkeys != NULL)
free_hostkeys(ip_hostkeys);
return -1;
}
/* returns 0 if key verifies or -1 if key does NOT verify */
int
verify_host_key(char *host, struct sockaddr *hostaddr, struct sshkey *host_key,
const struct ssh_conn_info *cinfo)
{
u_int i;
int r = -1, flags = 0;
char valid[64], *fp = NULL, *cafp = NULL;
struct sshkey *plain = NULL;
if ((fp = sshkey_fingerprint(host_key,
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
error_fr(r, "fingerprint host key");
r = -1;
goto out;
}
if (sshkey_is_cert(host_key)) {
if ((cafp = sshkey_fingerprint(host_key->cert->signature_key,
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
error_fr(r, "fingerprint CA key");
r = -1;
goto out;
}
sshkey_format_cert_validity(host_key->cert,
valid, sizeof(valid));
debug("Server host certificate: %s %s, serial %llu "
"ID \"%s\" CA %s %s valid %s",
sshkey_ssh_name(host_key), fp,
(unsigned long long)host_key->cert->serial,
host_key->cert->key_id,
sshkey_ssh_name(host_key->cert->signature_key), cafp,
valid);
for (i = 0; i < host_key->cert->nprincipals; i++) {
debug2("Server host certificate hostname: %s",
host_key->cert->principals[i]);
}
} else {
debug("Server host key: %s %s", sshkey_ssh_name(host_key), fp);
}
if (sshkey_equal(previous_host_key, host_key)) {
debug2_f("server host key %s %s matches cached key",
sshkey_type(host_key), fp);
r = 0;
goto out;
}
/* Check in RevokedHostKeys file if specified */
if (options.revoked_host_keys != NULL) {
r = sshkey_check_revoked(host_key, options.revoked_host_keys);
switch (r) {
case 0:
break; /* not revoked */
case SSH_ERR_KEY_REVOKED:
error("Host key %s %s revoked by file %s",
sshkey_type(host_key), fp,
options.revoked_host_keys);
r = -1;
goto out;
default:
error_r(r, "Error checking host key %s %s in "
"revoked keys file %s", sshkey_type(host_key),
fp, options.revoked_host_keys);
r = -1;
goto out;
}
}
if (options.verify_host_key_dns) {
/*
* XXX certs are not yet supported for DNS, so downgrade
* them and try the plain key.
*/
if ((r = sshkey_from_private(host_key, &plain)) != 0)
goto out;
if (sshkey_is_cert(plain))
sshkey_drop_cert(plain);
if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) {
if (flags & DNS_VERIFY_FOUND) {
if (options.verify_host_key_dns == 1 &&
flags & DNS_VERIFY_MATCH &&
flags & DNS_VERIFY_SECURE) {
r = 0;
goto out;
}
if (flags & DNS_VERIFY_MATCH) {
matching_host_key_dns = 1;
} else {
warn_changed_key(plain);
error("Update the SSHFP RR in DNS "
"with the new host key to get rid "
"of this message.");
}
}
}
}
r = check_host_key(host, cinfo, hostaddr, options.port, host_key,
RDRW, 0, options.user_hostfiles, options.num_user_hostfiles,
options.system_hostfiles, options.num_system_hostfiles,
options.known_hosts_command);
out:
sshkey_free(plain);
free(fp);
free(cafp);
if (r == 0 && host_key != NULL) {
sshkey_free(previous_host_key);
r = sshkey_from_private(host_key, &previous_host_key);
}
return r;
}
/*
* Starts a dialog with the server, and authenticates the current user on the
* server. This does not need any extra privileges. The basic connection
* to the server must already have been established before this is called.
* If login fails, this function prints an error and never returns.
* This function does not require super-user privileges.
*/
void
ssh_login(struct ssh *ssh, Sensitive *sensitive, const char *orighost,
struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms,
const struct ssh_conn_info *cinfo)
{
char *host;
char *server_user, *local_user;
int r;
local_user = xstrdup(pw->pw_name);
server_user = options.user ? options.user : local_user;
/* Convert the user-supplied hostname into all lowercase. */
host = xstrdup(orighost);
lowercase(host);
/* Exchange protocol version identification strings with the server. */
if ((r = kex_exchange_identification(ssh, timeout_ms, NULL)) != 0)
sshpkt_fatal(ssh, r, "banner exchange");
/* Put the connection into non-blocking mode. */
ssh_packet_set_nonblocking(ssh);
/* key exchange */
/* authenticate user */
debug("Authenticating to %s:%d as '%s'", host, port, server_user);
ssh_kex2(ssh, host, hostaddr, port, cinfo);
ssh_userauth2(ssh, local_user, server_user, host, sensitive);
free(local_user);
free(host);
}
/* print all known host keys for a given host, but skip keys of given type */
static int
show_other_keys(struct hostkeys *hostkeys, struct sshkey *key)
{
int type[] = {
KEY_RSA,
KEY_DSA,
KEY_ECDSA,
KEY_ED25519,
KEY_XMSS,
-1
};
int i, ret = 0;
char *fp, *ra;
const struct hostkey_entry *found;
for (i = 0; type[i] != -1; i++) {
if (type[i] == key->type)
continue;
if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i],
-1, &found))
continue;
fp = sshkey_fingerprint(found->key,
options.fingerprint_hash, SSH_FP_DEFAULT);
ra = sshkey_fingerprint(found->key,
options.fingerprint_hash, SSH_FP_RANDOMART);
if (fp == NULL || ra == NULL)
fatal_f("sshkey_fingerprint fail");
logit("WARNING: %s key found for host %s\n"
"in %s:%lu\n"
"%s key fingerprint %s.",
sshkey_type(found->key),
found->host, found->file, found->line,
sshkey_type(found->key), fp);
if (options.visual_host_key)
logit("%s", ra);
free(ra);
free(fp);
ret = 1;
}
return ret;
}
static void
warn_changed_key(struct sshkey *host_key)
{
char *fp;
fp = sshkey_fingerprint(host_key, options.fingerprint_hash,
SSH_FP_DEFAULT);
if (fp == NULL)
fatal_f("sshkey_fingerprint fail");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
error("It is also possible that a host key has just been changed.");
error("The fingerprint for the %s key sent by the remote host is\n%s.",
sshkey_type(host_key), fp);
error("Please contact your system administrator.");
free(fp);
}
/*
* Execute a local command
*/
int
ssh_local_cmd(const char *args)
{
char *shell;
pid_t pid;
int status;
void (*osighand)(int);
if (!options.permit_local_command ||
args == NULL || !*args)
return (1);
if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
shell = _PATH_BSHELL;
osighand = ssh_signal(SIGCHLD, SIG_DFL);
pid = fork();
if (pid == 0) {
ssh_signal(SIGPIPE, SIG_DFL);
debug3("Executing %s -c \"%s\"", shell, args);
execl(shell, shell, "-c", args, (char *)NULL);
error("Couldn't execute %s -c \"%s\": %s",
shell, args, strerror(errno));
_exit(1);
} else if (pid == -1)
fatal("fork failed: %.100s", strerror(errno));
while (waitpid(pid, &status, 0) == -1)
if (errno != EINTR)
fatal("Couldn't wait for child: %s", strerror(errno));
ssh_signal(SIGCHLD, osighand);
if (!WIFEXITED(status))
return (1);
return (WEXITSTATUS(status));
}
void
maybe_add_key_to_agent(const char *authfile, struct sshkey *private,
const char *comment, const char *passphrase)
{
int auth_sock = -1, r;
const char *skprovider = NULL;
if (options.add_keys_to_agent == 0)
return;
if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) {
debug3("no authentication agent, not adding key");
return;
}
if (options.add_keys_to_agent == 2 &&
!ask_permission("Add key %s (%s) to agent?", authfile, comment)) {
debug3("user denied adding this key");
close(auth_sock);
return;
}
if (sshkey_is_sk(private))
skprovider = options.sk_provider;
if ((r = ssh_add_identity_constrained(auth_sock, private,
comment == NULL ? authfile : comment,
options.add_keys_to_agent_lifespan,
(options.add_keys_to_agent == 3), 0, skprovider)) == 0)
debug("identity added to agent: %s", authfile);
else
debug("could not add identity to agent: %s (%d)", authfile, r);
close(auth_sock);
}
diff --git a/sshconnect2.c b/sshconnect2.c
index 059c9480db6a..a53ab95dbb2f 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1,2322 +1,2322 @@
-/* $OpenBSD: sshconnect2.c,v 1.346 2021/01/27 10:05:28 djm Exp $ */
+/* $OpenBSD: sshconnect2.c,v 1.347 2021/04/03 06:18:41 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <netdb.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
#include <vis.h>
#endif
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "ssh.h"
#include "ssh2.h"
#include "sshbuf.h"
#include "packet.h"
#include "compat.h"
#include "cipher.h"
#include "sshkey.h"
#include "kex.h"
#include "myproposal.h"
#include "sshconnect.h"
#include "authfile.h"
#include "dh.h"
#include "authfd.h"
#include "log.h"
#include "misc.h"
#include "readconf.h"
#include "match.h"
#include "dispatch.h"
#include "canohost.h"
#include "msg.h"
#include "pathnames.h"
#include "uidswap.h"
#include "hostfile.h"
#include "ssherr.h"
#include "utf8.h"
#include "ssh-sk.h"
#include "sk-api.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
/* import */
extern char *client_version_string;
extern char *server_version_string;
extern Options options;
/*
* SSH2 key exchange
*/
static char *xxx_host;
static struct sockaddr *xxx_hostaddr;
static const struct ssh_conn_info *xxx_conn_info;
static int
verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh)
{
if (verify_host_key(xxx_host, xxx_hostaddr, hostkey,
xxx_conn_info) == -1)
fatal("Host key verification failed.");
return 0;
}
/* Returns the first item from a comma-separated algorithm list */
static char *
first_alg(const char *algs)
{
char *ret, *cp;
ret = xstrdup(algs);
if ((cp = strchr(ret, ',')) != NULL)
*cp = '\0';
return ret;
}
static char *
order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port,
const struct ssh_conn_info *cinfo)
{
char *oavail = NULL, *avail = NULL, *first = NULL, *last = NULL;
char *alg = NULL, *hostname = NULL, *ret = NULL, *best = NULL;
size_t maxlen;
struct hostkeys *hostkeys = NULL;
int ktype;
u_int i;
/* Find all hostkeys for this hostname */
get_hostfile_hostname_ipaddr(host, hostaddr, port, &hostname, NULL);
hostkeys = init_hostkeys();
for (i = 0; i < options.num_user_hostfiles; i++)
load_hostkeys(hostkeys, hostname, options.user_hostfiles[i], 0);
for (i = 0; i < options.num_system_hostfiles; i++) {
load_hostkeys(hostkeys, hostname,
options.system_hostfiles[i], 0);
}
if (options.known_hosts_command != NULL) {
load_hostkeys_command(hostkeys, options.known_hosts_command,
"ORDER", cinfo, NULL, host);
}
/*
* If a plain public key exists that matches the type of the best
* preference HostkeyAlgorithms, then use the whole list as is.
* Note that we ignore whether the best preference algorithm is a
* certificate type, as sshconnect.c will downgrade certs to
* plain keys if necessary.
*/
best = first_alg(options.hostkeyalgorithms);
if (lookup_key_in_hostkeys_by_type(hostkeys,
sshkey_type_plain(sshkey_type_from_name(best)),
sshkey_ecdsa_nid_from_name(best), NULL)) {
debug3_f("have matching best-preference key type %s, "
"using HostkeyAlgorithms verbatim", best);
ret = xstrdup(options.hostkeyalgorithms);
goto out;
}
/*
* Otherwise, prefer the host key algorithms that match known keys
* while keeping the ordering of HostkeyAlgorithms as much as possible.
*/
oavail = avail = xstrdup(options.hostkeyalgorithms);
maxlen = strlen(avail) + 1;
first = xmalloc(maxlen);
last = xmalloc(maxlen);
*first = *last = '\0';
#define ALG_APPEND(to, from) \
do { \
if (*to != '\0') \
strlcat(to, ",", maxlen); \
strlcat(to, from, maxlen); \
} while (0)
while ((alg = strsep(&avail, ",")) && *alg != '\0') {
if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC)
fatal_f("unknown alg %s", alg);
/*
* If we have a @cert-authority marker in known_hosts then
* prefer all certificate algorithms.
*/
if (sshkey_type_is_cert(ktype) &&
lookup_marker_in_hostkeys(hostkeys, MRK_CA)) {
ALG_APPEND(first, alg);
continue;
}
/* If the key appears in known_hosts then prefer it */
if (lookup_key_in_hostkeys_by_type(hostkeys,
sshkey_type_plain(ktype),
sshkey_ecdsa_nid_from_name(alg), NULL)) {
ALG_APPEND(first, alg);
continue;
}
/* Otherwise, put it last */
ALG_APPEND(last, alg);
}
#undef ALG_APPEND
xasprintf(&ret, "%s%s%s", first,
(*first == '\0' || *last == '\0') ? "" : ",", last);
if (*first != '\0')
debug3_f("prefer hostkeyalgs: %s", first);
else
debug3_f("no algorithms matched; accept original");
out:
free(best);
free(first);
free(last);
free(hostname);
free(oavail);
free_hostkeys(hostkeys);
return ret;
}
void
ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port,
const struct ssh_conn_info *cinfo)
{
char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
char *s, *all_key;
int r, use_known_hosts_order = 0;
xxx_host = host;
xxx_hostaddr = hostaddr;
xxx_conn_info = cinfo;
/*
* If the user has not specified HostkeyAlgorithms, or has only
* appended or removed algorithms from that list then prefer algorithms
* that are in the list that are supported by known_hosts keys.
*/
if (options.hostkeyalgorithms == NULL ||
options.hostkeyalgorithms[0] == '-' ||
options.hostkeyalgorithms[0] == '+')
use_known_hosts_order = 1;
/* Expand or fill in HostkeyAlgorithms */
all_key = sshkey_alg_list(0, 0, 1, ',');
if ((r = kex_assemble_names(&options.hostkeyalgorithms,
kex_default_pk_alg(), all_key)) != 0)
fatal_fr(r, "kex_assemble_namelist");
free(all_key);
if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL)
fatal_f("kex_names_cat");
myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(ssh, s);
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
compat_cipher_proposal(ssh, options.ciphers);
myproposal[PROPOSAL_ENC_ALGS_STOC] =
compat_cipher_proposal(ssh, options.ciphers);
myproposal[PROPOSAL_COMP_ALGS_CTOS] =
myproposal[PROPOSAL_COMP_ALGS_STOC] =
(char *)compression_alg_list(options.compression);
myproposal[PROPOSAL_MAC_ALGS_CTOS] =
myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
if (use_known_hosts_order) {
/* Query known_hosts and prefer algorithms that appear there */
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
compat_pkalg_proposal(ssh,
order_hostkeyalgs(host, hostaddr, port, cinfo));
} else {
/* Use specified HostkeyAlgorithms exactly */
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
compat_pkalg_proposal(ssh, options.hostkeyalgorithms);
}
if (options.rekey_limit || options.rekey_interval)
ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
options.rekey_interval);
/* start key exchange */
if ((r = kex_setup(ssh, myproposal)) != 0)
fatal_r(r, "kex_setup");
#ifdef WITH_OPENSSL
ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_client;
ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_client;
ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_client;
ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_client;
ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_client;
ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
# ifdef OPENSSL_HAS_ECC
ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client;
# endif
#endif
ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client;
ssh->kex->verify_host_key=&verify_host_key_callback;
ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done);
/* remove ext-info from the KEX proposals for rekeying */
myproposal[PROPOSAL_KEX_ALGS] =
compat_kex_proposal(ssh, options.kex_algorithms);
if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0)
fatal_r(r, "kex_prop2buf");
#ifdef DEBUG_KEXDH
/* send 1st encrypted/maced/compressed message */
if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 ||
(r = sshpkt_put_cstring(ssh, "markus")) != 0 ||
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
fatal_fr(r, "send packet");
#endif
}
/*
* Authenticate user
*/
typedef struct cauthctxt Authctxt;
typedef struct cauthmethod Authmethod;
typedef struct identity Identity;
typedef struct idlist Idlist;
struct identity {
TAILQ_ENTRY(identity) next;
int agent_fd; /* >=0 if agent supports key */
struct sshkey *key; /* public/private key */
char *filename; /* comment for agent-only keys */
int tried;
int isprivate; /* key points to the private key */
int userprovided;
};
TAILQ_HEAD(idlist, identity);
struct cauthctxt {
const char *server_user;
const char *local_user;
const char *host;
const char *service;
struct cauthmethod *method;
sig_atomic_t success;
char *authlist;
#ifdef GSSAPI
/* gssapi */
gss_OID_set gss_supported_mechs;
u_int mech_tried;
#endif
/* pubkey */
struct idlist keys;
int agent_fd;
/* hostbased */
Sensitive *sensitive;
char *oktypes, *ktypes;
const char *active_ktype;
/* kbd-interactive */
int info_req_seen;
int attempt_kbdint;
/* password */
int attempt_passwd;
/* generic */
void *methoddata;
};
struct cauthmethod {
char *name; /* string to compare against server's list */
int (*userauth)(struct ssh *ssh);
void (*cleanup)(struct ssh *ssh);
int *enabled; /* flag in option struct that enables method */
int *batch_flag; /* flag in option struct that disables method */
};
static int input_userauth_service_accept(int, u_int32_t, struct ssh *);
static int input_userauth_ext_info(int, u_int32_t, struct ssh *);
static int input_userauth_success(int, u_int32_t, struct ssh *);
static int input_userauth_failure(int, u_int32_t, struct ssh *);
static int input_userauth_banner(int, u_int32_t, struct ssh *);
static int input_userauth_error(int, u_int32_t, struct ssh *);
static int input_userauth_info_req(int, u_int32_t, struct ssh *);
static int input_userauth_pk_ok(int, u_int32_t, struct ssh *);
static int input_userauth_passwd_changereq(int, u_int32_t, struct ssh *);
static int userauth_none(struct ssh *);
static int userauth_pubkey(struct ssh *);
static int userauth_passwd(struct ssh *);
static int userauth_kbdint(struct ssh *);
static int userauth_hostbased(struct ssh *);
#ifdef GSSAPI
static int userauth_gssapi(struct ssh *);
static void userauth_gssapi_cleanup(struct ssh *);
static int input_gssapi_response(int type, u_int32_t, struct ssh *);
static int input_gssapi_token(int type, u_int32_t, struct ssh *);
static int input_gssapi_error(int, u_int32_t, struct ssh *);
static int input_gssapi_errtok(int, u_int32_t, struct ssh *);
#endif
void userauth(struct ssh *, char *);
static void pubkey_cleanup(struct ssh *);
static int sign_and_send_pubkey(struct ssh *ssh, Identity *);
static void pubkey_prepare(Authctxt *);
static void pubkey_reset(Authctxt *);
static struct sshkey *load_identity_file(Identity *);
static Authmethod *authmethod_get(char *authlist);
static Authmethod *authmethod_lookup(const char *name);
static char *authmethods_get(void);
Authmethod authmethods[] = {
#ifdef GSSAPI
{"gssapi-with-mic",
userauth_gssapi,
userauth_gssapi_cleanup,
&options.gss_authentication,
NULL},
#endif
{"hostbased",
userauth_hostbased,
NULL,
&options.hostbased_authentication,
NULL},
{"publickey",
userauth_pubkey,
NULL,
&options.pubkey_authentication,
NULL},
{"keyboard-interactive",
userauth_kbdint,
NULL,
&options.kbd_interactive_authentication,
&options.batch_mode},
{"password",
userauth_passwd,
NULL,
&options.password_authentication,
&options.batch_mode},
{"none",
userauth_none,
NULL,
NULL,
NULL},
{NULL, NULL, NULL, NULL, NULL}
};
void
ssh_userauth2(struct ssh *ssh, const char *local_user,
const char *server_user, char *host, Sensitive *sensitive)
{
Authctxt authctxt;
int r;
if (options.challenge_response_authentication)
options.kbd_interactive_authentication = 1;
if (options.preferred_authentications == NULL)
options.preferred_authentications = authmethods_get();
/* setup authentication context */
memset(&authctxt, 0, sizeof(authctxt));
authctxt.server_user = server_user;
authctxt.local_user = local_user;
authctxt.host = host;
authctxt.service = "ssh-connection"; /* service name */
authctxt.success = 0;
authctxt.method = authmethod_lookup("none");
authctxt.authlist = NULL;
authctxt.methoddata = NULL;
authctxt.sensitive = sensitive;
authctxt.active_ktype = authctxt.oktypes = authctxt.ktypes = NULL;
authctxt.info_req_seen = 0;
authctxt.attempt_kbdint = 0;
authctxt.attempt_passwd = 0;
#if GSSAPI
authctxt.gss_supported_mechs = NULL;
authctxt.mech_tried = 0;
#endif
authctxt.agent_fd = -1;
pubkey_prepare(&authctxt);
if (authctxt.method == NULL) {
fatal_f("internal error: cannot send userauth none request");
}
if ((r = sshpkt_start(ssh, SSH2_MSG_SERVICE_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, "ssh-userauth")) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send packet");
ssh->authctxt = &authctxt;
ssh_dispatch_init(ssh, &input_userauth_error);
ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info);
ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept);
ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt.success); /* loop until success */
pubkey_cleanup(ssh);
ssh->authctxt = NULL;
ssh_dispatch_range(ssh, SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL);
if (!authctxt.success)
fatal("Authentication failed.");
debug("Authentication succeeded (%s).", authctxt.method->name);
}
/* ARGSUSED */
static int
input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh)
{
int r;
if (ssh_packet_remaining(ssh) > 0) {
char *reply;
if ((r = sshpkt_get_cstring(ssh, &reply, NULL)) != 0)
goto out;
debug2("service_accept: %s", reply);
free(reply);
} else {
debug2("buggy server: service_accept w/o service");
}
if ((r = sshpkt_get_end(ssh)) != 0)
goto out;
debug("SSH2_MSG_SERVICE_ACCEPT received");
/* initial userauth request */
userauth_none(ssh);
ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_error);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
r = 0;
out:
return r;
}
/* ARGSUSED */
static int
input_userauth_ext_info(int type, u_int32_t seqnr, struct ssh *ssh)
{
return kex_input_ext_info(type, seqnr, ssh);
}
void
userauth(struct ssh *ssh, char *authlist)
{
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
if (authctxt->method != NULL && authctxt->method->cleanup != NULL)
authctxt->method->cleanup(ssh);
free(authctxt->methoddata);
authctxt->methoddata = NULL;
if (authlist == NULL) {
authlist = authctxt->authlist;
} else {
free(authctxt->authlist);
authctxt->authlist = authlist;
}
for (;;) {
Authmethod *method = authmethod_get(authlist);
if (method == NULL)
fatal("%s@%s: Permission denied (%s).",
authctxt->server_user, authctxt->host, authlist);
authctxt->method = method;
/* reset the per method handler */
ssh_dispatch_range(ssh, SSH2_MSG_USERAUTH_PER_METHOD_MIN,
SSH2_MSG_USERAUTH_PER_METHOD_MAX, NULL);
/* and try new method */
if (method->userauth(ssh) != 0) {
debug2("we sent a %s packet, wait for reply", method->name);
break;
} else {
debug2("we did not send a packet, disable method");
method->enabled = NULL;
}
}
}
/* ARGSUSED */
static int
input_userauth_error(int type, u_int32_t seq, struct ssh *ssh)
{
fatal_f("bad message during authentication: type %d", type);
return 0;
}
/* ARGSUSED */
static int
input_userauth_banner(int type, u_int32_t seq, struct ssh *ssh)
{
char *msg = NULL;
size_t len;
int r;
debug3_f("entering");
if ((r = sshpkt_get_cstring(ssh, &msg, &len)) != 0 ||
(r = sshpkt_get_cstring(ssh, NULL, NULL)) != 0)
goto out;
if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO)
fmprintf(stderr, "%s", msg);
r = 0;
out:
free(msg);
return r;
}
/* ARGSUSED */
static int
input_userauth_success(int type, u_int32_t seq, struct ssh *ssh)
{
Authctxt *authctxt = ssh->authctxt;
if (authctxt == NULL)
fatal_f("no authentication context");
free(authctxt->authlist);
authctxt->authlist = NULL;
if (authctxt->method != NULL && authctxt->method->cleanup != NULL)
authctxt->method->cleanup(ssh);
free(authctxt->methoddata);
authctxt->methoddata = NULL;
authctxt->success = 1; /* break out */
return 0;
}
#if 0
static int
input_userauth_success_unexpected(int type, u_int32_t seq, struct ssh *ssh)
{
Authctxt *authctxt = ssh->authctxt;
if (authctxt == NULL)
fatal_f("no authentication context");
fatal("Unexpected authentication success during %s.",
authctxt->method->name);
return 0;
}
#endif
/* ARGSUSED */
static int
input_userauth_failure(int type, u_int32_t seq, struct ssh *ssh)
{
Authctxt *authctxt = ssh->authctxt;
char *authlist = NULL;
u_char partial;
if (authctxt == NULL)
fatal("input_userauth_failure: no authentication context");
if (sshpkt_get_cstring(ssh, &authlist, NULL) != 0 ||
sshpkt_get_u8(ssh, &partial) != 0 ||
sshpkt_get_end(ssh) != 0)
goto out;
if (partial != 0) {
verbose("Authenticated with partial success.");
/* reset state */
pubkey_reset(authctxt);
}
debug("Authentications that can continue: %s", authlist);
userauth(ssh, authlist);
authlist = NULL;
out:
free(authlist);
return 0;
}
/*
* Format an identity for logging including filename, key type, fingerprint
* and location (agent, etc.). Caller must free.
*/
static char *
format_identity(Identity *id)
{
char *fp = NULL, *ret = NULL;
const char *note = "";
if (id->key != NULL) {
- fp = sshkey_fingerprint(id->key, options.fingerprint_hash,
+ fp = sshkey_fingerprint(id->key, options.fingerprint_hash,
SSH_FP_DEFAULT);
}
if (id->key) {
if ((id->key->flags & SSHKEY_FLAG_EXT) != 0)
note = " token";
else if (sshkey_is_sk(id->key))
note = " authenticator";
}
xasprintf(&ret, "%s %s%s%s%s%s%s",
id->filename,
id->key ? sshkey_type(id->key) : "", id->key ? " " : "",
fp ? fp : "",
id->userprovided ? " explicit" : "", note,
id->agent_fd != -1 ? " agent" : "");
free(fp);
return ret;
}
/* ARGSUSED */
static int
input_userauth_pk_ok(int type, u_int32_t seq, struct ssh *ssh)
{
Authctxt *authctxt = ssh->authctxt;
struct sshkey *key = NULL;
Identity *id = NULL;
int pktype, found = 0, sent = 0;
size_t blen;
char *pkalg = NULL, *fp = NULL, *ident = NULL;
u_char *pkblob = NULL;
int r;
if (authctxt == NULL)
fatal("input_userauth_pk_ok: no authentication context");
if ((r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
(r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto done;
if ((pktype = sshkey_type_from_name(pkalg)) == KEY_UNSPEC) {
debug_f("server sent unknown pkalg %s", pkalg);
goto done;
}
if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
debug_r(r, "no key from blob. pkalg %s", pkalg);
goto done;
}
if (key->type != pktype) {
error("input_userauth_pk_ok: type mismatch "
"for decoded key (received %d, expected %d)",
key->type, pktype);
goto done;
}
/*
* search keys in the reverse order, because last candidate has been
* moved to the end of the queue. this also avoids confusion by
* duplicate keys
*/
TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) {
if (sshkey_equal(key, id->key)) {
found = 1;
break;
}
}
if (!found || id == NULL) {
fp = sshkey_fingerprint(key, options.fingerprint_hash,
SSH_FP_DEFAULT);
error_f("server replied with unknown key: %s %s",
sshkey_type(key), fp == NULL ? "<ERROR>" : fp);
goto done;
}
ident = format_identity(id);
debug("Server accepts key: %s", ident);
sent = sign_and_send_pubkey(ssh, id);
r = 0;
done:
sshkey_free(key);
free(ident);
free(fp);
free(pkalg);
free(pkblob);
/* try another method if we did not send a packet */
if (r == 0 && sent == 0)
userauth(ssh, NULL);
return r;
}
#ifdef GSSAPI
static int
userauth_gssapi(struct ssh *ssh)
{
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
Gssctxt *gssctxt = NULL;
OM_uint32 min;
int r, ok = 0;
gss_OID mech = NULL;
/* Try one GSSAPI method at a time, rather than sending them all at
* once. */
if (authctxt->gss_supported_mechs == NULL)
gss_indicate_mechs(&min, &authctxt->gss_supported_mechs);
/* Check to see whether the mechanism is usable before we offer it */
while (authctxt->mech_tried < authctxt->gss_supported_mechs->count &&
!ok) {
mech = &authctxt->gss_supported_mechs->
elements[authctxt->mech_tried];
/* My DER encoding requires length<128 */
if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt,
mech, authctxt->host)) {
ok = 1; /* Mechanism works */
} else {
authctxt->mech_tried++;
}
}
if (!ok || mech == NULL)
return 0;
authctxt->methoddata=(void *)gssctxt;
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
(r = sshpkt_put_u32(ssh, 1)) != 0 ||
(r = sshpkt_put_u32(ssh, (mech->length) + 2)) != 0 ||
(r = sshpkt_put_u8(ssh, SSH_GSS_OIDTYPE)) != 0 ||
(r = sshpkt_put_u8(ssh, mech->length)) != 0 ||
(r = sshpkt_put(ssh, mech->elements, mech->length)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send packet");
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
authctxt->mech_tried++; /* Move along to next candidate */
return 1;
}
static void
userauth_gssapi_cleanup(struct ssh *ssh)
{
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
Gssctxt *gssctxt = (Gssctxt *)authctxt->methoddata;
ssh_gssapi_delete_ctx(&gssctxt);
authctxt->methoddata = NULL;
free(authctxt->gss_supported_mechs);
authctxt->gss_supported_mechs = NULL;
}
static OM_uint32
process_gssapi_token(struct ssh *ssh, gss_buffer_t recv_tok)
{
Authctxt *authctxt = ssh->authctxt;
Gssctxt *gssctxt = authctxt->methoddata;
gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
gss_buffer_desc gssbuf;
OM_uint32 status, ms, flags;
int r;
status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
recv_tok, &send_tok, &flags);
if (send_tok.length > 0) {
u_char type = GSS_ERROR(status) ?
SSH2_MSG_USERAUTH_GSSAPI_ERRTOK :
SSH2_MSG_USERAUTH_GSSAPI_TOKEN;
if ((r = sshpkt_start(ssh, type)) != 0 ||
(r = sshpkt_put_string(ssh, send_tok.value,
send_tok.length)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send %u packet", type);
gss_release_buffer(&ms, &send_tok);
}
if (status == GSS_S_COMPLETE) {
/* send either complete or MIC, depending on mechanism */
if (!(flags & GSS_C_INTEG_FLAG)) {
if ((r = sshpkt_start(ssh,
SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send completion");
} else {
struct sshbuf *b;
if ((b = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
ssh_gssapi_buildmic(b, authctxt->server_user,
authctxt->service, "gssapi-with-mic",
ssh->kex->session_id);
if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL)
fatal_f("sshbuf_mutable_ptr failed");
gssbuf.length = sshbuf_len(b);
status = ssh_gssapi_sign(gssctxt, &gssbuf, &mic);
if (!GSS_ERROR(status)) {
if ((r = sshpkt_start(ssh,
SSH2_MSG_USERAUTH_GSSAPI_MIC)) != 0 ||
(r = sshpkt_put_string(ssh, mic.value,
mic.length)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send MIC");
}
sshbuf_free(b);
gss_release_buffer(&ms, &mic);
}
}
return status;
}
/* ARGSUSED */
static int
input_gssapi_response(int type, u_int32_t plen, struct ssh *ssh)
{
Authctxt *authctxt = ssh->authctxt;
Gssctxt *gssctxt;
size_t oidlen;
u_char *oidv = NULL;
int r;
if (authctxt == NULL)
fatal("input_gssapi_response: no authentication context");
gssctxt = authctxt->methoddata;
/* Setup our OID */
if ((r = sshpkt_get_string(ssh, &oidv, &oidlen)) != 0)
goto done;
if (oidlen <= 2 ||
oidv[0] != SSH_GSS_OIDTYPE ||
oidv[1] != oidlen - 2) {
debug("Badly encoded mechanism OID received");
userauth(ssh, NULL);
goto ok;
}
if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2))
fatal("Server returned different OID than expected");
if ((r = sshpkt_get_end(ssh)) != 0)
goto done;
if (GSS_ERROR(process_gssapi_token(ssh, GSS_C_NO_BUFFER))) {
/* Start again with next method on list */
debug("Trying to start again");
userauth(ssh, NULL);
goto ok;
}
ok:
r = 0;
done:
free(oidv);
return r;
}
/* ARGSUSED */
static int
input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh)
{
Authctxt *authctxt = ssh->authctxt;
gss_buffer_desc recv_tok;
u_char *p = NULL;
size_t len;
OM_uint32 status;
int r;
if (authctxt == NULL)
fatal("input_gssapi_response: no authentication context");
if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto out;
recv_tok.value = p;
recv_tok.length = len;
status = process_gssapi_token(ssh, &recv_tok);
/* Start again with the next method in the list */
if (GSS_ERROR(status)) {
userauth(ssh, NULL);
/* ok */
}
r = 0;
out:
free(p);
return r;
}
/* ARGSUSED */
static int
input_gssapi_errtok(int type, u_int32_t plen, struct ssh *ssh)
{
Authctxt *authctxt = ssh->authctxt;
Gssctxt *gssctxt;
gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
gss_buffer_desc recv_tok;
OM_uint32 ms;
u_char *p = NULL;
size_t len;
int r;
if (authctxt == NULL)
fatal("input_gssapi_response: no authentication context");
gssctxt = authctxt->methoddata;
if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0) {
free(p);
return r;
}
/* Stick it into GSSAPI and see what it says */
recv_tok.value = p;
recv_tok.length = len;
(void)ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
&recv_tok, &send_tok, NULL);
free(p);
gss_release_buffer(&ms, &send_tok);
/* Server will be returning a failed packet after this one */
return 0;
}
/* ARGSUSED */
static int
input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh)
{
char *msg = NULL;
char *lang = NULL;
int r;
if ((r = sshpkt_get_u32(ssh, NULL)) != 0 || /* maj */
(r = sshpkt_get_u32(ssh, NULL)) != 0 || /* min */
(r = sshpkt_get_cstring(ssh, &msg, NULL)) != 0 ||
(r = sshpkt_get_cstring(ssh, &lang, NULL)) != 0)
goto out;
r = sshpkt_get_end(ssh);
debug("Server GSSAPI Error:\n%s", msg);
out:
free(msg);
free(lang);
return r;
}
#endif /* GSSAPI */
static int
userauth_none(struct ssh *ssh)
{
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
int r;
/* initial userauth request */
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send packet");
return 1;
}
static int
userauth_passwd(struct ssh *ssh)
{
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
char *password, *prompt = NULL;
const char *host = options.host_key_alias ? options.host_key_alias :
authctxt->host;
int r;
if (authctxt->attempt_passwd++ >= options.number_of_password_prompts)
return 0;
if (authctxt->attempt_passwd != 1)
error("Permission denied, please try again.");
xasprintf(&prompt, "%s@%s's password: ", authctxt->server_user, host);
password = read_passphrase(prompt, 0);
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
(r = sshpkt_put_u8(ssh, 0)) != 0 ||
(r = sshpkt_put_cstring(ssh, password)) != 0 ||
(r = sshpkt_add_padding(ssh, 64)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send packet");
free(prompt);
if (password != NULL)
freezero(password, strlen(password));
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
&input_userauth_passwd_changereq);
return 1;
}
/*
* parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST
*/
/* ARGSUSED */
static int
input_userauth_passwd_changereq(int type, u_int32_t seqnr, struct ssh *ssh)
{
Authctxt *authctxt = ssh->authctxt;
char *info = NULL, *lang = NULL, *password = NULL, *retype = NULL;
char prompt[256];
const char *host;
int r;
debug2("input_userauth_passwd_changereq");
if (authctxt == NULL)
fatal("input_userauth_passwd_changereq: "
"no authentication context");
host = options.host_key_alias ? options.host_key_alias : authctxt->host;
if ((r = sshpkt_get_cstring(ssh, &info, NULL)) != 0 ||
(r = sshpkt_get_cstring(ssh, &lang, NULL)) != 0)
goto out;
if (strlen(info) > 0)
logit("%s", info);
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
(r = sshpkt_put_u8(ssh, 1)) != 0) /* additional info */
goto out;
snprintf(prompt, sizeof(prompt),
"Enter %.30s@%.128s's old password: ",
authctxt->server_user, host);
password = read_passphrase(prompt, 0);
if ((r = sshpkt_put_cstring(ssh, password)) != 0)
goto out;
freezero(password, strlen(password));
password = NULL;
while (password == NULL) {
snprintf(prompt, sizeof(prompt),
"Enter %.30s@%.128s's new password: ",
authctxt->server_user, host);
password = read_passphrase(prompt, RP_ALLOW_EOF);
if (password == NULL) {
/* bail out */
r = 0;
goto out;
}
snprintf(prompt, sizeof(prompt),
"Retype %.30s@%.128s's new password: ",
authctxt->server_user, host);
retype = read_passphrase(prompt, 0);
if (strcmp(password, retype) != 0) {
freezero(password, strlen(password));
logit("Mismatch; try again, EOF to quit.");
password = NULL;
}
freezero(retype, strlen(retype));
}
if ((r = sshpkt_put_cstring(ssh, password)) != 0 ||
(r = sshpkt_add_padding(ssh, 64)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
goto out;
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
&input_userauth_passwd_changereq);
r = 0;
out:
if (password)
freezero(password, strlen(password));
free(info);
free(lang);
return r;
}
/*
* Select an algorithm for publickey signatures.
* Returns algorithm (caller must free) or NULL if no mutual algorithm found.
*
* Call with ssh==NULL to ignore server-sig-algs extension list and
* only attempt with the key's base signature type.
*/
static char *
key_sig_algorithm(struct ssh *ssh, const struct sshkey *key)
{
char *allowed, *oallowed, *cp, *tmp, *alg = NULL;
/*
* The signature algorithm will only differ from the key algorithm
* for RSA keys/certs and when the server advertises support for
* newer (SHA2) algorithms.
*/
if (ssh == NULL || ssh->kex->server_sig_algs == NULL ||
(key->type != KEY_RSA && key->type != KEY_RSA_CERT) ||
(key->type == KEY_RSA_CERT && (ssh->compat & SSH_BUG_SIGTYPE))) {
/* Filter base key signature alg against our configuration */
return match_list(sshkey_ssh_name(key),
options.pubkey_accepted_algos, NULL);
}
/*
* For RSA keys/certs, since these might have a different sig type:
* find the first entry in PubkeyAcceptedAlgorithms of the right type
* that also appears in the supported signature algorithms list from
* the server.
*/
oallowed = allowed = xstrdup(options.pubkey_accepted_algos);
while ((cp = strsep(&allowed, ",")) != NULL) {
if (sshkey_type_from_name(cp) != key->type)
continue;
tmp = match_list(sshkey_sigalg_by_name(cp),
ssh->kex->server_sig_algs, NULL);
if (tmp != NULL)
alg = xstrdup(cp);
free(tmp);
if (alg != NULL)
break;
}
free(oallowed);
return alg;
}
static int
identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, u_int compat, const char *alg)
{
struct sshkey *sign_key = NULL, *prv = NULL;
int retried = 0, r = SSH_ERR_INTERNAL_ERROR;
struct notifier_ctx *notifier = NULL;
char *fp = NULL, *pin = NULL, *prompt = NULL;
*sigp = NULL;
*lenp = 0;
/* The agent supports this key. */
if (id->key != NULL && id->agent_fd != -1) {
return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp,
data, datalen, alg, compat);
}
/*
* We have already loaded the private key or the private key is
* stored in external hardware.
*/
if (id->key != NULL &&
(id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) {
sign_key = id->key;
} else {
/* Load the private key from the file. */
if ((prv = load_identity_file(id)) == NULL)
return SSH_ERR_KEY_NOT_FOUND;
if (id->key != NULL && !sshkey_equal_public(prv, id->key)) {
error_f("private key %s contents do not match public",
- id->filename);
+ id->filename);
r = SSH_ERR_KEY_NOT_FOUND;
goto out;
}
sign_key = prv;
if (sshkey_is_sk(sign_key)) {
if ((sign_key->sk_flags &
SSH_SK_USER_VERIFICATION_REQD)) {
retry_pin:
xasprintf(&prompt, "Enter PIN for %s key %s: ",
sshkey_type(sign_key), id->filename);
pin = read_passphrase(prompt, 0);
}
if ((sign_key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
/* XXX should batch mode just skip these? */
if ((fp = sshkey_fingerprint(sign_key,
options.fingerprint_hash,
SSH_FP_DEFAULT)) == NULL)
fatal_f("fingerprint failed");
notifier = notify_start(options.batch_mode,
"Confirm user presence for key %s %s",
sshkey_type(sign_key), fp);
free(fp);
}
}
}
if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen,
alg, options.sk_provider, pin, compat)) != 0) {
debug_fr(r, "sshkey_sign");
if (pin == NULL && !retried && sshkey_is_sk(sign_key) &&
r == SSH_ERR_KEY_WRONG_PASSPHRASE) {
notify_complete(notifier, NULL);
notifier = NULL;
retried = 1;
goto retry_pin;
}
goto out;
}
/*
* PKCS#11 tokens may not support all signature algorithms,
* so check what we get back.
*/
if ((r = sshkey_check_sigtype(*sigp, *lenp, alg)) != 0) {
debug_fr(r, "sshkey_check_sigtype");
goto out;
}
/* success */
r = 0;
out:
free(prompt);
if (pin != NULL)
freezero(pin, strlen(pin));
notify_complete(notifier, r == 0 ? "User presence confirmed" : NULL);
sshkey_free(prv);
return r;
}
static int
id_filename_matches(Identity *id, Identity *private_id)
{
const char *suffixes[] = { ".pub", "-cert.pub", NULL };
size_t len = strlen(id->filename), plen = strlen(private_id->filename);
size_t i, slen;
if (strcmp(id->filename, private_id->filename) == 0)
return 1;
for (i = 0; suffixes[i]; i++) {
slen = strlen(suffixes[i]);
if (len > slen && plen == len - slen &&
strcmp(id->filename + (len - slen), suffixes[i]) == 0 &&
memcmp(id->filename, private_id->filename, plen) == 0)
return 1;
}
return 0;
}
static int
sign_and_send_pubkey(struct ssh *ssh, Identity *id)
{
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
struct sshbuf *b = NULL;
Identity *private_id, *sign_id = NULL;
u_char *signature = NULL;
size_t slen = 0, skip = 0;
int r, fallback_sigtype, sent = 0;
char *alg = NULL, *fp = NULL;
const char *loc = "";
if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash,
SSH_FP_DEFAULT)) == NULL)
return 0;
debug3_f("%s %s", sshkey_type(id->key), fp);
/*
* If the key is an certificate, try to find a matching private key
* and use it to complete the signature.
* If no such private key exists, fall back to trying the certificate
* key itself in case it has a private half already loaded.
* This will try to set sign_id to the private key that will perform
* the signature.
*/
if (sshkey_is_cert(id->key)) {
TAILQ_FOREACH(private_id, &authctxt->keys, next) {
if (sshkey_equal_public(id->key, private_id->key) &&
id->key->type != private_id->key->type) {
sign_id = private_id;
break;
}
}
/*
* Exact key matches are preferred, but also allow
* filename matches for non-PKCS#11/agent keys that
* didn't load public keys. This supports the case
* of keeping just a private key file and public
* certificate on disk.
*/
if (sign_id == NULL &&
!id->isprivate && id->agent_fd == -1 &&
(id->key->flags & SSHKEY_FLAG_EXT) == 0) {
TAILQ_FOREACH(private_id, &authctxt->keys, next) {
if (private_id->key == NULL &&
id_filename_matches(id, private_id)) {
sign_id = private_id;
break;
}
}
}
if (sign_id != NULL) {
debug2_f("using private key \"%s\"%s for "
"certificate", id->filename,
id->agent_fd != -1 ? " from agent" : "");
} else {
debug_f("no separate private key for certificate "
"\"%s\"", id->filename);
}
}
/*
* If the above didn't select another identity to do the signing
* then default to the one we started with.
*/
if (sign_id == NULL)
sign_id = id;
/* assemble and sign data */
for (fallback_sigtype = 0; fallback_sigtype <= 1; fallback_sigtype++) {
free(alg);
slen = 0;
signature = NULL;
if ((alg = key_sig_algorithm(fallback_sigtype ? NULL : ssh,
id->key)) == NULL) {
error_f("no mutual signature supported");
goto out;
}
debug3_f("signing using %s %s", alg, fp);
sshbuf_free(b);
if ((b = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if (ssh->compat & SSH_OLD_SESSIONID) {
if ((r = sshbuf_putb(b, ssh->kex->session_id)) != 0)
fatal_fr(r, "sshbuf_putb");
} else {
if ((r = sshbuf_put_stringb(b,
ssh->kex->session_id)) != 0)
fatal_fr(r, "sshbuf_put_stringb");
}
skip = sshbuf_len(b);
if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
(r = sshbuf_put_cstring(b, authctxt->server_user)) != 0 ||
(r = sshbuf_put_cstring(b, authctxt->service)) != 0 ||
(r = sshbuf_put_cstring(b, authctxt->method->name)) != 0 ||
(r = sshbuf_put_u8(b, 1)) != 0 ||
(r = sshbuf_put_cstring(b, alg)) != 0 ||
(r = sshkey_puts(id->key, b)) != 0) {
fatal_fr(r, "assemble signed data");
}
/* generate signature */
r = identity_sign(sign_id, &signature, &slen,
sshbuf_ptr(b), sshbuf_len(b), ssh->compat, alg);
if (r == 0)
break;
else if (r == SSH_ERR_KEY_NOT_FOUND)
goto out; /* soft failure */
else if (r == SSH_ERR_SIGN_ALG_UNSUPPORTED &&
!fallback_sigtype) {
if (sign_id->agent_fd != -1)
loc = "agent ";
else if ((sign_id->key->flags & SSHKEY_FLAG_EXT) != 0)
loc = "token ";
logit("%skey %s %s returned incorrect signature type",
loc, sshkey_type(id->key), fp);
continue;
}
error_fr(r, "signing failed for %s \"%s\"%s",
sshkey_type(sign_id->key), sign_id->filename,
id->agent_fd != -1 ? " from agent" : "");
goto out;
}
if (slen == 0 || signature == NULL) /* shouldn't happen */
fatal_f("no signature");
/* append signature */
if ((r = sshbuf_put_string(b, signature, slen)) != 0)
fatal_fr(r, "append signature");
#ifdef DEBUG_PK
sshbuf_dump(b, stderr);
#endif
/* skip session id and packet type */
if ((r = sshbuf_consume(b, skip + 1)) != 0)
fatal_fr(r, "consume");
/* put remaining data from buffer into packet */
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
(r = sshpkt_putb(ssh, b)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "enqueue request");
/* success */
sent = 1;
out:
free(fp);
free(alg);
sshbuf_free(b);
freezero(signature, slen);
return sent;
}
static int
send_pubkey_test(struct ssh *ssh, Identity *id)
{
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
u_char *blob = NULL;
char *alg = NULL;
size_t bloblen;
u_int have_sig = 0;
int sent = 0, r;
if ((alg = key_sig_algorithm(ssh, id->key)) == NULL) {
debug_f("no mutual signature algorithm");
goto out;
}
if ((r = sshkey_to_blob(id->key, &blob, &bloblen)) != 0) {
/* we cannot handle this key */
debug3_f("cannot handle key");
goto out;
}
/* register callback for USERAUTH_PK_OK message */
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok);
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
(r = sshpkt_put_u8(ssh, have_sig)) != 0 ||
(r = sshpkt_put_cstring(ssh, alg)) != 0 ||
(r = sshpkt_put_string(ssh, blob, bloblen)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send packet");
sent = 1;
out:
free(alg);
free(blob);
return sent;
}
static struct sshkey *
load_identity_file(Identity *id)
{
struct sshkey *private = NULL;
char prompt[300], *passphrase, *comment;
int r, quit = 0, i;
struct stat st;
if (stat(id->filename, &st) == -1) {
do_log2(id->userprovided ?
SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_DEBUG3,
"no such identity: %s: %s", id->filename, strerror(errno));
return NULL;
}
snprintf(prompt, sizeof prompt,
"Enter passphrase for key '%.100s': ", id->filename);
for (i = 0; i <= options.number_of_password_prompts; i++) {
if (i == 0)
passphrase = "";
else {
passphrase = read_passphrase(prompt, 0);
if (*passphrase == '\0') {
debug2("no passphrase given, try next key");
free(passphrase);
break;
}
}
switch ((r = sshkey_load_private_type(KEY_UNSPEC, id->filename,
passphrase, &private, &comment))) {
case 0:
break;
case SSH_ERR_KEY_WRONG_PASSPHRASE:
if (options.batch_mode) {
quit = 1;
break;
}
if (i != 0)
debug2("bad passphrase given, try again...");
break;
case SSH_ERR_SYSTEM_ERROR:
if (errno == ENOENT) {
debug2_r(r, "Load key \"%s\"", id->filename);
quit = 1;
break;
}
/* FALLTHROUGH */
default:
error_r(r, "Load key \"%s\"", id->filename);
quit = 1;
break;
}
if (private != NULL && sshkey_is_sk(private) &&
options.sk_provider == NULL) {
debug("key \"%s\" is an authenticator-hosted key, "
"but no provider specified", id->filename);
sshkey_free(private);
private = NULL;
quit = 1;
}
if (!quit && private != NULL && id->agent_fd == -1 &&
!(id->key && id->isprivate))
maybe_add_key_to_agent(id->filename, private, comment,
passphrase);
if (i > 0)
freezero(passphrase, strlen(passphrase));
free(comment);
if (private != NULL || quit)
break;
}
return private;
}
static int
key_type_allowed_by_config(struct sshkey *key)
{
if (match_pattern_list(sshkey_ssh_name(key),
options.pubkey_accepted_algos, 0) == 1)
return 1;
/* RSA keys/certs might be allowed by alternate signature types */
switch (key->type) {
case KEY_RSA:
if (match_pattern_list("rsa-sha2-512",
options.pubkey_accepted_algos, 0) == 1)
return 1;
if (match_pattern_list("rsa-sha2-256",
options.pubkey_accepted_algos, 0) == 1)
return 1;
break;
case KEY_RSA_CERT:
if (match_pattern_list("rsa-sha2-512-cert-v01@openssh.com",
options.pubkey_accepted_algos, 0) == 1)
return 1;
if (match_pattern_list("rsa-sha2-256-cert-v01@openssh.com",
options.pubkey_accepted_algos, 0) == 1)
return 1;
break;
}
return 0;
}
/*
* try keys in the following order:
* 1. certificates listed in the config file
* 2. other input certificates
* 3. agent keys that are found in the config file
* 4. other agent keys
* 5. keys that are only listed in the config file
*/
static void
pubkey_prepare(Authctxt *authctxt)
{
struct identity *id, *id2, *tmp;
struct idlist agent, files, *preferred;
struct sshkey *key;
int agent_fd = -1, i, r, found;
size_t j;
struct ssh_identitylist *idlist;
char *ident;
TAILQ_INIT(&agent); /* keys from the agent */
TAILQ_INIT(&files); /* keys from the config file */
preferred = &authctxt->keys;
TAILQ_INIT(preferred); /* preferred order of keys */
/* list of keys stored in the filesystem and PKCS#11 */
for (i = 0; i < options.num_identity_files; i++) {
key = options.identity_keys[i];
if (key && key->cert &&
key->cert->type != SSH2_CERT_TYPE_USER) {
debug_f("ignoring certificate %s: not a user "
"certificate", options.identity_files[i]);
continue;
}
if (key && sshkey_is_sk(key) && options.sk_provider == NULL) {
debug_f("ignoring authenticator-hosted key %s as no "
"SecurityKeyProvider has been specified",
options.identity_files[i]);
continue;
}
options.identity_keys[i] = NULL;
id = xcalloc(1, sizeof(*id));
id->agent_fd = -1;
id->key = key;
id->filename = xstrdup(options.identity_files[i]);
id->userprovided = options.identity_file_userprovided[i];
TAILQ_INSERT_TAIL(&files, id, next);
}
/* list of certificates specified by user */
for (i = 0; i < options.num_certificate_files; i++) {
key = options.certificates[i];
if (!sshkey_is_cert(key) || key->cert == NULL ||
key->cert->type != SSH2_CERT_TYPE_USER) {
debug_f("ignoring certificate %s: not a user "
"certificate", options.identity_files[i]);
continue;
}
if (key && sshkey_is_sk(key) && options.sk_provider == NULL) {
debug_f("ignoring authenticator-hosted key "
"certificate %s as no "
"SecurityKeyProvider has been specified",
options.identity_files[i]);
continue;
}
id = xcalloc(1, sizeof(*id));
id->agent_fd = -1;
id->key = key;
id->filename = xstrdup(options.certificate_files[i]);
id->userprovided = options.certificate_file_userprovided[i];
TAILQ_INSERT_TAIL(preferred, id, next);
}
/* list of keys supported by the agent */
if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) {
if (r != SSH_ERR_AGENT_NOT_PRESENT)
debug_fr(r, "ssh_get_authentication_socket");
} else if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) {
if (r != SSH_ERR_AGENT_NO_IDENTITIES)
debug_fr(r, "ssh_fetch_identitylist");
close(agent_fd);
} else {
for (j = 0; j < idlist->nkeys; j++) {
found = 0;
TAILQ_FOREACH(id, &files, next) {
/*
* agent keys from the config file are
* preferred
*/
if (sshkey_equal(idlist->keys[j], id->key)) {
TAILQ_REMOVE(&files, id, next);
TAILQ_INSERT_TAIL(preferred, id, next);
id->agent_fd = agent_fd;
found = 1;
break;
}
}
if (!found && !options.identities_only) {
id = xcalloc(1, sizeof(*id));
/* XXX "steals" key/comment from idlist */
id->key = idlist->keys[j];
id->filename = idlist->comments[j];
idlist->keys[j] = NULL;
idlist->comments[j] = NULL;
id->agent_fd = agent_fd;
TAILQ_INSERT_TAIL(&agent, id, next);
}
}
ssh_free_identitylist(idlist);
/* append remaining agent keys */
TAILQ_CONCAT(preferred, &agent, next);
authctxt->agent_fd = agent_fd;
}
/* Prefer PKCS11 keys that are explicitly listed */
TAILQ_FOREACH_SAFE(id, &files, next, tmp) {
if (id->key == NULL || (id->key->flags & SSHKEY_FLAG_EXT) == 0)
continue;
found = 0;
TAILQ_FOREACH(id2, &files, next) {
if (id2->key == NULL ||
(id2->key->flags & SSHKEY_FLAG_EXT) != 0)
continue;
if (sshkey_equal(id->key, id2->key)) {
TAILQ_REMOVE(&files, id, next);
TAILQ_INSERT_TAIL(preferred, id, next);
found = 1;
break;
}
}
/* If IdentitiesOnly set and key not found then don't use it */
if (!found && options.identities_only) {
TAILQ_REMOVE(&files, id, next);
freezero(id, sizeof(*id));
}
}
/* append remaining keys from the config file */
TAILQ_CONCAT(preferred, &files, next);
/* finally, filter by PubkeyAcceptedAlgorithms */
TAILQ_FOREACH_SAFE(id, preferred, next, id2) {
if (id->key != NULL && !key_type_allowed_by_config(id->key)) {
debug("Skipping %s key %s - "
"corresponding algo not in PubkeyAcceptedAlgorithms",
sshkey_ssh_name(id->key), id->filename);
TAILQ_REMOVE(preferred, id, next);
sshkey_free(id->key);
free(id->filename);
memset(id, 0, sizeof(*id));
continue;
}
}
/* List the keys we plan on using */
TAILQ_FOREACH_SAFE(id, preferred, next, id2) {
ident = format_identity(id);
debug("Will attempt key: %s", ident);
free(ident);
}
debug2_f("done");
}
static void
pubkey_cleanup(struct ssh *ssh)
{
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
Identity *id;
if (authctxt->agent_fd != -1) {
ssh_close_authentication_socket(authctxt->agent_fd);
authctxt->agent_fd = -1;
}
for (id = TAILQ_FIRST(&authctxt->keys); id;
id = TAILQ_FIRST(&authctxt->keys)) {
TAILQ_REMOVE(&authctxt->keys, id, next);
sshkey_free(id->key);
free(id->filename);
free(id);
}
}
static void
pubkey_reset(Authctxt *authctxt)
{
Identity *id;
TAILQ_FOREACH(id, &authctxt->keys, next)
id->tried = 0;
}
static int
try_identity(struct ssh *ssh, Identity *id)
{
if (!id->key)
return (0);
if (sshkey_type_plain(id->key->type) == KEY_RSA &&
(ssh->compat & SSH_BUG_RSASIGMD5) != 0) {
debug("Skipped %s key %s for RSA/MD5 server",
sshkey_type(id->key), id->filename);
return (0);
}
return 1;
}
static int
userauth_pubkey(struct ssh *ssh)
{
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
Identity *id;
int sent = 0;
char *ident;
while ((id = TAILQ_FIRST(&authctxt->keys))) {
if (id->tried++)
return (0);
/* move key to the end of the queue */
TAILQ_REMOVE(&authctxt->keys, id, next);
TAILQ_INSERT_TAIL(&authctxt->keys, id, next);
/*
* send a test message if we have the public key. for
* encrypted keys we cannot do this and have to load the
* private key instead
*/
if (id->key != NULL) {
if (try_identity(ssh, id)) {
ident = format_identity(id);
debug("Offering public key: %s", ident);
free(ident);
sent = send_pubkey_test(ssh, id);
}
} else {
debug("Trying private key: %s", id->filename);
id->key = load_identity_file(id);
if (id->key != NULL) {
if (try_identity(ssh, id)) {
id->isprivate = 1;
sent = sign_and_send_pubkey(ssh, id);
}
sshkey_free(id->key);
id->key = NULL;
id->isprivate = 0;
}
}
if (sent)
return (sent);
}
return (0);
}
/*
* Send userauth request message specifying keyboard-interactive method.
*/
static int
userauth_kbdint(struct ssh *ssh)
{
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
int r;
if (authctxt->attempt_kbdint++ >= options.number_of_password_prompts)
return 0;
/* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */
if (authctxt->attempt_kbdint > 1 && !authctxt->info_req_seen) {
debug3("userauth_kbdint: disable: no info_req_seen");
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);
return 0;
}
debug2("userauth_kbdint");
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
(r = sshpkt_put_cstring(ssh, "")) != 0 || /* lang */
(r = sshpkt_put_cstring(ssh, options.kbd_interactive_devices ?
options.kbd_interactive_devices : "")) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send packet");
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
return 1;
}
/*
* parse INFO_REQUEST, prompt user and send INFO_RESPONSE
*/
static int
input_userauth_info_req(int type, u_int32_t seq, struct ssh *ssh)
{
Authctxt *authctxt = ssh->authctxt;
char *name = NULL, *inst = NULL, *lang = NULL, *prompt = NULL;
char *display_prompt = NULL, *response = NULL;
u_char echo = 0;
u_int num_prompts, i;
int r;
debug2_f("entering");
if (authctxt == NULL)
fatal_f("no authentication context");
authctxt->info_req_seen = 1;
if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0 ||
(r = sshpkt_get_cstring(ssh, &inst, NULL)) != 0 ||
(r = sshpkt_get_cstring(ssh, &lang, NULL)) != 0)
goto out;
if (strlen(name) > 0)
logit("%s", name);
if (strlen(inst) > 0)
logit("%s", inst);
if ((r = sshpkt_get_u32(ssh, &num_prompts)) != 0)
goto out;
/*
* Begin to build info response packet based on prompts requested.
* We commit to providing the correct number of responses, so if
* further on we run into a problem that prevents this, we have to
* be sure and clean this up and send a correct error response.
*/
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_INFO_RESPONSE)) != 0 ||
(r = sshpkt_put_u32(ssh, num_prompts)) != 0)
goto out;
debug2_f("num_prompts %d", num_prompts);
for (i = 0; i < num_prompts; i++) {
if ((r = sshpkt_get_cstring(ssh, &prompt, NULL)) != 0 ||
(r = sshpkt_get_u8(ssh, &echo)) != 0)
goto out;
if (asmprintf(&display_prompt, INT_MAX, NULL, "(%s@%s) %s",
authctxt->server_user, options.host_key_alias ?
options.host_key_alias : authctxt->host, prompt) == -1)
fatal_f("asmprintf failed");
response = read_passphrase(display_prompt, echo ? RP_ECHO : 0);
if ((r = sshpkt_put_cstring(ssh, response)) != 0)
goto out;
freezero(response, strlen(response));
free(prompt);
free(display_prompt);
display_prompt = response = prompt = NULL;
}
/* done with parsing incoming message. */
if ((r = sshpkt_get_end(ssh)) != 0 ||
(r = sshpkt_add_padding(ssh, 64)) != 0)
goto out;
r = sshpkt_send(ssh);
out:
if (response)
freezero(response, strlen(response));
free(prompt);
free(display_prompt);
free(name);
free(inst);
free(lang);
return r;
}
static int
ssh_keysign(struct ssh *ssh, struct sshkey *key, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen)
{
struct sshbuf *b;
struct stat st;
pid_t pid;
int r, to[2], from[2], status;
int sock = ssh_packet_get_connection_in(ssh);
u_char rversion = 0, version = 2;
void (*osigchld)(int);
*sigp = NULL;
*lenp = 0;
if (stat(_PATH_SSH_KEY_SIGN, &st) == -1) {
error_f("not installed: %s", strerror(errno));
return -1;
}
if (fflush(stdout) != 0) {
error_f("fflush: %s", strerror(errno));
return -1;
}
if (pipe(to) == -1) {
error_f("pipe: %s", strerror(errno));
return -1;
}
if (pipe(from) == -1) {
error_f("pipe: %s", strerror(errno));
return -1;
}
if ((pid = fork()) == -1) {
error_f("fork: %s", strerror(errno));
return -1;
}
osigchld = ssh_signal(SIGCHLD, SIG_DFL);
if (pid == 0) {
close(from[0]);
if (dup2(from[1], STDOUT_FILENO) == -1)
fatal_f("dup2: %s", strerror(errno));
close(to[1]);
if (dup2(to[0], STDIN_FILENO) == -1)
fatal_f("dup2: %s", strerror(errno));
close(from[1]);
close(to[0]);
if (dup2(sock, STDERR_FILENO + 1) == -1)
fatal_f("dup2: %s", strerror(errno));
sock = STDERR_FILENO + 1;
fcntl(sock, F_SETFD, 0); /* keep the socket on exec */
closefrom(sock + 1);
debug3_f("[child] pid=%ld, exec %s",
(long)getpid(), _PATH_SSH_KEY_SIGN);
execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *)NULL);
fatal_f("exec(%s): %s", _PATH_SSH_KEY_SIGN,
strerror(errno));
}
close(from[1]);
close(to[0]);
sock = STDERR_FILENO + 1;
if ((b = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
/* send # of sock, data to be signed */
if ((r = sshbuf_put_u32(b, sock)) != 0 ||
(r = sshbuf_put_string(b, data, datalen)) != 0)
fatal_fr(r, "buffer error");
if (ssh_msg_send(to[1], version, b) == -1)
fatal_f("couldn't send request");
sshbuf_reset(b);
r = ssh_msg_recv(from[0], b);
close(from[0]);
close(to[1]);
if (r < 0) {
error_f("no reply");
goto fail;
}
errno = 0;
while (waitpid(pid, &status, 0) == -1) {
if (errno != EINTR) {
error_f("waitpid %ld: %s", (long)pid, strerror(errno));
goto fail;
}
}
if (!WIFEXITED(status)) {
error_f("exited abnormally");
goto fail;
}
if (WEXITSTATUS(status) != 0) {
error_f("exited with status %d", WEXITSTATUS(status));
goto fail;
}
if ((r = sshbuf_get_u8(b, &rversion)) != 0) {
error_fr(r, "buffer error");
goto fail;
}
if (rversion != version) {
error_f("bad version");
goto fail;
}
if ((r = sshbuf_get_string(b, sigp, lenp)) != 0) {
error_fr(r, "buffer error");
fail:
ssh_signal(SIGCHLD, osigchld);
sshbuf_free(b);
return -1;
}
ssh_signal(SIGCHLD, osigchld);
sshbuf_free(b);
return 0;
}
static int
userauth_hostbased(struct ssh *ssh)
{
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
struct sshkey *private = NULL;
struct sshbuf *b = NULL;
u_char *sig = NULL, *keyblob = NULL;
char *fp = NULL, *chost = NULL, *lname = NULL;
size_t siglen = 0, keylen = 0;
int i, r, success = 0;
if (authctxt->ktypes == NULL) {
authctxt->oktypes = xstrdup(options.hostbased_accepted_algos);
authctxt->ktypes = authctxt->oktypes;
}
/*
* Work through each listed type pattern in HostbasedAcceptedAlgorithms,
* trying each hostkey that matches the type in turn.
*/
for (;;) {
if (authctxt->active_ktype == NULL)
authctxt->active_ktype = strsep(&authctxt->ktypes, ",");
if (authctxt->active_ktype == NULL ||
*authctxt->active_ktype == '\0')
break;
debug3_f("trying key type %s", authctxt->active_ktype);
/* check for a useful key */
private = NULL;
for (i = 0; i < authctxt->sensitive->nkeys; i++) {
if (authctxt->sensitive->keys[i] == NULL ||
authctxt->sensitive->keys[i]->type == KEY_UNSPEC)
continue;
if (match_pattern_list(
sshkey_ssh_name(authctxt->sensitive->keys[i]),
authctxt->active_ktype, 0) != 1)
continue;
/* we take and free the key */
private = authctxt->sensitive->keys[i];
authctxt->sensitive->keys[i] = NULL;
break;
}
/* Found one */
if (private != NULL)
break;
/* No more keys of this type; advance */
authctxt->active_ktype = NULL;
}
if (private == NULL) {
free(authctxt->oktypes);
authctxt->oktypes = authctxt->ktypes = NULL;
authctxt->active_ktype = NULL;
debug("No more client hostkeys for hostbased authentication.");
goto out;
}
if ((fp = sshkey_fingerprint(private, options.fingerprint_hash,
SSH_FP_DEFAULT)) == NULL) {
error_f("sshkey_fingerprint failed");
goto out;
}
debug_f("trying hostkey %s %s", sshkey_ssh_name(private), fp);
/* figure out a name for the client host */
lname = get_local_name(ssh_packet_get_connection_in(ssh));
if (lname == NULL) {
error_f("cannot get local ipaddr/name");
goto out;
}
/* XXX sshbuf_put_stringf? */
xasprintf(&chost, "%s.", lname);
debug2_f("chost %s", chost);
/* construct data */
if ((b = sshbuf_new()) == NULL) {
error_f("sshbuf_new failed");
goto out;
}
if ((r = sshkey_to_blob(private, &keyblob, &keylen)) != 0) {
error_fr(r, "sshkey_to_blob");
goto out;
}
if ((r = sshbuf_put_stringb(b, ssh->kex->session_id)) != 0 ||
(r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
(r = sshbuf_put_cstring(b, authctxt->server_user)) != 0 ||
(r = sshbuf_put_cstring(b, authctxt->service)) != 0 ||
(r = sshbuf_put_cstring(b, authctxt->method->name)) != 0 ||
(r = sshbuf_put_cstring(b, authctxt->active_ktype)) != 0 ||
(r = sshbuf_put_string(b, keyblob, keylen)) != 0 ||
(r = sshbuf_put_cstring(b, chost)) != 0 ||
(r = sshbuf_put_cstring(b, authctxt->local_user)) != 0) {
error_fr(r, "buffer error");
goto out;
}
#ifdef DEBUG_PK
sshbuf_dump(b, stderr);
#endif
if ((r = ssh_keysign(ssh, private, &sig, &siglen,
sshbuf_ptr(b), sshbuf_len(b))) != 0) {
error("sign using hostkey %s %s failed",
sshkey_ssh_name(private), fp);
goto out;
}
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->active_ktype)) != 0 ||
(r = sshpkt_put_string(ssh, keyblob, keylen)) != 0 ||
(r = sshpkt_put_cstring(ssh, chost)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->local_user)) != 0 ||
(r = sshpkt_put_string(ssh, sig, siglen)) != 0 ||
(r = sshpkt_send(ssh)) != 0) {
error_fr(r, "packet error");
goto out;
}
success = 1;
out:
if (sig != NULL)
freezero(sig, siglen);
free(keyblob);
free(lname);
free(fp);
free(chost);
sshkey_free(private);
sshbuf_free(b);
return success;
}
/* find auth method */
/*
* given auth method name, if configurable options permit this method fill
* in auth_ident field and return true, otherwise return false.
*/
static int
authmethod_is_enabled(Authmethod *method)
{
if (method == NULL)
return 0;
/* return false if options indicate this method is disabled */
if (method->enabled == NULL || *method->enabled == 0)
return 0;
/* return false if batch mode is enabled but method needs interactive mode */
if (method->batch_flag != NULL && *method->batch_flag != 0)
return 0;
return 1;
}
static Authmethod *
authmethod_lookup(const char *name)
{
Authmethod *method = NULL;
if (name != NULL)
for (method = authmethods; method->name != NULL; method++)
if (strcmp(name, method->name) == 0)
return method;
debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
return NULL;
}
/* XXX internal state */
static Authmethod *current = NULL;
static char *supported = NULL;
static char *preferred = NULL;
/*
* Given the authentication method list sent by the server, return the
* next method we should try. If the server initially sends a nil list,
* use a built-in default list.
*/
static Authmethod *
authmethod_get(char *authlist)
{
char *name = NULL;
u_int next;
/* Use a suitable default if we're passed a nil list. */
if (authlist == NULL || strlen(authlist) == 0)
authlist = options.preferred_authentications;
if (supported == NULL || strcmp(authlist, supported) != 0) {
debug3("start over, passed a different list %s", authlist);
free(supported);
supported = xstrdup(authlist);
preferred = options.preferred_authentications;
debug3("preferred %s", preferred);
current = NULL;
} else if (current != NULL && authmethod_is_enabled(current))
return current;
for (;;) {
if ((name = match_list(preferred, supported, &next)) == NULL) {
debug("No more authentication methods to try.");
current = NULL;
return NULL;
}
preferred += next;
debug3("authmethod_lookup %s", name);
debug3("remaining preferred: %s", preferred);
if ((current = authmethod_lookup(name)) != NULL &&
authmethod_is_enabled(current)) {
debug3("authmethod_is_enabled %s", name);
debug("Next authentication method: %s", name);
free(name);
return current;
}
free(name);
}
}
static char *
authmethods_get(void)
{
Authmethod *method = NULL;
struct sshbuf *b;
char *list;
int r;
if ((b = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
for (method = authmethods; method->name != NULL; method++) {
if (authmethod_is_enabled(method)) {
if ((r = sshbuf_putf(b, "%s%s",
sshbuf_len(b) ? "," : "", method->name)) != 0)
fatal_fr(r, "buffer error");
}
}
if ((list = sshbuf_dup_string(b)) == NULL)
fatal_f("sshbuf_dup_string failed");
sshbuf_free(b);
return list;
}
diff --git a/sshd.0 b/sshd.0
index e32e0082cab5..d9e77a37b61c 100644
--- a/sshd.0
+++ b/sshd.0
@@ -1,672 +1,672 @@
SSHD(8) System Manager's Manual SSHD(8)
NAME
sshd M-bM-^@M-^S OpenSSH daemon
SYNOPSIS
sshd [-46DdeiqTt] [-C connection_spec] [-c host_certificate_file]
[-E log_file] [-f config_file] [-g login_grace_time]
[-h host_key_file] [-o option] [-p port] [-u len]
DESCRIPTION
sshd (OpenSSH Daemon) is the daemon program for ssh(1). Together these
programs replace rlogin and rsh, and provide secure encrypted
communications between two untrusted hosts over an insecure network.
sshd listens for connections from clients. It is normally started at
boot from /etc/rc. It forks a new daemon for each incoming connection.
The forked daemons handle key exchange, encryption, authentication,
command execution, and data exchange.
sshd can be configured using command-line options or a configuration file
(by default sshd_config(5)); command-line options override values
specified in the configuration file. sshd rereads its configuration file
when it receives a hangup signal, SIGHUP, by executing itself with the
name and options it was started with, e.g. /usr/sbin/sshd.
The options are as follows:
-4 Forces sshd to use IPv4 addresses only.
-6 Forces sshd to use IPv6 addresses only.
-C connection_spec
Specify the connection parameters to use for the -T extended test
mode. If provided, any Match directives in the configuration
file that would apply are applied before the configuration is
written to standard output. The connection parameters are
supplied as keyword=value pairs and may be supplied in any order,
either with multiple -C options or as a comma-separated list.
The keywords are M-bM-^@M-^\addr,M-bM-^@M-^] M-bM-^@M-^\userM-bM-^@M-^], M-bM-^@M-^\hostM-bM-^@M-^], M-bM-^@M-^\laddrM-bM-^@M-^], M-bM-^@M-^\lportM-bM-^@M-^], and
M-bM-^@M-^\rdomainM-bM-^@M-^] and correspond to source address, user, resolved source
host name, local address, local port number and routing domain
respectively.
-c host_certificate_file
Specifies a path to a certificate file to identify sshd during
key exchange. The certificate file must match a host key file
specified using the -h option or the HostKey configuration
directive.
-D When this option is specified, sshd will not detach and does not
become a daemon. This allows easy monitoring of sshd.
-d Debug mode. The server sends verbose debug output to standard
error, and does not put itself in the background. The server
also will not fork and will only process one connection. This
option is only intended for debugging for the server. Multiple
-d options increase the debugging level. Maximum is 3.
-E log_file
Append debug logs to log_file instead of the system log.
-e Write debug logs to standard error instead of the system log.
-f config_file
Specifies the name of the configuration file. The default is
/etc/ssh/sshd_config. sshd refuses to start if there is no
configuration file.
-g login_grace_time
Gives the grace time for clients to authenticate themselves
(default 120 seconds). If the client fails to authenticate the
user within this many seconds, the server disconnects and exits.
A value of zero indicates no limit.
-h host_key_file
Specifies a file from which a host key is read. This option must
be given if sshd is not run as root (as the normal host key files
are normally not readable by anyone but root). The default is
/etc/ssh/ssh_host_ecdsa_key, /etc/ssh/ssh_host_ed25519_key and
/etc/ssh/ssh_host_rsa_key. It is possible to have multiple host
key files for the different host key algorithms.
-i Specifies that sshd is being run from inetd(8).
-o option
Can be used to give options in the format used in the
configuration file. This is useful for specifying options for
which there is no separate command-line flag. For full details
of the options, and their values, see sshd_config(5).
-p port
Specifies the port on which the server listens for connections
(default 22). Multiple port options are permitted. Ports
specified in the configuration file with the Port option are
ignored when a command-line port is specified. Ports specified
using the ListenAddress option override command-line ports.
-q Quiet mode. Nothing is sent to the system log. Normally the
beginning, authentication, and termination of each connection is
logged.
-T Extended test mode. Check the validity of the configuration
file, output the effective configuration to stdout and then exit.
Optionally, Match rules may be applied by specifying the
connection parameters using one or more -C options.
-t Test mode. Only check the validity of the configuration file and
sanity of the keys. This is useful for updating sshd reliably as
configuration options may change.
-u len This option is used to specify the size of the field in the utmp
structure that holds the remote host name. If the resolved host
name is longer than len, the dotted decimal value will be used
instead. This allows hosts with very long host names that
overflow this field to still be uniquely identified. Specifying
-u0 indicates that only dotted decimal addresses should be put
into the utmp file. -u0 may also be used to prevent sshd from
making DNS requests unless the authentication mechanism or
configuration requires it. Authentication mechanisms that may
require DNS include HostbasedAuthentication and using a
from="pattern-list" option in a key file. Configuration options
that require DNS include using a USER@HOST pattern in AllowUsers
or DenyUsers.
AUTHENTICATION
The OpenSSH SSH daemon supports SSH protocol 2 only. Each host has a
host-specific key, used to identify the host. Whenever a client
connects, the daemon responds with its public host key. The client
compares the host key against its own database to verify that it has not
changed. Forward secrecy is provided through a Diffie-Hellman key
agreement. This key agreement results in a shared session key. The rest
of the session is encrypted using a symmetric cipher. The client selects
the encryption algorithm to use from those offered by the server.
Additionally, session integrity is provided through a cryptographic
message authentication code (MAC).
Finally, the server and the client enter an authentication dialog. The
client tries to authenticate itself using host-based authentication,
public key authentication, challenge-response authentication, or password
authentication.
Regardless of the authentication type, the account is checked to ensure
that it is accessible. An account is not accessible if it is locked,
listed in DenyUsers or its group is listed in DenyGroups . The
definition of a locked account is system dependent. Some platforms have
their own account database (eg AIX) and some modify the passwd field (
M-bM-^@M-^X*LK*M-bM-^@M-^Y on Solaris and UnixWare, M-bM-^@M-^X*M-bM-^@M-^Y on HP-UX, containing M-bM-^@M-^XNologinM-bM-^@M-^Y on
Tru64, a leading M-bM-^@M-^X*LOCKED*M-bM-^@M-^Y on FreeBSD and a leading M-bM-^@M-^X!M-bM-^@M-^Y on most
Linuxes). If there is a requirement to disable password authentication
for the account while allowing still public-key, then the passwd field
should be set to something other than these values (eg M-bM-^@M-^XNPM-bM-^@M-^Y or M-bM-^@M-^X*NP*M-bM-^@M-^Y ).
If the client successfully authenticates itself, a dialog for preparing
the session is entered. At this time the client may request things like
allocating a pseudo-tty, forwarding X11 connections, forwarding TCP
connections, or forwarding the authentication agent connection over the
secure channel.
After this, the client either requests a shell or execution of a command.
The sides then enter session mode. In this mode, either side may send
data at any time, and such data is forwarded to/from the shell or command
on the server side, and the user terminal in the client side.
When the user program terminates and all forwarded X11 and other
connections have been closed, the server sends command exit status to the
client, and both sides exit.
LOGIN PROCESS
When a user successfully logs in, sshd does the following:
1. If the login is on a tty, and no command has been specified,
prints last login time and /etc/motd (unless prevented in the
configuration file or by ~/.hushlogin; see the FILES section).
2. If the login is on a tty, records login time.
3. Checks /etc/nologin; if it exists, prints contents and quits
(unless root).
4. Changes to run with normal user privileges.
5. Sets up basic environment.
6. Reads the file ~/.ssh/environment, if it exists, and users are
allowed to change their environment. See the
PermitUserEnvironment option in sshd_config(5).
7. Changes to user's home directory.
8. If ~/.ssh/rc exists and the sshd_config(5) PermitUserRC option
is set, runs it; else if /etc/ssh/sshrc exists, runs it;
otherwise runs xauth. The M-bM-^@M-^\rcM-bM-^@M-^] files are given the X11
authentication protocol and cookie in standard input. See
SSHRC, below.
9. Runs user's shell or command. All commands are run under the
user's login shell as specified in the system password
database.
SSHRC
If the file ~/.ssh/rc exists, sh(1) runs it after reading the environment
files but before starting the user's shell or command. It must not
produce any output on stdout; stderr must be used instead. If X11
forwarding is in use, it will receive the "proto cookie" pair in its
standard input (and DISPLAY in its environment). The script must call
xauth(1) because sshd will not run xauth automatically to add X11
cookies.
The primary purpose of this file is to run any initialization routines
which may be needed before the user's home directory becomes accessible;
AFS is a particular example of such an environment.
This file will probably contain some initialization code followed by
something similar to:
if read proto cookie && [ -n "$DISPLAY" ]; then
if [ `echo $DISPLAY | cut -c1-10` = 'localhost:' ]; then
# X11UseLocalhost=yes
echo add unix:`echo $DISPLAY |
cut -c11-` $proto $cookie
else
# X11UseLocalhost=no
echo add $DISPLAY $proto $cookie
fi | xauth -q -
fi
If this file does not exist, /etc/ssh/sshrc is run, and if that does not
exist either, xauth is used to add the cookie.
AUTHORIZED_KEYS FILE FORMAT
AuthorizedKeysFile specifies the files containing public keys for public
key authentication; if this option is not specified, the default is
~/.ssh/authorized_keys and ~/.ssh/authorized_keys2. Each line of the
file contains one key (empty lines and lines starting with a M-bM-^@M-^X#M-bM-^@M-^Y are
ignored as comments). Public keys consist of the following space-
separated fields: options, keytype, base64-encoded key, comment. The
options field is optional. The supported key types are:
sk-ecdsa-sha2-nistp256@openssh.com
ecdsa-sha2-nistp256
ecdsa-sha2-nistp384
ecdsa-sha2-nistp521
sk-ssh-ed25519@openssh.com
ssh-ed25519
ssh-dss
ssh-rsa
The comment field is not used for anything (but may be convenient for the
user to identify the key).
Note that lines in this file can be several hundred bytes long (because
of the size of the public key encoding) up to a limit of 8 kilobytes,
which permits RSA keys up to 16 kilobits. You don't want to type them
in; instead, copy the id_dsa.pub, id_ecdsa.pub, id_ecdsa_sk.pub,
id_ed25519.pub, id_ed25519_sk.pub, or the id_rsa.pub file and edit it.
sshd enforces a minimum RSA key modulus size of 1024 bits.
The options (if present) consist of comma-separated option
specifications. No spaces are permitted, except within double quotes.
The following option specifications are supported (note that option
keywords are case-insensitive):
agent-forwarding
Enable authentication agent forwarding previously disabled by the
restrict option.
cert-authority
Specifies that the listed key is a certification authority (CA)
that is trusted to validate signed certificates for user
authentication.
Certificates may encode access restrictions similar to these key
options. If both certificate restrictions and key options are
present, the most restrictive union of the two is applied.
command="command"
Specifies that the command is executed whenever this key is used
for authentication. The command supplied by the user (if any) is
ignored. The command is run on a pty if the client requests a
pty; otherwise it is run without a tty. If an 8-bit clean
channel is required, one must not request a pty or should specify
no-pty. A quote may be included in the command by quoting it
with a backslash.
This option might be useful to restrict certain public keys to
perform just a specific operation. An example might be a key
that permits remote backups but nothing else. Note that the
client may specify TCP and/or X11 forwarding unless they are
explicitly prohibited, e.g. using the restrict key option.
The command originally supplied by the client is available in the
SSH_ORIGINAL_COMMAND environment variable. Note that this option
applies to shell, command or subsystem execution. Also note that
this command may be superseded by a sshd_config(5) ForceCommand
directive.
If a command is specified and a forced-command is embedded in a
certificate used for authentication, then the certificate will be
accepted only if the two commands are identical.
environment="NAME=value"
Specifies that the string is to be added to the environment when
logging in using this key. Environment variables set this way
override other default environment values. Multiple options of
this type are permitted. Environment processing is disabled by
default and is controlled via the PermitUserEnvironment option.
expiry-time="timespec"
Specifies a time after which the key will not be accepted. The
time may be specified as a YYYYMMDD date or a YYYYMMDDHHMM[SS]
time in the system time-zone.
from="pattern-list"
Specifies that in addition to public key authentication, either
the canonical name of the remote host or its IP address must be
present in the comma-separated list of patterns. See PATTERNS in
ssh_config(5) for more information on patterns.
In addition to the wildcard matching that may be applied to
hostnames or addresses, a from stanza may match IP addresses
using CIDR address/masklen notation.
The purpose of this option is to optionally increase security:
public key authentication by itself does not trust the network or
name servers or anything (but the key); however, if somebody
somehow steals the key, the key permits an intruder to log in
from anywhere in the world. This additional option makes using a
stolen key more difficult (name servers and/or routers would have
to be compromised in addition to just the key).
no-agent-forwarding
Forbids authentication agent forwarding when this key is used for
authentication.
no-port-forwarding
Forbids TCP forwarding when this key is used for authentication.
Any port forward requests by the client will return an error.
This might be used, e.g. in connection with the command option.
no-pty Prevents tty allocation (a request to allocate a pty will fail).
no-user-rc
Disables execution of ~/.ssh/rc.
no-X11-forwarding
Forbids X11 forwarding when this key is used for authentication.
Any X11 forward requests by the client will return an error.
permitlisten="[host:]port"
Limit remote port forwarding with the ssh(1) -R option such that
it may only listen on the specified host (optional) and port.
IPv6 addresses can be specified by enclosing the address in
square brackets. Multiple permitlisten options may be applied
separated by commas. Hostnames may include wildcards as
described in the PATTERNS section in ssh_config(5). A port
specification of * matches any port. Note that the setting of
GatewayPorts may further restrict listen addresses. Note that
ssh(1) will send a hostname of M-bM-^@M-^\localhostM-bM-^@M-^] if a listen host was
not specified when the forwarding was requested, and that this
name is treated differently to the explicit localhost addresses
M-bM-^@M-^\127.0.0.1M-bM-^@M-^] and M-bM-^@M-^\::1M-bM-^@M-^].
permitopen="host:port"
Limit local port forwarding with the ssh(1) -L option such that
it may only connect to the specified host and port. IPv6
addresses can be specified by enclosing the address in square
brackets. Multiple permitopen options may be applied separated
by commas. No pattern matching or name lookup is performed on
the specified hostnames, they must be literal host names and/or
addresses. A port specification of * matches any port.
port-forwarding
Enable port forwarding previously disabled by the restrict
option.
principals="principals"
On a cert-authority line, specifies allowed principals for
certificate authentication as a comma-separated list. At least
one name from the list must appear in the certificate's list of
principals for the certificate to be accepted. This option is
ignored for keys that are not marked as trusted certificate
signers using the cert-authority option.
pty Permits tty allocation previously disabled by the restrict
option.
no-touch-required
Do not require demonstration of user presence for signatures made
using this key. This option only makes sense for the FIDO
authenticator algorithms ecdsa-sk and ed25519-sk.
verify-required
Require that signatures made using this key attest that they
verified the user, e.g. via a PIN. This option only makes sense
for the FIDO authenticator algorithms ecdsa-sk and ed25519-sk.
restrict
Enable all restrictions, i.e. disable port, agent and X11
forwarding, as well as disabling PTY allocation and execution of
~/.ssh/rc. If any future restriction capabilities are added to
authorized_keys files they will be included in this set.
tunnel="n"
Force a tun(4) device on the server. Without this option, the
next available device will be used if the client requests a
tunnel.
user-rc
Enables execution of ~/.ssh/rc previously disabled by the
restrict option.
X11-forwarding
Permits X11 forwarding previously disabled by the restrict
option.
An example authorized_keys file:
# Comments allowed at start of line
ssh-rsa AAAAB3Nza...LiPk== user@example.net
from="*.sales.example.net,!pc.sales.example.net" ssh-rsa
AAAAB2...19Q== john@example.net
command="dump /home",no-pty,no-port-forwarding ssh-rsa
AAAAC3...51R== example.net
permitopen="192.0.2.1:80",permitopen="192.0.2.2:25" ssh-rsa
AAAAB5...21S==
permitlisten="localhost:8080",permitopen="localhost:22000" ssh-rsa
AAAAB5...21S==
tunnel="0",command="sh /etc/netstart tun0" ssh-rsa AAAA...==
jane@example.net
restrict,command="uptime" ssh-rsa AAAA1C8...32Tv==
user@example.net
restrict,pty,command="nethack" ssh-rsa AAAA1f8...IrrC5==
user@example.net
no-touch-required sk-ecdsa-sha2-nistp256@openssh.com AAAAInN...Ko==
user@example.net
SSH_KNOWN_HOSTS FILE FORMAT
The /etc/ssh/ssh_known_hosts and ~/.ssh/known_hosts files contain host
public keys for all known hosts. The global file should be prepared by
the administrator (optional), and the per-user file is maintained
automatically: whenever the user connects to an unknown host, its key is
added to the per-user file.
- Each line in these files contains the following fields: markers
+ Each line in these files contains the following fields: marker
(optional), hostnames, keytype, base64-encoded key, comment. The fields
are separated by spaces.
The marker is optional, but if it is present then it must be one of
M-bM-^@M-^\@cert-authorityM-bM-^@M-^], to indicate that the line contains a certification
authority (CA) key, or M-bM-^@M-^\@revokedM-bM-^@M-^], to indicate that the key contained on
the line is revoked and must not ever be accepted. Only one marker
should be used on a key line.
Hostnames is a comma-separated list of patterns (M-bM-^@M-^X*M-bM-^@M-^Y and M-bM-^@M-^X?M-bM-^@M-^Y act as
wildcards); each pattern in turn is matched against the host name. When
sshd is authenticating a client, such as when using
HostbasedAuthentication, this will be the canonical client host name.
When ssh(1) is authenticating a server, this will be the host name given
by the user, the value of the ssh(1) HostkeyAlias if it was specified, or
the canonical server hostname if the ssh(1) CanonicalizeHostname option
was used.
A pattern may also be preceded by M-bM-^@M-^X!M-bM-^@M-^Y to indicate negation: if the host
name matches a negated pattern, it is not accepted (by that line) even if
it matched another pattern on the line. A hostname or address may
optionally be enclosed within M-bM-^@M-^X[M-bM-^@M-^Y and M-bM-^@M-^X]M-bM-^@M-^Y brackets then followed by M-bM-^@M-^X:M-bM-^@M-^Y
and a non-standard port number.
Alternately, hostnames may be stored in a hashed form which hides host
names and addresses should the file's contents be disclosed. Hashed
hostnames start with a M-bM-^@M-^X|M-bM-^@M-^Y character. Only one hashed hostname may
appear on a single line and none of the above negation or wildcard
operators may be applied.
The keytype and base64-encoded key are taken directly from the host key;
they can be obtained, for example, from /etc/ssh/ssh_host_rsa_key.pub.
The optional comment field continues to the end of the line, and is not
used.
Lines starting with M-bM-^@M-^X#M-bM-^@M-^Y and empty lines are ignored as comments.
When performing host authentication, authentication is accepted if any
matching line has the proper key; either one that matches exactly or, if
the server has presented a certificate for authentication, the key of the
certification authority that signed the certificate. For a key to be
trusted as a certification authority, it must use the M-bM-^@M-^\@cert-authorityM-bM-^@M-^]
marker described above.
The known hosts file also provides a facility to mark keys as revoked,
for example when it is known that the associated private key has been
stolen. Revoked keys are specified by including the M-bM-^@M-^\@revokedM-bM-^@M-^] marker at
the beginning of the key line, and are never accepted for authentication
or as certification authorities, but instead will produce a warning from
ssh(1) when they are encountered.
It is permissible (but not recommended) to have several lines or
different host keys for the same names. This will inevitably happen when
short forms of host names from different domains are put in the file. It
is possible that the files contain conflicting information;
authentication is accepted if valid information can be found from either
file.
Note that the lines in these files are typically hundreds of characters
long, and you definitely don't want to type in the host keys by hand.
Rather, generate them by a script, ssh-keyscan(1) or by taking, for
example, /etc/ssh/ssh_host_rsa_key.pub and adding the host names at the
front. ssh-keygen(1) also offers some basic automated editing for
~/.ssh/known_hosts including removing hosts matching a host name and
converting all host names to their hashed representations.
An example ssh_known_hosts file:
# Comments allowed at start of line
closenet,...,192.0.2.53 1024 37 159...93 closenet.example.net
cvs.example.net,192.0.2.10 ssh-rsa AAAA1234.....=
# A hashed hostname
|1|JfKTdBh7rNbXkVAQCRp4OQoPfmI=|USECr3SWf1JUPsms5AqfD5QfxkM= ssh-rsa
AAAA1234.....=
# A revoked key
@revoked * ssh-rsa AAAAB5W...
# A CA key, accepted for any host in *.mydomain.com or *.mydomain.org
@cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W...
FILES
~/.hushlogin
This file is used to suppress printing the last login time and
/etc/motd, if PrintLastLog and PrintMotd, respectively, are
enabled. It does not suppress printing of the banner specified
by Banner.
~/.rhosts
This file is used for host-based authentication (see ssh(1) for
more information). On some machines this file may need to be
world-readable if the user's home directory is on an NFS
partition, because sshd reads it as root. Additionally, this
file must be owned by the user, and must not have write
permissions for anyone else. The recommended permission for most
machines is read/write for the user, and not accessible by
others.
~/.shosts
This file is used in exactly the same way as .rhosts, but allows
host-based authentication without permitting login with
rlogin/rsh.
~/.ssh/
This directory is the default location for all user-specific
configuration and authentication information. There is no
general requirement to keep the entire contents of this directory
secret, but the recommended permissions are read/write/execute
for the user, and not accessible by others.
~/.ssh/authorized_keys
Lists the public keys (DSA, ECDSA, Ed25519, RSA) that can be used
for logging in as this user. The format of this file is
described above. The content of the file is not highly
sensitive, but the recommended permissions are read/write for the
user, and not accessible by others.
If this file, the ~/.ssh directory, or the user's home directory
are writable by other users, then the file could be modified or
replaced by unauthorized users. In this case, sshd will not
allow it to be used unless the StrictModes option has been set to
M-bM-^@M-^\noM-bM-^@M-^].
~/.ssh/environment
This file is read into the environment at login (if it exists).
It can only contain empty lines, comment lines (that start with
M-bM-^@M-^X#M-bM-^@M-^Y), and assignment lines of the form name=value. The file
should be writable only by the user; it need not be readable by
anyone else. Environment processing is disabled by default and
is controlled via the PermitUserEnvironment option.
~/.ssh/known_hosts
Contains a list of host keys for all hosts the user has logged
into that are not already in the systemwide list of known host
keys. The format of this file is described above. This file
should be writable only by root/the owner and can, but need not
be, world-readable.
~/.ssh/rc
Contains initialization routines to be run before the user's home
directory becomes accessible. This file should be writable only
by the user, and need not be readable by anyone else.
/etc/hosts.equiv
This file is for host-based authentication (see ssh(1)). It
should only be writable by root.
/etc/moduli
Contains Diffie-Hellman groups used for the "Diffie-Hellman Group
Exchange" key exchange method. The file format is described in
moduli(5). If no usable groups are found in this file then fixed
internal groups will be used.
/etc/motd
See motd(5).
/etc/nologin
If this file exists, sshd refuses to let anyone except root log
in. The contents of the file are displayed to anyone trying to
log in, and non-root connections are refused. The file should be
world-readable.
/etc/shosts.equiv
This file is used in exactly the same way as hosts.equiv, but
allows host-based authentication without permitting login with
rlogin/rsh.
/etc/ssh/ssh_host_ecdsa_key
/etc/ssh/ssh_host_ed25519_key
/etc/ssh/ssh_host_rsa_key
These files contain the private parts of the host keys. These
files should only be owned by root, readable only by root, and
not accessible to others. Note that sshd does not start if these
files are group/world-accessible.
/etc/ssh/ssh_host_ecdsa_key.pub
/etc/ssh/ssh_host_ed25519_key.pub
/etc/ssh/ssh_host_rsa_key.pub
These files contain the public parts of the host keys. These
files should be world-readable but writable only by root. Their
contents should match the respective private parts. These files
are not really used for anything; they are provided for the
convenience of the user so their contents can be copied to known
hosts files. These files are created using ssh-keygen(1).
/etc/ssh/ssh_known_hosts
Systemwide list of known host keys. This file should be prepared
by the system administrator to contain the public host keys of
all machines in the organization. The format of this file is
described above. This file should be writable only by root/the
owner and should be world-readable.
/etc/ssh/sshd_config
Contains configuration data for sshd. The file format and
configuration options are described in sshd_config(5).
/etc/ssh/sshrc
Similar to ~/.ssh/rc, it can be used to specify machine-specific
login-time initializations globally. This file should be
writable only by root, and should be world-readable.
/var/empty
chroot(2) directory used by sshd during privilege separation in
the pre-authentication phase. The directory should not contain
any files and must be owned by root and not group or world-
writable.
/var/run/sshd.pid
Contains the process ID of the sshd listening for connections (if
there are several daemons running concurrently for different
ports, this contains the process ID of the one started last).
The content of this file is not sensitive; it can be world-
readable.
SEE ALSO
scp(1), sftp(1), ssh(1), ssh-add(1), ssh-agent(1), ssh-keygen(1),
ssh-keyscan(1), chroot(2), login.conf(5), moduli(5), sshd_config(5),
inetd(8), sftp-server(8)
AUTHORS
OpenSSH is a derivative of the original and free ssh 1.2.12 release by
Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo
de Raadt and Dug Song removed many bugs, re-added newer features and
created OpenSSH. Markus Friedl contributed the support for SSH protocol
versions 1.5 and 2.0. Niels Provos and Markus Friedl contributed support
for privilege separation.
-OpenBSD 6.8 August 27, 2020 OpenBSD 6.8
+OpenBSD 6.9 April 3, 2021 OpenBSD 6.9
diff --git a/sshd.8 b/sshd.8
index b2fad56d3e3a..1aa56ba7ee0e 100644
--- a/sshd.8
+++ b/sshd.8
@@ -1,1020 +1,1020 @@
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
.\" All rights reserved
.\"
.\" As far as I am concerned, the code I have written for this software
.\" can be used freely for any purpose. Any derived versions of this
.\" software must be clearly marked as such, and if the derived work is
.\" incompatible with the protocol description in the RFC file, it must be
.\" called by a name other than "ssh" or "Secure Shell".
.\"
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.\" $OpenBSD: sshd.8,v 1.313 2020/08/27 01:07:10 djm Exp $
-.Dd $Mdocdate: August 27 2020 $
+.\" $OpenBSD: sshd.8,v 1.314 2021/04/03 05:46:41 djm Exp $
+.Dd $Mdocdate: April 3 2021 $
.Dt SSHD 8
.Os
.Sh NAME
.Nm sshd
.Nd OpenSSH daemon
.Sh SYNOPSIS
.Nm sshd
.Bk -words
.Op Fl 46DdeiqTt
.Op Fl C Ar connection_spec
.Op Fl c Ar host_certificate_file
.Op Fl E Ar log_file
.Op Fl f Ar config_file
.Op Fl g Ar login_grace_time
.Op Fl h Ar host_key_file
.Op Fl o Ar option
.Op Fl p Ar port
.Op Fl u Ar len
.Ek
.Sh DESCRIPTION
.Nm
(OpenSSH Daemon) is the daemon program for
.Xr ssh 1 .
Together these programs replace rlogin and rsh,
and provide secure encrypted communications between two untrusted hosts
over an insecure network.
.Pp
.Nm
listens for connections from clients.
It is normally started at boot from
.Pa /etc/rc .
It forks a new
daemon for each incoming connection.
The forked daemons handle
key exchange, encryption, authentication, command execution,
and data exchange.
.Pp
.Nm
can be configured using command-line options or a configuration file
(by default
.Xr sshd_config 5 ) ;
command-line options override values specified in the
configuration file.
.Nm
rereads its configuration file when it receives a hangup signal,
.Dv SIGHUP ,
by executing itself with the name and options it was started with, e.g.\&
.Pa /usr/sbin/sshd .
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl 4
Forces
.Nm
to use IPv4 addresses only.
.It Fl 6
Forces
.Nm
to use IPv6 addresses only.
.It Fl C Ar connection_spec
Specify the connection parameters to use for the
.Fl T
extended test mode.
If provided, any
.Cm Match
directives in the configuration file that would apply are applied before the
configuration is written to standard output.
The connection parameters are supplied as keyword=value pairs and may be
supplied in any order, either with multiple
.Fl C
options or as a comma-separated list.
The keywords are
.Dq addr,
.Dq user ,
.Dq host ,
.Dq laddr ,
.Dq lport ,
and
.Dq rdomain
and correspond to source address, user, resolved source host name,
local address, local port number and routing domain respectively.
.It Fl c Ar host_certificate_file
Specifies a path to a certificate file to identify
.Nm
during key exchange.
The certificate file must match a host key file specified using the
.Fl h
option or the
.Cm HostKey
configuration directive.
.It Fl D
When this option is specified,
.Nm
will not detach and does not become a daemon.
This allows easy monitoring of
.Nm sshd .
.It Fl d
Debug mode.
The server sends verbose debug output to standard error,
and does not put itself in the background.
The server also will not fork and will only process one connection.
This option is only intended for debugging for the server.
Multiple
.Fl d
options increase the debugging level.
Maximum is 3.
.It Fl E Ar log_file
Append debug logs to
.Ar log_file
instead of the system log.
.It Fl e
Write debug logs to standard error instead of the system log.
.It Fl f Ar config_file
Specifies the name of the configuration file.
The default is
.Pa /etc/ssh/sshd_config .
.Nm
refuses to start if there is no configuration file.
.It Fl g Ar login_grace_time
Gives the grace time for clients to authenticate themselves (default
120 seconds).
If the client fails to authenticate the user within
this many seconds, the server disconnects and exits.
A value of zero indicates no limit.
.It Fl h Ar host_key_file
Specifies a file from which a host key is read.
This option must be given if
.Nm
is not run as root (as the normal
host key files are normally not readable by anyone but root).
The default is
.Pa /etc/ssh/ssh_host_ecdsa_key ,
.Pa /etc/ssh/ssh_host_ed25519_key
and
.Pa /etc/ssh/ssh_host_rsa_key .
It is possible to have multiple host key files for
the different host key algorithms.
.It Fl i
Specifies that
.Nm
is being run from
.Xr inetd 8 .
.It Fl o Ar option
Can be used to give options in the format used in the configuration file.
This is useful for specifying options for which there is no separate
command-line flag.
For full details of the options, and their values, see
.Xr sshd_config 5 .
.It Fl p Ar port
Specifies the port on which the server listens for connections
(default 22).
Multiple port options are permitted.
Ports specified in the configuration file with the
.Cm Port
option are ignored when a command-line port is specified.
Ports specified using the
.Cm ListenAddress
option override command-line ports.
.It Fl q
Quiet mode.
Nothing is sent to the system log.
Normally the beginning,
authentication, and termination of each connection is logged.
.It Fl T
Extended test mode.
Check the validity of the configuration file, output the effective configuration
to stdout and then exit.
Optionally,
.Cm Match
rules may be applied by specifying the connection parameters using one or more
.Fl C
options.
.It Fl t
Test mode.
Only check the validity of the configuration file and sanity of the keys.
This is useful for updating
.Nm
reliably as configuration options may change.
.It Fl u Ar len
This option is used to specify the size of the field
in the
.Li utmp
structure that holds the remote host name.
If the resolved host name is longer than
.Ar len ,
the dotted decimal value will be used instead.
This allows hosts with very long host names that
overflow this field to still be uniquely identified.
Specifying
.Fl u0
indicates that only dotted decimal addresses
should be put into the
.Pa utmp
file.
.Fl u0
may also be used to prevent
.Nm
from making DNS requests unless the authentication
mechanism or configuration requires it.
Authentication mechanisms that may require DNS include
.Cm HostbasedAuthentication
and using a
.Cm from="pattern-list"
option in a key file.
Configuration options that require DNS include using a
USER@HOST pattern in
.Cm AllowUsers
or
.Cm DenyUsers .
.El
.Sh AUTHENTICATION
The OpenSSH SSH daemon supports SSH protocol 2 only.
Each host has a host-specific key,
used to identify the host.
Whenever a client connects, the daemon responds with its public
host key.
The client compares the
host key against its own database to verify that it has not changed.
Forward secrecy is provided through a Diffie-Hellman key agreement.
This key agreement results in a shared session key.
The rest of the session is encrypted using a symmetric cipher.
The client selects the encryption algorithm
to use from those offered by the server.
Additionally, session integrity is provided
through a cryptographic message authentication code (MAC).
.Pp
Finally, the server and the client enter an authentication dialog.
The client tries to authenticate itself using
host-based authentication,
public key authentication,
challenge-response authentication,
or password authentication.
.Pp
Regardless of the authentication type, the account is checked to
ensure that it is accessible. An account is not accessible if it is
locked, listed in
.Cm DenyUsers
or its group is listed in
.Cm DenyGroups
\&. The definition of a locked account is system dependent. Some platforms
have their own account database (eg AIX) and some modify the passwd field (
.Ql \&*LK\&*
on Solaris and UnixWare,
.Ql \&*
on HP-UX, containing
.Ql Nologin
on Tru64,
a leading
.Ql \&*LOCKED\&*
on FreeBSD and a leading
.Ql \&!
on most Linuxes).
If there is a requirement to disable password authentication
for the account while allowing still public-key, then the passwd field
should be set to something other than these values (eg
.Ql NP
or
.Ql \&*NP\&*
).
.Pp
If the client successfully authenticates itself, a dialog for
preparing the session is entered.
At this time the client may request
things like allocating a pseudo-tty, forwarding X11 connections,
forwarding TCP connections, or forwarding the authentication agent
connection over the secure channel.
.Pp
After this, the client either requests a shell or execution of a command.
The sides then enter session mode.
In this mode, either side may send
data at any time, and such data is forwarded to/from the shell or
command on the server side, and the user terminal in the client side.
.Pp
When the user program terminates and all forwarded X11 and other
connections have been closed, the server sends command exit status to
the client, and both sides exit.
.Sh LOGIN PROCESS
When a user successfully logs in,
.Nm
does the following:
.Bl -enum -offset indent
.It
If the login is on a tty, and no command has been specified,
prints last login time and
.Pa /etc/motd
(unless prevented in the configuration file or by
.Pa ~/.hushlogin ;
see the
.Sx FILES
section).
.It
If the login is on a tty, records login time.
.It
Checks
.Pa /etc/nologin ;
if it exists, prints contents and quits
(unless root).
.It
Changes to run with normal user privileges.
.It
Sets up basic environment.
.It
Reads the file
.Pa ~/.ssh/environment ,
if it exists, and users are allowed to change their environment.
See the
.Cm PermitUserEnvironment
option in
.Xr sshd_config 5 .
.It
Changes to user's home directory.
.It
If
.Pa ~/.ssh/rc
exists and the
.Xr sshd_config 5
.Cm PermitUserRC
option is set, runs it; else if
.Pa /etc/ssh/sshrc
exists, runs
it; otherwise runs xauth.
The
.Dq rc
files are given the X11
authentication protocol and cookie in standard input.
See
.Sx SSHRC ,
below.
.It
Runs user's shell or command.
All commands are run under the user's login shell as specified in the
system password database.
.El
.Sh SSHRC
If the file
.Pa ~/.ssh/rc
exists,
.Xr sh 1
runs it after reading the
environment files but before starting the user's shell or command.
It must not produce any output on stdout; stderr must be used
instead.
If X11 forwarding is in use, it will receive the "proto cookie" pair in
its standard input (and
.Ev DISPLAY
in its environment).
The script must call
.Xr xauth 1
because
.Nm
will not run xauth automatically to add X11 cookies.
.Pp
The primary purpose of this file is to run any initialization routines
which may be needed before the user's home directory becomes
accessible; AFS is a particular example of such an environment.
.Pp
This file will probably contain some initialization code followed by
something similar to:
.Bd -literal -offset 3n
if read proto cookie && [ -n "$DISPLAY" ]; then
if [ `echo $DISPLAY | cut -c1-10` = 'localhost:' ]; then
# X11UseLocalhost=yes
echo add unix:`echo $DISPLAY |
cut -c11-` $proto $cookie
else
# X11UseLocalhost=no
echo add $DISPLAY $proto $cookie
fi | xauth -q -
fi
.Ed
.Pp
If this file does not exist,
.Pa /etc/ssh/sshrc
is run, and if that
does not exist either, xauth is used to add the cookie.
.Sh AUTHORIZED_KEYS FILE FORMAT
.Cm AuthorizedKeysFile
specifies the files containing public keys for
public key authentication;
if this option is not specified, the default is
.Pa ~/.ssh/authorized_keys
and
.Pa ~/.ssh/authorized_keys2 .
Each line of the file contains one
key (empty lines and lines starting with a
.Ql #
are ignored as
comments).
Public keys consist of the following space-separated fields:
options, keytype, base64-encoded key, comment.
The options field is optional.
The supported key types are:
.Pp
.Bl -item -compact -offset indent
.It
sk-ecdsa-sha2-nistp256@openssh.com
.It
ecdsa-sha2-nistp256
.It
ecdsa-sha2-nistp384
.It
ecdsa-sha2-nistp521
.It
sk-ssh-ed25519@openssh.com
.It
ssh-ed25519
.It
ssh-dss
.It
ssh-rsa
.El
.Pp
The comment field is not used for anything (but may be convenient for the
user to identify the key).
.Pp
Note that lines in this file can be several hundred bytes long
(because of the size of the public key encoding) up to a limit of
8 kilobytes, which permits RSA keys up to 16 kilobits.
You don't want to type them in; instead, copy the
.Pa id_dsa.pub ,
.Pa id_ecdsa.pub ,
.Pa id_ecdsa_sk.pub ,
.Pa id_ed25519.pub ,
.Pa id_ed25519_sk.pub ,
or the
.Pa id_rsa.pub
file and edit it.
.Pp
.Nm
enforces a minimum RSA key modulus size of 1024 bits.
.Pp
The options (if present) consist of comma-separated option
specifications.
No spaces are permitted, except within double quotes.
The following option specifications are supported (note
that option keywords are case-insensitive):
.Bl -tag -width Ds
.It Cm agent-forwarding
Enable authentication agent forwarding previously disabled by the
.Cm restrict
option.
.It Cm cert-authority
Specifies that the listed key is a certification authority (CA) that is
trusted to validate signed certificates for user authentication.
.Pp
Certificates may encode access restrictions similar to these key options.
If both certificate restrictions and key options are present, the most
restrictive union of the two is applied.
.It Cm command="command"
Specifies that the command is executed whenever this key is used for
authentication.
The command supplied by the user (if any) is ignored.
The command is run on a pty if the client requests a pty;
otherwise it is run without a tty.
If an 8-bit clean channel is required,
one must not request a pty or should specify
.Cm no-pty .
A quote may be included in the command by quoting it with a backslash.
.Pp
This option might be useful
to restrict certain public keys to perform just a specific operation.
An example might be a key that permits remote backups but nothing else.
Note that the client may specify TCP and/or X11
forwarding unless they are explicitly prohibited, e.g. using the
.Cm restrict
key option.
.Pp
The command originally supplied by the client is available in the
.Ev SSH_ORIGINAL_COMMAND
environment variable.
Note that this option applies to shell, command or subsystem execution.
Also note that this command may be superseded by a
.Xr sshd_config 5
.Cm ForceCommand
directive.
.Pp
If a command is specified and a forced-command is embedded in a certificate
used for authentication, then the certificate will be accepted only if the
two commands are identical.
.It Cm environment="NAME=value"
Specifies that the string is to be added to the environment when
logging in using this key.
Environment variables set this way
override other default environment values.
Multiple options of this type are permitted.
Environment processing is disabled by default and is
controlled via the
.Cm PermitUserEnvironment
option.
.It Cm expiry-time="timespec"
Specifies a time after which the key will not be accepted.
The time may be specified as a YYYYMMDD date or a YYYYMMDDHHMM[SS] time
in the system time-zone.
.It Cm from="pattern-list"
Specifies that in addition to public key authentication, either the canonical
name of the remote host or its IP address must be present in the
comma-separated list of patterns.
See PATTERNS in
.Xr ssh_config 5
for more information on patterns.
.Pp
In addition to the wildcard matching that may be applied to hostnames or
addresses, a
.Cm from
stanza may match IP addresses using CIDR address/masklen notation.
.Pp
The purpose of this option is to optionally increase security: public key
authentication by itself does not trust the network or name servers or
anything (but the key); however, if somebody somehow steals the key, the key
permits an intruder to log in from anywhere in the world.
This additional option makes using a stolen key more difficult (name
servers and/or routers would have to be compromised in addition to
just the key).
.It Cm no-agent-forwarding
Forbids authentication agent forwarding when this key is used for
authentication.
.It Cm no-port-forwarding
Forbids TCP forwarding when this key is used for authentication.
Any port forward requests by the client will return an error.
This might be used, e.g. in connection with the
.Cm command
option.
.It Cm no-pty
Prevents tty allocation (a request to allocate a pty will fail).
.It Cm no-user-rc
Disables execution of
.Pa ~/.ssh/rc .
.It Cm no-X11-forwarding
Forbids X11 forwarding when this key is used for authentication.
Any X11 forward requests by the client will return an error.
.It Cm permitlisten="[host:]port"
Limit remote port forwarding with the
.Xr ssh 1
.Fl R
option such that it may only listen on the specified host (optional) and port.
IPv6 addresses can be specified by enclosing the address in square brackets.
Multiple
.Cm permitlisten
options may be applied separated by commas.
Hostnames may include wildcards as described in the PATTERNS section in
.Xr ssh_config 5 .
A port specification of
.Cm *
matches any port.
Note that the setting of
.Cm GatewayPorts
may further restrict listen addresses.
Note that
.Xr ssh 1
will send a hostname of
.Dq localhost
if a listen host was not specified when the forwarding was requested, and
that this name is treated differently to the explicit localhost addresses
.Dq 127.0.0.1
and
.Dq ::1 .
.It Cm permitopen="host:port"
Limit local port forwarding with the
.Xr ssh 1
.Fl L
option such that it may only connect to the specified host and port.
IPv6 addresses can be specified by enclosing the address in square brackets.
Multiple
.Cm permitopen
options may be applied separated by commas.
No pattern matching or name lookup is performed on the
specified hostnames, they must be literal host names and/or addresses.
A port specification of
.Cm *
matches any port.
.It Cm port-forwarding
Enable port forwarding previously disabled by the
.Cm restrict
option.
.It Cm principals="principals"
On a
.Cm cert-authority
line, specifies allowed principals for certificate authentication as a
comma-separated list.
At least one name from the list must appear in the certificate's
list of principals for the certificate to be accepted.
This option is ignored for keys that are not marked as trusted certificate
signers using the
.Cm cert-authority
option.
.It Cm pty
Permits tty allocation previously disabled by the
.Cm restrict
option.
.It Cm no-touch-required
Do not require demonstration of user presence
for signatures made using this key.
This option only makes sense for the FIDO authenticator algorithms
.Cm ecdsa-sk
and
.Cm ed25519-sk .
.It Cm verify-required
Require that signatures made using this key attest that they verified
the user, e.g. via a PIN.
This option only makes sense for the FIDO authenticator algorithms
.Cm ecdsa-sk
and
.Cm ed25519-sk .
.It Cm restrict
Enable all restrictions, i.e. disable port, agent and X11 forwarding,
as well as disabling PTY allocation
and execution of
.Pa ~/.ssh/rc .
If any future restriction capabilities are added to authorized_keys files
they will be included in this set.
.It Cm tunnel="n"
Force a
.Xr tun 4
device on the server.
Without this option, the next available device will be used if
the client requests a tunnel.
.It Cm user-rc
Enables execution of
.Pa ~/.ssh/rc
previously disabled by the
.Cm restrict
option.
.It Cm X11-forwarding
Permits X11 forwarding previously disabled by the
.Cm restrict
option.
.El
.Pp
An example authorized_keys file:
.Bd -literal -offset 3n
# Comments allowed at start of line
ssh-rsa AAAAB3Nza...LiPk== user@example.net
from="*.sales.example.net,!pc.sales.example.net" ssh-rsa
AAAAB2...19Q== john@example.net
command="dump /home",no-pty,no-port-forwarding ssh-rsa
AAAAC3...51R== example.net
permitopen="192.0.2.1:80",permitopen="192.0.2.2:25" ssh-rsa
AAAAB5...21S==
permitlisten="localhost:8080",permitopen="localhost:22000" ssh-rsa
AAAAB5...21S==
tunnel="0",command="sh /etc/netstart tun0" ssh-rsa AAAA...==
jane@example.net
restrict,command="uptime" ssh-rsa AAAA1C8...32Tv==
user@example.net
restrict,pty,command="nethack" ssh-rsa AAAA1f8...IrrC5==
user@example.net
no-touch-required sk-ecdsa-sha2-nistp256@openssh.com AAAAInN...Ko==
user@example.net
.Ed
.Sh SSH_KNOWN_HOSTS FILE FORMAT
The
.Pa /etc/ssh/ssh_known_hosts
and
.Pa ~/.ssh/known_hosts
files contain host public keys for all known hosts.
The global file should
be prepared by the administrator (optional), and the per-user file is
maintained automatically: whenever the user connects to an unknown host,
its key is added to the per-user file.
.Pp
-Each line in these files contains the following fields: markers (optional),
+Each line in these files contains the following fields: marker (optional),
hostnames, keytype, base64-encoded key, comment.
The fields are separated by spaces.
.Pp
The marker is optional, but if it is present then it must be one of
.Dq @cert-authority ,
to indicate that the line contains a certification authority (CA) key,
or
.Dq @revoked ,
to indicate that the key contained on the line is revoked and must not ever
be accepted.
Only one marker should be used on a key line.
.Pp
Hostnames is a comma-separated list of patterns
.Pf ( Ql *
and
.Ql \&?
act as
wildcards); each pattern in turn is matched against the host name.
When
.Nm sshd
is authenticating a client, such as when using
.Cm HostbasedAuthentication ,
this will be the canonical client host name.
When
.Xr ssh 1
is authenticating a server, this will be the host name
given by the user, the value of the
.Xr ssh 1
.Cm HostkeyAlias
if it was specified, or the canonical server hostname if the
.Xr ssh 1
.Cm CanonicalizeHostname
option was used.
.Pp
A pattern may also be preceded by
.Ql \&!
to indicate negation: if the host name matches a negated
pattern, it is not accepted (by that line) even if it matched another
pattern on the line.
A hostname or address may optionally be enclosed within
.Ql \&[
and
.Ql \&]
brackets then followed by
.Ql \&:
and a non-standard port number.
.Pp
Alternately, hostnames may be stored in a hashed form which hides host names
and addresses should the file's contents be disclosed.
Hashed hostnames start with a
.Ql |
character.
Only one hashed hostname may appear on a single line and none of the above
negation or wildcard operators may be applied.
.Pp
The keytype and base64-encoded key are taken directly from the host key; they
can be obtained, for example, from
.Pa /etc/ssh/ssh_host_rsa_key.pub .
The optional comment field continues to the end of the line, and is not used.
.Pp
Lines starting with
.Ql #
and empty lines are ignored as comments.
.Pp
When performing host authentication, authentication is accepted if any
matching line has the proper key; either one that matches exactly or,
if the server has presented a certificate for authentication, the key
of the certification authority that signed the certificate.
For a key to be trusted as a certification authority, it must use the
.Dq @cert-authority
marker described above.
.Pp
The known hosts file also provides a facility to mark keys as revoked,
for example when it is known that the associated private key has been
stolen.
Revoked keys are specified by including the
.Dq @revoked
marker at the beginning of the key line, and are never accepted for
authentication or as certification authorities, but instead will
produce a warning from
.Xr ssh 1
when they are encountered.
.Pp
It is permissible (but not
recommended) to have several lines or different host keys for the same
names.
This will inevitably happen when short forms of host names
from different domains are put in the file.
It is possible
that the files contain conflicting information; authentication is
accepted if valid information can be found from either file.
.Pp
Note that the lines in these files are typically hundreds of characters
long, and you definitely don't want to type in the host keys by hand.
Rather, generate them by a script,
.Xr ssh-keyscan 1
or by taking, for example,
.Pa /etc/ssh/ssh_host_rsa_key.pub
and adding the host names at the front.
.Xr ssh-keygen 1
also offers some basic automated editing for
.Pa ~/.ssh/known_hosts
including removing hosts matching a host name and converting all host
names to their hashed representations.
.Pp
An example ssh_known_hosts file:
.Bd -literal -offset 3n
# Comments allowed at start of line
closenet,...,192.0.2.53 1024 37 159...93 closenet.example.net
cvs.example.net,192.0.2.10 ssh-rsa AAAA1234.....=
# A hashed hostname
|1|JfKTdBh7rNbXkVAQCRp4OQoPfmI=|USECr3SWf1JUPsms5AqfD5QfxkM= ssh-rsa
AAAA1234.....=
# A revoked key
@revoked * ssh-rsa AAAAB5W...
# A CA key, accepted for any host in *.mydomain.com or *.mydomain.org
@cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W...
.Ed
.Sh FILES
.Bl -tag -width Ds -compact
.It Pa ~/.hushlogin
This file is used to suppress printing the last login time and
.Pa /etc/motd ,
if
.Cm PrintLastLog
and
.Cm PrintMotd ,
respectively,
are enabled.
It does not suppress printing of the banner specified by
.Cm Banner .
.Pp
.It Pa ~/.rhosts
This file is used for host-based authentication (see
.Xr ssh 1
for more information).
On some machines this file may need to be
world-readable if the user's home directory is on an NFS partition,
because
.Nm
reads it as root.
Additionally, this file must be owned by the user,
and must not have write permissions for anyone else.
The recommended
permission for most machines is read/write for the user, and not
accessible by others.
.Pp
.It Pa ~/.shosts
This file is used in exactly the same way as
.Pa .rhosts ,
but allows host-based authentication without permitting login with
rlogin/rsh.
.Pp
.It Pa ~/.ssh/
This directory is the default location for all user-specific configuration
and authentication information.
There is no general requirement to keep the entire contents of this directory
secret, but the recommended permissions are read/write/execute for the user,
and not accessible by others.
.Pp
.It Pa ~/.ssh/authorized_keys
Lists the public keys (DSA, ECDSA, Ed25519, RSA)
that can be used for logging in as this user.
The format of this file is described above.
The content of the file is not highly sensitive, but the recommended
permissions are read/write for the user, and not accessible by others.
.Pp
If this file, the
.Pa ~/.ssh
directory, or the user's home directory are writable
by other users, then the file could be modified or replaced by unauthorized
users.
In this case,
.Nm
will not allow it to be used unless the
.Cm StrictModes
option has been set to
.Dq no .
.Pp
.It Pa ~/.ssh/environment
This file is read into the environment at login (if it exists).
It can only contain empty lines, comment lines (that start with
.Ql # ) ,
and assignment lines of the form name=value.
The file should be writable
only by the user; it need not be readable by anyone else.
Environment processing is disabled by default and is
controlled via the
.Cm PermitUserEnvironment
option.
.Pp
.It Pa ~/.ssh/known_hosts
Contains a list of host keys for all hosts the user has logged into
that are not already in the systemwide list of known host keys.
The format of this file is described above.
This file should be writable only by root/the owner and
can, but need not be, world-readable.
.Pp
.It Pa ~/.ssh/rc
Contains initialization routines to be run before
the user's home directory becomes accessible.
This file should be writable only by the user, and need not be
readable by anyone else.
.Pp
.It Pa /etc/hosts.equiv
This file is for host-based authentication (see
.Xr ssh 1 ) .
It should only be writable by root.
.Pp
.It Pa /etc/moduli
Contains Diffie-Hellman groups used for the "Diffie-Hellman Group Exchange"
key exchange method.
The file format is described in
.Xr moduli 5 .
If no usable groups are found in this file then fixed internal groups will
be used.
.Pp
.It Pa /etc/motd
See
.Xr motd 5 .
.Pp
.It Pa /etc/nologin
If this file exists,
.Nm
refuses to let anyone except root log in.
The contents of the file
are displayed to anyone trying to log in, and non-root connections are
refused.
The file should be world-readable.
.Pp
.It Pa /etc/shosts.equiv
This file is used in exactly the same way as
.Pa hosts.equiv ,
but allows host-based authentication without permitting login with
rlogin/rsh.
.Pp
.It Pa /etc/ssh/ssh_host_ecdsa_key
.It Pa /etc/ssh/ssh_host_ed25519_key
.It Pa /etc/ssh/ssh_host_rsa_key
These files contain the private parts of the host keys.
These files should only be owned by root, readable only by root, and not
accessible to others.
Note that
.Nm
does not start if these files are group/world-accessible.
.Pp
.It Pa /etc/ssh/ssh_host_ecdsa_key.pub
.It Pa /etc/ssh/ssh_host_ed25519_key.pub
.It Pa /etc/ssh/ssh_host_rsa_key.pub
These files contain the public parts of the host keys.
These files should be world-readable but writable only by
root.
Their contents should match the respective private parts.
These files are not
really used for anything; they are provided for the convenience of
the user so their contents can be copied to known hosts files.
These files are created using
.Xr ssh-keygen 1 .
.Pp
.It Pa /etc/ssh/ssh_known_hosts
Systemwide list of known host keys.
This file should be prepared by the
system administrator to contain the public host keys of all machines in the
organization.
The format of this file is described above.
This file should be writable only by root/the owner and
should be world-readable.
.Pp
.It Pa /etc/ssh/sshd_config
Contains configuration data for
.Nm sshd .
The file format and configuration options are described in
.Xr sshd_config 5 .
.Pp
.It Pa /etc/ssh/sshrc
Similar to
.Pa ~/.ssh/rc ,
it can be used to specify
machine-specific login-time initializations globally.
This file should be writable only by root, and should be world-readable.
.Pp
.It Pa /var/empty
.Xr chroot 2
directory used by
.Nm
during privilege separation in the pre-authentication phase.
The directory should not contain any files and must be owned by root
and not group or world-writable.
.Pp
.It Pa /var/run/sshd.pid
Contains the process ID of the
.Nm
listening for connections (if there are several daemons running
concurrently for different ports, this contains the process ID of the one
started last).
The content of this file is not sensitive; it can be world-readable.
.El
.Sh SEE ALSO
.Xr scp 1 ,
.Xr sftp 1 ,
.Xr ssh 1 ,
.Xr ssh-add 1 ,
.Xr ssh-agent 1 ,
.Xr ssh-keygen 1 ,
.Xr ssh-keyscan 1 ,
.Xr chroot 2 ,
.Xr login.conf 5 ,
.Xr moduli 5 ,
.Xr sshd_config 5 ,
.Xr inetd 8 ,
.Xr sftp-server 8
.Sh AUTHORS
OpenSSH is a derivative of the original and free
ssh 1.2.12 release by Tatu Ylonen.
Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos,
Theo de Raadt and Dug Song
removed many bugs, re-added newer features and
created OpenSSH.
Markus Friedl contributed the support for SSH
protocol versions 1.5 and 2.0.
Niels Provos and Markus Friedl contributed support
for privilege separation.
diff --git a/sshd.c b/sshd.c
index 6277e6d6db89..5aa04d0507c0 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,2425 +1,2433 @@
-/* $OpenBSD: sshd.c,v 1.570 2021/02/05 02:20:23 dtucker Exp $ */
+/* $OpenBSD: sshd.c,v 1.572 2021/04/03 06:18:41 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* This program is the ssh daemon. It listens for connections from clients,
* and performs authentication, executes use commands or shell, and forwards
* information to/from the application to the user client over an encrypted
* connection. This can also handle forwarding of X11, TCP/IP, and
* authentication agent connections.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
* SSH2 implementation:
* Privilege Separation:
*
* Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved.
* Copyright (c) 2002 Niels Provos. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include "openbsd-compat/sys-tree.h"
#include "openbsd-compat/sys-queue.h"
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#include <grp.h>
#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#ifdef WITH_OPENSSL
#include <openssl/dh.h>
#include <openssl/bn.h>
#include <openssl/rand.h>
#include "openbsd-compat/openssl-compat.h"
#endif
#ifdef HAVE_SECUREWARE
#include <sys/security.h>
#include <prot.h>
#endif
#include "xmalloc.h"
#include "ssh.h"
#include "ssh2.h"
#include "sshpty.h"
#include "packet.h"
#include "log.h"
#include "sshbuf.h"
#include "misc.h"
#include "match.h"
#include "servconf.h"
#include "uidswap.h"
#include "compat.h"
#include "cipher.h"
#include "digest.h"
#include "sshkey.h"
#include "kex.h"
#include "myproposal.h"
#include "authfile.h"
#include "pathnames.h"
#include "atomicio.h"
#include "canohost.h"
#include "hostfile.h"
#include "auth.h"
#include "authfd.h"
#include "msg.h"
#include "dispatch.h"
#include "channels.h"
#include "session.h"
#include "monitor.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
#include "monitor_wrap.h"
#include "ssh-sandbox.h"
#include "auth-options.h"
#include "version.h"
#include "ssherr.h"
#include "sk-api.h"
#include "srclimit.h"
+#include "dh.h"
/* Re-exec fds */
#define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1)
#define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2)
#define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3)
#define REEXEC_MIN_FREE_FD (STDERR_FILENO + 4)
extern char *__progname;
/* Server configuration options. */
ServerOptions options;
/* Name of the server configuration file. */
char *config_file_name = _PATH_SERVER_CONFIG_FILE;
/*
* Debug mode flag. This can be set on the command line. If debug
* mode is enabled, extra debugging output will be sent to the system
* log, the daemon will not go to background, and will exit after processing
* the first connection.
*/
int debug_flag = 0;
/*
* Indicating that the daemon should only test the configuration and keys.
* If test_flag > 1 ("-T" flag), then sshd will also dump the effective
* configuration, optionally using connection information provided by the
* "-C" flag.
*/
static int test_flag = 0;
/* Flag indicating that the daemon is being started from inetd. */
static int inetd_flag = 0;
/* Flag indicating that sshd should not detach and become a daemon. */
static int no_daemon_flag = 0;
/* debug goes to stderr unless inetd_flag is set */
static int log_stderr = 0;
/* Saved arguments to main(). */
static char **saved_argv;
static int saved_argc;
/* re-exec */
static int rexeced_flag = 0;
static int rexec_flag = 1;
static int rexec_argc = 0;
static char **rexec_argv;
/*
* The sockets that the server is listening; this is used in the SIGHUP
* signal handler.
*/
#define MAX_LISTEN_SOCKS 16
static int listen_socks[MAX_LISTEN_SOCKS];
static int num_listen_socks = 0;
/* Daemon's agent connection */
int auth_sock = -1;
static int have_agent = 0;
/*
* Any really sensitive data in the application is contained in this
* structure. The idea is that this structure could be locked into memory so
* that the pages do not get written into swap. However, there are some
* problems. The private key contains BIGNUMs, and we do not (in principle)
* have access to the internals of them, and locking just the structure is
* not very useful. Currently, memory locking is not implemented.
*/
struct {
struct sshkey **host_keys; /* all private host keys */
struct sshkey **host_pubkeys; /* all public host keys */
struct sshkey **host_certificates; /* all public host certificates */
int have_ssh2_key;
} sensitive_data;
/* This is set to true when a signal is received. */
static volatile sig_atomic_t received_sighup = 0;
static volatile sig_atomic_t received_sigterm = 0;
/* record remote hostname or ip */
u_int utmp_len = HOST_NAME_MAX+1;
/*
* startup_pipes/flags are used for tracking children of the listening sshd
* process early in their lifespans. This tracking is needed for three things:
*
* 1) Implementing the MaxStartups limit of concurrent unauthenticated
* connections.
* 2) Avoiding a race condition for SIGHUP processing, where child processes
* may have listen_socks open that could collide with main listener process
* after it restarts.
* 3) Ensuring that rexec'd sshd processes have received their initial state
* from the parent listen process before handling SIGHUP.
*
* Child processes signal that they have completed closure of the listen_socks
* and (if applicable) received their rexec state by sending a char over their
* sock. Child processes signal that authentication has completed by closing
* the sock (or by exiting).
*/
static int *startup_pipes = NULL;
static int *startup_flags = NULL; /* Indicates child closed listener */
static int startup_pipe = -1; /* in child */
/* variables used for privilege separation */
int use_privsep = -1;
struct monitor *pmonitor = NULL;
int privsep_is_preauth = 1;
static int privsep_chroot = 1;
/* global connection state and authentication contexts */
Authctxt *the_authctxt = NULL;
struct ssh *the_active_state;
/* global key/cert auth options. XXX move to permanent ssh->authctxt? */
struct sshauthopt *auth_opts = NULL;
/* sshd_config buffer */
struct sshbuf *cfg;
/* Included files from the configuration file */
struct include_list includes = TAILQ_HEAD_INITIALIZER(includes);
/* message to be displayed after login */
struct sshbuf *loginmsg;
/* Unprivileged user */
struct passwd *privsep_pw = NULL;
/* Prototypes for various functions defined later in this file. */
void destroy_sensitive_data(void);
void demote_sensitive_data(void);
static void do_ssh2_kex(struct ssh *);
static char *listener_proctitle;
/*
* Close all listening sockets
*/
static void
close_listen_socks(void)
{
int i;
for (i = 0; i < num_listen_socks; i++)
close(listen_socks[i]);
num_listen_socks = -1;
}
static void
close_startup_pipes(void)
{
int i;
if (startup_pipes)
for (i = 0; i < options.max_startups; i++)
if (startup_pipes[i] != -1)
close(startup_pipes[i]);
}
/*
* Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP;
* the effect is to reread the configuration file (and to regenerate
* the server key).
*/
/*ARGSUSED*/
static void
sighup_handler(int sig)
{
received_sighup = 1;
}
/*
* Called from the main program after receiving SIGHUP.
* Restarts the server.
*/
static void
sighup_restart(void)
{
logit("Received SIGHUP; restarting.");
if (options.pid_file != NULL)
unlink(options.pid_file);
platform_pre_restart();
close_listen_socks();
close_startup_pipes();
ssh_signal(SIGHUP, SIG_IGN); /* will be restored after exec */
execv(saved_argv[0], saved_argv);
logit("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0],
strerror(errno));
exit(1);
}
/*
* Generic signal handler for terminating signals in the master daemon.
*/
/*ARGSUSED*/
static void
sigterm_handler(int sig)
{
received_sigterm = sig;
}
/*
* SIGCHLD handler. This is called whenever a child dies. This will then
* reap any zombies left by exited children.
*/
/*ARGSUSED*/
static void
main_sigchld_handler(int sig)
{
int save_errno = errno;
pid_t pid;
int status;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
(pid == -1 && errno == EINTR))
;
errno = save_errno;
}
/*
* Signal handler for the alarm after the login grace period has expired.
*/
/*ARGSUSED*/
static void
grace_alarm_handler(int sig)
{
if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0)
kill(pmonitor->m_pid, SIGALRM);
/*
* Try to kill any processes that we have spawned, E.g. authorized
* keys command helpers.
*/
if (getpgid(0) == getpid()) {
ssh_signal(SIGTERM, SIG_IGN);
kill(0, SIGTERM);
}
/* XXX pre-format ipaddr/port so we don't need to access active_state */
/* Log error and exit. */
sigdie("Timeout before authentication for %s port %d",
ssh_remote_ipaddr(the_active_state),
ssh_remote_port(the_active_state));
}
/* Destroy the host and server keys. They will no longer be needed. */
void
destroy_sensitive_data(void)
{
u_int i;
for (i = 0; i < options.num_host_key_files; i++) {
if (sensitive_data.host_keys[i]) {
sshkey_free(sensitive_data.host_keys[i]);
sensitive_data.host_keys[i] = NULL;
}
if (sensitive_data.host_certificates[i]) {
sshkey_free(sensitive_data.host_certificates[i]);
sensitive_data.host_certificates[i] = NULL;
}
}
}
/* Demote private to public keys for network child */
void
demote_sensitive_data(void)
{
struct sshkey *tmp;
u_int i;
int r;
for (i = 0; i < options.num_host_key_files; i++) {
if (sensitive_data.host_keys[i]) {
if ((r = sshkey_from_private(
sensitive_data.host_keys[i], &tmp)) != 0)
fatal_r(r, "could not demote host %s key",
sshkey_type(sensitive_data.host_keys[i]));
sshkey_free(sensitive_data.host_keys[i]);
sensitive_data.host_keys[i] = tmp;
}
/* Certs do not need demotion */
}
}
static void
reseed_prngs(void)
{
u_int32_t rnd[256];
#ifdef WITH_OPENSSL
RAND_poll();
#endif
arc4random_stir(); /* noop on recent arc4random() implementations */
arc4random_buf(rnd, sizeof(rnd)); /* let arc4random notice PID change */
#ifdef WITH_OPENSSL
RAND_seed(rnd, sizeof(rnd));
/* give libcrypto a chance to notice the PID change */
if ((RAND_bytes((u_char *)rnd, 1)) != 1)
fatal("%s: RAND_bytes failed", __func__);
#endif
explicit_bzero(rnd, sizeof(rnd));
}
static void
privsep_preauth_child(void)
{
gid_t gidset[1];
/* Enable challenge-response authentication for privilege separation */
privsep_challenge_enable();
#ifdef GSSAPI
/* Cache supported mechanism OIDs for later use */
ssh_gssapi_prepare_supported_oids();
#endif
reseed_prngs();
/* Demote the private keys to public keys. */
demote_sensitive_data();
/* Demote the child */
if (privsep_chroot) {
/* Change our root directory */
if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1)
fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR,
strerror(errno));
if (chdir("/") == -1)
fatal("chdir(\"/\"): %s", strerror(errno));
/* Drop our privileges */
debug3("privsep user:group %u:%u", (u_int)privsep_pw->pw_uid,
(u_int)privsep_pw->pw_gid);
gidset[0] = privsep_pw->pw_gid;
if (setgroups(1, gidset) == -1)
fatal("setgroups: %.100s", strerror(errno));
permanently_set_uid(privsep_pw);
}
}
static int
privsep_preauth(struct ssh *ssh)
{
int status, r;
pid_t pid;
struct ssh_sandbox *box = NULL;
/* Set up unprivileged child process to deal with network data */
pmonitor = monitor_init();
/* Store a pointer to the kex for later rekeying */
pmonitor->m_pkex = &ssh->kex;
if (use_privsep == PRIVSEP_ON)
box = ssh_sandbox_init(pmonitor);
pid = fork();
if (pid == -1) {
fatal("fork of unprivileged child failed");
} else if (pid != 0) {
debug2("Network child is on pid %ld", (long)pid);
pmonitor->m_pid = pid;
if (have_agent) {
r = ssh_get_authentication_socket(&auth_sock);
if (r != 0) {
error_r(r, "Could not get agent socket");
have_agent = 0;
}
}
if (box != NULL)
ssh_sandbox_parent_preauth(box, pid);
monitor_child_preauth(ssh, pmonitor);
/* Wait for the child's exit status */
while (waitpid(pid, &status, 0) == -1) {
if (errno == EINTR)
continue;
pmonitor->m_pid = -1;
fatal_f("waitpid: %s", strerror(errno));
}
privsep_is_preauth = 0;
pmonitor->m_pid = -1;
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != 0)
fatal_f("preauth child exited with status %d",
WEXITSTATUS(status));
} else if (WIFSIGNALED(status))
fatal_f("preauth child terminated by signal %d",
WTERMSIG(status));
if (box != NULL)
ssh_sandbox_parent_finish(box);
return 1;
} else {
/* child */
close(pmonitor->m_sendfd);
close(pmonitor->m_log_recvfd);
/* Arrange for logging to be sent to the monitor */
set_log_handler(mm_log_handler, pmonitor);
privsep_preauth_child();
setproctitle("%s", "[net]");
if (box != NULL)
ssh_sandbox_child(box);
return 0;
}
}
static void
privsep_postauth(struct ssh *ssh, Authctxt *authctxt)
{
#ifdef DISABLE_FD_PASSING
if (1) {
#else
if (authctxt->pw->pw_uid == 0) {
#endif
/* File descriptor passing is broken or root login */
use_privsep = 0;
goto skip;
}
/* New socket pair */
monitor_reinit(pmonitor);
pmonitor->m_pid = fork();
if (pmonitor->m_pid == -1)
fatal("fork of unprivileged child failed");
else if (pmonitor->m_pid != 0) {
verbose("User child is on pid %ld", (long)pmonitor->m_pid);
sshbuf_reset(loginmsg);
monitor_clear_keystate(ssh, pmonitor);
monitor_child_postauth(ssh, pmonitor);
/* NEVERREACHED */
exit(0);
}
/* child */
close(pmonitor->m_sendfd);
pmonitor->m_sendfd = -1;
/* Demote the private keys to public keys. */
demote_sensitive_data();
reseed_prngs();
/* Drop privileges */
do_setusercontext(authctxt->pw);
skip:
/* It is safe now to apply the key state */
monitor_apply_keystate(ssh, pmonitor);
/*
* Tell the packet layer that authentication was successful, since
* this information is not part of the key state.
*/
ssh_packet_set_authenticated(ssh);
}
static void
append_hostkey_type(struct sshbuf *b, const char *s)
{
int r;
if (match_pattern_list(s, options.hostkeyalgorithms, 0) != 1) {
debug3_f("%s key not permitted by HostkeyAlgorithms", s);
return;
}
if ((r = sshbuf_putf(b, "%s%s", sshbuf_len(b) > 0 ? "," : "", s)) != 0)
fatal_fr(r, "sshbuf_putf");
}
static char *
list_hostkey_types(void)
{
struct sshbuf *b;
struct sshkey *key;
char *ret;
u_int i;
if ((b = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
for (i = 0; i < options.num_host_key_files; i++) {
key = sensitive_data.host_keys[i];
if (key == NULL)
key = sensitive_data.host_pubkeys[i];
if (key == NULL)
continue;
switch (key->type) {
case KEY_RSA:
/* for RSA we also support SHA2 signatures */
append_hostkey_type(b, "rsa-sha2-512");
append_hostkey_type(b, "rsa-sha2-256");
/* FALLTHROUGH */
case KEY_DSA:
case KEY_ECDSA:
case KEY_ED25519:
case KEY_ECDSA_SK:
case KEY_ED25519_SK:
case KEY_XMSS:
append_hostkey_type(b, sshkey_ssh_name(key));
break;
}
/* If the private key has a cert peer, then list that too */
key = sensitive_data.host_certificates[i];
if (key == NULL)
continue;
switch (key->type) {
case KEY_RSA_CERT:
/* for RSA we also support SHA2 signatures */
append_hostkey_type(b,
"rsa-sha2-512-cert-v01@openssh.com");
append_hostkey_type(b,
"rsa-sha2-256-cert-v01@openssh.com");
/* FALLTHROUGH */
case KEY_DSA_CERT:
case KEY_ECDSA_CERT:
case KEY_ED25519_CERT:
case KEY_ECDSA_SK_CERT:
case KEY_ED25519_SK_CERT:
case KEY_XMSS_CERT:
append_hostkey_type(b, sshkey_ssh_name(key));
break;
}
}
if ((ret = sshbuf_dup_string(b)) == NULL)
fatal_f("sshbuf_dup_string failed");
sshbuf_free(b);
debug_f("%s", ret);
return ret;
}
static struct sshkey *
get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh)
{
u_int i;
struct sshkey *key;
for (i = 0; i < options.num_host_key_files; i++) {
switch (type) {
case KEY_RSA_CERT:
case KEY_DSA_CERT:
case KEY_ECDSA_CERT:
case KEY_ED25519_CERT:
case KEY_ECDSA_SK_CERT:
case KEY_ED25519_SK_CERT:
case KEY_XMSS_CERT:
key = sensitive_data.host_certificates[i];
break;
default:
key = sensitive_data.host_keys[i];
if (key == NULL && !need_private)
key = sensitive_data.host_pubkeys[i];
break;
}
if (key == NULL || key->type != type)
continue;
switch (type) {
case KEY_ECDSA:
case KEY_ECDSA_SK:
case KEY_ECDSA_CERT:
case KEY_ECDSA_SK_CERT:
if (key->ecdsa_nid != nid)
continue;
/* FALLTHROUGH */
default:
return need_private ?
sensitive_data.host_keys[i] : key;
}
}
return NULL;
}
struct sshkey *
get_hostkey_public_by_type(int type, int nid, struct ssh *ssh)
{
return get_hostkey_by_type(type, nid, 0, ssh);
}
struct sshkey *
get_hostkey_private_by_type(int type, int nid, struct ssh *ssh)
{
return get_hostkey_by_type(type, nid, 1, ssh);
}
struct sshkey *
get_hostkey_by_index(int ind)
{
if (ind < 0 || (u_int)ind >= options.num_host_key_files)
return (NULL);
return (sensitive_data.host_keys[ind]);
}
struct sshkey *
get_hostkey_public_by_index(int ind, struct ssh *ssh)
{
if (ind < 0 || (u_int)ind >= options.num_host_key_files)
return (NULL);
return (sensitive_data.host_pubkeys[ind]);
}
int
get_hostkey_index(struct sshkey *key, int compare, struct ssh *ssh)
{
u_int i;
for (i = 0; i < options.num_host_key_files; i++) {
if (sshkey_is_cert(key)) {
if (key == sensitive_data.host_certificates[i] ||
(compare && sensitive_data.host_certificates[i] &&
sshkey_equal(key,
sensitive_data.host_certificates[i])))
return (i);
} else {
if (key == sensitive_data.host_keys[i] ||
(compare && sensitive_data.host_keys[i] &&
sshkey_equal(key, sensitive_data.host_keys[i])))
return (i);
if (key == sensitive_data.host_pubkeys[i] ||
(compare && sensitive_data.host_pubkeys[i] &&
sshkey_equal(key, sensitive_data.host_pubkeys[i])))
return (i);
}
}
return (-1);
}
/* Inform the client of all hostkeys */
static void
notify_hostkeys(struct ssh *ssh)
{
struct sshbuf *buf;
struct sshkey *key;
u_int i, nkeys;
int r;
char *fp;
/* Some clients cannot cope with the hostkeys message, skip those. */
if (ssh->compat & SSH_BUG_HOSTKEYS)
return;
if ((buf = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
for (i = nkeys = 0; i < options.num_host_key_files; i++) {
key = get_hostkey_public_by_index(i, ssh);
if (key == NULL || key->type == KEY_UNSPEC ||
sshkey_is_cert(key))
continue;
fp = sshkey_fingerprint(key, options.fingerprint_hash,
SSH_FP_DEFAULT);
debug3_f("key %d: %s %s", i, sshkey_ssh_name(key), fp);
free(fp);
if (nkeys == 0) {
/*
* Start building the request when we find the
* first usable key.
*/
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, "hostkeys-00@openssh.com")) != 0 ||
(r = sshpkt_put_u8(ssh, 0)) != 0) /* want reply */
sshpkt_fatal(ssh, r, "%s: start request", __func__);
}
/* Append the key to the request */
sshbuf_reset(buf);
if ((r = sshkey_putb(key, buf)) != 0)
fatal_fr(r, "couldn't put hostkey %d", i);
if ((r = sshpkt_put_stringb(ssh, buf)) != 0)
sshpkt_fatal(ssh, r, "%s: append key", __func__);
nkeys++;
}
debug3_f("sent %u hostkeys", nkeys);
if (nkeys == 0)
fatal_f("no hostkeys");
if ((r = sshpkt_send(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: send", __func__);
sshbuf_free(buf);
}
/*
* returns 1 if connection should be dropped, 0 otherwise.
* dropping starts at connection #max_startups_begin with a probability
* of (max_startups_rate/100). the probability increases linearly until
* all connections are dropped for startups > max_startups
*/
static int
should_drop_connection(int startups)
{
int p, r;
if (startups < options.max_startups_begin)
return 0;
if (startups >= options.max_startups)
return 1;
if (options.max_startups_rate == 100)
return 1;
p = 100 - options.max_startups_rate;
p *= startups - options.max_startups_begin;
p /= options.max_startups - options.max_startups_begin;
p += options.max_startups_rate;
r = arc4random_uniform(100);
debug_f("p %d, r %d", p, r);
return (r < p) ? 1 : 0;
}
/*
* Check whether connection should be accepted by MaxStartups.
* Returns 0 if the connection is accepted. If the connection is refused,
* returns 1 and attempts to send notification to client.
* Logs when the MaxStartups condition is entered or exited, and periodically
* while in that state.
*/
static int
drop_connection(int sock, int startups, int notify_pipe)
{
char *laddr, *raddr;
const char msg[] = "Exceeded MaxStartups\r\n";
static time_t last_drop, first_drop;
static u_int ndropped;
LogLevel drop_level = SYSLOG_LEVEL_VERBOSE;
time_t now;
now = monotime();
if (!should_drop_connection(startups) &&
srclimit_check_allow(sock, notify_pipe) == 1) {
if (last_drop != 0 &&
startups < options.max_startups_begin - 1) {
/* XXX maybe need better hysteresis here */
logit("exited MaxStartups throttling after %s, "
"%u connections dropped",
fmt_timeframe(now - first_drop), ndropped);
last_drop = 0;
}
return 0;
}
#define SSHD_MAXSTARTUPS_LOG_INTERVAL (5 * 60)
if (last_drop == 0) {
error("beginning MaxStartups throttling");
drop_level = SYSLOG_LEVEL_INFO;
first_drop = now;
ndropped = 0;
} else if (last_drop + SSHD_MAXSTARTUPS_LOG_INTERVAL < now) {
/* Periodic logs */
error("in MaxStartups throttling for %s, "
"%u connections dropped",
fmt_timeframe(now - first_drop), ndropped + 1);
drop_level = SYSLOG_LEVEL_INFO;
}
last_drop = now;
ndropped++;
laddr = get_local_ipaddr(sock);
raddr = get_peer_ipaddr(sock);
do_log2(drop_level, "drop connection #%d from [%s]:%d on [%s]:%d "
"past MaxStartups", startups, raddr, get_peer_port(sock),
laddr, get_local_port(sock));
free(laddr);
free(raddr);
/* best-effort notification to client */
(void)write(sock, msg, sizeof(msg) - 1);
return 1;
}
static void
usage(void)
{
fprintf(stderr, "%s, %s\n", SSH_RELEASE, SSH_OPENSSL_VERSION);
fprintf(stderr,
"usage: sshd [-46DdeiqTt] [-C connection_spec] [-c host_cert_file]\n"
" [-E log_file] [-f config_file] [-g login_grace_time]\n"
" [-h host_key_file] [-o option] [-p port] [-u len]\n"
);
exit(1);
}
static void
send_rexec_state(int fd, struct sshbuf *conf)
{
struct sshbuf *m = NULL, *inc = NULL;
struct include_item *item = NULL;
int r;
debug3_f("entering fd = %d config len %zu", fd,
sshbuf_len(conf));
if ((m = sshbuf_new()) == NULL || (inc = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
/* pack includes into a string */
TAILQ_FOREACH(item, &includes, entry) {
if ((r = sshbuf_put_cstring(inc, item->selector)) != 0 ||
(r = sshbuf_put_cstring(inc, item->filename)) != 0 ||
(r = sshbuf_put_stringb(inc, item->contents)) != 0)
fatal_fr(r, "compose includes");
}
/*
* Protocol from reexec master to child:
* string configuration
* string included_files[] {
* string selector
* string filename
* string contents
* }
* string rng_seed (if required)
*/
if ((r = sshbuf_put_stringb(m, conf)) != 0 ||
(r = sshbuf_put_stringb(m, inc)) != 0)
fatal_fr(r, "compose config");
#if defined(WITH_OPENSSL) && !defined(OPENSSL_PRNG_ONLY)
rexec_send_rng_seed(m);
#endif
if (ssh_msg_send(fd, 0, m) == -1)
error_f("ssh_msg_send failed");
sshbuf_free(m);
sshbuf_free(inc);
debug3_f("done");
}
static void
recv_rexec_state(int fd, struct sshbuf *conf)
{
struct sshbuf *m, *inc;
u_char *cp, ver;
size_t len;
int r;
struct include_item *item;
debug3_f("entering fd = %d", fd);
if ((m = sshbuf_new()) == NULL || (inc = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if (ssh_msg_recv(fd, m) == -1)
fatal_f("ssh_msg_recv failed");
if ((r = sshbuf_get_u8(m, &ver)) != 0)
fatal_fr(r, "parse version");
if (ver != 0)
fatal_f("rexec version mismatch");
if ((r = sshbuf_get_string(m, &cp, &len)) != 0 ||
(r = sshbuf_get_stringb(m, inc)) != 0)
fatal_fr(r, "parse config");
#if defined(WITH_OPENSSL) && !defined(OPENSSL_PRNG_ONLY)
rexec_recv_rng_seed(m);
#endif
if (conf != NULL && (r = sshbuf_put(conf, cp, len)))
fatal_fr(r, "sshbuf_put");
while (sshbuf_len(inc) != 0) {
item = xcalloc(1, sizeof(*item));
if ((item->contents = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((r = sshbuf_get_cstring(inc, &item->selector, NULL)) != 0 ||
(r = sshbuf_get_cstring(inc, &item->filename, NULL)) != 0 ||
(r = sshbuf_get_stringb(inc, item->contents)) != 0)
fatal_fr(r, "parse includes");
TAILQ_INSERT_TAIL(&includes, item, entry);
}
free(cp);
sshbuf_free(m);
debug3_f("done");
}
/* Accept a connection from inetd */
static void
server_accept_inetd(int *sock_in, int *sock_out)
{
if (rexeced_flag) {
close(REEXEC_CONFIG_PASS_FD);
*sock_in = *sock_out = dup(STDIN_FILENO);
} else {
*sock_in = dup(STDIN_FILENO);
*sock_out = dup(STDOUT_FILENO);
}
/*
* We intentionally do not close the descriptors 0, 1, and 2
* as our code for setting the descriptors won't work if
* ttyfd happens to be one of those.
*/
if (stdfd_devnull(1, 1, !log_stderr) == -1)
error_f("stdfd_devnull failed");
debug("inetd sockets after dupping: %d, %d", *sock_in, *sock_out);
}
/*
* Listen for TCP connections
*/
static void
listen_on_addrs(struct listenaddr *la)
{
int ret, listen_sock;
struct addrinfo *ai;
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
for (ai = la->addrs; ai; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
continue;
if (num_listen_socks >= MAX_LISTEN_SOCKS)
fatal("Too many listen sockets. "
"Enlarge MAX_LISTEN_SOCKS");
if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen,
ntop, sizeof(ntop), strport, sizeof(strport),
NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
error("getnameinfo failed: %.100s",
ssh_gai_strerror(ret));
continue;
}
/* Create socket for listening. */
listen_sock = socket(ai->ai_family, ai->ai_socktype,
ai->ai_protocol);
if (listen_sock == -1) {
/* kernel may not support ipv6 */
verbose("socket: %.100s", strerror(errno));
continue;
}
if (set_nonblock(listen_sock) == -1) {
close(listen_sock);
continue;
}
if (fcntl(listen_sock, F_SETFD, FD_CLOEXEC) == -1) {
verbose("socket: CLOEXEC: %s", strerror(errno));
close(listen_sock);
continue;
}
/* Socket options */
set_reuseaddr(listen_sock);
if (la->rdomain != NULL &&
set_rdomain(listen_sock, la->rdomain) == -1) {
close(listen_sock);
continue;
}
/* Only communicate in IPv6 over AF_INET6 sockets. */
if (ai->ai_family == AF_INET6)
sock_set_v6only(listen_sock);
debug("Bind to port %s on %s.", strport, ntop);
/* Bind the socket to the desired port. */
if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) == -1) {
error("Bind to port %s on %s failed: %.200s.",
strport, ntop, strerror(errno));
close(listen_sock);
continue;
}
listen_socks[num_listen_socks] = listen_sock;
num_listen_socks++;
/* Start listening on the port. */
if (listen(listen_sock, SSH_LISTEN_BACKLOG) == -1)
fatal("listen on [%s]:%s: %.100s",
ntop, strport, strerror(errno));
logit("Server listening on %s port %s%s%s.",
ntop, strport,
la->rdomain == NULL ? "" : " rdomain ",
la->rdomain == NULL ? "" : la->rdomain);
}
}
static void
server_listen(void)
{
u_int i;
/* Initialise per-source limit tracking. */
srclimit_init(options.max_startups, options.per_source_max_startups,
options.per_source_masklen_ipv4, options.per_source_masklen_ipv6);
for (i = 0; i < options.num_listen_addrs; i++) {
listen_on_addrs(&options.listen_addrs[i]);
freeaddrinfo(options.listen_addrs[i].addrs);
free(options.listen_addrs[i].rdomain);
memset(&options.listen_addrs[i], 0,
sizeof(options.listen_addrs[i]));
}
free(options.listen_addrs);
options.listen_addrs = NULL;
options.num_listen_addrs = 0;
if (!num_listen_socks)
fatal("Cannot bind any address.");
}
/*
* The main TCP accept loop. Note that, for the non-debug case, returns
* from this function are in a forked subprocess.
*/
static void
server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
{
fd_set *fdset;
int i, j, ret, maxfd;
int ostartups = -1, startups = 0, listening = 0, lameduck = 0;
int startup_p[2] = { -1 , -1 };
char c = 0;
struct sockaddr_storage from;
socklen_t fromlen;
pid_t pid;
u_char rnd[256];
/* setup fd set for accept */
fdset = NULL;
maxfd = 0;
for (i = 0; i < num_listen_socks; i++)
if (listen_socks[i] > maxfd)
maxfd = listen_socks[i];
/* pipes connected to unauthenticated child sshd processes */
startup_pipes = xcalloc(options.max_startups, sizeof(int));
startup_flags = xcalloc(options.max_startups, sizeof(int));
for (i = 0; i < options.max_startups; i++)
startup_pipes[i] = -1;
/*
* Stay listening for connections until the system crashes or
* the daemon is killed with a signal.
*/
for (;;) {
if (ostartups != startups) {
setproctitle("%s [listener] %d of %d-%d startups",
listener_proctitle, startups,
options.max_startups_begin, options.max_startups);
ostartups = startups;
}
if (received_sighup) {
if (!lameduck) {
debug("Received SIGHUP; waiting for children");
close_listen_socks();
lameduck = 1;
}
if (listening <= 0)
sighup_restart();
}
free(fdset);
fdset = xcalloc(howmany(maxfd + 1, NFDBITS),
sizeof(fd_mask));
for (i = 0; i < num_listen_socks; i++)
FD_SET(listen_socks[i], fdset);
for (i = 0; i < options.max_startups; i++)
if (startup_pipes[i] != -1)
FD_SET(startup_pipes[i], fdset);
/* Wait in select until there is a connection. */
ret = select(maxfd+1, fdset, NULL, NULL, NULL);
if (ret == -1 && errno != EINTR)
error("select: %.100s", strerror(errno));
if (received_sigterm) {
logit("Received signal %d; terminating.",
(int) received_sigterm);
close_listen_socks();
if (options.pid_file != NULL)
unlink(options.pid_file);
exit(received_sigterm == SIGTERM ? 0 : 255);
}
if (ret == -1)
continue;
for (i = 0; i < options.max_startups; i++) {
if (startup_pipes[i] == -1 ||
!FD_ISSET(startup_pipes[i], fdset))
continue;
switch (read(startup_pipes[i], &c, sizeof(c))) {
case -1:
if (errno == EINTR || errno == EAGAIN)
continue;
if (errno != EPIPE) {
error_f("startup pipe %d (fd=%d): "
"read %s", i, startup_pipes[i],
strerror(errno));
}
/* FALLTHROUGH */
case 0:
/* child exited or completed auth */
close(startup_pipes[i]);
srclimit_done(startup_pipes[i]);
startup_pipes[i] = -1;
startups--;
if (startup_flags[i])
listening--;
break;
case 1:
/* child has finished preliminaries */
if (startup_flags[i]) {
listening--;
startup_flags[i] = 0;
}
break;
}
}
for (i = 0; i < num_listen_socks; i++) {
if (!FD_ISSET(listen_socks[i], fdset))
continue;
fromlen = sizeof(from);
*newsock = accept(listen_socks[i],
(struct sockaddr *)&from, &fromlen);
if (*newsock == -1) {
if (errno != EINTR && errno != EWOULDBLOCK &&
errno != ECONNABORTED && errno != EAGAIN)
error("accept: %.100s",
strerror(errno));
if (errno == EMFILE || errno == ENFILE)
usleep(100 * 1000);
continue;
}
if (unset_nonblock(*newsock) == -1 ||
pipe(startup_p) == -1)
continue;
if (drop_connection(*newsock, startups, startup_p[0])) {
close(*newsock);
close(startup_p[0]);
close(startup_p[1]);
continue;
}
if (rexec_flag && socketpair(AF_UNIX,
SOCK_STREAM, 0, config_s) == -1) {
error("reexec socketpair: %s",
strerror(errno));
close(*newsock);
close(startup_p[0]);
close(startup_p[1]);
continue;
}
for (j = 0; j < options.max_startups; j++)
if (startup_pipes[j] == -1) {
startup_pipes[j] = startup_p[0];
if (maxfd < startup_p[0])
maxfd = startup_p[0];
startups++;
startup_flags[j] = 1;
break;
}
/*
* Got connection. Fork a child to handle it, unless
* we are in debugging mode.
*/
if (debug_flag) {
/*
* In debugging mode. Close the listening
* socket, and start processing the
* connection without forking.
*/
debug("Server will not fork when running in debugging mode.");
close_listen_socks();
*sock_in = *newsock;
*sock_out = *newsock;
close(startup_p[0]);
close(startup_p[1]);
startup_pipe = -1;
pid = getpid();
if (rexec_flag) {
send_rexec_state(config_s[0], cfg);
close(config_s[0]);
}
return;
}
/*
* Normal production daemon. Fork, and have
* the child process the connection. The
* parent continues listening.
*/
platform_pre_fork();
listening++;
if ((pid = fork()) == 0) {
/*
* Child. Close the listening and
* max_startup sockets. Start using
* the accepted socket. Reinitialize
* logging (since our pid has changed).
* We return from this function to handle
* the connection.
*/
platform_post_fork_child();
startup_pipe = startup_p[1];
close_startup_pipes();
close_listen_socks();
*sock_in = *newsock;
*sock_out = *newsock;
log_init(__progname,
options.log_level,
options.log_facility,
log_stderr);
if (rexec_flag)
close(config_s[0]);
else {
/*
* Signal parent that the preliminaries
* for this child are complete. For the
* re-exec case, this happens after the
* child has received the rexec state
* from the server.
*/
(void)atomicio(vwrite, startup_pipe,
"\0", 1);
}
return;
}
/* Parent. Stay in the loop. */
platform_post_fork_parent(pid);
if (pid == -1)
error("fork: %.100s", strerror(errno));
else
debug("Forked child %ld.", (long)pid);
close(startup_p[1]);
if (rexec_flag) {
close(config_s[1]);
send_rexec_state(config_s[0], cfg);
close(config_s[0]);
}
close(*newsock);
/*
* Ensure that our random state differs
* from that of the child
*/
arc4random_stir();
arc4random_buf(rnd, sizeof(rnd));
#ifdef WITH_OPENSSL
RAND_seed(rnd, sizeof(rnd));
if ((RAND_bytes((u_char *)rnd, 1)) != 1)
fatal("%s: RAND_bytes failed", __func__);
#endif
explicit_bzero(rnd, sizeof(rnd));
}
}
}
/*
* If IP options are supported, make sure there are none (log and
* return an error if any are found). Basically we are worried about
* source routing; it can be used to pretend you are somebody
* (ip-address) you are not. That itself may be "almost acceptable"
* under certain circumstances, but rhosts authentication is useless
* if source routing is accepted. Notice also that if we just dropped
* source routing here, the other side could use IP spoofing to do
* rest of the interaction and could still bypass security. So we
* exit here if we detect any IP options.
*/
static void
check_ip_options(struct ssh *ssh)
{
#ifdef IP_OPTIONS
int sock_in = ssh_packet_get_connection_in(ssh);
struct sockaddr_storage from;
u_char opts[200];
socklen_t i, option_size = sizeof(opts), fromlen = sizeof(from);
char text[sizeof(opts) * 3 + 1];
memset(&from, 0, sizeof(from));
if (getpeername(sock_in, (struct sockaddr *)&from,
&fromlen) == -1)
return;
if (from.ss_family != AF_INET)
return;
/* XXX IPv6 options? */
if (getsockopt(sock_in, IPPROTO_IP, IP_OPTIONS, opts,
&option_size) >= 0 && option_size != 0) {
text[0] = '\0';
for (i = 0; i < option_size; i++)
snprintf(text + i*3, sizeof(text) - i*3,
" %2.2x", opts[i]);
fatal("Connection from %.100s port %d with IP opts: %.800s",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), text);
}
return;
#endif /* IP_OPTIONS */
}
/* Set the routing domain for this process */
static void
set_process_rdomain(struct ssh *ssh, const char *name)
{
#if defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
if (name == NULL)
return; /* default */
if (strcmp(name, "%D") == 0) {
/* "expands" to routing domain of connection */
if ((name = ssh_packet_rdomain_in(ssh)) == NULL)
return;
}
/* NB. We don't pass 'ssh' to sys_set_process_rdomain() */
return sys_set_process_rdomain(name);
#elif defined(__OpenBSD__)
int rtable, ortable = getrtable();
const char *errstr;
if (name == NULL)
return; /* default */
if (strcmp(name, "%D") == 0) {
/* "expands" to routing domain of connection */
if ((name = ssh_packet_rdomain_in(ssh)) == NULL)
return;
}
rtable = (int)strtonum(name, 0, 255, &errstr);
if (errstr != NULL) /* Shouldn't happen */
fatal("Invalid routing domain \"%s\": %s", name, errstr);
if (rtable != ortable && setrtable(rtable) != 0)
fatal("Unable to set routing domain %d: %s",
rtable, strerror(errno));
debug_f("set routing domain %d (was %d)", rtable, ortable);
#else /* defined(__OpenBSD__) */
fatal("Unable to set routing domain: not supported in this platform");
#endif
}
static void
accumulate_host_timing_secret(struct sshbuf *server_cfg,
struct sshkey *key)
{
static struct ssh_digest_ctx *ctx;
u_char *hash;
size_t len;
struct sshbuf *buf;
int r;
if (ctx == NULL && (ctx = ssh_digest_start(SSH_DIGEST_SHA512)) == NULL)
fatal_f("ssh_digest_start");
if (key == NULL) { /* finalize */
/* add server config in case we are using agent for host keys */
if (ssh_digest_update(ctx, sshbuf_ptr(server_cfg),
sshbuf_len(server_cfg)) != 0)
fatal_f("ssh_digest_update");
len = ssh_digest_bytes(SSH_DIGEST_SHA512);
hash = xmalloc(len);
if (ssh_digest_final(ctx, hash, len) != 0)
fatal_f("ssh_digest_final");
options.timing_secret = PEEK_U64(hash);
freezero(hash, len);
ssh_digest_free(ctx);
ctx = NULL;
return;
}
if ((buf = sshbuf_new()) == NULL)
fatal_f("could not allocate buffer");
if ((r = sshkey_private_serialize(key, buf)) != 0)
fatal_fr(r, "decode key");
if (ssh_digest_update(ctx, sshbuf_ptr(buf), sshbuf_len(buf)) != 0)
fatal_f("ssh_digest_update");
sshbuf_reset(buf);
sshbuf_free(buf);
}
static char *
prepare_proctitle(int ac, char **av)
{
char *ret = NULL;
int i;
for (i = 0; i < ac; i++)
xextendf(&ret, " ", "%s", av[i]);
return ret;
}
/*
* Main program for the daemon.
*/
int
main(int ac, char **av)
{
struct ssh *ssh = NULL;
extern char *optarg;
extern int optind;
int r, opt, on = 1, already_daemon, remote_port;
int sock_in = -1, sock_out = -1, newsock = -1;
const char *remote_ip, *rdomain;
char *fp, *line, *laddr, *logfile = NULL;
int config_s[2] = { -1 , -1 };
u_int i, j;
u_int64_t ibytes, obytes;
mode_t new_umask;
struct sshkey *key;
struct sshkey *pubkey;
int keytype;
Authctxt *authctxt;
struct connection_info *connection_info = NULL;
#ifdef HAVE_SECUREWARE
(void)set_auth_parameters(ac, av);
#endif
__progname = ssh_get_progname(av[0]);
/* Save argv. Duplicate so setproctitle emulation doesn't clobber it */
saved_argc = ac;
rexec_argc = ac;
saved_argv = xcalloc(ac + 1, sizeof(*saved_argv));
for (i = 0; (int)i < ac; i++)
saved_argv[i] = xstrdup(av[i]);
saved_argv[i] = NULL;
#ifndef HAVE_SETPROCTITLE
/* Prepare for later setproctitle emulation */
compat_init_setproctitle(ac, av);
av = saved_argv;
#endif
if (geteuid() == 0 && setgroups(0, NULL) == -1)
debug("setgroups(): %.200s", strerror(errno));
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
sanitise_stdfd();
seed_rng();
/* Initialize configuration options to their default values. */
initialize_server_options(&options);
/* Parse command-line arguments. */
while ((opt = getopt(ac, av,
"C:E:b:c:f:g:h:k:o:p:u:46DQRTdeiqrt")) != -1) {
switch (opt) {
case '4':
options.address_family = AF_INET;
break;
case '6':
options.address_family = AF_INET6;
break;
case 'f':
config_file_name = optarg;
break;
case 'c':
servconf_add_hostcert("[command-line]", 0,
&options, optarg);
break;
case 'd':
if (debug_flag == 0) {
debug_flag = 1;
options.log_level = SYSLOG_LEVEL_DEBUG1;
} else if (options.log_level < SYSLOG_LEVEL_DEBUG3)
options.log_level++;
break;
case 'D':
no_daemon_flag = 1;
break;
case 'E':
logfile = optarg;
/* FALLTHROUGH */
case 'e':
log_stderr = 1;
break;
case 'i':
inetd_flag = 1;
break;
case 'r':
rexec_flag = 0;
break;
case 'R':
rexeced_flag = 1;
inetd_flag = 1;
break;
case 'Q':
/* ignored */
break;
case 'q':
options.log_level = SYSLOG_LEVEL_QUIET;
break;
case 'b':
/* protocol 1, ignored */
break;
case 'p':
options.ports_from_cmdline = 1;
if (options.num_ports >= MAX_PORTS) {
fprintf(stderr, "too many ports.\n");
exit(1);
}
options.ports[options.num_ports++] = a2port(optarg);
if (options.ports[options.num_ports-1] <= 0) {
fprintf(stderr, "Bad port number.\n");
exit(1);
}
break;
case 'g':
if ((options.login_grace_time = convtime(optarg)) == -1) {
fprintf(stderr, "Invalid login grace time.\n");
exit(1);
}
break;
case 'k':
/* protocol 1, ignored */
break;
case 'h':
servconf_add_hostkey("[command-line]", 0,
&options, optarg, 1);
break;
case 't':
test_flag = 1;
break;
case 'T':
test_flag = 2;
break;
case 'C':
connection_info = get_connection_info(ssh, 0, 0);
if (parse_server_match_testspec(connection_info,
optarg) == -1)
exit(1);
break;
case 'u':
utmp_len = (u_int)strtonum(optarg, 0, HOST_NAME_MAX+1+1, NULL);
if (utmp_len > HOST_NAME_MAX+1) {
fprintf(stderr, "Invalid utmp length.\n");
exit(1);
}
break;
case 'o':
line = xstrdup(optarg);
if (process_server_config_line(&options, line,
"command-line", 0, NULL, NULL, &includes) != 0)
exit(1);
free(line);
break;
case '?':
default:
usage();
break;
}
}
if (rexeced_flag || inetd_flag)
rexec_flag = 0;
if (!test_flag && rexec_flag && !path_absolute(av[0]))
fatal("sshd re-exec requires execution with an absolute path");
if (rexeced_flag)
closefrom(REEXEC_MIN_FREE_FD);
else
closefrom(REEXEC_DEVCRYPTO_RESERVED_FD);
/* If requested, redirect the logs to the specified logfile. */
if (logfile != NULL)
log_redirect_stderr_to(logfile);
/*
* Force logging to stderr until we have loaded the private host
* key (unless started from inetd)
*/
log_init(__progname,
options.log_level == SYSLOG_LEVEL_NOT_SET ?
SYSLOG_LEVEL_INFO : options.log_level,
options.log_facility == SYSLOG_FACILITY_NOT_SET ?
SYSLOG_FACILITY_AUTH : options.log_facility,
log_stderr || !inetd_flag || debug_flag);
/*
* Unset KRB5CCNAME, otherwise the user's session may inherit it from
* root's environment
*/
if (getenv("KRB5CCNAME") != NULL)
(void) unsetenv("KRB5CCNAME");
sensitive_data.have_ssh2_key = 0;
/*
* If we're not doing an extended test do not silently ignore connection
* test params.
*/
if (test_flag < 2 && connection_info != NULL)
fatal("Config test connection parameter (-C) provided without "
- "test mode (-T)");
+ "test mode (-T)");
/* Fetch our configuration */
if ((cfg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if (rexeced_flag) {
setproctitle("%s", "[rexeced]");
recv_rexec_state(REEXEC_CONFIG_PASS_FD, cfg);
if (!debug_flag) {
startup_pipe = dup(REEXEC_STARTUP_PIPE_FD);
close(REEXEC_STARTUP_PIPE_FD);
/*
* Signal parent that this child is at a point where
* they can go away if they have a SIGHUP pending.
*/
(void)atomicio(vwrite, startup_pipe, "\0", 1);
}
} else if (strcasecmp(config_file_name, "none") != 0)
load_server_config(config_file_name, cfg);
parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name,
cfg, &includes, NULL);
+#ifdef WITH_OPENSSL
+ if (options.moduli_file != NULL)
+ dh_set_moduli_file(options.moduli_file);
+#endif
+
/* Fill in default values for those options not explicitly set. */
fill_default_server_options(&options);
/* challenge-response is implemented via keyboard interactive */
if (options.challenge_response_authentication)
options.kbd_interactive_authentication = 1;
/* Check that options are sensible */
if (options.authorized_keys_command_user == NULL &&
(options.authorized_keys_command != NULL &&
strcasecmp(options.authorized_keys_command, "none") != 0))
fatal("AuthorizedKeysCommand set without "
"AuthorizedKeysCommandUser");
if (options.authorized_principals_command_user == NULL &&
(options.authorized_principals_command != NULL &&
strcasecmp(options.authorized_principals_command, "none") != 0))
fatal("AuthorizedPrincipalsCommand set without "
"AuthorizedPrincipalsCommandUser");
/*
* Check whether there is any path through configured auth methods.
* Unfortunately it is not possible to verify this generally before
* daemonisation in the presence of Match block, but this catches
* and warns for trivial misconfigurations that could break login.
*/
if (options.num_auth_methods != 0) {
for (i = 0; i < options.num_auth_methods; i++) {
if (auth2_methods_valid(options.auth_methods[i],
1) == 0)
break;
}
if (i >= options.num_auth_methods)
fatal("AuthenticationMethods cannot be satisfied by "
"enabled authentication methods");
}
/* Check that there are no remaining arguments. */
if (optind < ac) {
fprintf(stderr, "Extra argument %s.\n", av[optind]);
exit(1);
}
debug("sshd version %s, %s", SSH_VERSION, SSH_OPENSSL_VERSION);
/* Store privilege separation user for later use if required. */
privsep_chroot = use_privsep && (getuid() == 0 || geteuid() == 0);
if ((privsep_pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) {
if (privsep_chroot || options.kerberos_authentication)
fatal("Privilege separation user %s does not exist",
SSH_PRIVSEP_USER);
} else {
privsep_pw = pwcopy(privsep_pw);
freezero(privsep_pw->pw_passwd, strlen(privsep_pw->pw_passwd));
privsep_pw->pw_passwd = xstrdup("*");
}
endpwent();
/* load host keys */
sensitive_data.host_keys = xcalloc(options.num_host_key_files,
sizeof(struct sshkey *));
sensitive_data.host_pubkeys = xcalloc(options.num_host_key_files,
sizeof(struct sshkey *));
if (options.host_key_agent) {
if (strcmp(options.host_key_agent, SSH_AUTHSOCKET_ENV_NAME))
setenv(SSH_AUTHSOCKET_ENV_NAME,
options.host_key_agent, 1);
if ((r = ssh_get_authentication_socket(NULL)) == 0)
have_agent = 1;
else
error_r(r, "Could not connect to agent \"%s\"",
options.host_key_agent);
}
for (i = 0; i < options.num_host_key_files; i++) {
int ll = options.host_key_file_userprovided[i] ?
SYSLOG_LEVEL_ERROR : SYSLOG_LEVEL_DEBUG1;
if (options.host_key_files[i] == NULL)
continue;
if ((r = sshkey_load_private(options.host_key_files[i], "",
&key, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR)
do_log2_r(r, ll, "Unable to load host key \"%s\"",
options.host_key_files[i]);
if (sshkey_is_sk(key) &&
key->sk_flags & SSH_SK_USER_PRESENCE_REQD) {
debug("host key %s requires user presence, ignoring",
options.host_key_files[i]);
key->sk_flags &= ~SSH_SK_USER_PRESENCE_REQD;
}
if (r == 0 && key != NULL &&
(r = sshkey_shield_private(key)) != 0) {
do_log2_r(r, ll, "Unable to shield host key \"%s\"",
options.host_key_files[i]);
sshkey_free(key);
key = NULL;
}
if ((r = sshkey_load_public(options.host_key_files[i],
&pubkey, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR)
do_log2_r(r, ll, "Unable to load host key \"%s\"",
options.host_key_files[i]);
if (pubkey != NULL && key != NULL) {
if (!sshkey_equal(pubkey, key)) {
error("Public key for %s does not match "
"private key", options.host_key_files[i]);
sshkey_free(pubkey);
pubkey = NULL;
}
}
if (pubkey == NULL && key != NULL) {
if ((r = sshkey_from_private(key, &pubkey)) != 0)
fatal_r(r, "Could not demote key: \"%s\"",
options.host_key_files[i]);
}
sensitive_data.host_keys[i] = key;
sensitive_data.host_pubkeys[i] = pubkey;
if (key == NULL && pubkey != NULL && have_agent) {
debug("will rely on agent for hostkey %s",
options.host_key_files[i]);
keytype = pubkey->type;
} else if (key != NULL) {
keytype = key->type;
accumulate_host_timing_secret(cfg, key);
} else {
do_log2(ll, "Unable to load host key: %s",
options.host_key_files[i]);
sensitive_data.host_keys[i] = NULL;
sensitive_data.host_pubkeys[i] = NULL;
continue;
}
switch (keytype) {
case KEY_RSA:
case KEY_DSA:
case KEY_ECDSA:
case KEY_ED25519:
case KEY_ECDSA_SK:
case KEY_ED25519_SK:
case KEY_XMSS:
if (have_agent || key != NULL)
sensitive_data.have_ssh2_key = 1;
break;
}
if ((fp = sshkey_fingerprint(pubkey, options.fingerprint_hash,
SSH_FP_DEFAULT)) == NULL)
fatal("sshkey_fingerprint failed");
debug("%s host key #%d: %s %s",
key ? "private" : "agent", i, sshkey_ssh_name(pubkey), fp);
free(fp);
}
accumulate_host_timing_secret(cfg, NULL);
if (!sensitive_data.have_ssh2_key) {
logit("sshd: no hostkeys available -- exiting.");
exit(1);
}
/*
* Load certificates. They are stored in an array at identical
* indices to the public keys that they relate to.
*/
sensitive_data.host_certificates = xcalloc(options.num_host_key_files,
sizeof(struct sshkey *));
for (i = 0; i < options.num_host_key_files; i++)
sensitive_data.host_certificates[i] = NULL;
for (i = 0; i < options.num_host_cert_files; i++) {
if (options.host_cert_files[i] == NULL)
continue;
if ((r = sshkey_load_public(options.host_cert_files[i],
&key, NULL)) != 0) {
error_r(r, "Could not load host certificate \"%s\"",
options.host_cert_files[i]);
continue;
}
if (!sshkey_is_cert(key)) {
error("Certificate file is not a certificate: %s",
options.host_cert_files[i]);
sshkey_free(key);
continue;
}
/* Find matching private key */
for (j = 0; j < options.num_host_key_files; j++) {
if (sshkey_equal_public(key,
sensitive_data.host_keys[j])) {
sensitive_data.host_certificates[j] = key;
break;
}
}
if (j >= options.num_host_key_files) {
error("No matching private key for certificate: %s",
options.host_cert_files[i]);
sshkey_free(key);
continue;
}
sensitive_data.host_certificates[j] = key;
debug("host certificate: #%u type %d %s", j, key->type,
sshkey_type(key));
}
if (privsep_chroot) {
struct stat st;
if ((stat(_PATH_PRIVSEP_CHROOT_DIR, &st) == -1) ||
(S_ISDIR(st.st_mode) == 0))
fatal("Missing privilege separation directory: %s",
_PATH_PRIVSEP_CHROOT_DIR);
#ifdef HAVE_CYGWIN
if (check_ntsec(_PATH_PRIVSEP_CHROOT_DIR) &&
(st.st_uid != getuid () ||
(st.st_mode & (S_IWGRP|S_IWOTH)) != 0))
#else
if (st.st_uid != 0 || (st.st_mode & (S_IWGRP|S_IWOTH)) != 0)
#endif
fatal("%s must be owned by root and not group or "
"world-writable.", _PATH_PRIVSEP_CHROOT_DIR);
}
if (test_flag > 1) {
/*
* If no connection info was provided by -C then use
* use a blank one that will cause no predicate to match.
*/
if (connection_info == NULL)
connection_info = get_connection_info(ssh, 0, 0);
connection_info->test = 1;
parse_server_match_config(&options, &includes, connection_info);
dump_config(&options);
}
/* Configuration looks good, so exit if in test mode. */
if (test_flag)
exit(0);
/*
* Clear out any supplemental groups we may have inherited. This
* prevents inadvertent creation of files with bad modes (in the
* portable version at least, it's certainly possible for PAM
* to create a file, and we can't control the code in every
* module which might be used).
*/
if (setgroups(0, NULL) < 0)
debug("setgroups() failed: %.200s", strerror(errno));
if (rexec_flag) {
if (rexec_argc < 0)
fatal("rexec_argc %d < 0", rexec_argc);
rexec_argv = xcalloc(rexec_argc + 2, sizeof(char *));
for (i = 0; i < (u_int)rexec_argc; i++) {
debug("rexec_argv[%d]='%s'", i, saved_argv[i]);
rexec_argv[i] = saved_argv[i];
}
rexec_argv[rexec_argc] = "-R";
rexec_argv[rexec_argc + 1] = NULL;
}
listener_proctitle = prepare_proctitle(ac, av);
/* Ensure that umask disallows at least group and world write */
new_umask = umask(0077) | 0022;
(void) umask(new_umask);
/* Initialize the log (it is reinitialized below in case we forked). */
if (debug_flag && (!inetd_flag || rexeced_flag))
log_stderr = 1;
log_init(__progname, options.log_level,
options.log_facility, log_stderr);
for (i = 0; i < options.num_log_verbose; i++)
log_verbose_add(options.log_verbose[i]);
/*
* If not in debugging mode, not started from inetd and not already
* daemonized (eg re-exec via SIGHUP), disconnect from the controlling
* terminal, and fork. The original process exits.
*/
already_daemon = daemonized();
if (!(debug_flag || inetd_flag || no_daemon_flag || already_daemon)) {
if (daemon(0, 0) == -1)
fatal("daemon() failed: %.200s", strerror(errno));
disconnect_controlling_tty();
}
/* Reinitialize the log (because of the fork above). */
log_init(__progname, options.log_level, options.log_facility, log_stderr);
- /* Chdir to the root directory so that the current disk can be
- unmounted if desired. */
+ /*
+ * Chdir to the root directory so that the current disk can be
+ * unmounted if desired.
+ */
if (chdir("/") == -1)
error("chdir(\"/\"): %s", strerror(errno));
/* ignore SIGPIPE */
ssh_signal(SIGPIPE, SIG_IGN);
/* Get a connection, either from inetd or a listening TCP socket */
if (inetd_flag) {
server_accept_inetd(&sock_in, &sock_out);
} else {
platform_pre_listen();
server_listen();
ssh_signal(SIGHUP, sighup_handler);
ssh_signal(SIGCHLD, main_sigchld_handler);
ssh_signal(SIGTERM, sigterm_handler);
ssh_signal(SIGQUIT, sigterm_handler);
/*
* Write out the pid file after the sigterm handler
* is setup and the listen sockets are bound
*/
if (options.pid_file != NULL && !debug_flag) {
FILE *f = fopen(options.pid_file, "w");
if (f == NULL) {
error("Couldn't create pid file \"%s\": %s",
options.pid_file, strerror(errno));
} else {
fprintf(f, "%ld\n", (long) getpid());
fclose(f);
}
}
/* Accept a connection and return in a forked child */
server_accept_loop(&sock_in, &sock_out,
&newsock, config_s);
}
/* This is the child processing a new connection. */
setproctitle("%s", "[accepted]");
/*
* Create a new session and process group since the 4.4BSD
* setlogin() affects the entire process group. We don't
* want the child to be able to affect the parent.
*/
#if !defined(SSHD_ACQUIRES_CTTY)
/*
* If setsid is called, on some platforms sshd will later acquire a
* controlling terminal which will result in "could not set
* controlling tty" errors.
*/
if (!debug_flag && !inetd_flag && setsid() == -1)
error("setsid: %.100s", strerror(errno));
#endif
if (rexec_flag) {
debug("rexec start in %d out %d newsock %d pipe %d sock %d",
sock_in, sock_out, newsock, startup_pipe, config_s[0]);
dup2(newsock, STDIN_FILENO);
dup2(STDIN_FILENO, STDOUT_FILENO);
if (startup_pipe == -1)
close(REEXEC_STARTUP_PIPE_FD);
else if (startup_pipe != REEXEC_STARTUP_PIPE_FD) {
dup2(startup_pipe, REEXEC_STARTUP_PIPE_FD);
close(startup_pipe);
startup_pipe = REEXEC_STARTUP_PIPE_FD;
}
dup2(config_s[1], REEXEC_CONFIG_PASS_FD);
close(config_s[1]);
ssh_signal(SIGHUP, SIG_IGN); /* avoid reset to SIG_DFL */
execv(rexec_argv[0], rexec_argv);
/* Reexec has failed, fall back and continue */
error("rexec of %s failed: %s", rexec_argv[0], strerror(errno));
recv_rexec_state(REEXEC_CONFIG_PASS_FD, NULL);
log_init(__progname, options.log_level,
options.log_facility, log_stderr);
/* Clean up fds */
close(REEXEC_CONFIG_PASS_FD);
newsock = sock_out = sock_in = dup(STDIN_FILENO);
if (stdfd_devnull(1, 1, 0) == -1)
error_f("stdfd_devnull failed");
debug("rexec cleanup in %d out %d newsock %d pipe %d sock %d",
sock_in, sock_out, newsock, startup_pipe, config_s[0]);
}
/* Executed child processes don't need these. */
fcntl(sock_out, F_SETFD, FD_CLOEXEC);
fcntl(sock_in, F_SETFD, FD_CLOEXEC);
/* We will not restart on SIGHUP since it no longer makes sense. */
ssh_signal(SIGALRM, SIG_DFL);
ssh_signal(SIGHUP, SIG_DFL);
ssh_signal(SIGTERM, SIG_DFL);
ssh_signal(SIGQUIT, SIG_DFL);
ssh_signal(SIGCHLD, SIG_DFL);
ssh_signal(SIGINT, SIG_DFL);
/*
* Register our connection. This turns encryption off because we do
* not have a key.
*/
if ((ssh = ssh_packet_set_connection(NULL, sock_in, sock_out)) == NULL)
fatal("Unable to create connection");
the_active_state = ssh;
ssh_packet_set_server(ssh);
check_ip_options(ssh);
/* Prepare the channels layer */
channel_init_channels(ssh);
channel_set_af(ssh, options.address_family);
process_permitopen(ssh, &options);
/* Set SO_KEEPALIVE if requested. */
if (options.tcp_keep_alive && ssh_packet_connection_is_on_socket(ssh) &&
setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1)
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
if ((remote_port = ssh_remote_port(ssh)) < 0) {
debug("ssh_remote_port failed");
cleanup_exit(255);
}
if (options.routing_domain != NULL)
set_process_rdomain(ssh, options.routing_domain);
/*
* The rest of the code depends on the fact that
* ssh_remote_ipaddr() caches the remote ip, even if
* the socket goes away.
*/
remote_ip = ssh_remote_ipaddr(ssh);
#ifdef SSH_AUDIT_EVENTS
audit_connection_from(remote_ip, remote_port);
#endif
rdomain = ssh_packet_rdomain_in(ssh);
/* Log the connection. */
laddr = get_local_ipaddr(sock_in);
verbose("Connection from %s port %d on %s port %d%s%s%s",
remote_ip, remote_port, laddr, ssh_local_port(ssh),
rdomain == NULL ? "" : " rdomain \"",
rdomain == NULL ? "" : rdomain,
rdomain == NULL ? "" : "\"");
free(laddr);
/*
* We don't want to listen forever unless the other side
* successfully authenticates itself. So we set up an alarm which is
* cleared after successful authentication. A limit of zero
* indicates no limit. Note that we don't set the alarm in debugging
* mode; it is just annoying to have the server exit just when you
* are about to discover the bug.
*/
ssh_signal(SIGALRM, grace_alarm_handler);
if (!debug_flag)
alarm(options.login_grace_time);
if ((r = kex_exchange_identification(ssh, -1,
options.version_addendum)) != 0)
sshpkt_fatal(ssh, r, "banner exchange");
ssh_packet_set_nonblocking(ssh);
/* allocate authentication context */
authctxt = xcalloc(1, sizeof(*authctxt));
ssh->authctxt = authctxt;
authctxt->loginmsg = loginmsg;
/* XXX global for cleanup, access from other modules */
the_authctxt = authctxt;
/* Set default key authentication options */
if ((auth_opts = sshauthopt_new_with_keys_defaults()) == NULL)
fatal("allocation failed");
/* prepare buffer to collect messages to display to user after login */
if ((loginmsg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
auth_debug_reset();
if (use_privsep) {
if (privsep_preauth(ssh) == 1)
goto authenticated;
} else if (have_agent) {
if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) {
error_r(r, "Unable to get agent socket");
have_agent = 0;
}
}
/* perform the key exchange */
/* authenticate user and start session */
do_ssh2_kex(ssh);
do_authentication2(ssh);
/*
* If we use privilege separation, the unprivileged child transfers
* the current keystate and exits
*/
if (use_privsep) {
mm_send_keystate(ssh, pmonitor);
ssh_packet_clear_keys(ssh);
exit(0);
}
authenticated:
/*
* Cancel the alarm we set to limit the time taken for
* authentication.
*/
alarm(0);
ssh_signal(SIGALRM, SIG_DFL);
authctxt->authenticated = 1;
if (startup_pipe != -1) {
close(startup_pipe);
startup_pipe = -1;
}
#ifdef SSH_AUDIT_EVENTS
audit_event(ssh, SSH_AUTH_SUCCESS);
#endif
#ifdef GSSAPI
if (options.gss_authentication) {
temporarily_use_uid(authctxt->pw);
ssh_gssapi_storecreds();
restore_uid();
}
#endif
#ifdef USE_PAM
if (options.use_pam) {
do_pam_setcred(1);
do_pam_session(ssh);
}
#endif
/*
* In privilege separation, we fork another child and prepare
* file descriptor passing.
*/
if (use_privsep) {
privsep_postauth(ssh, authctxt);
/* the monitor process [priv] will not return */
}
ssh_packet_set_timeout(ssh, options.client_alive_interval,
options.client_alive_count_max);
/* Try to send all our hostkeys to the client */
notify_hostkeys(ssh);
/* Start session. */
do_authenticated(ssh, authctxt);
/* The connection has been terminated. */
ssh_packet_get_bytes(ssh, &ibytes, &obytes);
verbose("Transferred: sent %llu, received %llu bytes",
(unsigned long long)obytes, (unsigned long long)ibytes);
verbose("Closing connection to %.500s port %d", remote_ip, remote_port);
#ifdef USE_PAM
if (options.use_pam)
finish_pam();
#endif /* USE_PAM */
#ifdef SSH_AUDIT_EVENTS
PRIVSEP(audit_event(ssh, SSH_CONNECTION_CLOSE));
#endif
ssh_packet_close(ssh);
if (use_privsep)
mm_terminate();
exit(0);
}
int
sshd_hostkey_sign(struct ssh *ssh, struct sshkey *privkey,
struct sshkey *pubkey, u_char **signature, size_t *slenp,
const u_char *data, size_t dlen, const char *alg)
{
int r;
if (use_privsep) {
if (privkey) {
if (mm_sshkey_sign(ssh, privkey, signature, slenp,
data, dlen, alg, options.sk_provider, NULL,
ssh->compat) < 0)
fatal_f("privkey sign failed");
} else {
if (mm_sshkey_sign(ssh, pubkey, signature, slenp,
data, dlen, alg, options.sk_provider, NULL,
ssh->compat) < 0)
fatal_f("pubkey sign failed");
}
} else {
if (privkey) {
if (sshkey_sign(privkey, signature, slenp, data, dlen,
alg, options.sk_provider, NULL, ssh->compat) < 0)
fatal_f("privkey sign failed");
} else {
if ((r = ssh_agent_sign(auth_sock, pubkey,
signature, slenp, data, dlen, alg,
ssh->compat)) != 0) {
fatal_fr(r, "agent sign failed");
}
}
}
return 0;
}
/* SSH2 key exchange */
static void
do_ssh2_kex(struct ssh *ssh)
{
char *myproposal[PROPOSAL_MAX] = { KEX_SERVER };
struct kex *kex;
int r;
myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(ssh,
options.kex_algorithms);
myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(ssh,
options.ciphers);
myproposal[PROPOSAL_ENC_ALGS_STOC] = compat_cipher_proposal(ssh,
options.ciphers);
myproposal[PROPOSAL_MAC_ALGS_CTOS] =
myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
if (options.compression == COMP_NONE) {
myproposal[PROPOSAL_COMP_ALGS_CTOS] =
myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
}
if (options.rekey_limit || options.rekey_interval)
ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
options.rekey_interval);
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal(
ssh, list_hostkey_types());
/* start key exchange */
if ((r = kex_setup(ssh, myproposal)) != 0)
fatal_r(r, "kex_setup");
kex = ssh->kex;
#ifdef WITH_OPENSSL
kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server;
kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server;
kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_server;
kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_server;
kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_server;
kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
# ifdef OPENSSL_HAS_ECC
kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
# endif
#endif
kex->kex[KEX_C25519_SHA256] = kex_gen_server;
kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server;
kex->load_host_public_key=&get_hostkey_public_by_type;
kex->load_host_private_key=&get_hostkey_private_by_type;
kex->host_key_index=&get_hostkey_index;
kex->sign = sshd_hostkey_sign;
ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &kex->done);
#ifdef DEBUG_KEXDH
/* send 1st encrypted/maced/compressed message */
if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 ||
(r = sshpkt_put_cstring(ssh, "markus")) != 0 ||
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
fatal_fr(r, "send test");
#endif
debug("KEX done");
}
/* server specific fatal cleanup */
void
cleanup_exit(int i)
{
if (the_active_state != NULL && the_authctxt != NULL) {
do_cleanup(the_active_state, the_authctxt);
if (use_privsep && privsep_is_preauth &&
pmonitor != NULL && pmonitor->m_pid > 1) {
debug("Killing privsep child %d", pmonitor->m_pid);
if (kill(pmonitor->m_pid, SIGKILL) != 0 &&
errno != ESRCH) {
error_f("kill(%d): %s", pmonitor->m_pid,
strerror(errno));
}
}
}
#ifdef SSH_AUDIT_EVENTS
/* done after do_cleanup so it can cancel the PAM auth 'thread' */
if (the_active_state != NULL && (!use_privsep || mm_is_monitor()))
audit_event(the_active_state, SSH_CONNECTION_ABANDON);
#endif
_exit(i);
}
diff --git a/sshd_config.0 b/sshd_config.0
index 750e569cd618..b947bc9b7f3e 100644
--- a/sshd_config.0
+++ b/sshd_config.0
@@ -1,1184 +1,1191 @@
SSHD_CONFIG(5) File Formats Manual SSHD_CONFIG(5)
NAME
sshd_config M-bM-^@M-^S OpenSSH daemon configuration file
DESCRIPTION
sshd(8) reads configuration data from /etc/ssh/sshd_config (or the file
specified with -f on the command line). The file contains keyword-
argument pairs, one per line. For each keyword, the first obtained value
will be used. Lines starting with M-bM-^@M-^X#M-bM-^@M-^Y and empty lines are interpreted as
comments. Arguments may optionally be enclosed in double quotes (") in
order to represent arguments containing spaces.
The possible keywords and their meanings are as follows (note that
keywords are case-insensitive and arguments are case-sensitive):
AcceptEnv
Specifies what environment variables sent by the client will be
copied into the session's environ(7). See SendEnv and SetEnv in
ssh_config(5) for how to configure the client. The TERM
environment variable is always accepted whenever the client
requests a pseudo-terminal as it is required by the protocol.
Variables are specified by name, which may contain the wildcard
characters M-bM-^@M-^X*M-bM-^@M-^Y and M-bM-^@M-^X?M-bM-^@M-^Y. Multiple environment variables may be
separated by whitespace or spread across multiple AcceptEnv
directives. Be warned that some environment variables could be
used to bypass restricted user environments. For this reason,
care should be taken in the use of this directive. The default
is not to accept any environment variables.
AddressFamily
Specifies which address family should be used by sshd(8). Valid
arguments are any (the default), inet (use IPv4 only), or inet6
(use IPv6 only).
AllowAgentForwarding
Specifies whether ssh-agent(1) forwarding is permitted. The
default is yes. Note that disabling agent forwarding does not
improve security unless users are also denied shell access, as
they can always install their own forwarders.
AllowGroups
This keyword can be followed by a list of group name patterns,
separated by spaces. If specified, login is allowed only for
users whose primary group or supplementary group list matches one
of the patterns. Only group names are valid; a numerical group
ID is not recognized. By default, login is allowed for all
groups. The allow/deny groups directives are processed in the
following order: DenyGroups, AllowGroups.
See PATTERNS in ssh_config(5) for more information on patterns.
AllowStreamLocalForwarding
Specifies whether StreamLocal (Unix-domain socket) forwarding is
permitted. The available options are yes (the default) or all to
allow StreamLocal forwarding, no to prevent all StreamLocal
forwarding, local to allow local (from the perspective of ssh(1))
forwarding only or remote to allow remote forwarding only. Note
that disabling StreamLocal forwarding does not improve security
unless users are also denied shell access, as they can always
install their own forwarders.
AllowTcpForwarding
Specifies whether TCP forwarding is permitted. The available
options are yes (the default) or all to allow TCP forwarding, no
to prevent all TCP forwarding, local to allow local (from the
perspective of ssh(1)) forwarding only or remote to allow remote
forwarding only. Note that disabling TCP forwarding does not
improve security unless users are also denied shell access, as
they can always install their own forwarders.
AllowUsers
This keyword can be followed by a list of user name patterns,
separated by spaces. If specified, login is allowed only for
user names that match one of the patterns. Only user names are
valid; a numerical user ID is not recognized. By default, login
is allowed for all users. If the pattern takes the form
USER@HOST then USER and HOST are separately checked, restricting
logins to particular users from particular hosts. HOST criteria
may additionally contain addresses to match in CIDR
address/masklen format. The allow/deny users directives are
processed in the following order: DenyUsers, AllowUsers.
See PATTERNS in ssh_config(5) for more information on patterns.
AuthenticationMethods
Specifies the authentication methods that must be successfully
completed for a user to be granted access. This option must be
followed by one or more lists of comma-separated authentication
method names, or by the single string any to indicate the default
behaviour of accepting any single authentication method. If the
default is overridden, then successful authentication requires
completion of every method in at least one of these lists.
For example, "publickey,password publickey,keyboard-interactive"
would require the user to complete public key authentication,
followed by either password or keyboard interactive
authentication. Only methods that are next in one or more lists
are offered at each stage, so for this example it would not be
possible to attempt password or keyboard-interactive
authentication before public key.
For keyboard interactive authentication it is also possible to
restrict authentication to a specific device by appending a colon
followed by the device identifier bsdauth or pam. depending on
the server configuration. For example,
"keyboard-interactive:bsdauth" would restrict keyboard
interactive authentication to the bsdauth device.
If the publickey method is listed more than once, sshd(8)
verifies that keys that have been used successfully are not
reused for subsequent authentications. For example,
"publickey,publickey" requires successful authentication using
two different public keys.
Note that each authentication method listed should also be
explicitly enabled in the configuration.
The available authentication methods are: "gssapi-with-mic",
"hostbased", "keyboard-interactive", "none" (used for access to
password-less accounts when PermitEmptyPasswords is enabled),
"password" and "publickey".
AuthorizedKeysCommand
Specifies a program to be used to look up the user's public keys.
The program must be owned by root, not writable by group or
others and specified by an absolute path. Arguments to
AuthorizedKeysCommand accept the tokens described in the TOKENS
section. If no arguments are specified then the username of the
target user is used.
The program should produce on standard output zero or more lines
of authorized_keys output (see AUTHORIZED_KEYS in sshd(8)).
AuthorizedKeysCommand is tried after the usual AuthorizedKeysFile
files and will not be executed if a matching key is found there.
By default, no AuthorizedKeysCommand is run.
AuthorizedKeysCommandUser
Specifies the user under whose account the AuthorizedKeysCommand
is run. It is recommended to use a dedicated user that has no
other role on the host than running authorized keys commands. If
AuthorizedKeysCommand is specified but AuthorizedKeysCommandUser
is not, then sshd(8) will refuse to start.
AuthorizedKeysFile
Specifies the file that contains the public keys used for user
authentication. The format is described in the AUTHORIZED_KEYS
FILE FORMAT section of sshd(8). Arguments to AuthorizedKeysFile
accept the tokens described in the TOKENS section. After
expansion, AuthorizedKeysFile is taken to be an absolute path or
one relative to the user's home directory. Multiple files may be
listed, separated by whitespace. Alternately this option may be
set to none to skip checking for user keys in files. The default
is ".ssh/authorized_keys .ssh/authorized_keys2".
AuthorizedPrincipalsCommand
Specifies a program to be used to generate the list of allowed
certificate principals as per AuthorizedPrincipalsFile. The
program must be owned by root, not writable by group or others
and specified by an absolute path. Arguments to
AuthorizedPrincipalsCommand accept the tokens described in the
TOKENS section. If no arguments are specified then the username
of the target user is used.
The program should produce on standard output zero or more lines
of AuthorizedPrincipalsFile output. If either
AuthorizedPrincipalsCommand or AuthorizedPrincipalsFile is
specified, then certificates offered by the client for
authentication must contain a principal that is listed. By
default, no AuthorizedPrincipalsCommand is run.
AuthorizedPrincipalsCommandUser
Specifies the user under whose account the
AuthorizedPrincipalsCommand is run. It is recommended to use a
dedicated user that has no other role on the host than running
authorized principals commands. If AuthorizedPrincipalsCommand
is specified but AuthorizedPrincipalsCommandUser is not, then
sshd(8) will refuse to start.
AuthorizedPrincipalsFile
Specifies a file that lists principal names that are accepted for
certificate authentication. When using certificates signed by a
key listed in TrustedUserCAKeys, this file lists names, one of
which must appear in the certificate for it to be accepted for
authentication. Names are listed one per line preceded by key
options (as described in AUTHORIZED_KEYS FILE FORMAT in sshd(8)).
Empty lines and comments starting with M-bM-^@M-^X#M-bM-^@M-^Y are ignored.
Arguments to AuthorizedPrincipalsFile accept the tokens described
in the TOKENS section. After expansion, AuthorizedPrincipalsFile
is taken to be an absolute path or one relative to the user's
home directory. The default is none, i.e. not to use a
principals file M-bM-^@M-^S in this case, the username of the user must
appear in a certificate's principals list for it to be accepted.
Note that AuthorizedPrincipalsFile is only used when
authentication proceeds using a CA listed in TrustedUserCAKeys
and is not consulted for certification authorities trusted via
~/.ssh/authorized_keys, though the principals= key option offers
a similar facility (see sshd(8) for details).
Banner The contents of the specified file are sent to the remote user
before authentication is allowed. If the argument is none then
no banner is displayed. By default, no banner is displayed.
CASignatureAlgorithms
Specifies which algorithms are allowed for signing of
certificates by certificate authorities (CAs). The default is:
- ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,
- ecdsa-sha2-nistp521,rsa-sha2-512,rsa-sha2-256,ssh-rsa
+ ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
+ sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com,
+ rsa-sha2-512,rsa-sha2-256
Certificates signed using other algorithms will not be accepted
for public key or host-based authentication.
ChallengeResponseAuthentication
Specifies whether challenge-response authentication is allowed
(e.g. via PAM or through authentication styles supported in
login.conf(5)) The default is yes.
ChrootDirectory
Specifies the pathname of a directory to chroot(2) to after
authentication. At session startup sshd(8) checks that all
components of the pathname are root-owned directories which are
not writable by any other user or group. After the chroot,
sshd(8) changes the working directory to the user's home
directory. Arguments to ChrootDirectory accept the tokens
described in the TOKENS section.
The ChrootDirectory must contain the necessary files and
directories to support the user's session. For an interactive
session this requires at least a shell, typically sh(1), and
basic /dev nodes such as null(4), zero(4), stdin(4), stdout(4),
stderr(4), and tty(4) devices. For file transfer sessions using
SFTP no additional configuration of the environment is necessary
if the in-process sftp-server is used, though sessions which use
logging may require /dev/log inside the chroot directory on some
operating systems (see sftp-server(8) for details).
For safety, it is very important that the directory hierarchy be
prevented from modification by other processes on the system
(especially those outside the jail). Misconfiguration can lead
to unsafe environments which sshd(8) cannot detect.
The default is none, indicating not to chroot(2).
Ciphers
Specifies the ciphers allowed. Multiple ciphers must be comma-
separated. If the specified list begins with a M-bM-^@M-^X+M-bM-^@M-^Y character,
then the specified ciphers will be appended to the default set
instead of replacing them. If the specified list begins with a
M-bM-^@M-^X-M-bM-^@M-^Y character, then the specified ciphers (including wildcards)
will be removed from the default set instead of replacing them.
If the specified list begins with a M-bM-^@M-^X^M-bM-^@M-^Y character, then the
specified ciphers will be placed at the head of the default set.
The supported ciphers are:
3des-cbc
aes128-cbc
aes192-cbc
aes256-cbc
aes128-ctr
aes192-ctr
aes256-ctr
aes128-gcm@openssh.com
aes256-gcm@openssh.com
chacha20-poly1305@openssh.com
The default is:
chacha20-poly1305@openssh.com,
aes128-ctr,aes192-ctr,aes256-ctr,
aes128-gcm@openssh.com,aes256-gcm@openssh.com
The list of available ciphers may also be obtained using "ssh -Q
cipher".
ClientAliveCountMax
Sets the number of client alive messages which may be sent
without sshd(8) receiving any messages back from the client. If
this threshold is reached while client alive messages are being
sent, sshd will disconnect the client, terminating the session.
It is important to note that the use of client alive messages is
very different from TCPKeepAlive. The client alive messages are
sent through the encrypted channel and therefore will not be
spoofable. The TCP keepalive option enabled by TCPKeepAlive is
spoofable. The client alive mechanism is valuable when the
client or server depend on knowing when a connection has become
unresponsive.
The default value is 3. If ClientAliveInterval is set to 15, and
ClientAliveCountMax is left at the default, unresponsive SSH
clients will be disconnected after approximately 45 seconds.
Setting a zero ClientAliveCountMax disables connection
termination.
ClientAliveInterval
Sets a timeout interval in seconds after which if no data has
been received from the client, sshd(8) will send a message
through the encrypted channel to request a response from the
client. The default is 0, indicating that these messages will
not be sent to the client.
Compression
Specifies whether compression is enabled after the user has
authenticated successfully. The argument must be yes, delayed (a
legacy synonym for yes) or no. The default is yes.
DenyGroups
This keyword can be followed by a list of group name patterns,
separated by spaces. Login is disallowed for users whose primary
group or supplementary group list matches one of the patterns.
Only group names are valid; a numerical group ID is not
recognized. By default, login is allowed for all groups. The
allow/deny groups directives are processed in the following
order: DenyGroups, AllowGroups.
See PATTERNS in ssh_config(5) for more information on patterns.
DenyUsers
This keyword can be followed by a list of user name patterns,
separated by spaces. Login is disallowed for user names that
match one of the patterns. Only user names are valid; a
numerical user ID is not recognized. By default, login is
allowed for all users. If the pattern takes the form USER@HOST
then USER and HOST are separately checked, restricting logins to
particular users from particular hosts. HOST criteria may
additionally contain addresses to match in CIDR address/masklen
format. The allow/deny users directives are processed in the
following order: DenyUsers, AllowUsers.
See PATTERNS in ssh_config(5) for more information on patterns.
DisableForwarding
Disables all forwarding features, including X11, ssh-agent(1),
TCP and StreamLocal. This option overrides all other forwarding-
related options and may simplify restricted configurations.
ExposeAuthInfo
Writes a temporary file containing a list of authentication
methods and public credentials (e.g. keys) used to authenticate
the user. The location of the file is exposed to the user
session through the SSH_USER_AUTH environment variable. The
default is no.
FingerprintHash
Specifies the hash algorithm used when logging key fingerprints.
Valid options are: md5 and sha256. The default is sha256.
ForceCommand
Forces the execution of the command specified by ForceCommand,
ignoring any command supplied by the client and ~/.ssh/rc if
present. The command is invoked by using the user's login shell
with the -c option. This applies to shell, command, or subsystem
execution. It is most useful inside a Match block. The command
originally supplied by the client is available in the
SSH_ORIGINAL_COMMAND environment variable. Specifying a command
of internal-sftp will force the use of an in-process SFTP server
that requires no support files when used with ChrootDirectory.
The default is none.
GatewayPorts
Specifies whether remote hosts are allowed to connect to ports
forwarded for the client. By default, sshd(8) binds remote port
forwardings to the loopback address. This prevents other remote
hosts from connecting to forwarded ports. GatewayPorts can be
used to specify that sshd should allow remote port forwardings to
bind to non-loopback addresses, thus allowing other hosts to
connect. The argument may be no to force remote port forwardings
to be available to the local host only, yes to force remote port
forwardings to bind to the wildcard address, or clientspecified
to allow the client to select the address to which the forwarding
is bound. The default is no.
GSSAPIAuthentication
Specifies whether user authentication based on GSSAPI is allowed.
The default is no.
GSSAPICleanupCredentials
Specifies whether to automatically destroy the user's credentials
cache on logout. The default is yes.
GSSAPIStrictAcceptorCheck
Determines whether to be strict about the identity of the GSSAPI
acceptor a client authenticates against. If set to yes then the
client must authenticate against the host service on the current
hostname. If set to no then the client may authenticate against
any service key stored in the machine's default store. This
facility is provided to assist with operation on multi homed
machines. The default is yes.
HostbasedAcceptedAlgorithms
Specifies the signature algorithms that will be accepted for
hostbased authentication as a list of comma-separated patterns.
Alternately if the specified list begins with a M-bM-^@M-^X+M-bM-^@M-^Y character,
then the specified signature algorithms will be appended to the
default set instead of replacing them. If the specified list
begins with a M-bM-^@M-^X-M-bM-^@M-^Y character, then the specified signature
algorithms (including wildcards) will be removed from the default
set instead of replacing them. If the specified list begins with
a M-bM-^@M-^X^M-bM-^@M-^Y character, then the specified signature algorithms will be
placed at the head of the default set. The default for this
option is:
ssh-ed25519-cert-v01@openssh.com,
ecdsa-sha2-nistp256-cert-v01@openssh.com,
ecdsa-sha2-nistp384-cert-v01@openssh.com,
ecdsa-sha2-nistp521-cert-v01@openssh.com,
sk-ssh-ed25519-cert-v01@openssh.com,
sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
rsa-sha2-512-cert-v01@openssh.com,
rsa-sha2-256-cert-v01@openssh.com,
ssh-rsa-cert-v01@openssh.com,
ssh-ed25519,
ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
sk-ssh-ed25519@openssh.com,
sk-ecdsa-sha2-nistp256@openssh.com,
rsa-sha2-512,rsa-sha2-256,ssh-rsa
The list of available signature algorithms may also be obtained
using "ssh -Q HostbasedAcceptedAlgorithms". This was formerly
named HostbasedAcceptedKeyTypes.
HostbasedAuthentication
Specifies whether rhosts or /etc/hosts.equiv authentication
together with successful public key client host authentication is
allowed (host-based authentication). The default is no.
HostbasedUsesNameFromPacketOnly
Specifies whether or not the server will attempt to perform a
reverse name lookup when matching the name in the ~/.shosts,
~/.rhosts, and /etc/hosts.equiv files during
HostbasedAuthentication. A setting of yes means that sshd(8)
uses the name supplied by the client rather than attempting to
resolve the name from the TCP connection itself. The default is
no.
HostCertificate
Specifies a file containing a public host certificate. The
certificate's public key must match a private host key already
specified by HostKey. The default behaviour of sshd(8) is not to
load any certificates.
HostKey
Specifies a file containing a private host key used by SSH. The
defaults are /etc/ssh/ssh_host_ecdsa_key,
/etc/ssh/ssh_host_ed25519_key and /etc/ssh/ssh_host_rsa_key.
Note that sshd(8) will refuse to use a file if it is group/world-
accessible and that the HostKeyAlgorithms option restricts which
of the keys are actually used by sshd(8).
It is possible to have multiple host key files. It is also
possible to specify public host key files instead. In this case
operations on the private key will be delegated to an
ssh-agent(1).
HostKeyAgent
Identifies the UNIX-domain socket used to communicate with an
agent that has access to the private host keys. If the string
"SSH_AUTH_SOCK" is specified, the location of the socket will be
read from the SSH_AUTH_SOCK environment variable.
HostKeyAlgorithms
Specifies the host key signature algorithms that the server
offers. The default for this option is:
ssh-ed25519-cert-v01@openssh.com,
ecdsa-sha2-nistp256-cert-v01@openssh.com,
ecdsa-sha2-nistp384-cert-v01@openssh.com,
ecdsa-sha2-nistp521-cert-v01@openssh.com,
sk-ssh-ed25519-cert-v01@openssh.com,
sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
rsa-sha2-512-cert-v01@openssh.com,
rsa-sha2-256-cert-v01@openssh.com,
ssh-rsa-cert-v01@openssh.com,
ssh-ed25519,
ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
sk-ssh-ed25519@openssh.com,
sk-ecdsa-sha2-nistp256@openssh.com,
rsa-sha2-512,rsa-sha2-256,ssh-rsa
The list of available signature algorithms may also be obtained
using "ssh -Q HostKeyAlgorithms".
IgnoreRhosts
Specifies whether to ignore per-user .rhosts and .shosts files
during HostbasedAuthentication. The system-wide /etc/hosts.equiv
and /etc/shosts.equiv are still used regardless of this setting.
Accepted values are yes (the default) to ignore all per-user
files, shosts-only to allow the use of .shosts but to ignore
.rhosts or no to allow both .shosts and rhosts.
IgnoreUserKnownHosts
Specifies whether sshd(8) should ignore the user's
~/.ssh/known_hosts during HostbasedAuthentication and use only
the system-wide known hosts file /etc/ssh/known_hosts. The
default is M-bM-^@M-^\noM-bM-^@M-^].
Include
Include the specified configuration file(s). Multiple pathnames
may be specified and each pathname may contain glob(7) wildcards
that will be expanded and processed in lexical order. Files
without absolute paths are assumed to be in /etc/ssh. An Include
directive may appear inside a Match block to perform conditional
inclusion.
IPQoS Specifies the IPv4 type-of-service or DSCP class for the
connection. Accepted values are af11, af12, af13, af21, af22,
af23, af31, af32, af33, af41, af42, af43, cs0, cs1, cs2, cs3,
cs4, cs5, cs6, cs7, ef, le, lowdelay, throughput, reliability, a
numeric value, or none to use the operating system default. This
option may take one or two arguments, separated by whitespace.
If one argument is specified, it is used as the packet class
unconditionally. If two values are specified, the first is
automatically selected for interactive sessions and the second
for non-interactive sessions. The default is af21 (Low-Latency
Data) for interactive sessions and cs1 (Lower Effort) for non-
interactive sessions.
KbdInteractiveAuthentication
Specifies whether to allow keyboard-interactive authentication.
The argument to this keyword must be yes or no. The default is
to use whatever value ChallengeResponseAuthentication is set to
(by default yes).
KerberosAuthentication
Specifies whether the password provided by the user for
PasswordAuthentication will be validated through the Kerberos
KDC. To use this option, the server needs a Kerberos servtab
which allows the verification of the KDC's identity. The default
is no.
KerberosGetAFSToken
If AFS is active and the user has a Kerberos 5 TGT, attempt to
acquire an AFS token before accessing the user's home directory.
The default is no.
KerberosOrLocalPasswd
If password authentication through Kerberos fails then the
password will be validated via any additional local mechanism
such as /etc/passwd. The default is yes.
KerberosTicketCleanup
Specifies whether to automatically destroy the user's ticket
cache file on logout. The default is yes.
KexAlgorithms
Specifies the available KEX (Key Exchange) algorithms. Multiple
algorithms must be comma-separated. Alternately if the specified
list begins with a M-bM-^@M-^X+M-bM-^@M-^Y character, then the specified methods will
be appended to the default set instead of replacing them. If the
specified list begins with a M-bM-^@M-^X-M-bM-^@M-^Y character, then the specified
methods (including wildcards) will be removed from the default
set instead of replacing them. If the specified list begins with
a M-bM-^@M-^X^M-bM-^@M-^Y character, then the specified methods will be placed at the
head of the default set. The supported algorithms are:
curve25519-sha256
curve25519-sha256@libssh.org
diffie-hellman-group1-sha1
diffie-hellman-group14-sha1
diffie-hellman-group14-sha256
diffie-hellman-group16-sha512
diffie-hellman-group18-sha512
diffie-hellman-group-exchange-sha1
diffie-hellman-group-exchange-sha256
ecdh-sha2-nistp256
ecdh-sha2-nistp384
ecdh-sha2-nistp521
sntrup761x25519-sha512@openssh.com
The default is:
curve25519-sha256,curve25519-sha256@libssh.org,
ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,
diffie-hellman-group-exchange-sha256,
diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,
diffie-hellman-group14-sha256
The list of available key exchange algorithms may also be
obtained using "ssh -Q KexAlgorithms".
ListenAddress
Specifies the local addresses sshd(8) should listen on. The
following forms may be used:
ListenAddress hostname|address [rdomain domain]
ListenAddress hostname:port [rdomain domain]
ListenAddress IPv4_address:port [rdomain domain]
ListenAddress [hostname|address]:port [rdomain domain]
The optional rdomain qualifier requests sshd(8) listen in an
explicit routing domain. If port is not specified, sshd will
listen on the address and all Port options specified. The
default is to listen on all local addresses on the current
default routing domain. Multiple ListenAddress options are
permitted. For more information on routing domains, see
rdomain(4).
LoginGraceTime
The server disconnects after this time if the user has not
successfully logged in. If the value is 0, there is no time
limit. The default is 120 seconds.
LogLevel
Gives the verbosity level that is used when logging messages from
sshd(8). The possible values are: QUIET, FATAL, ERROR, INFO,
VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3. The default is INFO.
DEBUG and DEBUG1 are equivalent. DEBUG2 and DEBUG3 each specify
higher levels of debugging output. Logging with a DEBUG level
violates the privacy of users and is not recommended.
LogVerbose
Specify one or more overrides to LogLevel. An override consists
of a pattern lists that matches the source file, function and
line number to force detailed logging for. For example, an
override pattern of:
kex.c:*:1000,*:kex_exchange_identification():*,packet.c:*
would enable detailed logging for line 1000 of kex.c, everything
in the kex_exchange_identification() function, and all code in
the packet.c file. This option is intended for debugging and no
overrides are enabled by default.
MACs Specifies the available MAC (message authentication code)
algorithms. The MAC algorithm is used for data integrity
protection. Multiple algorithms must be comma-separated. If the
specified list begins with a M-bM-^@M-^X+M-bM-^@M-^Y character, then the specified
algorithms will be appended to the default set instead of
replacing them. If the specified list begins with a M-bM-^@M-^X-M-bM-^@M-^Y
character, then the specified algorithms (including wildcards)
will be removed from the default set instead of replacing them.
If the specified list begins with a M-bM-^@M-^X^M-bM-^@M-^Y character, then the
specified algorithms will be placed at the head of the default
set.
The algorithms that contain "-etm" calculate the MAC after
encryption (encrypt-then-mac). These are considered safer and
their use recommended. The supported MACs are:
hmac-md5
hmac-md5-96
hmac-sha1
hmac-sha1-96
hmac-sha2-256
hmac-sha2-512
umac-64@openssh.com
umac-128@openssh.com
hmac-md5-etm@openssh.com
hmac-md5-96-etm@openssh.com
hmac-sha1-etm@openssh.com
hmac-sha1-96-etm@openssh.com
hmac-sha2-256-etm@openssh.com
hmac-sha2-512-etm@openssh.com
umac-64-etm@openssh.com
umac-128-etm@openssh.com
The default is:
umac-64-etm@openssh.com,umac-128-etm@openssh.com,
hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,
hmac-sha1-etm@openssh.com,
umac-64@openssh.com,umac-128@openssh.com,
hmac-sha2-256,hmac-sha2-512,hmac-sha1
The list of available MAC algorithms may also be obtained using
"ssh -Q mac".
Match Introduces a conditional block. If all of the criteria on the
Match line are satisfied, the keywords on the following lines
override those set in the global section of the config file,
until either another Match line or the end of the file. If a
keyword appears in multiple Match blocks that are satisfied, only
the first instance of the keyword is applied.
The arguments to Match are one or more criteria-pattern pairs or
the single token All which matches all criteria. The available
criteria are User, Group, Host, LocalAddress, LocalPort, RDomain,
and Address (with RDomain representing the rdomain(4) on which
the connection was received).
The match patterns may consist of single entries or comma-
separated lists and may use the wildcard and negation operators
described in the PATTERNS section of ssh_config(5).
The patterns in an Address criteria may additionally contain
addresses to match in CIDR address/masklen format, such as
192.0.2.0/24 or 2001:db8::/32. Note that the mask length
provided must be consistent with the address - it is an error to
specify a mask length that is too long for the address or one
with bits set in this host portion of the address. For example,
192.0.2.0/33 and 192.0.2.0/8, respectively.
Only a subset of keywords may be used on the lines following a
Match keyword. Available keywords are AcceptEnv,
AllowAgentForwarding, AllowGroups, AllowStreamLocalForwarding,
AllowTcpForwarding, AllowUsers, AuthenticationMethods,
AuthorizedKeysCommand, AuthorizedKeysCommandUser,
AuthorizedKeysFile, AuthorizedPrincipalsCommand,
AuthorizedPrincipalsCommandUser, AuthorizedPrincipalsFile,
Banner, ChrootDirectory, ClientAliveCountMax,
ClientAliveInterval, DenyGroups, DenyUsers, DisableForwarding,
ForceCommand, GatewayPorts, GSSAPIAuthentication,
HostbasedAcceptedAlgorithms, HostbasedAuthentication,
HostbasedUsesNameFromPacketOnly, IgnoreRhosts, Include, IPQoS,
KbdInteractiveAuthentication, KerberosAuthentication, LogLevel,
MaxAuthTries, MaxSessions, PasswordAuthentication,
PermitEmptyPasswords, PermitListen, PermitOpen, PermitRootLogin,
PermitTTY, PermitTunnel, PermitUserRC, PubkeyAcceptedAlgorithms,
PubkeyAuthentication, RekeyLimit, RevokedKeys, RDomain, SetEnv,
StreamLocalBindMask, StreamLocalBindUnlink, TrustedUserCAKeys,
X11DisplayOffset, X11Forwarding and X11UseLocalhost.
MaxAuthTries
Specifies the maximum number of authentication attempts permitted
per connection. Once the number of failures reaches half this
value, additional failures are logged. The default is 6.
MaxSessions
Specifies the maximum number of open shell, login or subsystem
(e.g. sftp) sessions permitted per network connection. Multiple
sessions may be established by clients that support connection
multiplexing. Setting MaxSessions to 1 will effectively disable
session multiplexing, whereas setting it to 0 will prevent all
shell, login and subsystem sessions while still permitting
forwarding. The default is 10.
MaxStartups
Specifies the maximum number of concurrent unauthenticated
connections to the SSH daemon. Additional connections will be
dropped until authentication succeeds or the LoginGraceTime
expires for a connection. The default is 10:30:100.
Alternatively, random early drop can be enabled by specifying the
three colon separated values start:rate:full (e.g. "10:30:60").
sshd(8) will refuse connection attempts with a probability of
rate/100 (30%) if there are currently start (10) unauthenticated
connections. The probability increases linearly and all
connection attempts are refused if the number of unauthenticated
connections reaches full (60).
+ ModuliFile
+ Specifies the moduli(5) file that contains the Diffie-Hellman
+ groups used for the M-bM-^@M-^\diffie-hellman-group-exchange-sha1M-bM-^@M-^] and
+ M-bM-^@M-^\diffie-hellman-group-exchange-sha256M-bM-^@M-^] key exchange methods. The
+ default is /etc/moduli.
+
PasswordAuthentication
Specifies whether password authentication is allowed. The
default is yes.
PermitEmptyPasswords
When password authentication is allowed, it specifies whether the
server allows login to accounts with empty password strings. The
default is no.
PermitListen
Specifies the addresses/ports on which a remote TCP port
forwarding may listen. The listen specification must be one of
the following forms:
PermitListen port
PermitListen host:port
Multiple permissions may be specified by separating them with
whitespace. An argument of any can be used to remove all
restrictions and permit any listen requests. An argument of none
can be used to prohibit all listen requests. The host name may
contain wildcards as described in the PATTERNS section in
ssh_config(5). The wildcard M-bM-^@M-^X*M-bM-^@M-^Y can also be used in place of a
port number to allow all ports. By default all port forwarding
listen requests are permitted. Note that the GatewayPorts option
may further restrict which addresses may be listened on. Note
also that ssh(1) will request a listen host of M-bM-^@M-^\localhostM-bM-^@M-^] if no
listen host was specifically requested, and this name is treated
differently to explicit localhost addresses of M-bM-^@M-^\127.0.0.1M-bM-^@M-^] and
M-bM-^@M-^\::1M-bM-^@M-^].
PermitOpen
Specifies the destinations to which TCP port forwarding is
permitted. The forwarding specification must be one of the
following forms:
PermitOpen host:port
PermitOpen IPv4_addr:port
PermitOpen [IPv6_addr]:port
Multiple forwards may be specified by separating them with
whitespace. An argument of any can be used to remove all
restrictions and permit any forwarding requests. An argument of
none can be used to prohibit all forwarding requests. The
wildcard M-bM-^@M-^X*M-bM-^@M-^Y can be used for host or port to allow all hosts or
ports respectively. Otherwise, no pattern matching or address
lookups are performed on supplied names. By default all port
forwarding requests are permitted.
PermitRootLogin
Specifies whether root can log in using ssh(1). The argument
must be yes, prohibit-password, forced-commands-only, or no. The
default is prohibit-password.
If this option is set to prohibit-password (or its deprecated
alias, without-password), password and keyboard-interactive
authentication are disabled for root.
If this option is set to forced-commands-only, root login with
public key authentication will be allowed, but only if the
command option has been specified (which may be useful for taking
remote backups even if root login is normally not allowed). All
other authentication methods are disabled for root.
If this option is set to no, root is not allowed to log in.
PermitTTY
Specifies whether pty(4) allocation is permitted. The default is
yes.
PermitTunnel
Specifies whether tun(4) device forwarding is allowed. The
argument must be yes, point-to-point (layer 3), ethernet (layer
2), or no. Specifying yes permits both point-to-point and
ethernet. The default is no.
Independent of this setting, the permissions of the selected
tun(4) device must allow access to the user.
PermitUserEnvironment
Specifies whether ~/.ssh/environment and environment= options in
~/.ssh/authorized_keys are processed by sshd(8). Valid options
are yes, no or a pattern-list specifying which environment
variable names to accept (for example "LANG,LC_*"). The default
is no. Enabling environment processing may enable users to
bypass access restrictions in some configurations using
mechanisms such as LD_PRELOAD.
PermitUserRC
Specifies whether any ~/.ssh/rc file is executed. The default is
yes.
PerSourceMaxStartups
Specifies the number of unauthenticated connections allowed from
a given source address, or M-bM-^@M-^\noneM-bM-^@M-^] if there is no limit. This
limit is applied in addition to MaxStartups, whichever is lower.
The default is none.
PerSourceNetBlockSize
Specifies the number of bits of source address that are grouped
together for the purposes of applying PerSourceMaxStartups
limits. Values for IPv4 and optionally IPv6 may be specified,
separated by a colon. The default is 32:128, which means each
address is considered individually.
PidFile
Specifies the file that contains the process ID of the SSH
daemon, or none to not write one. The default is
/var/run/sshd.pid.
Port Specifies the port number that sshd(8) listens on. The default
is 22. Multiple options of this type are permitted. See also
ListenAddress.
PrintLastLog
Specifies whether sshd(8) should print the date and time of the
last user login when a user logs in interactively. The default
is yes.
PrintMotd
Specifies whether sshd(8) should print /etc/motd when a user logs
in interactively. (On some systems it is also printed by the
shell, /etc/profile, or equivalent.) The default is yes.
PubkeyAcceptedAlgorithms
Specifies the signature algorithms that will be accepted for
public key authentication as a list of comma-separated patterns.
Alternately if the specified list begins with a M-bM-^@M-^X+M-bM-^@M-^Y character,
then the specified algorithms will be appended to the default set
instead of replacing them. If the specified list begins with a
M-bM-^@M-^X-M-bM-^@M-^Y character, then the specified algorithms (including
wildcards) will be removed from the default set instead of
replacing them. If the specified list begins with a M-bM-^@M-^X^M-bM-^@M-^Y
character, then the specified algorithms will be placed at the
head of the default set. The default for this option is:
ssh-ed25519-cert-v01@openssh.com,
ecdsa-sha2-nistp256-cert-v01@openssh.com,
ecdsa-sha2-nistp384-cert-v01@openssh.com,
ecdsa-sha2-nistp521-cert-v01@openssh.com,
sk-ssh-ed25519-cert-v01@openssh.com,
sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
rsa-sha2-512-cert-v01@openssh.com,
rsa-sha2-256-cert-v01@openssh.com,
ssh-rsa-cert-v01@openssh.com,
ssh-ed25519,
ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
sk-ssh-ed25519@openssh.com,
sk-ecdsa-sha2-nistp256@openssh.com,
rsa-sha2-512,rsa-sha2-256,ssh-rsa
The list of available signature algorithms may also be obtained
using "ssh -Q PubkeyAcceptedAlgorithms".
PubkeyAuthOptions
Sets one or more public key authentication options. The
supported keywords are: none (the default; indicating no
additional options are enabled), touch-required and
verify-required.
The touch-required option causes public key authentication using
a FIDO authenticator algorithm (i.e. ecdsa-sk or ed25519-sk) to
always require the signature to attest that a physically present
user explicitly confirmed the authentication (usually by touching
the authenticator). By default, sshd(8) requires user presence
unless overridden with an authorized_keys option. The
touch-required flag disables this override.
The verify-required option requires a FIDO key signature attest
that the user was verified, e.g. via a PIN.
Neither the touch-required or verify-required options have any
effect for other, non-FIDO, public key types.
PubkeyAuthentication
Specifies whether public key authentication is allowed. The
default is yes.
RekeyLimit
Specifies the maximum amount of data that may be transmitted
before the session key is renegotiated, optionally followed by a
maximum amount of time that may pass before the session key is
renegotiated. The first argument is specified in bytes and may
have a suffix of M-bM-^@M-^XKM-bM-^@M-^Y, M-bM-^@M-^XMM-bM-^@M-^Y, or M-bM-^@M-^XGM-bM-^@M-^Y to indicate Kilobytes,
Megabytes, or Gigabytes, respectively. The default is between
M-bM-^@M-^X1GM-bM-^@M-^Y and M-bM-^@M-^X4GM-bM-^@M-^Y, depending on the cipher. The optional second
value is specified in seconds and may use any of the units
documented in the TIME FORMATS section. The default value for
RekeyLimit is default none, which means that rekeying is
performed after the cipher's default amount of data has been sent
or received and no time based rekeying is done.
RevokedKeys
Specifies revoked public keys file, or none to not use one. Keys
listed in this file will be refused for public key
authentication. Note that if this file is not readable, then
public key authentication will be refused for all users. Keys
may be specified as a text file, listing one public key per line,
or as an OpenSSH Key Revocation List (KRL) as generated by
ssh-keygen(1). For more information on KRLs, see the KEY
REVOCATION LISTS section in ssh-keygen(1).
RDomain
Specifies an explicit routing domain that is applied after
authentication has completed. The user session, as well and any
forwarded or listening IP sockets, will be bound to this
rdomain(4). If the routing domain is set to %D, then the domain
in which the incoming connection was received will be applied.
SecurityKeyProvider
Specifies a path to a library that will be used when loading FIDO
authenticator-hosted keys, overriding the default of using the
built-in USB HID support.
SetEnv Specifies one or more environment variables to set in child
sessions started by sshd(8) as M-bM-^@M-^\NAME=VALUEM-bM-^@M-^]. The environment
value may be quoted (e.g. if it contains whitespace characters).
Environment variables set by SetEnv override the default
environment and any variables specified by the user via AcceptEnv
or PermitUserEnvironment.
StreamLocalBindMask
Sets the octal file creation mode mask (umask) used when creating
a Unix-domain socket file for local or remote port forwarding.
This option is only used for port forwarding to a Unix-domain
socket file.
The default value is 0177, which creates a Unix-domain socket
file that is readable and writable only by the owner. Note that
not all operating systems honor the file mode on Unix-domain
socket files.
StreamLocalBindUnlink
Specifies whether to remove an existing Unix-domain socket file
for local or remote port forwarding before creating a new one.
If the socket file already exists and StreamLocalBindUnlink is
not enabled, sshd will be unable to forward the port to the Unix-
domain socket file. This option is only used for port forwarding
to a Unix-domain socket file.
The argument must be yes or no. The default is no.
StrictModes
Specifies whether sshd(8) should check file modes and ownership
of the user's files and home directory before accepting login.
This is normally desirable because novices sometimes accidentally
leave their directory or files world-writable. The default is
yes. Note that this does not apply to ChrootDirectory, whose
permissions and ownership are checked unconditionally.
Subsystem
Configures an external subsystem (e.g. file transfer daemon).
Arguments should be a subsystem name and a command (with optional
arguments) to execute upon subsystem request.
The command sftp-server implements the SFTP file transfer
subsystem.
Alternately the name internal-sftp implements an in-process SFTP
server. This may simplify configurations using ChrootDirectory
to force a different filesystem root on clients.
By default no subsystems are defined.
SyslogFacility
Gives the facility code that is used when logging messages from
sshd(8). The possible values are: DAEMON, USER, AUTH, LOCAL0,
LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The
default is AUTH.
TCPKeepAlive
Specifies whether the system should send TCP keepalive messages
to the other side. If they are sent, death of the connection or
crash of one of the machines will be properly noticed. However,
this means that connections will die if the route is down
temporarily, and some people find it annoying. On the other
hand, if TCP keepalives are not sent, sessions may hang
indefinitely on the server, leaving "ghost" users and consuming
server resources.
The default is yes (to send TCP keepalive messages), and the
server will notice if the network goes down or the client host
crashes. This avoids infinitely hanging sessions.
To disable TCP keepalive messages, the value should be set to no.
TrustedUserCAKeys
Specifies a file containing public keys of certificate
authorities that are trusted to sign user certificates for
authentication, or none to not use one. Keys are listed one per
line; empty lines and comments starting with M-bM-^@M-^X#M-bM-^@M-^Y are allowed. If
a certificate is presented for authentication and has its signing
CA key listed in this file, then it may be used for
authentication for any user listed in the certificate's
principals list. Note that certificates that lack a list of
principals will not be permitted for authentication using
TrustedUserCAKeys. For more details on certificates, see the
CERTIFICATES section in ssh-keygen(1).
UseDNS Specifies whether sshd(8) should look up the remote host name,
and to check that the resolved host name for the remote IP
address maps back to the very same IP address.
If this option is set to no (the default) then only addresses and
not host names may be used in ~/.ssh/authorized_keys from and
sshd_config Match Host directives.
UsePAM Enables the Pluggable Authentication Module interface. If set to
yes this will enable PAM authentication using
ChallengeResponseAuthentication and PasswordAuthentication in
addition to PAM account and session module processing for all
authentication types.
Because PAM challenge-response authentication usually serves an
equivalent role to password authentication, you should disable
either PasswordAuthentication or ChallengeResponseAuthentication.
If UsePAM is enabled, you will not be able to run sshd(8) as a
non-root user. The default is no.
VersionAddendum
Optionally specifies additional text to append to the SSH
protocol banner sent by the server upon connection. The default
is none.
X11DisplayOffset
Specifies the first display number available for sshd(8)'s X11
forwarding. This prevents sshd from interfering with real X11
servers. The default is 10.
X11Forwarding
Specifies whether X11 forwarding is permitted. The argument must
be yes or no. The default is no.
When X11 forwarding is enabled, there may be additional exposure
to the server and to client displays if the sshd(8) proxy display
is configured to listen on the wildcard address (see
X11UseLocalhost), though this is not the default. Additionally,
the authentication spoofing and authentication data verification
and substitution occur on the client side. The security risk of
using X11 forwarding is that the client's X11 display server may
be exposed to attack when the SSH client requests forwarding (see
the warnings for ForwardX11 in ssh_config(5)). A system
administrator may have a stance in which they want to protect
clients that may expose themselves to attack by unwittingly
requesting X11 forwarding, which can warrant a no setting.
Note that disabling X11 forwarding does not prevent users from
forwarding X11 traffic, as users can always install their own
forwarders.
X11UseLocalhost
Specifies whether sshd(8) should bind the X11 forwarding server
to the loopback address or to the wildcard address. By default,
sshd binds the forwarding server to the loopback address and sets
the hostname part of the DISPLAY environment variable to
localhost. This prevents remote hosts from connecting to the
proxy display. However, some older X11 clients may not function
with this configuration. X11UseLocalhost may be set to no to
specify that the forwarding server should be bound to the
wildcard address. The argument must be yes or no. The default
is yes.
XAuthLocation
Specifies the full pathname of the xauth(1) program, or none to
not use one. The default is /usr/X11R6/bin/xauth.
TIME FORMATS
sshd(8) command-line arguments and configuration file options that
specify time may be expressed using a sequence of the form:
time[qualifier], where time is a positive integer value and qualifier is
one of the following:
M-bM-^_M-(noneM-bM-^_M-) seconds
s | S seconds
m | M minutes
h | H hours
d | D days
w | W weeks
Each member of the sequence is added together to calculate the total time
value.
Time format examples:
600 600 seconds (10 minutes)
10m 10 minutes
1h30m 1 hour 30 minutes (90 minutes)
TOKENS
Arguments to some keywords can make use of tokens, which are expanded at
runtime:
%% A literal M-bM-^@M-^X%M-bM-^@M-^Y.
%D The routing domain in which the incoming connection was
received.
%F The fingerprint of the CA key.
%f The fingerprint of the key or certificate.
%h The home directory of the user.
%i The key ID in the certificate.
%K The base64-encoded CA key.
%k The base64-encoded key or certificate for authentication.
%s The serial number of the certificate.
%T The type of the CA key.
%t The key or certificate type.
%U The numeric user ID of the target user.
%u The username.
AuthorizedKeysCommand accepts the tokens %%, %f, %h, %k, %t, %U, and %u.
AuthorizedKeysFile accepts the tokens %%, %h, %U, and %u.
AuthorizedPrincipalsCommand accepts the tokens %%, %F, %f, %h, %i, %K,
%k, %s, %T, %t, %U, and %u.
AuthorizedPrincipalsFile accepts the tokens %%, %h, %U, and %u.
ChrootDirectory accepts the tokens %%, %h, %U, and %u.
RoutingDomain accepts the token %D.
FILES
/etc/ssh/sshd_config
Contains configuration data for sshd(8). This file should be
writable by root only, but it is recommended (though not
necessary) that it be world-readable.
SEE ALSO
sftp-server(8), sshd(8)
AUTHORS
OpenSSH is a derivative of the original and free ssh 1.2.12 release by
Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo
de Raadt and Dug Song removed many bugs, re-added newer features and
created OpenSSH. Markus Friedl contributed the support for SSH protocol
versions 1.5 and 2.0. Niels Provos and Markus Friedl contributed support
for privilege separation.
-OpenBSD 6.8 February 27, 2021 OpenBSD 6.8
+OpenBSD 6.9 April 4, 2021 OpenBSD 6.9
diff --git a/sshd_config.5 b/sshd_config.5
index 3db9353c9118..3b339aafbc14 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -1,1955 +1,1966 @@
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
.\" All rights reserved
.\"
.\" As far as I am concerned, the code I have written for this software
.\" can be used freely for any purpose. Any derived versions of this
.\" software must be clearly marked as such, and if the derived work is
.\" incompatible with the protocol description in the RFC file, it must be
.\" called by a name other than "ssh" or "Secure Shell".
.\"
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.\" $OpenBSD: sshd_config.5,v 1.328 2021/02/27 23:42:37 djm Exp $
-.Dd $Mdocdate: February 27 2021 $
+.\" $OpenBSD: sshd_config.5,v 1.331 2021/04/04 11:36:56 jmc Exp $
+.Dd $Mdocdate: April 4 2021 $
.Dt SSHD_CONFIG 5
.Os
.Sh NAME
.Nm sshd_config
.Nd OpenSSH daemon configuration file
.Sh DESCRIPTION
.Xr sshd 8
reads configuration data from
.Pa /etc/ssh/sshd_config
(or the file specified with
.Fl f
on the command line).
The file contains keyword-argument pairs, one per line.
For each keyword, the first obtained value will be used.
Lines starting with
.Ql #
and empty lines are interpreted as comments.
Arguments may optionally be enclosed in double quotes
.Pq \&"
in order to represent arguments containing spaces.
.Pp
The possible
keywords and their meanings are as follows (note that
keywords are case-insensitive and arguments are case-sensitive):
.Bl -tag -width Ds
.It Cm AcceptEnv
Specifies what environment variables sent by the client will be copied into
the session's
.Xr environ 7 .
See
.Cm SendEnv
and
.Cm SetEnv
in
.Xr ssh_config 5
for how to configure the client.
The
.Ev TERM
environment variable is always accepted whenever the client
requests a pseudo-terminal as it is required by the protocol.
Variables are specified by name, which may contain the wildcard characters
.Ql *
and
.Ql \&? .
Multiple environment variables may be separated by whitespace or spread
across multiple
.Cm AcceptEnv
directives.
Be warned that some environment variables could be used to bypass restricted
user environments.
For this reason, care should be taken in the use of this directive.
The default is not to accept any environment variables.
.It Cm AddressFamily
Specifies which address family should be used by
.Xr sshd 8 .
Valid arguments are
.Cm any
(the default),
.Cm inet
(use IPv4 only), or
.Cm inet6
(use IPv6 only).
.It Cm AllowAgentForwarding
Specifies whether
.Xr ssh-agent 1
forwarding is permitted.
The default is
.Cm yes .
Note that disabling agent forwarding does not improve security
unless users are also denied shell access, as they can always install
their own forwarders.
.It Cm AllowGroups
This keyword can be followed by a list of group name patterns, separated
by spaces.
If specified, login is allowed only for users whose primary
group or supplementary group list matches one of the patterns.
Only group names are valid; a numerical group ID is not recognized.
By default, login is allowed for all groups.
The allow/deny groups directives are processed in the following order:
.Cm DenyGroups ,
.Cm AllowGroups .
.Pp
See PATTERNS in
.Xr ssh_config 5
for more information on patterns.
.It Cm AllowStreamLocalForwarding
Specifies whether StreamLocal (Unix-domain socket) forwarding is permitted.
The available options are
.Cm yes
(the default)
or
.Cm all
to allow StreamLocal forwarding,
.Cm no
to prevent all StreamLocal forwarding,
.Cm local
to allow local (from the perspective of
.Xr ssh 1 )
forwarding only or
.Cm remote
to allow remote forwarding only.
Note that disabling StreamLocal forwarding does not improve security unless
users are also denied shell access, as they can always install their
own forwarders.
.It Cm AllowTcpForwarding
Specifies whether TCP forwarding is permitted.
The available options are
.Cm yes
(the default)
or
.Cm all
to allow TCP forwarding,
.Cm no
to prevent all TCP forwarding,
.Cm local
to allow local (from the perspective of
.Xr ssh 1 )
forwarding only or
.Cm remote
to allow remote forwarding only.
Note that disabling TCP forwarding does not improve security unless
users are also denied shell access, as they can always install their
own forwarders.
.It Cm AllowUsers
This keyword can be followed by a list of user name patterns, separated
by spaces.
If specified, login is allowed only for user names that
match one of the patterns.
Only user names are valid; a numerical user ID is not recognized.
By default, login is allowed for all users.
If the pattern takes the form USER@HOST then USER and HOST
are separately checked, restricting logins to particular
users from particular hosts.
HOST criteria may additionally contain addresses to match in CIDR
address/masklen format.
The allow/deny users directives are processed in the following order:
.Cm DenyUsers ,
.Cm AllowUsers .
.Pp
See PATTERNS in
.Xr ssh_config 5
for more information on patterns.
.It Cm AuthenticationMethods
Specifies the authentication methods that must be successfully completed
for a user to be granted access.
This option must be followed by one or more lists of comma-separated
authentication method names, or by the single string
.Cm any
to indicate the default behaviour of accepting any single authentication
method.
If the default is overridden, then successful authentication requires
completion of every method in at least one of these lists.
.Pp
For example,
.Qq publickey,password publickey,keyboard-interactive
would require the user to complete public key authentication, followed by
either password or keyboard interactive authentication.
Only methods that are next in one or more lists are offered at each stage,
so for this example it would not be possible to attempt password or
keyboard-interactive authentication before public key.
.Pp
For keyboard interactive authentication it is also possible to
restrict authentication to a specific device by appending a
colon followed by the device identifier
.Cm bsdauth
or
.Cm pam .
depending on the server configuration.
For example,
.Qq keyboard-interactive:bsdauth
would restrict keyboard interactive authentication to the
.Cm bsdauth
device.
.Pp
If the publickey method is listed more than once,
.Xr sshd 8
verifies that keys that have been used successfully are not reused for
subsequent authentications.
For example,
.Qq publickey,publickey
requires successful authentication using two different public keys.
.Pp
Note that each authentication method listed should also be explicitly enabled
in the configuration.
.Pp
The available authentication methods are:
.Qq gssapi-with-mic ,
.Qq hostbased ,
.Qq keyboard-interactive ,
.Qq none
(used for access to password-less accounts when
.Cm PermitEmptyPasswords
is enabled),
.Qq password
and
.Qq publickey .
.It Cm AuthorizedKeysCommand
Specifies a program to be used to look up the user's public keys.
The program must be owned by root, not writable by group or others and
specified by an absolute path.
Arguments to
.Cm AuthorizedKeysCommand
accept the tokens described in the
.Sx TOKENS
section.
If no arguments are specified then the username of the target user is used.
.Pp
The program should produce on standard output zero or
more lines of authorized_keys output (see
.Sx AUTHORIZED_KEYS
in
.Xr sshd 8 ) .
.Cm AuthorizedKeysCommand
is tried after the usual
.Cm AuthorizedKeysFile
files and will not be executed if a matching key is found there.
By default, no
.Cm AuthorizedKeysCommand
is run.
.It Cm AuthorizedKeysCommandUser
Specifies the user under whose account the
.Cm AuthorizedKeysCommand
is run.
It is recommended to use a dedicated user that has no other role on the host
than running authorized keys commands.
If
.Cm AuthorizedKeysCommand
is specified but
.Cm AuthorizedKeysCommandUser
is not, then
.Xr sshd 8
will refuse to start.
.It Cm AuthorizedKeysFile
Specifies the file that contains the public keys used for user authentication.
The format is described in the AUTHORIZED_KEYS FILE FORMAT section of
.Xr sshd 8 .
Arguments to
.Cm AuthorizedKeysFile
accept the tokens described in the
.Sx TOKENS
section.
After expansion,
.Cm AuthorizedKeysFile
is taken to be an absolute path or one relative to the user's home
directory.
Multiple files may be listed, separated by whitespace.
Alternately this option may be set to
.Cm none
to skip checking for user keys in files.
The default is
.Qq .ssh/authorized_keys .ssh/authorized_keys2 .
.It Cm AuthorizedPrincipalsCommand
Specifies a program to be used to generate the list of allowed
certificate principals as per
.Cm AuthorizedPrincipalsFile .
The program must be owned by root, not writable by group or others and
specified by an absolute path.
Arguments to
.Cm AuthorizedPrincipalsCommand
accept the tokens described in the
.Sx TOKENS
section.
If no arguments are specified then the username of the target user is used.
.Pp
The program should produce on standard output zero or
more lines of
.Cm AuthorizedPrincipalsFile
output.
If either
.Cm AuthorizedPrincipalsCommand
or
.Cm AuthorizedPrincipalsFile
is specified, then certificates offered by the client for authentication
must contain a principal that is listed.
By default, no
.Cm AuthorizedPrincipalsCommand
is run.
.It Cm AuthorizedPrincipalsCommandUser
Specifies the user under whose account the
.Cm AuthorizedPrincipalsCommand
is run.
It is recommended to use a dedicated user that has no other role on the host
than running authorized principals commands.
If
.Cm AuthorizedPrincipalsCommand
is specified but
.Cm AuthorizedPrincipalsCommandUser
is not, then
.Xr sshd 8
will refuse to start.
.It Cm AuthorizedPrincipalsFile
Specifies a file that lists principal names that are accepted for
certificate authentication.
When using certificates signed by a key listed in
.Cm TrustedUserCAKeys ,
this file lists names, one of which must appear in the certificate for it
to be accepted for authentication.
Names are listed one per line preceded by key options (as described in
.Sx AUTHORIZED_KEYS FILE FORMAT
in
.Xr sshd 8 ) .
Empty lines and comments starting with
.Ql #
are ignored.
.Pp
Arguments to
.Cm AuthorizedPrincipalsFile
accept the tokens described in the
.Sx TOKENS
section.
After expansion,
.Cm AuthorizedPrincipalsFile
is taken to be an absolute path or one relative to the user's home directory.
The default is
.Cm none ,
i.e. not to use a principals file \(en in this case, the username
of the user must appear in a certificate's principals list for it to be
accepted.
.Pp
Note that
.Cm AuthorizedPrincipalsFile
is only used when authentication proceeds using a CA listed in
.Cm TrustedUserCAKeys
and is not consulted for certification authorities trusted via
.Pa ~/.ssh/authorized_keys ,
though the
.Cm principals=
key option offers a similar facility (see
.Xr sshd 8
for details).
.It Cm Banner
The contents of the specified file are sent to the remote user before
authentication is allowed.
If the argument is
.Cm none
then no banner is displayed.
By default, no banner is displayed.
.It Cm CASignatureAlgorithms
Specifies which algorithms are allowed for signing of certificates
by certificate authorities (CAs).
The default is:
.Bd -literal -offset indent
-ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,
-ecdsa-sha2-nistp521,rsa-sha2-512,rsa-sha2-256,ssh-rsa
+ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
+sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com,
+rsa-sha2-512,rsa-sha2-256
.Ed
.Pp
Certificates signed using other algorithms will not be accepted for
public key or host-based authentication.
.It Cm ChallengeResponseAuthentication
Specifies whether challenge-response authentication is allowed (e.g. via
PAM or through authentication styles supported in
.Xr login.conf 5 )
The default is
.Cm yes .
.It Cm ChrootDirectory
Specifies the pathname of a directory to
.Xr chroot 2
to after authentication.
At session startup
.Xr sshd 8
checks that all components of the pathname are root-owned directories
which are not writable by any other user or group.
After the chroot,
.Xr sshd 8
changes the working directory to the user's home directory.
Arguments to
.Cm ChrootDirectory
accept the tokens described in the
.Sx TOKENS
section.
.Pp
The
.Cm ChrootDirectory
must contain the necessary files and directories to support the
user's session.
For an interactive session this requires at least a shell, typically
.Xr sh 1 ,
and basic
.Pa /dev
nodes such as
.Xr null 4 ,
.Xr zero 4 ,
.Xr stdin 4 ,
.Xr stdout 4 ,
.Xr stderr 4 ,
and
.Xr tty 4
devices.
For file transfer sessions using SFTP
no additional configuration of the environment is necessary if the in-process
sftp-server is used,
though sessions which use logging may require
.Pa /dev/log
inside the chroot directory on some operating systems (see
.Xr sftp-server 8
for details).
.Pp
For safety, it is very important that the directory hierarchy be
prevented from modification by other processes on the system (especially
those outside the jail).
Misconfiguration can lead to unsafe environments which
.Xr sshd 8
cannot detect.
.Pp
The default is
.Cm none ,
indicating not to
.Xr chroot 2 .
.It Cm Ciphers
Specifies the ciphers allowed.
Multiple ciphers must be comma-separated.
If the specified list begins with a
.Sq +
character, then the specified ciphers will be appended to the default set
instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified ciphers (including wildcards) will be removed
from the default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified ciphers will be placed at the head of the
default set.
.Pp
The supported ciphers are:
.Pp
.Bl -item -compact -offset indent
.It
3des-cbc
.It
aes128-cbc
.It
aes192-cbc
.It
aes256-cbc
.It
aes128-ctr
.It
aes192-ctr
.It
aes256-ctr
.It
aes128-gcm@openssh.com
.It
aes256-gcm@openssh.com
.It
chacha20-poly1305@openssh.com
.El
.Pp
The default is:
.Bd -literal -offset indent
chacha20-poly1305@openssh.com,
aes128-ctr,aes192-ctr,aes256-ctr,
aes128-gcm@openssh.com,aes256-gcm@openssh.com
.Ed
.Pp
The list of available ciphers may also be obtained using
.Qq ssh -Q cipher .
.It Cm ClientAliveCountMax
Sets the number of client alive messages which may be sent without
.Xr sshd 8
receiving any messages back from the client.
If this threshold is reached while client alive messages are being sent,
sshd will disconnect the client, terminating the session.
It is important to note that the use of client alive messages is very
different from
.Cm TCPKeepAlive .
The client alive messages are sent through the encrypted channel
and therefore will not be spoofable.
The TCP keepalive option enabled by
.Cm TCPKeepAlive
is spoofable.
The client alive mechanism is valuable when the client or
server depend on knowing when a connection has become unresponsive.
.Pp
The default value is 3.
If
.Cm ClientAliveInterval
is set to 15, and
.Cm ClientAliveCountMax
is left at the default, unresponsive SSH clients
will be disconnected after approximately 45 seconds.
Setting a zero
.Cm ClientAliveCountMax
disables connection termination.
.It Cm ClientAliveInterval
Sets a timeout interval in seconds after which if no data has been received
from the client,
.Xr sshd 8
will send a message through the encrypted
channel to request a response from the client.
The default
is 0, indicating that these messages will not be sent to the client.
.It Cm Compression
Specifies whether compression is enabled after
the user has authenticated successfully.
The argument must be
.Cm yes ,
.Cm delayed
(a legacy synonym for
.Cm yes )
or
.Cm no .
The default is
.Cm yes .
.It Cm DenyGroups
This keyword can be followed by a list of group name patterns, separated
by spaces.
Login is disallowed for users whose primary group or supplementary
group list matches one of the patterns.
Only group names are valid; a numerical group ID is not recognized.
By default, login is allowed for all groups.
The allow/deny groups directives are processed in the following order:
.Cm DenyGroups ,
.Cm AllowGroups .
.Pp
See PATTERNS in
.Xr ssh_config 5
for more information on patterns.
.It Cm DenyUsers
This keyword can be followed by a list of user name patterns, separated
by spaces.
Login is disallowed for user names that match one of the patterns.
Only user names are valid; a numerical user ID is not recognized.
By default, login is allowed for all users.
If the pattern takes the form USER@HOST then USER and HOST
are separately checked, restricting logins to particular
users from particular hosts.
HOST criteria may additionally contain addresses to match in CIDR
address/masklen format.
The allow/deny users directives are processed in the following order:
.Cm DenyUsers ,
.Cm AllowUsers .
.Pp
See PATTERNS in
.Xr ssh_config 5
for more information on patterns.
.It Cm DisableForwarding
Disables all forwarding features, including X11,
.Xr ssh-agent 1 ,
TCP and StreamLocal.
This option overrides all other forwarding-related options and may
simplify restricted configurations.
.It Cm ExposeAuthInfo
Writes a temporary file containing a list of authentication methods and
public credentials (e.g. keys) used to authenticate the user.
The location of the file is exposed to the user session through the
.Ev SSH_USER_AUTH
environment variable.
The default is
.Cm no .
.It Cm FingerprintHash
Specifies the hash algorithm used when logging key fingerprints.
Valid options are:
.Cm md5
and
.Cm sha256 .
The default is
.Cm sha256 .
.It Cm ForceCommand
Forces the execution of the command specified by
.Cm ForceCommand ,
ignoring any command supplied by the client and
.Pa ~/.ssh/rc
if present.
The command is invoked by using the user's login shell with the -c option.
This applies to shell, command, or subsystem execution.
It is most useful inside a
.Cm Match
block.
The command originally supplied by the client is available in the
.Ev SSH_ORIGINAL_COMMAND
environment variable.
Specifying a command of
.Cm internal-sftp
will force the use of an in-process SFTP server that requires no support
files when used with
.Cm ChrootDirectory .
The default is
.Cm none .
.It Cm GatewayPorts
Specifies whether remote hosts are allowed to connect to ports
forwarded for the client.
By default,
.Xr sshd 8
binds remote port forwardings to the loopback address.
This prevents other remote hosts from connecting to forwarded ports.
.Cm GatewayPorts
can be used to specify that sshd
should allow remote port forwardings to bind to non-loopback addresses, thus
allowing other hosts to connect.
The argument may be
.Cm no
to force remote port forwardings to be available to the local host only,
.Cm yes
to force remote port forwardings to bind to the wildcard address, or
.Cm clientspecified
to allow the client to select the address to which the forwarding is bound.
The default is
.Cm no .
.It Cm GSSAPIAuthentication
Specifies whether user authentication based on GSSAPI is allowed.
The default is
.Cm no .
.It Cm GSSAPICleanupCredentials
Specifies whether to automatically destroy the user's credentials cache
on logout.
The default is
.Cm yes .
.It Cm GSSAPIStrictAcceptorCheck
Determines whether to be strict about the identity of the GSSAPI acceptor
a client authenticates against.
If set to
.Cm yes
then the client must authenticate against the host
service on the current hostname.
If set to
.Cm no
then the client may authenticate against any service key stored in the
machine's default store.
This facility is provided to assist with operation on multi homed machines.
The default is
.Cm yes .
.It Cm HostbasedAcceptedAlgorithms
Specifies the signature algorithms that will be accepted for hostbased
authentication as a list of comma-separated patterns.
Alternately if the specified list begins with a
.Sq +
character, then the specified signature algorithms will be appended to
the default set instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified signature algorithms (including wildcards)
will be removed from the default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified signature algorithms will be placed at
the head of the default set.
The default for this option is:
.Bd -literal -offset 3n
ssh-ed25519-cert-v01@openssh.com,
ecdsa-sha2-nistp256-cert-v01@openssh.com,
ecdsa-sha2-nistp384-cert-v01@openssh.com,
ecdsa-sha2-nistp521-cert-v01@openssh.com,
sk-ssh-ed25519-cert-v01@openssh.com,
sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
rsa-sha2-512-cert-v01@openssh.com,
rsa-sha2-256-cert-v01@openssh.com,
ssh-rsa-cert-v01@openssh.com,
ssh-ed25519,
ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
sk-ssh-ed25519@openssh.com,
sk-ecdsa-sha2-nistp256@openssh.com,
rsa-sha2-512,rsa-sha2-256,ssh-rsa
.Ed
.Pp
The list of available signature algorithms may also be obtained using
.Qq ssh -Q HostbasedAcceptedAlgorithms .
This was formerly named HostbasedAcceptedKeyTypes.
.It Cm HostbasedAuthentication
Specifies whether rhosts or /etc/hosts.equiv authentication together
with successful public key client host authentication is allowed
(host-based authentication).
The default is
.Cm no .
.It Cm HostbasedUsesNameFromPacketOnly
Specifies whether or not the server will attempt to perform a reverse
name lookup when matching the name in the
.Pa ~/.shosts ,
.Pa ~/.rhosts ,
and
.Pa /etc/hosts.equiv
files during
.Cm HostbasedAuthentication .
A setting of
.Cm yes
means that
.Xr sshd 8
uses the name supplied by the client rather than
attempting to resolve the name from the TCP connection itself.
The default is
.Cm no .
.It Cm HostCertificate
Specifies a file containing a public host certificate.
The certificate's public key must match a private host key already specified
by
.Cm HostKey .
The default behaviour of
.Xr sshd 8
is not to load any certificates.
.It Cm HostKey
Specifies a file containing a private host key
used by SSH.
The defaults are
.Pa /etc/ssh/ssh_host_ecdsa_key ,
.Pa /etc/ssh/ssh_host_ed25519_key
and
.Pa /etc/ssh/ssh_host_rsa_key .
.Pp
Note that
.Xr sshd 8
will refuse to use a file if it is group/world-accessible
and that the
.Cm HostKeyAlgorithms
option restricts which of the keys are actually used by
.Xr sshd 8 .
.Pp
It is possible to have multiple host key files.
It is also possible to specify public host key files instead.
In this case operations on the private key will be delegated
to an
.Xr ssh-agent 1 .
.It Cm HostKeyAgent
Identifies the UNIX-domain socket used to communicate
with an agent that has access to the private host keys.
If the string
.Qq SSH_AUTH_SOCK
is specified, the location of the socket will be read from the
.Ev SSH_AUTH_SOCK
environment variable.
.It Cm HostKeyAlgorithms
Specifies the host key signature algorithms
that the server offers.
The default for this option is:
.Bd -literal -offset 3n
ssh-ed25519-cert-v01@openssh.com,
ecdsa-sha2-nistp256-cert-v01@openssh.com,
ecdsa-sha2-nistp384-cert-v01@openssh.com,
ecdsa-sha2-nistp521-cert-v01@openssh.com,
sk-ssh-ed25519-cert-v01@openssh.com,
sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
rsa-sha2-512-cert-v01@openssh.com,
rsa-sha2-256-cert-v01@openssh.com,
ssh-rsa-cert-v01@openssh.com,
ssh-ed25519,
ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
sk-ssh-ed25519@openssh.com,
sk-ecdsa-sha2-nistp256@openssh.com,
rsa-sha2-512,rsa-sha2-256,ssh-rsa
.Ed
.Pp
The list of available signature algorithms may also be obtained using
.Qq ssh -Q HostKeyAlgorithms .
.It Cm IgnoreRhosts
Specifies whether to ignore per-user
.Pa .rhosts
and
.Pa .shosts
files during
.Cm HostbasedAuthentication .
The system-wide
.Pa /etc/hosts.equiv
and
.Pa /etc/shosts.equiv
are still used regardless of this setting.
.Pp
Accepted values are
.Cm yes
(the default) to ignore all per-user files,
.Cm shosts-only
to allow the use of
.Pa .shosts
but to ignore
.Pa .rhosts
or
.Cm no
to allow both
.Pa .shosts
and
.Pa rhosts .
.It Cm IgnoreUserKnownHosts
Specifies whether
.Xr sshd 8
should ignore the user's
.Pa ~/.ssh/known_hosts
during
.Cm HostbasedAuthentication
and use only the system-wide known hosts file
.Pa /etc/ssh/known_hosts .
The default is
.Dq no .
.It Cm Include
Include the specified configuration file(s).
Multiple pathnames may be specified and each pathname may contain
.Xr glob 7
wildcards that will be expanded and processed in lexical order.
Files without absolute paths are assumed to be in
.Pa /etc/ssh .
An
.Cm Include
directive may appear inside a
.Cm Match
block
to perform conditional inclusion.
.It Cm IPQoS
Specifies the IPv4 type-of-service or DSCP class for the connection.
Accepted values are
.Cm af11 ,
.Cm af12 ,
.Cm af13 ,
.Cm af21 ,
.Cm af22 ,
.Cm af23 ,
.Cm af31 ,
.Cm af32 ,
.Cm af33 ,
.Cm af41 ,
.Cm af42 ,
.Cm af43 ,
.Cm cs0 ,
.Cm cs1 ,
.Cm cs2 ,
.Cm cs3 ,
.Cm cs4 ,
.Cm cs5 ,
.Cm cs6 ,
.Cm cs7 ,
.Cm ef ,
.Cm le ,
.Cm lowdelay ,
.Cm throughput ,
.Cm reliability ,
a numeric value, or
.Cm none
to use the operating system default.
This option may take one or two arguments, separated by whitespace.
If one argument is specified, it is used as the packet class unconditionally.
If two values are specified, the first is automatically selected for
interactive sessions and the second for non-interactive sessions.
The default is
.Cm af21
(Low-Latency Data)
for interactive sessions and
.Cm cs1
(Lower Effort)
for non-interactive sessions.
.It Cm KbdInteractiveAuthentication
Specifies whether to allow keyboard-interactive authentication.
The argument to this keyword must be
.Cm yes
or
.Cm no .
The default is to use whatever value
.Cm ChallengeResponseAuthentication
is set to
(by default
.Cm yes ) .
.It Cm KerberosAuthentication
Specifies whether the password provided by the user for
.Cm PasswordAuthentication
will be validated through the Kerberos KDC.
To use this option, the server needs a
Kerberos servtab which allows the verification of the KDC's identity.
The default is
.Cm no .
.It Cm KerberosGetAFSToken
If AFS is active and the user has a Kerberos 5 TGT, attempt to acquire
an AFS token before accessing the user's home directory.
The default is
.Cm no .
.It Cm KerberosOrLocalPasswd
If password authentication through Kerberos fails then
the password will be validated via any additional local mechanism
such as
.Pa /etc/passwd .
The default is
.Cm yes .
.It Cm KerberosTicketCleanup
Specifies whether to automatically destroy the user's ticket cache
file on logout.
The default is
.Cm yes .
.It Cm KexAlgorithms
Specifies the available KEX (Key Exchange) algorithms.
Multiple algorithms must be comma-separated.
Alternately if the specified list begins with a
.Sq +
character, then the specified methods will be appended to the default set
instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified methods (including wildcards) will be removed
from the default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified methods will be placed at the head of the
default set.
The supported algorithms are:
.Pp
.Bl -item -compact -offset indent
.It
curve25519-sha256
.It
curve25519-sha256@libssh.org
.It
diffie-hellman-group1-sha1
.It
diffie-hellman-group14-sha1
.It
diffie-hellman-group14-sha256
.It
diffie-hellman-group16-sha512
.It
diffie-hellman-group18-sha512
.It
diffie-hellman-group-exchange-sha1
.It
diffie-hellman-group-exchange-sha256
.It
ecdh-sha2-nistp256
.It
ecdh-sha2-nistp384
.It
ecdh-sha2-nistp521
.It
sntrup761x25519-sha512@openssh.com
.El
.Pp
The default is:
.Bd -literal -offset indent
curve25519-sha256,curve25519-sha256@libssh.org,
ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,
diffie-hellman-group-exchange-sha256,
diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,
diffie-hellman-group14-sha256
.Ed
.Pp
The list of available key exchange algorithms may also be obtained using
.Qq ssh -Q KexAlgorithms .
.It Cm ListenAddress
Specifies the local addresses
.Xr sshd 8
should listen on.
The following forms may be used:
.Pp
.Bl -item -offset indent -compact
.It
.Cm ListenAddress
.Sm off
.Ar hostname | address
.Sm on
.Op Cm rdomain Ar domain
.It
.Cm ListenAddress
.Sm off
.Ar hostname : port
.Sm on
.Op Cm rdomain Ar domain
.It
.Cm ListenAddress
.Sm off
.Ar IPv4_address : port
.Sm on
.Op Cm rdomain Ar domain
.It
.Cm ListenAddress
.Sm off
.Oo Ar hostname | address Oc : Ar port
.Sm on
.Op Cm rdomain Ar domain
.El
.Pp
The optional
.Cm rdomain
qualifier requests
.Xr sshd 8
listen in an explicit routing domain.
If
.Ar port
is not specified,
sshd will listen on the address and all
.Cm Port
options specified.
The default is to listen on all local addresses on the current default
routing domain.
Multiple
.Cm ListenAddress
options are permitted.
For more information on routing domains, see
.Xr rdomain 4 .
.It Cm LoginGraceTime
The server disconnects after this time if the user has not
successfully logged in.
If the value is 0, there is no time limit.
The default is 120 seconds.
.It Cm LogLevel
Gives the verbosity level that is used when logging messages from
.Xr sshd 8 .
The possible values are:
QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3.
The default is INFO.
DEBUG and DEBUG1 are equivalent.
DEBUG2 and DEBUG3 each specify higher levels of debugging output.
Logging with a DEBUG level violates the privacy of users and is not recommended.
.It Cm LogVerbose
Specify one or more overrides to LogLevel.
An override consists of a pattern lists that matches the source file, function
and line number to force detailed logging for.
For example, an override pattern of:
.Bd -literal -offset indent
kex.c:*:1000,*:kex_exchange_identification():*,packet.c:*
.Ed
.Pp
would enable detailed logging for line 1000 of
.Pa kex.c ,
everything in the
.Fn kex_exchange_identification
function, and all code in the
.Pa packet.c
file.
This option is intended for debugging and no overrides are enabled by default.
.It Cm MACs
Specifies the available MAC (message authentication code) algorithms.
The MAC algorithm is used for data integrity protection.
Multiple algorithms must be comma-separated.
If the specified list begins with a
.Sq +
character, then the specified algorithms will be appended to the default set
instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified algorithms (including wildcards) will be removed
from the default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified algorithms will be placed at the head of the
default set.
.Pp
The algorithms that contain
.Qq -etm
calculate the MAC after encryption (encrypt-then-mac).
These are considered safer and their use recommended.
The supported MACs are:
.Pp
.Bl -item -compact -offset indent
.It
hmac-md5
.It
hmac-md5-96
.It
hmac-sha1
.It
hmac-sha1-96
.It
hmac-sha2-256
.It
hmac-sha2-512
.It
umac-64@openssh.com
.It
umac-128@openssh.com
.It
hmac-md5-etm@openssh.com
.It
hmac-md5-96-etm@openssh.com
.It
hmac-sha1-etm@openssh.com
.It
hmac-sha1-96-etm@openssh.com
.It
hmac-sha2-256-etm@openssh.com
.It
hmac-sha2-512-etm@openssh.com
.It
umac-64-etm@openssh.com
.It
umac-128-etm@openssh.com
.El
.Pp
The default is:
.Bd -literal -offset indent
umac-64-etm@openssh.com,umac-128-etm@openssh.com,
hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,
hmac-sha1-etm@openssh.com,
umac-64@openssh.com,umac-128@openssh.com,
hmac-sha2-256,hmac-sha2-512,hmac-sha1
.Ed
.Pp
The list of available MAC algorithms may also be obtained using
.Qq ssh -Q mac .
.It Cm Match
Introduces a conditional block.
If all of the criteria on the
.Cm Match
line are satisfied, the keywords on the following lines override those
set in the global section of the config file, until either another
.Cm Match
line or the end of the file.
If a keyword appears in multiple
.Cm Match
blocks that are satisfied, only the first instance of the keyword is
applied.
.Pp
The arguments to
.Cm Match
are one or more criteria-pattern pairs or the single token
.Cm All
which matches all criteria.
The available criteria are
.Cm User ,
.Cm Group ,
.Cm Host ,
.Cm LocalAddress ,
.Cm LocalPort ,
.Cm RDomain ,
and
.Cm Address
(with
.Cm RDomain
representing the
.Xr rdomain 4
on which the connection was received).
.Pp
The match patterns may consist of single entries or comma-separated
lists and may use the wildcard and negation operators described in the
.Sx PATTERNS
section of
.Xr ssh_config 5 .
.Pp
The patterns in an
.Cm Address
criteria may additionally contain addresses to match in CIDR
address/masklen format,
such as 192.0.2.0/24 or 2001:db8::/32.
Note that the mask length provided must be consistent with the address -
it is an error to specify a mask length that is too long for the address
or one with bits set in this host portion of the address.
For example, 192.0.2.0/33 and 192.0.2.0/8, respectively.
.Pp
Only a subset of keywords may be used on the lines following a
.Cm Match
keyword.
Available keywords are
.Cm AcceptEnv ,
.Cm AllowAgentForwarding ,
.Cm AllowGroups ,
.Cm AllowStreamLocalForwarding ,
.Cm AllowTcpForwarding ,
.Cm AllowUsers ,
.Cm AuthenticationMethods ,
.Cm AuthorizedKeysCommand ,
.Cm AuthorizedKeysCommandUser ,
.Cm AuthorizedKeysFile ,
.Cm AuthorizedPrincipalsCommand ,
.Cm AuthorizedPrincipalsCommandUser ,
.Cm AuthorizedPrincipalsFile ,
.Cm Banner ,
.Cm ChrootDirectory ,
.Cm ClientAliveCountMax ,
.Cm ClientAliveInterval ,
.Cm DenyGroups ,
.Cm DenyUsers ,
.Cm DisableForwarding ,
.Cm ForceCommand ,
.Cm GatewayPorts ,
.Cm GSSAPIAuthentication ,
.Cm HostbasedAcceptedAlgorithms ,
.Cm HostbasedAuthentication ,
.Cm HostbasedUsesNameFromPacketOnly ,
.Cm IgnoreRhosts ,
.Cm Include ,
.Cm IPQoS ,
.Cm KbdInteractiveAuthentication ,
.Cm KerberosAuthentication ,
.Cm LogLevel ,
.Cm MaxAuthTries ,
.Cm MaxSessions ,
.Cm PasswordAuthentication ,
.Cm PermitEmptyPasswords ,
.Cm PermitListen ,
.Cm PermitOpen ,
.Cm PermitRootLogin ,
.Cm PermitTTY ,
.Cm PermitTunnel ,
.Cm PermitUserRC ,
.Cm PubkeyAcceptedAlgorithms ,
.Cm PubkeyAuthentication ,
.Cm RekeyLimit ,
.Cm RevokedKeys ,
.Cm RDomain ,
.Cm SetEnv ,
.Cm StreamLocalBindMask ,
.Cm StreamLocalBindUnlink ,
.Cm TrustedUserCAKeys ,
.Cm X11DisplayOffset ,
.Cm X11Forwarding
and
.Cm X11UseLocalhost .
.It Cm MaxAuthTries
Specifies the maximum number of authentication attempts permitted per
connection.
Once the number of failures reaches half this value,
additional failures are logged.
The default is 6.
.It Cm MaxSessions
Specifies the maximum number of open shell, login or subsystem (e.g. sftp)
sessions permitted per network connection.
Multiple sessions may be established by clients that support connection
multiplexing.
Setting
.Cm MaxSessions
to 1 will effectively disable session multiplexing, whereas setting it to 0
will prevent all shell, login and subsystem sessions while still permitting
forwarding.
The default is 10.
.It Cm MaxStartups
Specifies the maximum number of concurrent unauthenticated connections to the
SSH daemon.
Additional connections will be dropped until authentication succeeds or the
.Cm LoginGraceTime
expires for a connection.
The default is 10:30:100.
.Pp
Alternatively, random early drop can be enabled by specifying
the three colon separated values
start:rate:full (e.g. "10:30:60").
.Xr sshd 8
will refuse connection attempts with a probability of rate/100 (30%)
if there are currently start (10) unauthenticated connections.
The probability increases linearly and all connection attempts
are refused if the number of unauthenticated connections reaches full (60).
+.It Cm ModuliFile
+Specifies the
+.Xr moduli 5
+file that contains the Diffie-Hellman groups used for the
+.Dq diffie-hellman-group-exchange-sha1
+and
+.Dq diffie-hellman-group-exchange-sha256
+key exchange methods.
+The default is
+.Pa /etc/moduli .
.It Cm PasswordAuthentication
Specifies whether password authentication is allowed.
The default is
.Cm yes .
.It Cm PermitEmptyPasswords
When password authentication is allowed, it specifies whether the
server allows login to accounts with empty password strings.
The default is
.Cm no .
.It Cm PermitListen
Specifies the addresses/ports on which a remote TCP port forwarding may listen.
The listen specification must be one of the following forms:
.Pp
.Bl -item -offset indent -compact
.It
.Cm PermitListen
.Sm off
.Ar port
.Sm on
.It
.Cm PermitListen
.Sm off
.Ar host : port
.Sm on
.El
.Pp
Multiple permissions may be specified by separating them with whitespace.
An argument of
.Cm any
can be used to remove all restrictions and permit any listen requests.
An argument of
.Cm none
can be used to prohibit all listen requests.
The host name may contain wildcards as described in the PATTERNS section in
.Xr ssh_config 5 .
The wildcard
.Sq *
can also be used in place of a port number to allow all ports.
By default all port forwarding listen requests are permitted.
Note that the
.Cm GatewayPorts
option may further restrict which addresses may be listened on.
Note also that
.Xr ssh 1
will request a listen host of
.Dq localhost
if no listen host was specifically requested, and this name is
treated differently to explicit localhost addresses of
.Dq 127.0.0.1
and
.Dq ::1 .
.It Cm PermitOpen
Specifies the destinations to which TCP port forwarding is permitted.
The forwarding specification must be one of the following forms:
.Pp
.Bl -item -offset indent -compact
.It
.Cm PermitOpen
.Sm off
.Ar host : port
.Sm on
.It
.Cm PermitOpen
.Sm off
.Ar IPv4_addr : port
.Sm on
.It
.Cm PermitOpen
.Sm off
.Ar \&[ IPv6_addr \&] : port
.Sm on
.El
.Pp
Multiple forwards may be specified by separating them with whitespace.
An argument of
.Cm any
can be used to remove all restrictions and permit any forwarding requests.
An argument of
.Cm none
can be used to prohibit all forwarding requests.
The wildcard
.Sq *
can be used for host or port to allow all hosts or ports respectively.
Otherwise, no pattern matching or address lookups are performed on supplied
names.
By default all port forwarding requests are permitted.
.It Cm PermitRootLogin
Specifies whether root can log in using
.Xr ssh 1 .
The argument must be
.Cm yes ,
.Cm prohibit-password ,
.Cm forced-commands-only ,
or
.Cm no .
The default is
.Cm prohibit-password .
.Pp
If this option is set to
.Cm prohibit-password
(or its deprecated alias,
.Cm without-password ) ,
password and keyboard-interactive authentication are disabled for root.
.Pp
If this option is set to
.Cm forced-commands-only ,
root login with public key authentication will be allowed,
but only if the
.Ar command
option has been specified
(which may be useful for taking remote backups even if root login is
normally not allowed).
All other authentication methods are disabled for root.
.Pp
If this option is set to
.Cm no ,
root is not allowed to log in.
.It Cm PermitTTY
Specifies whether
.Xr pty 4
allocation is permitted.
The default is
.Cm yes .
.It Cm PermitTunnel
Specifies whether
.Xr tun 4
device forwarding is allowed.
The argument must be
.Cm yes ,
.Cm point-to-point
(layer 3),
.Cm ethernet
(layer 2), or
.Cm no .
Specifying
.Cm yes
permits both
.Cm point-to-point
and
.Cm ethernet .
The default is
.Cm no .
.Pp
Independent of this setting, the permissions of the selected
.Xr tun 4
device must allow access to the user.
.It Cm PermitUserEnvironment
Specifies whether
.Pa ~/.ssh/environment
and
.Cm environment=
options in
.Pa ~/.ssh/authorized_keys
are processed by
.Xr sshd 8 .
Valid options are
.Cm yes ,
.Cm no
or a pattern-list specifying which environment variable names to accept
(for example
.Qq LANG,LC_* ) .
The default is
.Cm no .
Enabling environment processing may enable users to bypass access
restrictions in some configurations using mechanisms such as
.Ev LD_PRELOAD .
.It Cm PermitUserRC
Specifies whether any
.Pa ~/.ssh/rc
file is executed.
The default is
.Cm yes .
.It Cm PerSourceMaxStartups
Specifies the number of unauthenticated connections allowed from a
given source address, or
.Dq none
if there is no limit.
This limit is applied in addition to
.Cm MaxStartups ,
whichever is lower.
The default is
.Cm none .
.It Cm PerSourceNetBlockSize
Specifies the number of bits of source address that are grouped together
for the purposes of applying PerSourceMaxStartups limits.
Values for IPv4 and optionally IPv6 may be specified, separated by a colon.
The default is
.Cm 32:128 ,
which means each address is considered individually.
.It Cm PidFile
Specifies the file that contains the process ID of the
SSH daemon, or
.Cm none
to not write one.
The default is
.Pa /var/run/sshd.pid .
.It Cm Port
Specifies the port number that
.Xr sshd 8
listens on.
The default is 22.
Multiple options of this type are permitted.
See also
.Cm ListenAddress .
.It Cm PrintLastLog
Specifies whether
.Xr sshd 8
should print the date and time of the last user login when a user logs
in interactively.
The default is
.Cm yes .
.It Cm PrintMotd
Specifies whether
.Xr sshd 8
should print
.Pa /etc/motd
when a user logs in interactively.
(On some systems it is also printed by the shell,
.Pa /etc/profile ,
or equivalent.)
The default is
.Cm yes .
.It Cm PubkeyAcceptedAlgorithms
Specifies the signature algorithms that will be accepted for public key
authentication as a list of comma-separated patterns.
Alternately if the specified list begins with a
.Sq +
character, then the specified algorithms will be appended to the default set
instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified algorithms (including wildcards) will be removed
from the default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified algorithms will be placed at the head of the
default set.
The default for this option is:
.Bd -literal -offset 3n
ssh-ed25519-cert-v01@openssh.com,
ecdsa-sha2-nistp256-cert-v01@openssh.com,
ecdsa-sha2-nistp384-cert-v01@openssh.com,
ecdsa-sha2-nistp521-cert-v01@openssh.com,
sk-ssh-ed25519-cert-v01@openssh.com,
sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
rsa-sha2-512-cert-v01@openssh.com,
rsa-sha2-256-cert-v01@openssh.com,
ssh-rsa-cert-v01@openssh.com,
ssh-ed25519,
ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
sk-ssh-ed25519@openssh.com,
sk-ecdsa-sha2-nistp256@openssh.com,
rsa-sha2-512,rsa-sha2-256,ssh-rsa
.Ed
.Pp
The list of available signature algorithms may also be obtained using
.Qq ssh -Q PubkeyAcceptedAlgorithms .
.It Cm PubkeyAuthOptions
Sets one or more public key authentication options.
The supported keywords are:
.Cm none
(the default; indicating no additional options are enabled),
.Cm touch-required
and
.Cm verify-required .
.Pp
The
.Cm touch-required
option causes public key authentication using a FIDO authenticator algorithm
(i.e.\&
.Cm ecdsa-sk
or
.Cm ed25519-sk )
to always require the signature to attest that a physically present user
explicitly confirmed the authentication (usually by touching the authenticator).
By default,
.Xr sshd 8
requires user presence unless overridden with an authorized_keys option.
The
.Cm touch-required
flag disables this override.
.Pp
The
.Cm verify-required
option requires a FIDO key signature attest that the user was verified,
e.g. via a PIN.
.Pp
Neither the
.Cm touch-required
or
.Cm verify-required
options have any effect for other, non-FIDO, public key types.
.It Cm PubkeyAuthentication
Specifies whether public key authentication is allowed.
The default is
.Cm yes .
.It Cm RekeyLimit
Specifies the maximum amount of data that may be transmitted before the
session key is renegotiated, optionally followed by a maximum amount of
time that may pass before the session key is renegotiated.
The first argument is specified in bytes and may have a suffix of
.Sq K ,
.Sq M ,
or
.Sq G
to indicate Kilobytes, Megabytes, or Gigabytes, respectively.
The default is between
.Sq 1G
and
.Sq 4G ,
depending on the cipher.
The optional second value is specified in seconds and may use any of the
units documented in the
.Sx TIME FORMATS
section.
The default value for
.Cm RekeyLimit
is
.Cm default none ,
which means that rekeying is performed after the cipher's default amount
of data has been sent or received and no time based rekeying is done.
.It Cm RevokedKeys
Specifies revoked public keys file, or
.Cm none
to not use one.
Keys listed in this file will be refused for public key authentication.
Note that if this file is not readable, then public key authentication will
be refused for all users.
Keys may be specified as a text file, listing one public key per line, or as
an OpenSSH Key Revocation List (KRL) as generated by
.Xr ssh-keygen 1 .
For more information on KRLs, see the KEY REVOCATION LISTS section in
.Xr ssh-keygen 1 .
.It Cm RDomain
Specifies an explicit routing domain that is applied after authentication
has completed.
The user session, as well and any forwarded or listening IP sockets,
will be bound to this
.Xr rdomain 4 .
If the routing domain is set to
.Cm \&%D ,
then the domain in which the incoming connection was received will be applied.
.It Cm SecurityKeyProvider
Specifies a path to a library that will be used when loading
FIDO authenticator-hosted keys, overriding the default of using
the built-in USB HID support.
.It Cm SetEnv
Specifies one or more environment variables to set in child sessions started
by
.Xr sshd 8
as
.Dq NAME=VALUE .
The environment value may be quoted (e.g. if it contains whitespace
characters).
Environment variables set by
.Cm SetEnv
override the default environment and any variables specified by the user
via
.Cm AcceptEnv
or
.Cm PermitUserEnvironment .
.It Cm StreamLocalBindMask
Sets the octal file creation mode mask
.Pq umask
used when creating a Unix-domain socket file for local or remote
port forwarding.
This option is only used for port forwarding to a Unix-domain socket file.
.Pp
The default value is 0177, which creates a Unix-domain socket file that is
readable and writable only by the owner.
Note that not all operating systems honor the file mode on Unix-domain
socket files.
.It Cm StreamLocalBindUnlink
Specifies whether to remove an existing Unix-domain socket file for local
or remote port forwarding before creating a new one.
If the socket file already exists and
.Cm StreamLocalBindUnlink
is not enabled,
.Nm sshd
will be unable to forward the port to the Unix-domain socket file.
This option is only used for port forwarding to a Unix-domain socket file.
.Pp
The argument must be
.Cm yes
or
.Cm no .
The default is
.Cm no .
.It Cm StrictModes
Specifies whether
.Xr sshd 8
should check file modes and ownership of the
user's files and home directory before accepting login.
This is normally desirable because novices sometimes accidentally leave their
directory or files world-writable.
The default is
.Cm yes .
Note that this does not apply to
.Cm ChrootDirectory ,
whose permissions and ownership are checked unconditionally.
.It Cm Subsystem
Configures an external subsystem (e.g. file transfer daemon).
Arguments should be a subsystem name and a command (with optional arguments)
to execute upon subsystem request.
.Pp
The command
.Cm sftp-server
implements the SFTP file transfer subsystem.
.Pp
Alternately the name
.Cm internal-sftp
implements an in-process SFTP server.
This may simplify configurations using
.Cm ChrootDirectory
to force a different filesystem root on clients.
.Pp
By default no subsystems are defined.
.It Cm SyslogFacility
Gives the facility code that is used when logging messages from
.Xr sshd 8 .
The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2,
LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
The default is AUTH.
.It Cm TCPKeepAlive
Specifies whether the system should send TCP keepalive messages to the
other side.
If they are sent, death of the connection or crash of one
of the machines will be properly noticed.
However, this means that
connections will die if the route is down temporarily, and some people
find it annoying.
On the other hand, if TCP keepalives are not sent,
sessions may hang indefinitely on the server, leaving
.Qq ghost
users and consuming server resources.
.Pp
The default is
.Cm yes
(to send TCP keepalive messages), and the server will notice
if the network goes down or the client host crashes.
This avoids infinitely hanging sessions.
.Pp
To disable TCP keepalive messages, the value should be set to
.Cm no .
.It Cm TrustedUserCAKeys
Specifies a file containing public keys of certificate authorities that are
trusted to sign user certificates for authentication, or
.Cm none
to not use one.
Keys are listed one per line; empty lines and comments starting with
.Ql #
are allowed.
If a certificate is presented for authentication and has its signing CA key
listed in this file, then it may be used for authentication for any user
listed in the certificate's principals list.
Note that certificates that lack a list of principals will not be permitted
for authentication using
.Cm TrustedUserCAKeys .
For more details on certificates, see the CERTIFICATES section in
.Xr ssh-keygen 1 .
.It Cm UseDNS
Specifies whether
.Xr sshd 8
should look up the remote host name, and to check that
the resolved host name for the remote IP address maps back to the
very same IP address.
.Pp
If this option is set to
.Cm no
(the default) then only addresses and not host names may be used in
.Pa ~/.ssh/authorized_keys
.Cm from
and
.Nm
.Cm Match
.Cm Host
directives.
.It Cm UsePAM
Enables the Pluggable Authentication Module interface.
If set to
.Cm yes
this will enable PAM authentication using
.Cm ChallengeResponseAuthentication
and
.Cm PasswordAuthentication
in addition to PAM account and session module processing for all
authentication types.
.Pp
Because PAM challenge-response authentication usually serves an equivalent
role to password authentication, you should disable either
.Cm PasswordAuthentication
or
.Cm ChallengeResponseAuthentication.
.Pp
If
.Cm UsePAM
is enabled, you will not be able to run
.Xr sshd 8
as a non-root user.
The default is
.Cm no .
.It Cm VersionAddendum
Optionally specifies additional text to append to the SSH protocol banner
sent by the server upon connection.
The default is
.Cm none .
.It Cm X11DisplayOffset
Specifies the first display number available for
.Xr sshd 8 Ns 's
X11 forwarding.
This prevents sshd from interfering with real X11 servers.
The default is 10.
.It Cm X11Forwarding
Specifies whether X11 forwarding is permitted.
The argument must be
.Cm yes
or
.Cm no .
The default is
.Cm no .
.Pp
When X11 forwarding is enabled, there may be additional exposure to
the server and to client displays if the
.Xr sshd 8
proxy display is configured to listen on the wildcard address (see
.Cm X11UseLocalhost ) ,
though this is not the default.
Additionally, the authentication spoofing and authentication data
verification and substitution occur on the client side.
The security risk of using X11 forwarding is that the client's X11
display server may be exposed to attack when the SSH client requests
forwarding (see the warnings for
.Cm ForwardX11
in
.Xr ssh_config 5 ) .
A system administrator may have a stance in which they want to
protect clients that may expose themselves to attack by unwittingly
requesting X11 forwarding, which can warrant a
.Cm no
setting.
.Pp
Note that disabling X11 forwarding does not prevent users from
forwarding X11 traffic, as users can always install their own forwarders.
.It Cm X11UseLocalhost
Specifies whether
.Xr sshd 8
should bind the X11 forwarding server to the loopback address or to
the wildcard address.
By default,
sshd binds the forwarding server to the loopback address and sets the
hostname part of the
.Ev DISPLAY
environment variable to
.Cm localhost .
This prevents remote hosts from connecting to the proxy display.
However, some older X11 clients may not function with this
configuration.
.Cm X11UseLocalhost
may be set to
.Cm no
to specify that the forwarding server should be bound to the wildcard
address.
The argument must be
.Cm yes
or
.Cm no .
The default is
.Cm yes .
.It Cm XAuthLocation
Specifies the full pathname of the
.Xr xauth 1
program, or
.Cm none
to not use one.
The default is
.Pa /usr/X11R6/bin/xauth .
.El
.Sh TIME FORMATS
.Xr sshd 8
command-line arguments and configuration file options that specify time
may be expressed using a sequence of the form:
.Sm off
.Ar time Op Ar qualifier ,
.Sm on
where
.Ar time
is a positive integer value and
.Ar qualifier
is one of the following:
.Pp
.Bl -tag -width Ds -compact -offset indent
.It Aq Cm none
seconds
.It Cm s | Cm S
seconds
.It Cm m | Cm M
minutes
.It Cm h | Cm H
hours
.It Cm d | Cm D
days
.It Cm w | Cm W
weeks
.El
.Pp
Each member of the sequence is added together to calculate
the total time value.
.Pp
Time format examples:
.Pp
.Bl -tag -width Ds -compact -offset indent
.It 600
600 seconds (10 minutes)
.It 10m
10 minutes
.It 1h30m
1 hour 30 minutes (90 minutes)
.El
.Sh TOKENS
Arguments to some keywords can make use of tokens,
which are expanded at runtime:
.Pp
.Bl -tag -width XXXX -offset indent -compact
.It %%
A literal
.Sq % .
.It \&%D
The routing domain in which the incoming connection was received.
.It %F
The fingerprint of the CA key.
.It %f
The fingerprint of the key or certificate.
.It %h
The home directory of the user.
.It %i
The key ID in the certificate.
.It %K
The base64-encoded CA key.
.It %k
The base64-encoded key or certificate for authentication.
.It %s
The serial number of the certificate.
.It \&%T
The type of the CA key.
.It %t
The key or certificate type.
.It \&%U
The numeric user ID of the target user.
.It %u
The username.
.El
.Pp
.Cm AuthorizedKeysCommand
accepts the tokens %%, %f, %h, %k, %t, %U, and %u.
.Pp
.Cm AuthorizedKeysFile
accepts the tokens %%, %h, %U, and %u.
.Pp
.Cm AuthorizedPrincipalsCommand
accepts the tokens %%, %F, %f, %h, %i, %K, %k, %s, %T, %t, %U, and %u.
.Pp
.Cm AuthorizedPrincipalsFile
accepts the tokens %%, %h, %U, and %u.
.Pp
.Cm ChrootDirectory
accepts the tokens %%, %h, %U, and %u.
.Pp
.Cm RoutingDomain
accepts the token %D.
.Sh FILES
.Bl -tag -width Ds
.It Pa /etc/ssh/sshd_config
Contains configuration data for
.Xr sshd 8 .
This file should be writable by root only, but it is recommended
(though not necessary) that it be world-readable.
.El
.Sh SEE ALSO
.Xr sftp-server 8 ,
.Xr sshd 8
.Sh AUTHORS
.An -nosplit
OpenSSH is a derivative of the original and free
ssh 1.2.12 release by
.An Tatu Ylonen .
.An Aaron Campbell , Bob Beck , Markus Friedl , Niels Provos ,
.An Theo de Raadt
and
.An Dug Song
removed many bugs, re-added newer features and
created OpenSSH.
.An Markus Friedl
contributed the support for SSH protocol versions 1.5 and 2.0.
.An Niels Provos
and
.An Markus Friedl
contributed support for privilege separation.
diff --git a/sshkey-xmss.c b/sshkey-xmss.c
index c81c689634e7..f5235ef2fbd8 100644
--- a/sshkey-xmss.c
+++ b/sshkey-xmss.c
@@ -1,1114 +1,1113 @@
-/* $OpenBSD: sshkey-xmss.c,v 1.9 2020/10/19 22:49:23 dtucker Exp $ */
+/* $OpenBSD: sshkey-xmss.c,v 1.11 2021/04/03 06:18:41 djm Exp $ */
/*
* Copyright (c) 2017 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#ifdef WITH_XMSS
#include <sys/types.h>
#include <sys/uio.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#ifdef HAVE_SYS_FILE_H
# include <sys/file.h>
#endif
#include "ssh2.h"
#include "ssherr.h"
#include "sshbuf.h"
#include "cipher.h"
#include "sshkey.h"
#include "sshkey-xmss.h"
#include "atomicio.h"
#include "log.h"
#include "xmss_fast.h"
/* opaque internal XMSS state */
#define XMSS_MAGIC "xmss-state-v1"
#define XMSS_CIPHERNAME "aes256-gcm@openssh.com"
struct ssh_xmss_state {
xmss_params params;
u_int32_t n, w, h, k;
bds_state bds;
u_char *stack;
u_int32_t stackoffset;
u_char *stacklevels;
u_char *auth;
u_char *keep;
u_char *th_nodes;
u_char *retain;
treehash_inst *treehash;
u_int32_t idx; /* state read from file */
u_int32_t maxidx; /* restricted # of signatures */
int have_state; /* .state file exists */
int lockfd; /* locked in sshkey_xmss_get_state() */
u_char allow_update; /* allow sshkey_xmss_update_state() */
char *enc_ciphername;/* encrypt state with cipher */
u_char *enc_keyiv; /* encrypt state with key */
u_int32_t enc_keyiv_len; /* length of enc_keyiv */
};
int sshkey_xmss_init_bds_state(struct sshkey *);
int sshkey_xmss_init_enc_key(struct sshkey *, const char *);
void sshkey_xmss_free_bds(struct sshkey *);
int sshkey_xmss_get_state_from_file(struct sshkey *, const char *,
int *, int);
int sshkey_xmss_encrypt_state(const struct sshkey *, struct sshbuf *,
struct sshbuf **);
int sshkey_xmss_decrypt_state(const struct sshkey *, struct sshbuf *,
struct sshbuf **);
int sshkey_xmss_serialize_enc_key(const struct sshkey *, struct sshbuf *);
int sshkey_xmss_deserialize_enc_key(struct sshkey *, struct sshbuf *);
#define PRINT(...) do { if (printerror) sshlog(__FILE__, __func__, __LINE__, \
- 0, SYSLOG_LEVEL_ERROR, __VA_ARGS__); } while (0)
+ 0, SYSLOG_LEVEL_ERROR, NULL, __VA_ARGS__); } while (0)
int
sshkey_xmss_init(struct sshkey *key, const char *name)
{
struct ssh_xmss_state *state;
if (key->xmss_state != NULL)
return SSH_ERR_INVALID_FORMAT;
if (name == NULL)
return SSH_ERR_INVALID_FORMAT;
state = calloc(sizeof(struct ssh_xmss_state), 1);
if (state == NULL)
return SSH_ERR_ALLOC_FAIL;
if (strcmp(name, XMSS_SHA2_256_W16_H10_NAME) == 0) {
state->n = 32;
state->w = 16;
state->h = 10;
} else if (strcmp(name, XMSS_SHA2_256_W16_H16_NAME) == 0) {
state->n = 32;
state->w = 16;
state->h = 16;
} else if (strcmp(name, XMSS_SHA2_256_W16_H20_NAME) == 0) {
state->n = 32;
state->w = 16;
state->h = 20;
} else {
free(state);
return SSH_ERR_KEY_TYPE_UNKNOWN;
}
if ((key->xmss_name = strdup(name)) == NULL) {
free(state);
return SSH_ERR_ALLOC_FAIL;
}
state->k = 2; /* XXX hardcoded */
state->lockfd = -1;
if (xmss_set_params(&state->params, state->n, state->h, state->w,
state->k) != 0) {
free(state);
return SSH_ERR_INVALID_FORMAT;
}
key->xmss_state = state;
return 0;
}
void
sshkey_xmss_free_state(struct sshkey *key)
{
struct ssh_xmss_state *state = key->xmss_state;
sshkey_xmss_free_bds(key);
if (state) {
if (state->enc_keyiv) {
explicit_bzero(state->enc_keyiv, state->enc_keyiv_len);
free(state->enc_keyiv);
}
free(state->enc_ciphername);
free(state);
}
key->xmss_state = NULL;
}
#define SSH_XMSS_K2_MAGIC "k=2"
#define num_stack(x) ((x->h+1)*(x->n))
#define num_stacklevels(x) (x->h+1)
#define num_auth(x) ((x->h)*(x->n))
#define num_keep(x) ((x->h >> 1)*(x->n))
#define num_th_nodes(x) ((x->h - x->k)*(x->n))
#define num_retain(x) (((1ULL << x->k) - x->k - 1) * (x->n))
#define num_treehash(x) ((x->h) - (x->k))
int
sshkey_xmss_init_bds_state(struct sshkey *key)
{
struct ssh_xmss_state *state = key->xmss_state;
u_int32_t i;
state->stackoffset = 0;
if ((state->stack = calloc(num_stack(state), 1)) == NULL ||
(state->stacklevels = calloc(num_stacklevels(state), 1))== NULL ||
(state->auth = calloc(num_auth(state), 1)) == NULL ||
(state->keep = calloc(num_keep(state), 1)) == NULL ||
(state->th_nodes = calloc(num_th_nodes(state), 1)) == NULL ||
(state->retain = calloc(num_retain(state), 1)) == NULL ||
(state->treehash = calloc(num_treehash(state),
sizeof(treehash_inst))) == NULL) {
sshkey_xmss_free_bds(key);
return SSH_ERR_ALLOC_FAIL;
}
for (i = 0; i < state->h - state->k; i++)
state->treehash[i].node = &state->th_nodes[state->n*i];
xmss_set_bds_state(&state->bds, state->stack, state->stackoffset,
state->stacklevels, state->auth, state->keep, state->treehash,
state->retain, 0);
return 0;
}
void
sshkey_xmss_free_bds(struct sshkey *key)
{
struct ssh_xmss_state *state = key->xmss_state;
if (state == NULL)
return;
free(state->stack);
free(state->stacklevels);
free(state->auth);
free(state->keep);
free(state->th_nodes);
free(state->retain);
free(state->treehash);
state->stack = NULL;
state->stacklevels = NULL;
state->auth = NULL;
state->keep = NULL;
state->th_nodes = NULL;
state->retain = NULL;
state->treehash = NULL;
}
void *
sshkey_xmss_params(const struct sshkey *key)
{
struct ssh_xmss_state *state = key->xmss_state;
if (state == NULL)
return NULL;
return &state->params;
}
void *
sshkey_xmss_bds_state(const struct sshkey *key)
{
struct ssh_xmss_state *state = key->xmss_state;
if (state == NULL)
return NULL;
return &state->bds;
}
int
sshkey_xmss_siglen(const struct sshkey *key, size_t *lenp)
{
struct ssh_xmss_state *state = key->xmss_state;
if (lenp == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if (state == NULL)
return SSH_ERR_INVALID_FORMAT;
*lenp = 4 + state->n +
state->params.wots_par.keysize +
state->h * state->n;
return 0;
}
size_t
sshkey_xmss_pklen(const struct sshkey *key)
{
struct ssh_xmss_state *state = key->xmss_state;
if (state == NULL)
return 0;
return state->n * 2;
}
size_t
sshkey_xmss_sklen(const struct sshkey *key)
{
struct ssh_xmss_state *state = key->xmss_state;
if (state == NULL)
return 0;
return state->n * 4 + 4;
}
int
sshkey_xmss_init_enc_key(struct sshkey *k, const char *ciphername)
{
struct ssh_xmss_state *state = k->xmss_state;
const struct sshcipher *cipher;
size_t keylen = 0, ivlen = 0;
if (state == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if ((cipher = cipher_by_name(ciphername)) == NULL)
return SSH_ERR_INTERNAL_ERROR;
if ((state->enc_ciphername = strdup(ciphername)) == NULL)
return SSH_ERR_ALLOC_FAIL;
keylen = cipher_keylen(cipher);
ivlen = cipher_ivlen(cipher);
state->enc_keyiv_len = keylen + ivlen;
if ((state->enc_keyiv = calloc(state->enc_keyiv_len, 1)) == NULL) {
free(state->enc_ciphername);
state->enc_ciphername = NULL;
return SSH_ERR_ALLOC_FAIL;
}
arc4random_buf(state->enc_keyiv, state->enc_keyiv_len);
return 0;
}
int
sshkey_xmss_serialize_enc_key(const struct sshkey *k, struct sshbuf *b)
{
struct ssh_xmss_state *state = k->xmss_state;
int r;
if (state == NULL || state->enc_keyiv == NULL ||
state->enc_ciphername == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if ((r = sshbuf_put_cstring(b, state->enc_ciphername)) != 0 ||
(r = sshbuf_put_string(b, state->enc_keyiv,
state->enc_keyiv_len)) != 0)
return r;
return 0;
}
int
sshkey_xmss_deserialize_enc_key(struct sshkey *k, struct sshbuf *b)
{
struct ssh_xmss_state *state = k->xmss_state;
size_t len;
int r;
if (state == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if ((r = sshbuf_get_cstring(b, &state->enc_ciphername, NULL)) != 0 ||
(r = sshbuf_get_string(b, &state->enc_keyiv, &len)) != 0)
return r;
state->enc_keyiv_len = len;
return 0;
}
int
sshkey_xmss_serialize_pk_info(const struct sshkey *k, struct sshbuf *b,
enum sshkey_serialize_rep opts)
{
struct ssh_xmss_state *state = k->xmss_state;
u_char have_info = 1;
u_int32_t idx;
int r;
if (state == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if (opts != SSHKEY_SERIALIZE_INFO)
return 0;
idx = k->xmss_sk ? PEEK_U32(k->xmss_sk) : state->idx;
if ((r = sshbuf_put_u8(b, have_info)) != 0 ||
(r = sshbuf_put_u32(b, idx)) != 0 ||
(r = sshbuf_put_u32(b, state->maxidx)) != 0)
return r;
return 0;
}
int
sshkey_xmss_deserialize_pk_info(struct sshkey *k, struct sshbuf *b)
{
struct ssh_xmss_state *state = k->xmss_state;
u_char have_info;
int r;
if (state == NULL)
return SSH_ERR_INVALID_ARGUMENT;
/* optional */
if (sshbuf_len(b) == 0)
return 0;
if ((r = sshbuf_get_u8(b, &have_info)) != 0)
return r;
if (have_info != 1)
return SSH_ERR_INVALID_ARGUMENT;
if ((r = sshbuf_get_u32(b, &state->idx)) != 0 ||
(r = sshbuf_get_u32(b, &state->maxidx)) != 0)
return r;
return 0;
}
int
sshkey_xmss_generate_private_key(struct sshkey *k, u_int bits)
{
int r;
const char *name;
if (bits == 10) {
name = XMSS_SHA2_256_W16_H10_NAME;
} else if (bits == 16) {
name = XMSS_SHA2_256_W16_H16_NAME;
} else if (bits == 20) {
name = XMSS_SHA2_256_W16_H20_NAME;
} else {
name = XMSS_DEFAULT_NAME;
}
if ((r = sshkey_xmss_init(k, name)) != 0 ||
(r = sshkey_xmss_init_bds_state(k)) != 0 ||
(r = sshkey_xmss_init_enc_key(k, XMSS_CIPHERNAME)) != 0)
return r;
if ((k->xmss_pk = malloc(sshkey_xmss_pklen(k))) == NULL ||
(k->xmss_sk = malloc(sshkey_xmss_sklen(k))) == NULL) {
return SSH_ERR_ALLOC_FAIL;
}
xmss_keypair(k->xmss_pk, k->xmss_sk, sshkey_xmss_bds_state(k),
sshkey_xmss_params(k));
return 0;
}
int
sshkey_xmss_get_state_from_file(struct sshkey *k, const char *filename,
int *have_file, int printerror)
{
struct sshbuf *b = NULL, *enc = NULL;
int ret = SSH_ERR_SYSTEM_ERROR, r, fd = -1;
u_int32_t len;
unsigned char buf[4], *data = NULL;
*have_file = 0;
if ((fd = open(filename, O_RDONLY)) >= 0) {
*have_file = 1;
if (atomicio(read, fd, buf, sizeof(buf)) != sizeof(buf)) {
- PRINT("%s: corrupt state file: %s", __func__, filename);
+ PRINT("corrupt state file: %s", filename);
goto done;
}
len = PEEK_U32(buf);
if ((data = calloc(len, 1)) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto done;
}
if (atomicio(read, fd, data, len) != len) {
- PRINT("%s: cannot read blob: %s", __func__, filename);
+ PRINT("cannot read blob: %s", filename);
goto done;
}
if ((enc = sshbuf_from(data, len)) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto done;
}
sshkey_xmss_free_bds(k);
if ((r = sshkey_xmss_decrypt_state(k, enc, &b)) != 0) {
ret = r;
goto done;
}
if ((r = sshkey_xmss_deserialize_state(k, b)) != 0) {
ret = r;
goto done;
}
ret = 0;
}
done:
if (fd != -1)
close(fd);
free(data);
sshbuf_free(enc);
sshbuf_free(b);
return ret;
}
int
sshkey_xmss_get_state(const struct sshkey *k, int printerror)
{
struct ssh_xmss_state *state = k->xmss_state;
u_int32_t idx = 0;
char *filename = NULL;
char *statefile = NULL, *ostatefile = NULL, *lockfile = NULL;
int lockfd = -1, have_state = 0, have_ostate, tries = 0;
int ret = SSH_ERR_INVALID_ARGUMENT, r;
if (state == NULL)
goto done;
/*
* If maxidx is set, then we are allowed a limited number
* of signatures, but don't need to access the disk.
* Otherwise we need to deal with the on-disk state.
*/
if (state->maxidx) {
/* xmss_sk always contains the current state */
idx = PEEK_U32(k->xmss_sk);
if (idx < state->maxidx) {
state->allow_update = 1;
return 0;
}
return SSH_ERR_INVALID_ARGUMENT;
}
if ((filename = k->xmss_filename) == NULL)
goto done;
if (asprintf(&lockfile, "%s.lock", filename) == -1 ||
asprintf(&statefile, "%s.state", filename) == -1 ||
asprintf(&ostatefile, "%s.ostate", filename) == -1) {
ret = SSH_ERR_ALLOC_FAIL;
goto done;
}
if ((lockfd = open(lockfile, O_CREAT|O_RDONLY, 0600)) == -1) {
ret = SSH_ERR_SYSTEM_ERROR;
- PRINT("%s: cannot open/create: %s", __func__, lockfile);
+ PRINT("cannot open/create: %s", lockfile);
goto done;
}
while (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
if (errno != EWOULDBLOCK) {
ret = SSH_ERR_SYSTEM_ERROR;
- PRINT("%s: cannot lock: %s", __func__, lockfile);
+ PRINT("cannot lock: %s", lockfile);
goto done;
}
if (++tries > 10) {
ret = SSH_ERR_SYSTEM_ERROR;
- PRINT("%s: giving up on: %s", __func__, lockfile);
+ PRINT("giving up on: %s", lockfile);
goto done;
}
usleep(1000*100*tries);
}
/* XXX no longer const */
if ((r = sshkey_xmss_get_state_from_file((struct sshkey *)k,
statefile, &have_state, printerror)) != 0) {
if ((r = sshkey_xmss_get_state_from_file((struct sshkey *)k,
ostatefile, &have_ostate, printerror)) == 0) {
state->allow_update = 1;
r = sshkey_xmss_forward_state(k, 1);
state->idx = PEEK_U32(k->xmss_sk);
state->allow_update = 0;
}
}
if (!have_state && !have_ostate) {
/* check that bds state is initialized */
if (state->bds.auth == NULL)
goto done;
- PRINT("%s: start from scratch idx 0: %u", __func__, state->idx);
+ PRINT("start from scratch idx 0: %u", state->idx);
} else if (r != 0) {
ret = r;
goto done;
}
if (state->idx + 1 < state->idx) {
- PRINT("%s: state wrap: %u", __func__, state->idx);
+ PRINT("state wrap: %u", state->idx);
goto done;
}
state->have_state = have_state;
state->lockfd = lockfd;
state->allow_update = 1;
lockfd = -1;
ret = 0;
done:
if (lockfd != -1)
close(lockfd);
free(lockfile);
free(statefile);
free(ostatefile);
return ret;
}
int
sshkey_xmss_forward_state(const struct sshkey *k, u_int32_t reserve)
{
struct ssh_xmss_state *state = k->xmss_state;
u_char *sig = NULL;
size_t required_siglen;
unsigned long long smlen;
u_char data;
int ret, r;
if (state == NULL || !state->allow_update)
return SSH_ERR_INVALID_ARGUMENT;
if (reserve == 0)
return SSH_ERR_INVALID_ARGUMENT;
if (state->idx + reserve <= state->idx)
return SSH_ERR_INVALID_ARGUMENT;
if ((r = sshkey_xmss_siglen(k, &required_siglen)) != 0)
return r;
if ((sig = malloc(required_siglen)) == NULL)
return SSH_ERR_ALLOC_FAIL;
while (reserve-- > 0) {
state->idx = PEEK_U32(k->xmss_sk);
smlen = required_siglen;
if ((ret = xmss_sign(k->xmss_sk, sshkey_xmss_bds_state(k),
sig, &smlen, &data, 0, sshkey_xmss_params(k))) != 0) {
r = SSH_ERR_INVALID_ARGUMENT;
break;
}
}
free(sig);
return r;
}
int
sshkey_xmss_update_state(const struct sshkey *k, int printerror)
{
struct ssh_xmss_state *state = k->xmss_state;
struct sshbuf *b = NULL, *enc = NULL;
u_int32_t idx = 0;
unsigned char buf[4];
char *filename = NULL;
char *statefile = NULL, *ostatefile = NULL, *nstatefile = NULL;
int fd = -1;
int ret = SSH_ERR_INVALID_ARGUMENT;
if (state == NULL || !state->allow_update)
return ret;
if (state->maxidx) {
/* no update since the number of signatures is limited */
ret = 0;
goto done;
}
idx = PEEK_U32(k->xmss_sk);
if (idx == state->idx) {
/* no signature happened, no need to update */
ret = 0;
goto done;
} else if (idx != state->idx + 1) {
- PRINT("%s: more than one signature happened: idx %u state %u",
- __func__, idx, state->idx);
+ PRINT("more than one signature happened: idx %u state %u",
+ idx, state->idx);
goto done;
}
state->idx = idx;
if ((filename = k->xmss_filename) == NULL)
goto done;
if (asprintf(&statefile, "%s.state", filename) == -1 ||
asprintf(&ostatefile, "%s.ostate", filename) == -1 ||
asprintf(&nstatefile, "%s.nstate", filename) == -1) {
ret = SSH_ERR_ALLOC_FAIL;
goto done;
}
unlink(nstatefile);
if ((b = sshbuf_new()) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto done;
}
if ((ret = sshkey_xmss_serialize_state(k, b)) != 0) {
- PRINT("%s: SERLIALIZE FAILED: %d", __func__, ret);
+ PRINT("SERLIALIZE FAILED: %d", ret);
goto done;
}
if ((ret = sshkey_xmss_encrypt_state(k, b, &enc)) != 0) {
- PRINT("%s: ENCRYPT FAILED: %d", __func__, ret);
+ PRINT("ENCRYPT FAILED: %d", ret);
goto done;
}
if ((fd = open(nstatefile, O_CREAT|O_WRONLY|O_EXCL, 0600)) == -1) {
ret = SSH_ERR_SYSTEM_ERROR;
- PRINT("%s: open new state file: %s", __func__, nstatefile);
+ PRINT("open new state file: %s", nstatefile);
goto done;
}
POKE_U32(buf, sshbuf_len(enc));
if (atomicio(vwrite, fd, buf, sizeof(buf)) != sizeof(buf)) {
ret = SSH_ERR_SYSTEM_ERROR;
- PRINT("%s: write new state file hdr: %s", __func__, nstatefile);
+ PRINT("write new state file hdr: %s", nstatefile);
close(fd);
goto done;
}
if (atomicio(vwrite, fd, sshbuf_mutable_ptr(enc), sshbuf_len(enc)) !=
sshbuf_len(enc)) {
ret = SSH_ERR_SYSTEM_ERROR;
- PRINT("%s: write new state file data: %s", __func__, nstatefile);
+ PRINT("write new state file data: %s", nstatefile);
close(fd);
goto done;
}
if (fsync(fd) == -1) {
ret = SSH_ERR_SYSTEM_ERROR;
- PRINT("%s: sync new state file: %s", __func__, nstatefile);
+ PRINT("sync new state file: %s", nstatefile);
close(fd);
goto done;
}
if (close(fd) == -1) {
ret = SSH_ERR_SYSTEM_ERROR;
- PRINT("%s: close new state file: %s", __func__, nstatefile);
+ PRINT("close new state file: %s", nstatefile);
goto done;
}
if (state->have_state) {
unlink(ostatefile);
if (link(statefile, ostatefile)) {
ret = SSH_ERR_SYSTEM_ERROR;
- PRINT("%s: backup state %s to %s", __func__, statefile,
- ostatefile);
+ PRINT("backup state %s to %s", statefile, ostatefile);
goto done;
}
}
if (rename(nstatefile, statefile) == -1) {
ret = SSH_ERR_SYSTEM_ERROR;
- PRINT("%s: rename %s to %s", __func__, nstatefile, statefile);
+ PRINT("rename %s to %s", nstatefile, statefile);
goto done;
}
ret = 0;
done:
if (state->lockfd != -1) {
close(state->lockfd);
state->lockfd = -1;
}
if (nstatefile)
unlink(nstatefile);
free(statefile);
free(ostatefile);
free(nstatefile);
sshbuf_free(b);
sshbuf_free(enc);
return ret;
}
int
sshkey_xmss_serialize_state(const struct sshkey *k, struct sshbuf *b)
{
struct ssh_xmss_state *state = k->xmss_state;
treehash_inst *th;
u_int32_t i, node;
int r;
if (state == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if (state->stack == NULL)
return SSH_ERR_INVALID_ARGUMENT;
state->stackoffset = state->bds.stackoffset; /* copy back */
if ((r = sshbuf_put_cstring(b, SSH_XMSS_K2_MAGIC)) != 0 ||
(r = sshbuf_put_u32(b, state->idx)) != 0 ||
(r = sshbuf_put_string(b, state->stack, num_stack(state))) != 0 ||
(r = sshbuf_put_u32(b, state->stackoffset)) != 0 ||
(r = sshbuf_put_string(b, state->stacklevels, num_stacklevels(state))) != 0 ||
(r = sshbuf_put_string(b, state->auth, num_auth(state))) != 0 ||
(r = sshbuf_put_string(b, state->keep, num_keep(state))) != 0 ||
(r = sshbuf_put_string(b, state->th_nodes, num_th_nodes(state))) != 0 ||
(r = sshbuf_put_string(b, state->retain, num_retain(state))) != 0 ||
(r = sshbuf_put_u32(b, num_treehash(state))) != 0)
return r;
for (i = 0; i < num_treehash(state); i++) {
th = &state->treehash[i];
node = th->node - state->th_nodes;
if ((r = sshbuf_put_u32(b, th->h)) != 0 ||
(r = sshbuf_put_u32(b, th->next_idx)) != 0 ||
(r = sshbuf_put_u32(b, th->stackusage)) != 0 ||
(r = sshbuf_put_u8(b, th->completed)) != 0 ||
(r = sshbuf_put_u32(b, node)) != 0)
return r;
}
return 0;
}
int
sshkey_xmss_serialize_state_opt(const struct sshkey *k, struct sshbuf *b,
enum sshkey_serialize_rep opts)
{
struct ssh_xmss_state *state = k->xmss_state;
int r = SSH_ERR_INVALID_ARGUMENT;
u_char have_stack, have_filename, have_enc;
if (state == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if ((r = sshbuf_put_u8(b, opts)) != 0)
return r;
switch (opts) {
case SSHKEY_SERIALIZE_STATE:
r = sshkey_xmss_serialize_state(k, b);
break;
case SSHKEY_SERIALIZE_FULL:
if ((r = sshkey_xmss_serialize_enc_key(k, b)) != 0)
return r;
r = sshkey_xmss_serialize_state(k, b);
break;
case SSHKEY_SERIALIZE_SHIELD:
/* all of stack/filename/enc are optional */
have_stack = state->stack != NULL;
if ((r = sshbuf_put_u8(b, have_stack)) != 0)
return r;
if (have_stack) {
state->idx = PEEK_U32(k->xmss_sk); /* update */
if ((r = sshkey_xmss_serialize_state(k, b)) != 0)
return r;
}
have_filename = k->xmss_filename != NULL;
if ((r = sshbuf_put_u8(b, have_filename)) != 0)
return r;
if (have_filename &&
(r = sshbuf_put_cstring(b, k->xmss_filename)) != 0)
return r;
have_enc = state->enc_keyiv != NULL;
if ((r = sshbuf_put_u8(b, have_enc)) != 0)
return r;
if (have_enc &&
(r = sshkey_xmss_serialize_enc_key(k, b)) != 0)
return r;
if ((r = sshbuf_put_u32(b, state->maxidx)) != 0 ||
(r = sshbuf_put_u8(b, state->allow_update)) != 0)
return r;
break;
case SSHKEY_SERIALIZE_DEFAULT:
r = 0;
break;
default:
r = SSH_ERR_INVALID_ARGUMENT;
break;
}
return r;
}
int
sshkey_xmss_deserialize_state(struct sshkey *k, struct sshbuf *b)
{
struct ssh_xmss_state *state = k->xmss_state;
treehash_inst *th;
u_int32_t i, lh, node;
size_t ls, lsl, la, lk, ln, lr;
char *magic;
int r = SSH_ERR_INTERNAL_ERROR;
if (state == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if (k->xmss_sk == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if ((state->treehash = calloc(num_treehash(state),
sizeof(treehash_inst))) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_get_cstring(b, &magic, NULL)) != 0 ||
(r = sshbuf_get_u32(b, &state->idx)) != 0 ||
(r = sshbuf_get_string(b, &state->stack, &ls)) != 0 ||
(r = sshbuf_get_u32(b, &state->stackoffset)) != 0 ||
(r = sshbuf_get_string(b, &state->stacklevels, &lsl)) != 0 ||
(r = sshbuf_get_string(b, &state->auth, &la)) != 0 ||
(r = sshbuf_get_string(b, &state->keep, &lk)) != 0 ||
(r = sshbuf_get_string(b, &state->th_nodes, &ln)) != 0 ||
(r = sshbuf_get_string(b, &state->retain, &lr)) != 0 ||
(r = sshbuf_get_u32(b, &lh)) != 0)
goto out;
if (strcmp(magic, SSH_XMSS_K2_MAGIC) != 0) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
/* XXX check stackoffset */
if (ls != num_stack(state) ||
lsl != num_stacklevels(state) ||
la != num_auth(state) ||
lk != num_keep(state) ||
ln != num_th_nodes(state) ||
lr != num_retain(state) ||
lh != num_treehash(state)) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
for (i = 0; i < num_treehash(state); i++) {
th = &state->treehash[i];
if ((r = sshbuf_get_u32(b, &th->h)) != 0 ||
(r = sshbuf_get_u32(b, &th->next_idx)) != 0 ||
(r = sshbuf_get_u32(b, &th->stackusage)) != 0 ||
(r = sshbuf_get_u8(b, &th->completed)) != 0 ||
(r = sshbuf_get_u32(b, &node)) != 0)
goto out;
if (node < num_th_nodes(state))
th->node = &state->th_nodes[node];
}
POKE_U32(k->xmss_sk, state->idx);
xmss_set_bds_state(&state->bds, state->stack, state->stackoffset,
state->stacklevels, state->auth, state->keep, state->treehash,
state->retain, 0);
/* success */
r = 0;
out:
free(magic);
return r;
}
int
sshkey_xmss_deserialize_state_opt(struct sshkey *k, struct sshbuf *b)
{
struct ssh_xmss_state *state = k->xmss_state;
enum sshkey_serialize_rep opts;
u_char have_state, have_stack, have_filename, have_enc;
int r;
if ((r = sshbuf_get_u8(b, &have_state)) != 0)
return r;
opts = have_state;
switch (opts) {
case SSHKEY_SERIALIZE_DEFAULT:
r = 0;
break;
case SSHKEY_SERIALIZE_SHIELD:
if ((r = sshbuf_get_u8(b, &have_stack)) != 0)
return r;
if (have_stack &&
(r = sshkey_xmss_deserialize_state(k, b)) != 0)
return r;
if ((r = sshbuf_get_u8(b, &have_filename)) != 0)
return r;
if (have_filename &&
(r = sshbuf_get_cstring(b, &k->xmss_filename, NULL)) != 0)
return r;
if ((r = sshbuf_get_u8(b, &have_enc)) != 0)
return r;
if (have_enc &&
(r = sshkey_xmss_deserialize_enc_key(k, b)) != 0)
return r;
if ((r = sshbuf_get_u32(b, &state->maxidx)) != 0 ||
(r = sshbuf_get_u8(b, &state->allow_update)) != 0)
return r;
break;
case SSHKEY_SERIALIZE_STATE:
if ((r = sshkey_xmss_deserialize_state(k, b)) != 0)
return r;
break;
case SSHKEY_SERIALIZE_FULL:
if ((r = sshkey_xmss_deserialize_enc_key(k, b)) != 0 ||
(r = sshkey_xmss_deserialize_state(k, b)) != 0)
return r;
break;
default:
r = SSH_ERR_INVALID_FORMAT;
break;
}
return r;
}
int
sshkey_xmss_encrypt_state(const struct sshkey *k, struct sshbuf *b,
struct sshbuf **retp)
{
struct ssh_xmss_state *state = k->xmss_state;
struct sshbuf *encrypted = NULL, *encoded = NULL, *padded = NULL;
struct sshcipher_ctx *ciphercontext = NULL;
const struct sshcipher *cipher;
u_char *cp, *key, *iv = NULL;
size_t i, keylen, ivlen, blocksize, authlen, encrypted_len, aadlen;
int r = SSH_ERR_INTERNAL_ERROR;
if (retp != NULL)
*retp = NULL;
if (state == NULL ||
state->enc_keyiv == NULL ||
state->enc_ciphername == NULL)
return SSH_ERR_INTERNAL_ERROR;
if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) {
r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
blocksize = cipher_blocksize(cipher);
keylen = cipher_keylen(cipher);
ivlen = cipher_ivlen(cipher);
authlen = cipher_authlen(cipher);
if (state->enc_keyiv_len != keylen + ivlen) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
key = state->enc_keyiv;
if ((encrypted = sshbuf_new()) == NULL ||
(encoded = sshbuf_new()) == NULL ||
(padded = sshbuf_new()) == NULL ||
(iv = malloc(ivlen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* replace first 4 bytes of IV with index to ensure uniqueness */
memcpy(iv, key + keylen, ivlen);
POKE_U32(iv, state->idx);
if ((r = sshbuf_put(encoded, XMSS_MAGIC, sizeof(XMSS_MAGIC))) != 0 ||
(r = sshbuf_put_u32(encoded, state->idx)) != 0)
goto out;
/* padded state will be encrypted */
if ((r = sshbuf_putb(padded, b)) != 0)
goto out;
i = 0;
while (sshbuf_len(padded) % blocksize) {
if ((r = sshbuf_put_u8(padded, ++i & 0xff)) != 0)
goto out;
}
encrypted_len = sshbuf_len(padded);
/* header including the length of state is used as AAD */
if ((r = sshbuf_put_u32(encoded, encrypted_len)) != 0)
goto out;
aadlen = sshbuf_len(encoded);
/* concat header and state */
if ((r = sshbuf_putb(encoded, padded)) != 0)
goto out;
/* reserve space for encryption of encoded data plus auth tag */
/* encrypt at offset addlen */
if ((r = sshbuf_reserve(encrypted,
encrypted_len + aadlen + authlen, &cp)) != 0 ||
(r = cipher_init(&ciphercontext, cipher, key, keylen,
iv, ivlen, 1)) != 0 ||
(r = cipher_crypt(ciphercontext, 0, cp, sshbuf_ptr(encoded),
encrypted_len, aadlen, authlen)) != 0)
goto out;
/* success */
r = 0;
out:
if (retp != NULL) {
*retp = encrypted;
encrypted = NULL;
}
sshbuf_free(padded);
sshbuf_free(encoded);
sshbuf_free(encrypted);
cipher_free(ciphercontext);
free(iv);
return r;
}
int
sshkey_xmss_decrypt_state(const struct sshkey *k, struct sshbuf *encoded,
struct sshbuf **retp)
{
struct ssh_xmss_state *state = k->xmss_state;
struct sshbuf *copy = NULL, *decrypted = NULL;
struct sshcipher_ctx *ciphercontext = NULL;
const struct sshcipher *cipher = NULL;
u_char *key, *iv = NULL, *dp;
size_t keylen, ivlen, authlen, aadlen;
u_int blocksize, encrypted_len, index;
int r = SSH_ERR_INTERNAL_ERROR;
if (retp != NULL)
*retp = NULL;
if (state == NULL ||
state->enc_keyiv == NULL ||
state->enc_ciphername == NULL)
return SSH_ERR_INTERNAL_ERROR;
if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
blocksize = cipher_blocksize(cipher);
keylen = cipher_keylen(cipher);
ivlen = cipher_ivlen(cipher);
authlen = cipher_authlen(cipher);
if (state->enc_keyiv_len != keylen + ivlen) {
r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
key = state->enc_keyiv;
if ((copy = sshbuf_fromb(encoded)) == NULL ||
(decrypted = sshbuf_new()) == NULL ||
(iv = malloc(ivlen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* check magic */
if (sshbuf_len(encoded) < sizeof(XMSS_MAGIC) ||
memcmp(sshbuf_ptr(encoded), XMSS_MAGIC, sizeof(XMSS_MAGIC))) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* parse public portion */
if ((r = sshbuf_consume(encoded, sizeof(XMSS_MAGIC))) != 0 ||
(r = sshbuf_get_u32(encoded, &index)) != 0 ||
(r = sshbuf_get_u32(encoded, &encrypted_len)) != 0)
goto out;
/* check size of encrypted key blob */
if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* check that an appropriate amount of auth data is present */
if (sshbuf_len(encoded) < authlen ||
sshbuf_len(encoded) - authlen < encrypted_len) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
aadlen = sshbuf_len(copy) - sshbuf_len(encoded);
/* replace first 4 bytes of IV with index to ensure uniqueness */
memcpy(iv, key + keylen, ivlen);
POKE_U32(iv, index);
/* decrypt private state of key */
if ((r = sshbuf_reserve(decrypted, aadlen + encrypted_len, &dp)) != 0 ||
(r = cipher_init(&ciphercontext, cipher, key, keylen,
iv, ivlen, 0)) != 0 ||
(r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(copy),
encrypted_len, aadlen, authlen)) != 0)
goto out;
/* there should be no trailing data */
if ((r = sshbuf_consume(encoded, encrypted_len + authlen)) != 0)
goto out;
if (sshbuf_len(encoded) != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* remove AAD */
if ((r = sshbuf_consume(decrypted, aadlen)) != 0)
goto out;
/* XXX encrypted includes unchecked padding */
/* success */
r = 0;
if (retp != NULL) {
*retp = decrypted;
decrypted = NULL;
}
out:
cipher_free(ciphercontext);
sshbuf_free(copy);
sshbuf_free(decrypted);
free(iv);
return r;
}
u_int32_t
sshkey_xmss_signatures_left(const struct sshkey *k)
{
struct ssh_xmss_state *state = k->xmss_state;
u_int32_t idx;
if (sshkey_type_plain(k->type) == KEY_XMSS && state &&
state->maxidx) {
idx = k->xmss_sk ? PEEK_U32(k->xmss_sk) : state->idx;
if (idx < state->maxidx)
return state->maxidx - idx;
}
return 0;
}
int
sshkey_xmss_enable_maxsign(struct sshkey *k, u_int32_t maxsign)
{
struct ssh_xmss_state *state = k->xmss_state;
if (sshkey_type_plain(k->type) != KEY_XMSS)
return SSH_ERR_INVALID_ARGUMENT;
if (maxsign == 0)
return 0;
if (state->idx + maxsign < state->idx)
return SSH_ERR_INVALID_ARGUMENT;
state->maxidx = state->idx + maxsign;
return 0;
}
#endif /* WITH_XMSS */
diff --git a/sshkey-xmss.h b/sshkey-xmss.h
index bf52d293c3a4..32a12be620b1 100644
--- a/sshkey-xmss.h
+++ b/sshkey-xmss.h
@@ -1,56 +1,56 @@
-/* $OpenBSD: sshkey-xmss.h,v 1.2 2020/10/19 22:49:23 dtucker Exp $ */
+/* $OpenBSD: sshkey-xmss.h,v 1.3 2021/04/03 06:18:41 djm Exp $ */
/*
* Copyright (c) 2017 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SSHKEY_XMSS_H
#define SSHKEY_XMSS_H
-#define XMSS_SHA2_256_W16_H10_NAME "XMSS_SHA2-256_W16_H10"
-#define XMSS_SHA2_256_W16_H16_NAME "XMSS_SHA2-256_W16_H16"
-#define XMSS_SHA2_256_W16_H20_NAME "XMSS_SHA2-256_W16_H20"
-#define XMSS_DEFAULT_NAME XMSS_SHA2_256_W16_H10_NAME
+#define XMSS_SHA2_256_W16_H10_NAME "XMSS_SHA2-256_W16_H10"
+#define XMSS_SHA2_256_W16_H16_NAME "XMSS_SHA2-256_W16_H16"
+#define XMSS_SHA2_256_W16_H20_NAME "XMSS_SHA2-256_W16_H20"
+#define XMSS_DEFAULT_NAME XMSS_SHA2_256_W16_H10_NAME
size_t sshkey_xmss_pklen(const struct sshkey *);
size_t sshkey_xmss_sklen(const struct sshkey *);
int sshkey_xmss_init(struct sshkey *, const char *);
void sshkey_xmss_free_state(struct sshkey *);
int sshkey_xmss_generate_private_key(struct sshkey *, u_int);
int sshkey_xmss_serialize_state(const struct sshkey *, struct sshbuf *);
int sshkey_xmss_serialize_state_opt(const struct sshkey *, struct sshbuf *,
- enum sshkey_serialize_rep);
+ enum sshkey_serialize_rep);
int sshkey_xmss_serialize_pk_info(const struct sshkey *, struct sshbuf *,
enum sshkey_serialize_rep);
int sshkey_xmss_deserialize_state(struct sshkey *, struct sshbuf *);
int sshkey_xmss_deserialize_state_opt(struct sshkey *, struct sshbuf *);
int sshkey_xmss_deserialize_pk_info(struct sshkey *, struct sshbuf *);
int sshkey_xmss_siglen(const struct sshkey *, size_t *);
void *sshkey_xmss_params(const struct sshkey *);
void *sshkey_xmss_bds_state(const struct sshkey *);
int sshkey_xmss_get_state(const struct sshkey *, int);
int sshkey_xmss_enable_maxsign(struct sshkey *, u_int32_t);
int sshkey_xmss_forward_state(const struct sshkey *, u_int32_t);
int sshkey_xmss_update_state(const struct sshkey *, int);
u_int32_t sshkey_xmss_signatures_left(const struct sshkey *);
#endif /* SSHKEY_XMSS_H */
diff --git a/sshkey.c b/sshkey.c
index b25c59a208ec..e92709dc1d2e 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -1,4831 +1,4831 @@
-/* $OpenBSD: sshkey.c,v 1.115 2021/02/02 22:36:46 djm Exp $ */
+/* $OpenBSD: sshkey.c,v 1.116 2021/04/03 06:18:41 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Alexander von Gernler. All rights reserved.
* Copyright (c) 2010,2011 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <netinet/in.h>
#ifdef WITH_OPENSSL
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#endif
#include "crypto_api.h"
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <resolv.h>
#include <time.h>
#ifdef HAVE_UTIL_H
#include <util.h>
#endif /* HAVE_UTIL_H */
#include "ssh2.h"
#include "ssherr.h"
#include "misc.h"
#include "sshbuf.h"
#include "cipher.h"
#include "digest.h"
#define SSHKEY_INTERNAL
#include "sshkey.h"
#include "match.h"
#include "ssh-sk.h"
#ifdef WITH_XMSS
#include "sshkey-xmss.h"
#include "xmss_fast.h"
#endif
#include "openbsd-compat/openssl-compat.h"
/* openssh private key file format */
#define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n"
#define MARK_END "-----END OPENSSH PRIVATE KEY-----\n"
#define MARK_BEGIN_LEN (sizeof(MARK_BEGIN) - 1)
#define MARK_END_LEN (sizeof(MARK_END) - 1)
#define KDFNAME "bcrypt"
#define AUTH_MAGIC "openssh-key-v1"
#define SALT_LEN 16
#define DEFAULT_CIPHERNAME "aes256-ctr"
#define DEFAULT_ROUNDS 16
/* Version identification string for SSH v1 identity files. */
#define LEGACY_BEGIN "SSH PRIVATE KEY FILE FORMAT 1.1\n"
/*
* Constants relating to "shielding" support; protection of keys expected
* to remain in memory for long durations
*/
#define SSHKEY_SHIELD_PREKEY_LEN (16 * 1024)
#define SSHKEY_SHIELD_CIPHER "aes256-ctr" /* XXX want AES-EME* */
#define SSHKEY_SHIELD_PREKEY_HASH SSH_DIGEST_SHA512
int sshkey_private_serialize_opt(struct sshkey *key,
struct sshbuf *buf, enum sshkey_serialize_rep);
static int sshkey_from_blob_internal(struct sshbuf *buf,
struct sshkey **keyp, int allow_cert);
/* Supported key types */
struct keytype {
const char *name;
const char *shortname;
const char *sigalg;
int type;
int nid;
int cert;
int sigonly;
};
static const struct keytype keytypes[] = {
{ "ssh-ed25519", "ED25519", NULL, KEY_ED25519, 0, 0, 0 },
{ "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", NULL,
KEY_ED25519_CERT, 0, 1, 0 },
{ "sk-ssh-ed25519@openssh.com", "ED25519-SK", NULL,
KEY_ED25519_SK, 0, 0, 0 },
{ "sk-ssh-ed25519-cert-v01@openssh.com", "ED25519-SK-CERT", NULL,
KEY_ED25519_SK_CERT, 0, 1, 0 },
#ifdef WITH_XMSS
{ "ssh-xmss@openssh.com", "XMSS", NULL, KEY_XMSS, 0, 0, 0 },
{ "ssh-xmss-cert-v01@openssh.com", "XMSS-CERT", NULL,
KEY_XMSS_CERT, 0, 1, 0 },
#endif /* WITH_XMSS */
#ifdef WITH_OPENSSL
{ "ssh-rsa", "RSA", NULL, KEY_RSA, 0, 0, 0 },
{ "rsa-sha2-256", "RSA", NULL, KEY_RSA, 0, 0, 1 },
{ "rsa-sha2-512", "RSA", NULL, KEY_RSA, 0, 0, 1 },
{ "ssh-dss", "DSA", NULL, KEY_DSA, 0, 0, 0 },
# ifdef OPENSSL_HAS_ECC
{ "ecdsa-sha2-nistp256", "ECDSA", NULL,
KEY_ECDSA, NID_X9_62_prime256v1, 0, 0 },
{ "ecdsa-sha2-nistp384", "ECDSA", NULL,
KEY_ECDSA, NID_secp384r1, 0, 0 },
# ifdef OPENSSL_HAS_NISTP521
{ "ecdsa-sha2-nistp521", "ECDSA", NULL,
KEY_ECDSA, NID_secp521r1, 0, 0 },
# endif /* OPENSSL_HAS_NISTP521 */
{ "sk-ecdsa-sha2-nistp256@openssh.com", "ECDSA-SK", NULL,
KEY_ECDSA_SK, NID_X9_62_prime256v1, 0, 0 },
{ "webauthn-sk-ecdsa-sha2-nistp256@openssh.com", "ECDSA-SK", NULL,
KEY_ECDSA_SK, NID_X9_62_prime256v1, 0, 1 },
# endif /* OPENSSL_HAS_ECC */
{ "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", NULL,
KEY_RSA_CERT, 0, 1, 0 },
{ "rsa-sha2-256-cert-v01@openssh.com", "RSA-CERT",
"rsa-sha2-256", KEY_RSA_CERT, 0, 1, 1 },
{ "rsa-sha2-512-cert-v01@openssh.com", "RSA-CERT",
"rsa-sha2-512", KEY_RSA_CERT, 0, 1, 1 },
{ "ssh-dss-cert-v01@openssh.com", "DSA-CERT", NULL,
KEY_DSA_CERT, 0, 1, 0 },
# ifdef OPENSSL_HAS_ECC
{ "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT", NULL,
KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1, 0 },
{ "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT", NULL,
KEY_ECDSA_CERT, NID_secp384r1, 1, 0 },
# ifdef OPENSSL_HAS_NISTP521
{ "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT", NULL,
- KEY_ECDSA_CERT, NID_secp521r1, 1, 0 },
+ KEY_ECDSA_CERT, NID_secp521r1, 1, 0 },
# endif /* OPENSSL_HAS_NISTP521 */
{ "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-SK-CERT", NULL,
KEY_ECDSA_SK_CERT, NID_X9_62_prime256v1, 1, 0 },
# endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
{ NULL, NULL, NULL, -1, -1, 0, 0 }
};
const char *
sshkey_type(const struct sshkey *k)
{
const struct keytype *kt;
for (kt = keytypes; kt->type != -1; kt++) {
if (kt->type == k->type)
return kt->shortname;
}
return "unknown";
}
static const char *
sshkey_ssh_name_from_type_nid(int type, int nid)
{
const struct keytype *kt;
for (kt = keytypes; kt->type != -1; kt++) {
if (kt->type == type && (kt->nid == 0 || kt->nid == nid))
return kt->name;
}
return "ssh-unknown";
}
int
sshkey_type_is_cert(int type)
{
const struct keytype *kt;
for (kt = keytypes; kt->type != -1; kt++) {
if (kt->type == type)
return kt->cert;
}
return 0;
}
const char *
sshkey_ssh_name(const struct sshkey *k)
{
return sshkey_ssh_name_from_type_nid(k->type, k->ecdsa_nid);
}
const char *
sshkey_ssh_name_plain(const struct sshkey *k)
{
return sshkey_ssh_name_from_type_nid(sshkey_type_plain(k->type),
k->ecdsa_nid);
}
int
sshkey_type_from_name(const char *name)
{
const struct keytype *kt;
for (kt = keytypes; kt->type != -1; kt++) {
/* Only allow shortname matches for plain key types */
if ((kt->name != NULL && strcmp(name, kt->name) == 0) ||
(!kt->cert && strcasecmp(kt->shortname, name) == 0))
return kt->type;
}
return KEY_UNSPEC;
}
static int
key_type_is_ecdsa_variant(int type)
{
switch (type) {
case KEY_ECDSA:
case KEY_ECDSA_CERT:
case KEY_ECDSA_SK:
case KEY_ECDSA_SK_CERT:
return 1;
}
return 0;
}
int
sshkey_ecdsa_nid_from_name(const char *name)
{
const struct keytype *kt;
for (kt = keytypes; kt->type != -1; kt++) {
if (!key_type_is_ecdsa_variant(kt->type))
continue;
if (kt->name != NULL && strcmp(name, kt->name) == 0)
return kt->nid;
}
return -1;
}
char *
sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep)
{
char *tmp, *ret = NULL;
size_t nlen, rlen = 0;
const struct keytype *kt;
for (kt = keytypes; kt->type != -1; kt++) {
if (kt->name == NULL)
continue;
if (!include_sigonly && kt->sigonly)
continue;
if ((certs_only && !kt->cert) || (plain_only && kt->cert))
continue;
if (ret != NULL)
ret[rlen++] = sep;
nlen = strlen(kt->name);
if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
free(ret);
return NULL;
}
ret = tmp;
memcpy(ret + rlen, kt->name, nlen + 1);
rlen += nlen;
}
return ret;
}
int
sshkey_names_valid2(const char *names, int allow_wildcard)
{
char *s, *cp, *p;
const struct keytype *kt;
int type;
if (names == NULL || strcmp(names, "") == 0)
return 0;
if ((s = cp = strdup(names)) == NULL)
return 0;
for ((p = strsep(&cp, ",")); p && *p != '\0';
(p = strsep(&cp, ","))) {
type = sshkey_type_from_name(p);
if (type == KEY_UNSPEC) {
if (allow_wildcard) {
/*
* Try matching key types against the string.
* If any has a positive or negative match then
* the component is accepted.
*/
for (kt = keytypes; kt->type != -1; kt++) {
if (match_pattern_list(kt->name,
p, 0) != 0)
break;
}
if (kt->type != -1)
continue;
}
free(s);
return 0;
}
}
free(s);
return 1;
}
u_int
sshkey_size(const struct sshkey *k)
{
#ifdef WITH_OPENSSL
const BIGNUM *rsa_n, *dsa_p;
#endif /* WITH_OPENSSL */
switch (k->type) {
#ifdef WITH_OPENSSL
case KEY_RSA:
case KEY_RSA_CERT:
if (k->rsa == NULL)
return 0;
RSA_get0_key(k->rsa, &rsa_n, NULL, NULL);
return BN_num_bits(rsa_n);
case KEY_DSA:
case KEY_DSA_CERT:
if (k->dsa == NULL)
return 0;
DSA_get0_pqg(k->dsa, &dsa_p, NULL, NULL);
return BN_num_bits(dsa_p);
case KEY_ECDSA:
case KEY_ECDSA_CERT:
case KEY_ECDSA_SK:
case KEY_ECDSA_SK_CERT:
return sshkey_curve_nid_to_bits(k->ecdsa_nid);
#endif /* WITH_OPENSSL */
case KEY_ED25519:
case KEY_ED25519_CERT:
case KEY_ED25519_SK:
case KEY_ED25519_SK_CERT:
case KEY_XMSS:
case KEY_XMSS_CERT:
return 256; /* XXX */
}
return 0;
}
static int
sshkey_type_is_valid_ca(int type)
{
switch (type) {
case KEY_RSA:
case KEY_DSA:
case KEY_ECDSA:
case KEY_ECDSA_SK:
case KEY_ED25519:
case KEY_ED25519_SK:
case KEY_XMSS:
return 1;
default:
return 0;
}
}
int
sshkey_is_cert(const struct sshkey *k)
{
if (k == NULL)
return 0;
return sshkey_type_is_cert(k->type);
}
int
sshkey_is_sk(const struct sshkey *k)
{
if (k == NULL)
return 0;
switch (sshkey_type_plain(k->type)) {
case KEY_ECDSA_SK:
case KEY_ED25519_SK:
return 1;
default:
return 0;
}
}
/* Return the cert-less equivalent to a certified key type */
int
sshkey_type_plain(int type)
{
switch (type) {
case KEY_RSA_CERT:
return KEY_RSA;
case KEY_DSA_CERT:
return KEY_DSA;
case KEY_ECDSA_CERT:
return KEY_ECDSA;
case KEY_ECDSA_SK_CERT:
return KEY_ECDSA_SK;
case KEY_ED25519_CERT:
return KEY_ED25519;
case KEY_ED25519_SK_CERT:
return KEY_ED25519_SK;
case KEY_XMSS_CERT:
return KEY_XMSS;
default:
return type;
}
}
#ifdef WITH_OPENSSL
/* XXX: these are really begging for a table-driven approach */
int
sshkey_curve_name_to_nid(const char *name)
{
if (strcmp(name, "nistp256") == 0)
return NID_X9_62_prime256v1;
else if (strcmp(name, "nistp384") == 0)
return NID_secp384r1;
# ifdef OPENSSL_HAS_NISTP521
else if (strcmp(name, "nistp521") == 0)
return NID_secp521r1;
# endif /* OPENSSL_HAS_NISTP521 */
else
return -1;
}
u_int
sshkey_curve_nid_to_bits(int nid)
{
switch (nid) {
case NID_X9_62_prime256v1:
return 256;
case NID_secp384r1:
return 384;
# ifdef OPENSSL_HAS_NISTP521
case NID_secp521r1:
return 521;
# endif /* OPENSSL_HAS_NISTP521 */
default:
return 0;
}
}
int
sshkey_ecdsa_bits_to_nid(int bits)
{
switch (bits) {
case 256:
return NID_X9_62_prime256v1;
case 384:
return NID_secp384r1;
# ifdef OPENSSL_HAS_NISTP521
case 521:
return NID_secp521r1;
# endif /* OPENSSL_HAS_NISTP521 */
default:
return -1;
}
}
const char *
sshkey_curve_nid_to_name(int nid)
{
switch (nid) {
case NID_X9_62_prime256v1:
return "nistp256";
case NID_secp384r1:
return "nistp384";
# ifdef OPENSSL_HAS_NISTP521
case NID_secp521r1:
return "nistp521";
# endif /* OPENSSL_HAS_NISTP521 */
default:
return NULL;
}
}
int
sshkey_ec_nid_to_hash_alg(int nid)
{
int kbits = sshkey_curve_nid_to_bits(nid);
if (kbits <= 0)
return -1;
/* RFC5656 section 6.2.1 */
if (kbits <= 256)
return SSH_DIGEST_SHA256;
else if (kbits <= 384)
return SSH_DIGEST_SHA384;
else
return SSH_DIGEST_SHA512;
}
#endif /* WITH_OPENSSL */
static void
cert_free(struct sshkey_cert *cert)
{
u_int i;
if (cert == NULL)
return;
sshbuf_free(cert->certblob);
sshbuf_free(cert->critical);
sshbuf_free(cert->extensions);
free(cert->key_id);
for (i = 0; i < cert->nprincipals; i++)
free(cert->principals[i]);
free(cert->principals);
sshkey_free(cert->signature_key);
free(cert->signature_type);
freezero(cert, sizeof(*cert));
}
static struct sshkey_cert *
cert_new(void)
{
struct sshkey_cert *cert;
if ((cert = calloc(1, sizeof(*cert))) == NULL)
return NULL;
if ((cert->certblob = sshbuf_new()) == NULL ||
(cert->critical = sshbuf_new()) == NULL ||
(cert->extensions = sshbuf_new()) == NULL) {
cert_free(cert);
return NULL;
}
cert->key_id = NULL;
cert->principals = NULL;
cert->signature_key = NULL;
cert->signature_type = NULL;
return cert;
}
struct sshkey *
sshkey_new(int type)
{
struct sshkey *k;
#ifdef WITH_OPENSSL
RSA *rsa;
DSA *dsa;
#endif /* WITH_OPENSSL */
if ((k = calloc(1, sizeof(*k))) == NULL)
return NULL;
k->type = type;
k->ecdsa = NULL;
k->ecdsa_nid = -1;
k->dsa = NULL;
k->rsa = NULL;
k->cert = NULL;
k->ed25519_sk = NULL;
k->ed25519_pk = NULL;
k->xmss_sk = NULL;
k->xmss_pk = NULL;
switch (k->type) {
#ifdef WITH_OPENSSL
case KEY_RSA:
case KEY_RSA_CERT:
if ((rsa = RSA_new()) == NULL) {
free(k);
return NULL;
}
k->rsa = rsa;
break;
case KEY_DSA:
case KEY_DSA_CERT:
if ((dsa = DSA_new()) == NULL) {
free(k);
return NULL;
}
k->dsa = dsa;
break;
case KEY_ECDSA:
case KEY_ECDSA_CERT:
case KEY_ECDSA_SK:
case KEY_ECDSA_SK_CERT:
/* Cannot do anything until we know the group */
break;
#endif /* WITH_OPENSSL */
case KEY_ED25519:
case KEY_ED25519_CERT:
case KEY_ED25519_SK:
case KEY_ED25519_SK_CERT:
case KEY_XMSS:
case KEY_XMSS_CERT:
/* no need to prealloc */
break;
case KEY_UNSPEC:
break;
default:
free(k);
return NULL;
}
if (sshkey_is_cert(k)) {
if ((k->cert = cert_new()) == NULL) {
sshkey_free(k);
return NULL;
}
}
return k;
}
void
sshkey_free(struct sshkey *k)
{
if (k == NULL)
return;
switch (k->type) {
#ifdef WITH_OPENSSL
case KEY_RSA:
case KEY_RSA_CERT:
RSA_free(k->rsa);
k->rsa = NULL;
break;
case KEY_DSA:
case KEY_DSA_CERT:
DSA_free(k->dsa);
k->dsa = NULL;
break;
# ifdef OPENSSL_HAS_ECC
case KEY_ECDSA_SK:
case KEY_ECDSA_SK_CERT:
free(k->sk_application);
sshbuf_free(k->sk_key_handle);
sshbuf_free(k->sk_reserved);
/* FALLTHROUGH */
case KEY_ECDSA:
case KEY_ECDSA_CERT:
EC_KEY_free(k->ecdsa);
k->ecdsa = NULL;
break;
# endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
case KEY_ED25519_SK:
case KEY_ED25519_SK_CERT:
free(k->sk_application);
sshbuf_free(k->sk_key_handle);
sshbuf_free(k->sk_reserved);
/* FALLTHROUGH */
case KEY_ED25519:
case KEY_ED25519_CERT:
freezero(k->ed25519_pk, ED25519_PK_SZ);
k->ed25519_pk = NULL;
freezero(k->ed25519_sk, ED25519_SK_SZ);
k->ed25519_sk = NULL;
break;
#ifdef WITH_XMSS
case KEY_XMSS:
case KEY_XMSS_CERT:
freezero(k->xmss_pk, sshkey_xmss_pklen(k));
k->xmss_pk = NULL;
freezero(k->xmss_sk, sshkey_xmss_sklen(k));
k->xmss_sk = NULL;
sshkey_xmss_free_state(k);
free(k->xmss_name);
k->xmss_name = NULL;
free(k->xmss_filename);
k->xmss_filename = NULL;
break;
#endif /* WITH_XMSS */
case KEY_UNSPEC:
break;
default:
break;
}
if (sshkey_is_cert(k))
cert_free(k->cert);
freezero(k->shielded_private, k->shielded_len);
freezero(k->shield_prekey, k->shield_prekey_len);
freezero(k, sizeof(*k));
}
static int
cert_compare(struct sshkey_cert *a, struct sshkey_cert *b)
{
if (a == NULL && b == NULL)
return 1;
if (a == NULL || b == NULL)
return 0;
if (sshbuf_len(a->certblob) != sshbuf_len(b->certblob))
return 0;
if (timingsafe_bcmp(sshbuf_ptr(a->certblob), sshbuf_ptr(b->certblob),
sshbuf_len(a->certblob)) != 0)
return 0;
return 1;
}
/*
* Compare public portions of key only, allowing comparisons between
* certificates and plain keys too.
*/
int
sshkey_equal_public(const struct sshkey *a, const struct sshkey *b)
{
#if defined(WITH_OPENSSL)
const BIGNUM *rsa_e_a, *rsa_n_a;
const BIGNUM *rsa_e_b, *rsa_n_b;
const BIGNUM *dsa_p_a, *dsa_q_a, *dsa_g_a, *dsa_pub_key_a;
const BIGNUM *dsa_p_b, *dsa_q_b, *dsa_g_b, *dsa_pub_key_b;
#endif /* WITH_OPENSSL */
if (a == NULL || b == NULL ||
sshkey_type_plain(a->type) != sshkey_type_plain(b->type))
return 0;
switch (a->type) {
#ifdef WITH_OPENSSL
case KEY_RSA_CERT:
case KEY_RSA:
if (a->rsa == NULL || b->rsa == NULL)
return 0;
RSA_get0_key(a->rsa, &rsa_n_a, &rsa_e_a, NULL);
RSA_get0_key(b->rsa, &rsa_n_b, &rsa_e_b, NULL);
return BN_cmp(rsa_e_a, rsa_e_b) == 0 &&
BN_cmp(rsa_n_a, rsa_n_b) == 0;
case KEY_DSA_CERT:
case KEY_DSA:
if (a->dsa == NULL || b->dsa == NULL)
return 0;
DSA_get0_pqg(a->dsa, &dsa_p_a, &dsa_q_a, &dsa_g_a);
DSA_get0_pqg(b->dsa, &dsa_p_b, &dsa_q_b, &dsa_g_b);
DSA_get0_key(a->dsa, &dsa_pub_key_a, NULL);
DSA_get0_key(b->dsa, &dsa_pub_key_b, NULL);
return BN_cmp(dsa_p_a, dsa_p_b) == 0 &&
BN_cmp(dsa_q_a, dsa_q_b) == 0 &&
BN_cmp(dsa_g_a, dsa_g_b) == 0 &&
BN_cmp(dsa_pub_key_a, dsa_pub_key_b) == 0;
# ifdef OPENSSL_HAS_ECC
case KEY_ECDSA_SK:
case KEY_ECDSA_SK_CERT:
if (a->sk_application == NULL || b->sk_application == NULL)
return 0;
if (strcmp(a->sk_application, b->sk_application) != 0)
return 0;
/* FALLTHROUGH */
case KEY_ECDSA_CERT:
case KEY_ECDSA:
if (a->ecdsa == NULL || b->ecdsa == NULL ||
EC_KEY_get0_public_key(a->ecdsa) == NULL ||
EC_KEY_get0_public_key(b->ecdsa) == NULL)
return 0;
if (EC_GROUP_cmp(EC_KEY_get0_group(a->ecdsa),
EC_KEY_get0_group(b->ecdsa), NULL) != 0 ||
EC_POINT_cmp(EC_KEY_get0_group(a->ecdsa),
EC_KEY_get0_public_key(a->ecdsa),
EC_KEY_get0_public_key(b->ecdsa), NULL) != 0)
return 0;
return 1;
# endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
case KEY_ED25519_SK:
case KEY_ED25519_SK_CERT:
if (a->sk_application == NULL || b->sk_application == NULL)
return 0;
if (strcmp(a->sk_application, b->sk_application) != 0)
return 0;
/* FALLTHROUGH */
case KEY_ED25519:
case KEY_ED25519_CERT:
return a->ed25519_pk != NULL && b->ed25519_pk != NULL &&
memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0;
#ifdef WITH_XMSS
case KEY_XMSS:
case KEY_XMSS_CERT:
return a->xmss_pk != NULL && b->xmss_pk != NULL &&
sshkey_xmss_pklen(a) == sshkey_xmss_pklen(b) &&
memcmp(a->xmss_pk, b->xmss_pk, sshkey_xmss_pklen(a)) == 0;
#endif /* WITH_XMSS */
default:
return 0;
}
/* NOTREACHED */
}
int
sshkey_equal(const struct sshkey *a, const struct sshkey *b)
{
if (a == NULL || b == NULL || a->type != b->type)
return 0;
if (sshkey_is_cert(a)) {
if (!cert_compare(a->cert, b->cert))
return 0;
}
return sshkey_equal_public(a, b);
}
static int
to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain,
enum sshkey_serialize_rep opts)
{
int type, ret = SSH_ERR_INTERNAL_ERROR;
const char *typename;
#ifdef WITH_OPENSSL
const BIGNUM *rsa_n, *rsa_e, *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
#endif /* WITH_OPENSSL */
if (key == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if (sshkey_is_cert(key)) {
if (key->cert == NULL)
return SSH_ERR_EXPECTED_CERT;
if (sshbuf_len(key->cert->certblob) == 0)
return SSH_ERR_KEY_LACKS_CERTBLOB;
}
type = force_plain ? sshkey_type_plain(key->type) : key->type;
typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid);
switch (type) {
#ifdef WITH_OPENSSL
case KEY_DSA_CERT:
case KEY_ECDSA_CERT:
case KEY_ECDSA_SK_CERT:
case KEY_RSA_CERT:
#endif /* WITH_OPENSSL */
case KEY_ED25519_CERT:
case KEY_ED25519_SK_CERT:
#ifdef WITH_XMSS
case KEY_XMSS_CERT:
#endif /* WITH_XMSS */
/* Use the existing blob */
/* XXX modified flag? */
if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0)
return ret;
break;
#ifdef WITH_OPENSSL
case KEY_DSA:
if (key->dsa == NULL)
return SSH_ERR_INVALID_ARGUMENT;
DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g);
DSA_get0_key(key->dsa, &dsa_pub_key, NULL);
if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
(ret = sshbuf_put_bignum2(b, dsa_p)) != 0 ||
(ret = sshbuf_put_bignum2(b, dsa_q)) != 0 ||
(ret = sshbuf_put_bignum2(b, dsa_g)) != 0 ||
(ret = sshbuf_put_bignum2(b, dsa_pub_key)) != 0)
return ret;
break;
# ifdef OPENSSL_HAS_ECC
case KEY_ECDSA:
case KEY_ECDSA_SK:
if (key->ecdsa == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
(ret = sshbuf_put_cstring(b,
sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
(ret = sshbuf_put_eckey(b, key->ecdsa)) != 0)
return ret;
if (type == KEY_ECDSA_SK) {
if ((ret = sshbuf_put_cstring(b,
key->sk_application)) != 0)
return ret;
}
break;
# endif
case KEY_RSA:
if (key->rsa == NULL)
return SSH_ERR_INVALID_ARGUMENT;
RSA_get0_key(key->rsa, &rsa_n, &rsa_e, NULL);
if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
(ret = sshbuf_put_bignum2(b, rsa_e)) != 0 ||
(ret = sshbuf_put_bignum2(b, rsa_n)) != 0)
return ret;
break;
#endif /* WITH_OPENSSL */
case KEY_ED25519:
case KEY_ED25519_SK:
if (key->ed25519_pk == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
(ret = sshbuf_put_string(b,
key->ed25519_pk, ED25519_PK_SZ)) != 0)
return ret;
if (type == KEY_ED25519_SK) {
if ((ret = sshbuf_put_cstring(b,
key->sk_application)) != 0)
return ret;
}
break;
#ifdef WITH_XMSS
case KEY_XMSS:
if (key->xmss_name == NULL || key->xmss_pk == NULL ||
sshkey_xmss_pklen(key) == 0)
return SSH_ERR_INVALID_ARGUMENT;
if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
(ret = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
(ret = sshbuf_put_string(b,
key->xmss_pk, sshkey_xmss_pklen(key))) != 0 ||
(ret = sshkey_xmss_serialize_pk_info(key, b, opts)) != 0)
return ret;
break;
#endif /* WITH_XMSS */
default:
return SSH_ERR_KEY_TYPE_UNKNOWN;
}
return 0;
}
int
sshkey_putb(const struct sshkey *key, struct sshbuf *b)
{
return to_blob_buf(key, b, 0, SSHKEY_SERIALIZE_DEFAULT);
}
int
sshkey_puts_opts(const struct sshkey *key, struct sshbuf *b,
enum sshkey_serialize_rep opts)
{
struct sshbuf *tmp;
int r;
if ((tmp = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
r = to_blob_buf(key, tmp, 0, opts);
if (r == 0)
r = sshbuf_put_stringb(b, tmp);
sshbuf_free(tmp);
return r;
}
int
sshkey_puts(const struct sshkey *key, struct sshbuf *b)
{
return sshkey_puts_opts(key, b, SSHKEY_SERIALIZE_DEFAULT);
}
int
sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b)
{
return to_blob_buf(key, b, 1, SSHKEY_SERIALIZE_DEFAULT);
}
static int
to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain,
enum sshkey_serialize_rep opts)
{
int ret = SSH_ERR_INTERNAL_ERROR;
size_t len;
struct sshbuf *b = NULL;
if (lenp != NULL)
*lenp = 0;
if (blobp != NULL)
*blobp = NULL;
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((ret = to_blob_buf(key, b, force_plain, opts)) != 0)
goto out;
len = sshbuf_len(b);
if (lenp != NULL)
*lenp = len;
if (blobp != NULL) {
if ((*blobp = malloc(len)) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(*blobp, sshbuf_ptr(b), len);
}
ret = 0;
out:
sshbuf_free(b);
return ret;
}
int
sshkey_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
{
return to_blob(key, blobp, lenp, 0, SSHKEY_SERIALIZE_DEFAULT);
}
int
sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
{
return to_blob(key, blobp, lenp, 1, SSHKEY_SERIALIZE_DEFAULT);
}
int
sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg,
u_char **retp, size_t *lenp)
{
u_char *blob = NULL, *ret = NULL;
size_t blob_len = 0;
int r = SSH_ERR_INTERNAL_ERROR;
if (retp != NULL)
*retp = NULL;
if (lenp != NULL)
*lenp = 0;
if (ssh_digest_bytes(dgst_alg) == 0) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((r = to_blob(k, &blob, &blob_len, 1, SSHKEY_SERIALIZE_DEFAULT))
!= 0)
goto out;
if ((ret = calloc(1, SSH_DIGEST_MAX_LENGTH)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = ssh_digest_memory(dgst_alg, blob, blob_len,
ret, SSH_DIGEST_MAX_LENGTH)) != 0)
goto out;
/* success */
if (retp != NULL) {
*retp = ret;
ret = NULL;
}
if (lenp != NULL)
*lenp = ssh_digest_bytes(dgst_alg);
r = 0;
out:
free(ret);
if (blob != NULL)
freezero(blob, blob_len);
return r;
}
static char *
fingerprint_b64(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
{
char *ret;
size_t plen = strlen(alg) + 1;
size_t rlen = ((dgst_raw_len + 2) / 3) * 4 + plen + 1;
if (dgst_raw_len > 65536 || (ret = calloc(1, rlen)) == NULL)
return NULL;
strlcpy(ret, alg, rlen);
strlcat(ret, ":", rlen);
if (dgst_raw_len == 0)
return ret;
if (b64_ntop(dgst_raw, dgst_raw_len, ret + plen, rlen - plen) == -1) {
freezero(ret, rlen);
return NULL;
}
/* Trim padding characters from end */
ret[strcspn(ret, "=")] = '\0';
return ret;
}
static char *
fingerprint_hex(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
{
char *retval, hex[5];
size_t i, rlen = dgst_raw_len * 3 + strlen(alg) + 2;
if (dgst_raw_len > 65536 || (retval = calloc(1, rlen)) == NULL)
return NULL;
strlcpy(retval, alg, rlen);
strlcat(retval, ":", rlen);
for (i = 0; i < dgst_raw_len; i++) {
snprintf(hex, sizeof(hex), "%s%02x",
i > 0 ? ":" : "", dgst_raw[i]);
strlcat(retval, hex, rlen);
}
return retval;
}
static char *
fingerprint_bubblebabble(u_char *dgst_raw, size_t dgst_raw_len)
{
char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
u_int i, j = 0, rounds, seed = 1;
char *retval;
rounds = (dgst_raw_len / 2) + 1;
if ((retval = calloc(rounds, 6)) == NULL)
return NULL;
retval[j++] = 'x';
for (i = 0; i < rounds; i++) {
u_int idx0, idx1, idx2, idx3, idx4;
if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) {
idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) +
seed) % 6;
idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15;
idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) +
(seed / 6)) % 6;
retval[j++] = vowels[idx0];
retval[j++] = consonants[idx1];
retval[j++] = vowels[idx2];
if ((i + 1) < rounds) {
idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15;
idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15;
retval[j++] = consonants[idx3];
retval[j++] = '-';
retval[j++] = consonants[idx4];
seed = ((seed * 5) +
((((u_int)(dgst_raw[2 * i])) * 7) +
((u_int)(dgst_raw[(2 * i) + 1])))) % 36;
}
} else {
idx0 = seed % 6;
idx1 = 16;
idx2 = seed / 6;
retval[j++] = vowels[idx0];
retval[j++] = consonants[idx1];
retval[j++] = vowels[idx2];
}
}
retval[j++] = 'x';
retval[j++] = '\0';
return retval;
}
/*
* Draw an ASCII-Art representing the fingerprint so human brain can
* profit from its built-in pattern recognition ability.
* This technique is called "random art" and can be found in some
* scientific publications like this original paper:
*
* "Hash Visualization: a New Technique to improve Real-World Security",
* Perrig A. and Song D., 1999, International Workshop on Cryptographic
* Techniques and E-Commerce (CrypTEC '99)
* sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
*
* The subject came up in a talk by Dan Kaminsky, too.
*
* If you see the picture is different, the key is different.
* If the picture looks the same, you still know nothing.
*
* The algorithm used here is a worm crawling over a discrete plane,
* leaving a trace (augmenting the field) everywhere it goes.
* Movement is taken from dgst_raw 2bit-wise. Bumping into walls
* makes the respective movement vector be ignored for this turn.
* Graphs are not unambiguous, because circles in graphs can be
* walked in either direction.
*/
/*
* Field sizes for the random art. Have to be odd, so the starting point
* can be in the exact middle of the picture, and FLDBASE should be >=8 .
* Else pictures would be too dense, and drawing the frame would
* fail, too, because the key type would not fit in anymore.
*/
#define FLDBASE 8
#define FLDSIZE_Y (FLDBASE + 1)
#define FLDSIZE_X (FLDBASE * 2 + 1)
static char *
fingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len,
const struct sshkey *k)
{
/*
* Chars to be used after each other every time the worm
* intersects with itself. Matter of taste.
*/
char *augmentation_string = " .o+=*BOX@%&#/^SE";
char *retval, *p, title[FLDSIZE_X], hash[FLDSIZE_X];
u_char field[FLDSIZE_X][FLDSIZE_Y];
size_t i, tlen, hlen;
u_int b;
int x, y, r;
size_t len = strlen(augmentation_string) - 1;
if ((retval = calloc((FLDSIZE_X + 3), (FLDSIZE_Y + 2))) == NULL)
return NULL;
/* initialize field */
memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
x = FLDSIZE_X / 2;
y = FLDSIZE_Y / 2;
/* process raw key */
for (i = 0; i < dgst_raw_len; i++) {
int input;
/* each byte conveys four 2-bit move commands */
input = dgst_raw[i];
for (b = 0; b < 4; b++) {
/* evaluate 2 bit, rest is shifted later */
x += (input & 0x1) ? 1 : -1;
y += (input & 0x2) ? 1 : -1;
/* assure we are still in bounds */
x = MAXIMUM(x, 0);
y = MAXIMUM(y, 0);
x = MINIMUM(x, FLDSIZE_X - 1);
y = MINIMUM(y, FLDSIZE_Y - 1);
/* augment the field */
if (field[x][y] < len - 2)
field[x][y]++;
input = input >> 2;
}
}
/* mark starting point and end point*/
field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
field[x][y] = len;
/* assemble title */
r = snprintf(title, sizeof(title), "[%s %u]",
sshkey_type(k), sshkey_size(k));
/* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */
if (r < 0 || r > (int)sizeof(title))
r = snprintf(title, sizeof(title), "[%s]", sshkey_type(k));
tlen = (r <= 0) ? 0 : strlen(title);
/* assemble hash ID. */
r = snprintf(hash, sizeof(hash), "[%s]", alg);
hlen = (r <= 0) ? 0 : strlen(hash);
/* output upper border */
p = retval;
*p++ = '+';
for (i = 0; i < (FLDSIZE_X - tlen) / 2; i++)
*p++ = '-';
memcpy(p, title, tlen);
p += tlen;
for (i += tlen; i < FLDSIZE_X; i++)
*p++ = '-';
*p++ = '+';
*p++ = '\n';
/* output content */
for (y = 0; y < FLDSIZE_Y; y++) {
*p++ = '|';
for (x = 0; x < FLDSIZE_X; x++)
*p++ = augmentation_string[MINIMUM(field[x][y], len)];
*p++ = '|';
*p++ = '\n';
}
/* output lower border */
*p++ = '+';
for (i = 0; i < (FLDSIZE_X - hlen) / 2; i++)
*p++ = '-';
memcpy(p, hash, hlen);
p += hlen;
for (i += hlen; i < FLDSIZE_X; i++)
*p++ = '-';
*p++ = '+';
return retval;
}
char *
sshkey_fingerprint(const struct sshkey *k, int dgst_alg,
enum sshkey_fp_rep dgst_rep)
{
char *retval = NULL;
u_char *dgst_raw;
size_t dgst_raw_len;
if (sshkey_fingerprint_raw(k, dgst_alg, &dgst_raw, &dgst_raw_len) != 0)
return NULL;
switch (dgst_rep) {
case SSH_FP_DEFAULT:
if (dgst_alg == SSH_DIGEST_MD5) {
retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
dgst_raw, dgst_raw_len);
} else {
retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
dgst_raw, dgst_raw_len);
}
break;
case SSH_FP_HEX:
retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
dgst_raw, dgst_raw_len);
break;
case SSH_FP_BASE64:
retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
dgst_raw, dgst_raw_len);
break;
case SSH_FP_BUBBLEBABBLE:
retval = fingerprint_bubblebabble(dgst_raw, dgst_raw_len);
break;
case SSH_FP_RANDOMART:
retval = fingerprint_randomart(ssh_digest_alg_name(dgst_alg),
dgst_raw, dgst_raw_len, k);
break;
default:
freezero(dgst_raw, dgst_raw_len);
return NULL;
}
freezero(dgst_raw, dgst_raw_len);
return retval;
}
static int
peek_type_nid(const char *s, size_t l, int *nid)
{
const struct keytype *kt;
for (kt = keytypes; kt->type != -1; kt++) {
if (kt->name == NULL || strlen(kt->name) != l)
continue;
if (memcmp(s, kt->name, l) == 0) {
*nid = -1;
if (key_type_is_ecdsa_variant(kt->type))
*nid = kt->nid;
return kt->type;
}
}
return KEY_UNSPEC;
}
/* XXX this can now be made const char * */
int
sshkey_read(struct sshkey *ret, char **cpp)
{
struct sshkey *k;
char *cp, *blobcopy;
size_t space;
int r, type, curve_nid = -1;
struct sshbuf *blob;
if (ret == NULL)
return SSH_ERR_INVALID_ARGUMENT;
switch (ret->type) {
case KEY_UNSPEC:
case KEY_RSA:
case KEY_DSA:
case KEY_ECDSA:
case KEY_ECDSA_SK:
case KEY_ED25519:
case KEY_ED25519_SK:
case KEY_DSA_CERT:
case KEY_ECDSA_CERT:
case KEY_ECDSA_SK_CERT:
case KEY_RSA_CERT:
case KEY_ED25519_CERT:
case KEY_ED25519_SK_CERT:
#ifdef WITH_XMSS
case KEY_XMSS:
case KEY_XMSS_CERT:
#endif /* WITH_XMSS */
break; /* ok */
default:
return SSH_ERR_INVALID_ARGUMENT;
}
/* Decode type */
cp = *cpp;
space = strcspn(cp, " \t");
if (space == strlen(cp))
return SSH_ERR_INVALID_FORMAT;
if ((type = peek_type_nid(cp, space, &curve_nid)) == KEY_UNSPEC)
return SSH_ERR_INVALID_FORMAT;
/* skip whitespace */
for (cp += space; *cp == ' ' || *cp == '\t'; cp++)
;
if (*cp == '\0')
return SSH_ERR_INVALID_FORMAT;
if (ret->type != KEY_UNSPEC && ret->type != type)
return SSH_ERR_KEY_TYPE_MISMATCH;
if ((blob = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
/* find end of keyblob and decode */
space = strcspn(cp, " \t");
if ((blobcopy = strndup(cp, space)) == NULL) {
sshbuf_free(blob);
return SSH_ERR_ALLOC_FAIL;
}
if ((r = sshbuf_b64tod(blob, blobcopy)) != 0) {
free(blobcopy);
sshbuf_free(blob);
return r;
}
free(blobcopy);
if ((r = sshkey_fromb(blob, &k)) != 0) {
sshbuf_free(blob);
return r;
}
sshbuf_free(blob);
/* skip whitespace and leave cp at start of comment */
for (cp += space; *cp == ' ' || *cp == '\t'; cp++)
;
/* ensure type of blob matches type at start of line */
if (k->type != type) {
sshkey_free(k);
return SSH_ERR_KEY_TYPE_MISMATCH;
}
if (key_type_is_ecdsa_variant(type) && curve_nid != k->ecdsa_nid) {
sshkey_free(k);
return SSH_ERR_EC_CURVE_MISMATCH;
}
/* Fill in ret from parsed key */
ret->type = type;
if (sshkey_is_cert(ret)) {
if (!sshkey_is_cert(k)) {
sshkey_free(k);
return SSH_ERR_EXPECTED_CERT;
}
if (ret->cert != NULL)
cert_free(ret->cert);
ret->cert = k->cert;
k->cert = NULL;
}
switch (sshkey_type_plain(ret->type)) {
#ifdef WITH_OPENSSL
case KEY_RSA:
RSA_free(ret->rsa);
ret->rsa = k->rsa;
k->rsa = NULL;
#ifdef DEBUG_PK
RSA_print_fp(stderr, ret->rsa, 8);
#endif
break;
case KEY_DSA:
DSA_free(ret->dsa);
ret->dsa = k->dsa;
k->dsa = NULL;
#ifdef DEBUG_PK
DSA_print_fp(stderr, ret->dsa, 8);
#endif
break;
# ifdef OPENSSL_HAS_ECC
case KEY_ECDSA:
EC_KEY_free(ret->ecdsa);
ret->ecdsa = k->ecdsa;
ret->ecdsa_nid = k->ecdsa_nid;
k->ecdsa = NULL;
k->ecdsa_nid = -1;
#ifdef DEBUG_PK
sshkey_dump_ec_key(ret->ecdsa);
#endif
break;
case KEY_ECDSA_SK:
EC_KEY_free(ret->ecdsa);
ret->ecdsa = k->ecdsa;
ret->ecdsa_nid = k->ecdsa_nid;
ret->sk_application = k->sk_application;
k->ecdsa = NULL;
k->ecdsa_nid = -1;
k->sk_application = NULL;
#ifdef DEBUG_PK
sshkey_dump_ec_key(ret->ecdsa);
fprintf(stderr, "App: %s\n", ret->sk_application);
#endif
break;
# endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
case KEY_ED25519:
freezero(ret->ed25519_pk, ED25519_PK_SZ);
ret->ed25519_pk = k->ed25519_pk;
k->ed25519_pk = NULL;
#ifdef DEBUG_PK
/* XXX */
#endif
break;
case KEY_ED25519_SK:
freezero(ret->ed25519_pk, ED25519_PK_SZ);
ret->ed25519_pk = k->ed25519_pk;
ret->sk_application = k->sk_application;
k->ed25519_pk = NULL;
k->sk_application = NULL;
break;
#ifdef WITH_XMSS
case KEY_XMSS:
free(ret->xmss_pk);
ret->xmss_pk = k->xmss_pk;
k->xmss_pk = NULL;
free(ret->xmss_state);
ret->xmss_state = k->xmss_state;
k->xmss_state = NULL;
free(ret->xmss_name);
ret->xmss_name = k->xmss_name;
k->xmss_name = NULL;
free(ret->xmss_filename);
ret->xmss_filename = k->xmss_filename;
k->xmss_filename = NULL;
#ifdef DEBUG_PK
/* XXX */
#endif
break;
#endif /* WITH_XMSS */
default:
sshkey_free(k);
return SSH_ERR_INTERNAL_ERROR;
}
sshkey_free(k);
/* success */
*cpp = cp;
return 0;
}
int
sshkey_to_base64(const struct sshkey *key, char **b64p)
{
int r = SSH_ERR_INTERNAL_ERROR;
struct sshbuf *b = NULL;
char *uu = NULL;
if (b64p != NULL)
*b64p = NULL;
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshkey_putb(key, b)) != 0)
goto out;
if ((uu = sshbuf_dtob64_string(b, 0)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* Success */
if (b64p != NULL) {
*b64p = uu;
uu = NULL;
}
r = 0;
out:
sshbuf_free(b);
free(uu);
return r;
}
int
sshkey_format_text(const struct sshkey *key, struct sshbuf *b)
{
int r = SSH_ERR_INTERNAL_ERROR;
char *uu = NULL;
if ((r = sshkey_to_base64(key, &uu)) != 0)
goto out;
if ((r = sshbuf_putf(b, "%s %s",
sshkey_ssh_name(key), uu)) != 0)
goto out;
r = 0;
out:
free(uu);
return r;
}
int
sshkey_write(const struct sshkey *key, FILE *f)
{
struct sshbuf *b = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshkey_format_text(key, b)) != 0)
goto out;
if (fwrite(sshbuf_ptr(b), sshbuf_len(b), 1, f) != 1) {
if (feof(f))
errno = EPIPE;
r = SSH_ERR_SYSTEM_ERROR;
goto out;
}
/* Success */
r = 0;
out:
sshbuf_free(b);
return r;
}
const char *
sshkey_cert_type(const struct sshkey *k)
{
switch (k->cert->type) {
case SSH2_CERT_TYPE_USER:
return "user";
case SSH2_CERT_TYPE_HOST:
return "host";
default:
return "unknown";
}
}
#ifdef WITH_OPENSSL
static int
rsa_generate_private_key(u_int bits, RSA **rsap)
{
RSA *private = NULL;
BIGNUM *f4 = NULL;
int ret = SSH_ERR_INTERNAL_ERROR;
if (rsap == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if (bits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
bits > SSHBUF_MAX_BIGNUM * 8)
return SSH_ERR_KEY_LENGTH;
*rsap = NULL;
if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (!BN_set_word(f4, RSA_F4) ||
!RSA_generate_key_ex(private, bits, f4, NULL)) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
*rsap = private;
private = NULL;
ret = 0;
out:
RSA_free(private);
BN_free(f4);
return ret;
}
static int
dsa_generate_private_key(u_int bits, DSA **dsap)
{
DSA *private;
int ret = SSH_ERR_INTERNAL_ERROR;
if (dsap == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if (bits != 1024)
return SSH_ERR_KEY_LENGTH;
if ((private = DSA_new()) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
*dsap = NULL;
if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL,
NULL, NULL) || !DSA_generate_key(private)) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
*dsap = private;
private = NULL;
ret = 0;
out:
DSA_free(private);
return ret;
}
# ifdef OPENSSL_HAS_ECC
int
sshkey_ecdsa_key_to_nid(EC_KEY *k)
{
EC_GROUP *eg;
int nids[] = {
NID_X9_62_prime256v1,
NID_secp384r1,
# ifdef OPENSSL_HAS_NISTP521
NID_secp521r1,
# endif /* OPENSSL_HAS_NISTP521 */
-1
};
int nid;
u_int i;
const EC_GROUP *g = EC_KEY_get0_group(k);
/*
* The group may be stored in a ASN.1 encoded private key in one of two
* ways: as a "named group", which is reconstituted by ASN.1 object ID
* or explicit group parameters encoded into the key blob. Only the
* "named group" case sets the group NID for us, but we can figure
* it out for the other case by comparing against all the groups that
* are supported.
*/
if ((nid = EC_GROUP_get_curve_name(g)) > 0)
return nid;
for (i = 0; nids[i] != -1; i++) {
if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL)
return -1;
if (EC_GROUP_cmp(g, eg, NULL) == 0)
break;
EC_GROUP_free(eg);
}
if (nids[i] != -1) {
/* Use the group with the NID attached */
EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE);
if (EC_KEY_set_group(k, eg) != 1) {
EC_GROUP_free(eg);
return -1;
}
}
return nids[i];
}
static int
ecdsa_generate_private_key(u_int bits, int *nid, EC_KEY **ecdsap)
{
EC_KEY *private;
int ret = SSH_ERR_INTERNAL_ERROR;
if (nid == NULL || ecdsap == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if ((*nid = sshkey_ecdsa_bits_to_nid(bits)) == -1)
return SSH_ERR_KEY_LENGTH;
*ecdsap = NULL;
if ((private = EC_KEY_new_by_curve_name(*nid)) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (EC_KEY_generate_key(private) != 1) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE);
*ecdsap = private;
private = NULL;
ret = 0;
out:
EC_KEY_free(private);
return ret;
}
# endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
int
sshkey_generate(int type, u_int bits, struct sshkey **keyp)
{
struct sshkey *k;
int ret = SSH_ERR_INTERNAL_ERROR;
if (keyp == NULL)
return SSH_ERR_INVALID_ARGUMENT;
*keyp = NULL;
if ((k = sshkey_new(KEY_UNSPEC)) == NULL)
return SSH_ERR_ALLOC_FAIL;
switch (type) {
case KEY_ED25519:
if ((k->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL ||
(k->ed25519_sk = malloc(ED25519_SK_SZ)) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
break;
}
crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk);
ret = 0;
break;
#ifdef WITH_XMSS
case KEY_XMSS:
ret = sshkey_xmss_generate_private_key(k, bits);
break;
#endif /* WITH_XMSS */
#ifdef WITH_OPENSSL
case KEY_DSA:
ret = dsa_generate_private_key(bits, &k->dsa);
break;
# ifdef OPENSSL_HAS_ECC
case KEY_ECDSA:
ret = ecdsa_generate_private_key(bits, &k->ecdsa_nid,
&k->ecdsa);
break;
# endif /* OPENSSL_HAS_ECC */
case KEY_RSA:
ret = rsa_generate_private_key(bits, &k->rsa);
break;
#endif /* WITH_OPENSSL */
default:
ret = SSH_ERR_INVALID_ARGUMENT;
}
if (ret == 0) {
k->type = type;
*keyp = k;
} else
sshkey_free(k);
return ret;
}
int
sshkey_cert_copy(const struct sshkey *from_key, struct sshkey *to_key)
{
u_int i;
const struct sshkey_cert *from;
struct sshkey_cert *to;
int r = SSH_ERR_INTERNAL_ERROR;
if (to_key == NULL || (from = from_key->cert) == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if ((to = cert_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_putb(to->certblob, from->certblob)) != 0 ||
(r = sshbuf_putb(to->critical, from->critical)) != 0 ||
(r = sshbuf_putb(to->extensions, from->extensions)) != 0)
goto out;
to->serial = from->serial;
to->type = from->type;
if (from->key_id == NULL)
to->key_id = NULL;
else if ((to->key_id = strdup(from->key_id)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
to->valid_after = from->valid_after;
to->valid_before = from->valid_before;
if (from->signature_key == NULL)
to->signature_key = NULL;
else if ((r = sshkey_from_private(from->signature_key,
&to->signature_key)) != 0)
goto out;
if (from->signature_type != NULL &&
(to->signature_type = strdup(from->signature_type)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (from->nprincipals > SSHKEY_CERT_MAX_PRINCIPALS) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if (from->nprincipals > 0) {
if ((to->principals = calloc(from->nprincipals,
sizeof(*to->principals))) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
for (i = 0; i < from->nprincipals; i++) {
to->principals[i] = strdup(from->principals[i]);
if (to->principals[i] == NULL) {
to->nprincipals = i;
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
}
}
to->nprincipals = from->nprincipals;
/* success */
cert_free(to_key->cert);
to_key->cert = to;
to = NULL;
r = 0;
out:
cert_free(to);
return r;
}
int
sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
{
struct sshkey *n = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
#ifdef WITH_OPENSSL
const BIGNUM *rsa_n, *rsa_e;
BIGNUM *rsa_n_dup = NULL, *rsa_e_dup = NULL;
const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
BIGNUM *dsa_p_dup = NULL, *dsa_q_dup = NULL, *dsa_g_dup = NULL;
BIGNUM *dsa_pub_key_dup = NULL;
#endif /* WITH_OPENSSL */
*pkp = NULL;
if ((n = sshkey_new(k->type)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
switch (k->type) {
#ifdef WITH_OPENSSL
case KEY_DSA:
case KEY_DSA_CERT:
DSA_get0_pqg(k->dsa, &dsa_p, &dsa_q, &dsa_g);
DSA_get0_key(k->dsa, &dsa_pub_key, NULL);
if ((dsa_p_dup = BN_dup(dsa_p)) == NULL ||
(dsa_q_dup = BN_dup(dsa_q)) == NULL ||
(dsa_g_dup = BN_dup(dsa_g)) == NULL ||
(dsa_pub_key_dup = BN_dup(dsa_pub_key)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (!DSA_set0_pqg(n->dsa, dsa_p_dup, dsa_q_dup, dsa_g_dup)) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
dsa_p_dup = dsa_q_dup = dsa_g_dup = NULL; /* transferred */
if (!DSA_set0_key(n->dsa, dsa_pub_key_dup, NULL)) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
dsa_pub_key_dup = NULL; /* transferred */
break;
# ifdef OPENSSL_HAS_ECC
case KEY_ECDSA:
case KEY_ECDSA_CERT:
case KEY_ECDSA_SK:
case KEY_ECDSA_SK_CERT:
n->ecdsa_nid = k->ecdsa_nid;
n->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
if (n->ecdsa == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (EC_KEY_set_public_key(n->ecdsa,
EC_KEY_get0_public_key(k->ecdsa)) != 1) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if (k->type != KEY_ECDSA_SK && k->type != KEY_ECDSA_SK_CERT)
break;
/* Append security-key application string */
if ((n->sk_application = strdup(k->sk_application)) == NULL)
goto out;
break;
# endif /* OPENSSL_HAS_ECC */
case KEY_RSA:
case KEY_RSA_CERT:
RSA_get0_key(k->rsa, &rsa_n, &rsa_e, NULL);
if ((rsa_n_dup = BN_dup(rsa_n)) == NULL ||
(rsa_e_dup = BN_dup(rsa_e)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (!RSA_set0_key(n->rsa, rsa_n_dup, rsa_e_dup, NULL)) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
rsa_n_dup = rsa_e_dup = NULL; /* transferred */
break;
#endif /* WITH_OPENSSL */
case KEY_ED25519:
case KEY_ED25519_CERT:
case KEY_ED25519_SK:
case KEY_ED25519_SK_CERT:
if (k->ed25519_pk != NULL) {
if ((n->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
}
if (k->type != KEY_ED25519_SK &&
k->type != KEY_ED25519_SK_CERT)
break;
/* Append security-key application string */
if ((n->sk_application = strdup(k->sk_application)) == NULL)
goto out;
break;
#ifdef WITH_XMSS
case KEY_XMSS:
case KEY_XMSS_CERT:
if ((r = sshkey_xmss_init(n, k->xmss_name)) != 0)
goto out;
if (k->xmss_pk != NULL) {
u_int32_t left;
size_t pklen = sshkey_xmss_pklen(k);
if (pklen == 0 || sshkey_xmss_pklen(n) != pklen) {
r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
if ((n->xmss_pk = malloc(pklen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(n->xmss_pk, k->xmss_pk, pklen);
/* simulate number of signatures left on pubkey */
left = sshkey_xmss_signatures_left(k);
if (left)
sshkey_xmss_enable_maxsign(n, left);
}
break;
#endif /* WITH_XMSS */
default:
r = SSH_ERR_KEY_TYPE_UNKNOWN;
goto out;
}
if (sshkey_is_cert(k) && (r = sshkey_cert_copy(k, n)) != 0)
goto out;
/* success */
*pkp = n;
n = NULL;
r = 0;
out:
sshkey_free(n);
#ifdef WITH_OPENSSL
BN_clear_free(rsa_n_dup);
BN_clear_free(rsa_e_dup);
BN_clear_free(dsa_p_dup);
BN_clear_free(dsa_q_dup);
BN_clear_free(dsa_g_dup);
BN_clear_free(dsa_pub_key_dup);
#endif
return r;
}
int
sshkey_is_shielded(struct sshkey *k)
{
return k != NULL && k->shielded_private != NULL;
}
int
sshkey_shield_private(struct sshkey *k)
{
struct sshbuf *prvbuf = NULL;
u_char *prekey = NULL, *enc = NULL, keyiv[SSH_DIGEST_MAX_LENGTH];
struct sshcipher_ctx *cctx = NULL;
const struct sshcipher *cipher;
size_t i, enclen = 0;
struct sshkey *kswap = NULL, tmp;
int r = SSH_ERR_INTERNAL_ERROR;
#ifdef DEBUG_PK
fprintf(stderr, "%s: entering for %s\n", __func__, sshkey_ssh_name(k));
#endif
if ((cipher = cipher_by_name(SSHKEY_SHIELD_CIPHER)) == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if (cipher_keylen(cipher) + cipher_ivlen(cipher) >
ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH)) {
r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
/* Prepare a random pre-key, and from it an ephemeral key */
if ((prekey = malloc(SSHKEY_SHIELD_PREKEY_LEN)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
arc4random_buf(prekey, SSHKEY_SHIELD_PREKEY_LEN);
if ((r = ssh_digest_memory(SSHKEY_SHIELD_PREKEY_HASH,
prekey, SSHKEY_SHIELD_PREKEY_LEN,
keyiv, SSH_DIGEST_MAX_LENGTH)) != 0)
goto out;
#ifdef DEBUG_PK
fprintf(stderr, "%s: key+iv\n", __func__);
sshbuf_dump_data(keyiv, ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH),
stderr);
#endif
if ((r = cipher_init(&cctx, cipher, keyiv, cipher_keylen(cipher),
keyiv + cipher_keylen(cipher), cipher_ivlen(cipher), 1)) != 0)
goto out;
/* Serialise and encrypt the private key using the ephemeral key */
if ((prvbuf = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (sshkey_is_shielded(k) && (r = sshkey_unshield_private(k)) != 0)
goto out;
if ((r = sshkey_private_serialize_opt(k, prvbuf,
- SSHKEY_SERIALIZE_SHIELD)) != 0)
+ SSHKEY_SERIALIZE_SHIELD)) != 0)
goto out;
/* pad to cipher blocksize */
i = 0;
while (sshbuf_len(prvbuf) % cipher_blocksize(cipher)) {
if ((r = sshbuf_put_u8(prvbuf, ++i & 0xff)) != 0)
goto out;
}
#ifdef DEBUG_PK
fprintf(stderr, "%s: serialised\n", __func__);
sshbuf_dump(prvbuf, stderr);
#endif
/* encrypt */
enclen = sshbuf_len(prvbuf);
if ((enc = malloc(enclen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = cipher_crypt(cctx, 0, enc,
sshbuf_ptr(prvbuf), sshbuf_len(prvbuf), 0, 0)) != 0)
goto out;
#ifdef DEBUG_PK
fprintf(stderr, "%s: encrypted\n", __func__);
sshbuf_dump_data(enc, enclen, stderr);
#endif
/* Make a scrubbed, public-only copy of our private key argument */
if ((r = sshkey_from_private(k, &kswap)) != 0)
goto out;
/* Swap the private key out (it will be destroyed below) */
tmp = *kswap;
*kswap = *k;
*k = tmp;
/* Insert the shielded key into our argument */
k->shielded_private = enc;
k->shielded_len = enclen;
k->shield_prekey = prekey;
k->shield_prekey_len = SSHKEY_SHIELD_PREKEY_LEN;
enc = prekey = NULL; /* transferred */
enclen = 0;
/* preserve key fields that are required for correct operation */
k->sk_flags = kswap->sk_flags;
/* success */
r = 0;
out:
/* XXX behaviour on error - invalidate original private key? */
cipher_free(cctx);
explicit_bzero(keyiv, sizeof(keyiv));
explicit_bzero(&tmp, sizeof(tmp));
freezero(enc, enclen);
freezero(prekey, SSHKEY_SHIELD_PREKEY_LEN);
sshkey_free(kswap);
sshbuf_free(prvbuf);
return r;
}
int
sshkey_unshield_private(struct sshkey *k)
{
struct sshbuf *prvbuf = NULL;
u_char pad, *cp, keyiv[SSH_DIGEST_MAX_LENGTH];
struct sshcipher_ctx *cctx = NULL;
const struct sshcipher *cipher;
size_t i;
struct sshkey *kswap = NULL, tmp;
int r = SSH_ERR_INTERNAL_ERROR;
#ifdef DEBUG_PK
fprintf(stderr, "%s: entering for %s\n", __func__, sshkey_ssh_name(k));
#endif
if (!sshkey_is_shielded(k))
return 0; /* nothing to do */
if ((cipher = cipher_by_name(SSHKEY_SHIELD_CIPHER)) == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if (cipher_keylen(cipher) + cipher_ivlen(cipher) >
ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH)) {
r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
/* check size of shielded key blob */
if (k->shielded_len < cipher_blocksize(cipher) ||
(k->shielded_len % cipher_blocksize(cipher)) != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* Calculate the ephemeral key from the prekey */
if ((r = ssh_digest_memory(SSHKEY_SHIELD_PREKEY_HASH,
k->shield_prekey, k->shield_prekey_len,
keyiv, SSH_DIGEST_MAX_LENGTH)) != 0)
goto out;
if ((r = cipher_init(&cctx, cipher, keyiv, cipher_keylen(cipher),
keyiv + cipher_keylen(cipher), cipher_ivlen(cipher), 0)) != 0)
goto out;
#ifdef DEBUG_PK
fprintf(stderr, "%s: key+iv\n", __func__);
sshbuf_dump_data(keyiv, ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH),
stderr);
#endif
/* Decrypt and parse the shielded private key using the ephemeral key */
if ((prvbuf = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_reserve(prvbuf, k->shielded_len, &cp)) != 0)
goto out;
/* decrypt */
#ifdef DEBUG_PK
fprintf(stderr, "%s: encrypted\n", __func__);
sshbuf_dump_data(k->shielded_private, k->shielded_len, stderr);
#endif
if ((r = cipher_crypt(cctx, 0, cp,
k->shielded_private, k->shielded_len, 0, 0)) != 0)
goto out;
#ifdef DEBUG_PK
fprintf(stderr, "%s: serialised\n", __func__);
sshbuf_dump(prvbuf, stderr);
#endif
/* Parse private key */
if ((r = sshkey_private_deserialize(prvbuf, &kswap)) != 0)
goto out;
/* Check deterministic padding */
i = 0;
while (sshbuf_len(prvbuf)) {
if ((r = sshbuf_get_u8(prvbuf, &pad)) != 0)
goto out;
if (pad != (++i & 0xff)) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
}
/* Swap the parsed key back into place */
tmp = *kswap;
*kswap = *k;
*k = tmp;
/* success */
r = 0;
out:
cipher_free(cctx);
explicit_bzero(keyiv, sizeof(keyiv));
explicit_bzero(&tmp, sizeof(tmp));
sshkey_free(kswap);
sshbuf_free(prvbuf);
return r;
}
static int
cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf)
{
struct sshbuf *principals = NULL, *crit = NULL;
struct sshbuf *exts = NULL, *ca = NULL;
u_char *sig = NULL;
size_t signed_len = 0, slen = 0, kidlen = 0;
int ret = SSH_ERR_INTERNAL_ERROR;
/* Copy the entire key blob for verification and later serialisation */
if ((ret = sshbuf_putb(key->cert->certblob, certbuf)) != 0)
return ret;
/* Parse body of certificate up to signature */
if ((ret = sshbuf_get_u64(b, &key->cert->serial)) != 0 ||
(ret = sshbuf_get_u32(b, &key->cert->type)) != 0 ||
(ret = sshbuf_get_cstring(b, &key->cert->key_id, &kidlen)) != 0 ||
(ret = sshbuf_froms(b, &principals)) != 0 ||
(ret = sshbuf_get_u64(b, &key->cert->valid_after)) != 0 ||
(ret = sshbuf_get_u64(b, &key->cert->valid_before)) != 0 ||
(ret = sshbuf_froms(b, &crit)) != 0 ||
(ret = sshbuf_froms(b, &exts)) != 0 ||
(ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0 ||
(ret = sshbuf_froms(b, &ca)) != 0) {
/* XXX debug print error for ret */
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* Signature is left in the buffer so we can calculate this length */
signed_len = sshbuf_len(key->cert->certblob) - sshbuf_len(b);
if ((ret = sshbuf_get_string(b, &sig, &slen)) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (key->cert->type != SSH2_CERT_TYPE_USER &&
key->cert->type != SSH2_CERT_TYPE_HOST) {
ret = SSH_ERR_KEY_CERT_UNKNOWN_TYPE;
goto out;
}
/* Parse principals section */
while (sshbuf_len(principals) > 0) {
char *principal = NULL;
char **oprincipals = NULL;
if (key->cert->nprincipals >= SSHKEY_CERT_MAX_PRINCIPALS) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((ret = sshbuf_get_cstring(principals, &principal,
NULL)) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
oprincipals = key->cert->principals;
key->cert->principals = recallocarray(key->cert->principals,
key->cert->nprincipals, key->cert->nprincipals + 1,
sizeof(*key->cert->principals));
if (key->cert->principals == NULL) {
free(principal);
key->cert->principals = oprincipals;
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
key->cert->principals[key->cert->nprincipals++] = principal;
}
/*
* Stash a copies of the critical options and extensions sections
* for later use.
*/
if ((ret = sshbuf_putb(key->cert->critical, crit)) != 0 ||
(exts != NULL &&
(ret = sshbuf_putb(key->cert->extensions, exts)) != 0))
goto out;
/*
* Validate critical options and extensions sections format.
*/
while (sshbuf_len(crit) != 0) {
if ((ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0 ||
(ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0) {
sshbuf_reset(key->cert->critical);
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
}
while (exts != NULL && sshbuf_len(exts) != 0) {
if ((ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0 ||
(ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0) {
sshbuf_reset(key->cert->extensions);
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
}
/* Parse CA key and check signature */
if (sshkey_from_blob_internal(ca, &key->cert->signature_key, 0) != 0) {
ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
goto out;
}
if (!sshkey_type_is_valid_ca(key->cert->signature_key->type)) {
ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
goto out;
}
if ((ret = sshkey_verify(key->cert->signature_key, sig, slen,
sshbuf_ptr(key->cert->certblob), signed_len, NULL, 0, NULL)) != 0)
goto out;
if ((ret = sshkey_get_sigtype(sig, slen,
&key->cert->signature_type)) != 0)
goto out;
/* Success */
ret = 0;
out:
sshbuf_free(ca);
sshbuf_free(crit);
sshbuf_free(exts);
sshbuf_free(principals);
free(sig);
return ret;
}
#ifdef WITH_OPENSSL
static int
check_rsa_length(const RSA *rsa)
{
const BIGNUM *rsa_n;
RSA_get0_key(rsa, &rsa_n, NULL, NULL);
if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
return SSH_ERR_KEY_LENGTH;
return 0;
}
#endif
static int
sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
int allow_cert)
{
int type, ret = SSH_ERR_INTERNAL_ERROR;
char *ktype = NULL, *curve = NULL, *xmss_name = NULL;
struct sshkey *key = NULL;
size_t len;
u_char *pk = NULL;
struct sshbuf *copy;
#if defined(WITH_OPENSSL)
BIGNUM *rsa_n = NULL, *rsa_e = NULL;
BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_pub_key = NULL;
# if defined(OPENSSL_HAS_ECC)
EC_POINT *q = NULL;
# endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
#ifdef DEBUG_PK /* XXX */
sshbuf_dump(b, stderr);
#endif
if (keyp != NULL)
*keyp = NULL;
if ((copy = sshbuf_fromb(b)) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (sshbuf_get_cstring(b, &ktype, NULL) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
type = sshkey_type_from_name(ktype);
if (!allow_cert && sshkey_type_is_cert(type)) {
ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
goto out;
}
switch (type) {
#ifdef WITH_OPENSSL
case KEY_RSA_CERT:
/* Skip nonce */
if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* FALLTHROUGH */
case KEY_RSA:
if ((key = sshkey_new(type)) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (sshbuf_get_bignum2(b, &rsa_e) != 0 ||
sshbuf_get_bignum2(b, &rsa_n) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, NULL)) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
rsa_n = rsa_e = NULL; /* transferred */
if ((ret = check_rsa_length(key->rsa)) != 0)
goto out;
#ifdef DEBUG_PK
RSA_print_fp(stderr, key->rsa, 8);
#endif
break;
case KEY_DSA_CERT:
/* Skip nonce */
if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* FALLTHROUGH */
case KEY_DSA:
if ((key = sshkey_new(type)) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (sshbuf_get_bignum2(b, &dsa_p) != 0 ||
sshbuf_get_bignum2(b, &dsa_q) != 0 ||
sshbuf_get_bignum2(b, &dsa_g) != 0 ||
sshbuf_get_bignum2(b, &dsa_pub_key) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g)) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
dsa_p = dsa_q = dsa_g = NULL; /* transferred */
if (!DSA_set0_key(key->dsa, dsa_pub_key, NULL)) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
dsa_pub_key = NULL; /* transferred */
#ifdef DEBUG_PK
DSA_print_fp(stderr, key->dsa, 8);
#endif
break;
# ifdef OPENSSL_HAS_ECC
case KEY_ECDSA_CERT:
case KEY_ECDSA_SK_CERT:
/* Skip nonce */
if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* FALLTHROUGH */
case KEY_ECDSA:
case KEY_ECDSA_SK:
if ((key = sshkey_new(type)) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
key->ecdsa_nid = sshkey_ecdsa_nid_from_name(ktype);
if (sshbuf_get_cstring(b, &curve, NULL) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (key->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
ret = SSH_ERR_EC_CURVE_MISMATCH;
goto out;
}
EC_KEY_free(key->ecdsa);
if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid))
== NULL) {
ret = SSH_ERR_EC_CURVE_INVALID;
goto out;
}
if ((q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (sshbuf_get_ec(b, q, EC_KEY_get0_group(key->ecdsa)) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa),
q) != 0) {
ret = SSH_ERR_KEY_INVALID_EC_VALUE;
goto out;
}
if (EC_KEY_set_public_key(key->ecdsa, q) != 1) {
/* XXX assume it is a allocation error */
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
#ifdef DEBUG_PK
sshkey_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q);
#endif
if (type == KEY_ECDSA_SK || type == KEY_ECDSA_SK_CERT) {
/* Parse additional security-key application string */
if (sshbuf_get_cstring(b, &key->sk_application,
NULL) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
#ifdef DEBUG_PK
fprintf(stderr, "App: %s\n", key->sk_application);
#endif
}
break;
# endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
case KEY_ED25519_CERT:
case KEY_ED25519_SK_CERT:
/* Skip nonce */
if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* FALLTHROUGH */
case KEY_ED25519:
case KEY_ED25519_SK:
if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
goto out;
if (len != ED25519_PK_SZ) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((key = sshkey_new(type)) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (type == KEY_ED25519_SK || type == KEY_ED25519_SK_CERT) {
/* Parse additional security-key application string */
if (sshbuf_get_cstring(b, &key->sk_application,
NULL) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
#ifdef DEBUG_PK
fprintf(stderr, "App: %s\n", key->sk_application);
#endif
}
key->ed25519_pk = pk;
pk = NULL;
break;
#ifdef WITH_XMSS
case KEY_XMSS_CERT:
/* Skip nonce */
if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* FALLTHROUGH */
case KEY_XMSS:
if ((ret = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0)
goto out;
if ((key = sshkey_new(type)) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((ret = sshkey_xmss_init(key, xmss_name)) != 0)
goto out;
if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
goto out;
if (len == 0 || len != sshkey_xmss_pklen(key)) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
key->xmss_pk = pk;
pk = NULL;
if (type != KEY_XMSS_CERT &&
(ret = sshkey_xmss_deserialize_pk_info(key, b)) != 0)
goto out;
break;
#endif /* WITH_XMSS */
case KEY_UNSPEC:
default:
ret = SSH_ERR_KEY_TYPE_UNKNOWN;
goto out;
}
/* Parse certificate potion */
if (sshkey_is_cert(key) && (ret = cert_parse(b, key, copy)) != 0)
goto out;
if (key != NULL && sshbuf_len(b) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
goto out;
}
ret = 0;
if (keyp != NULL) {
*keyp = key;
key = NULL;
}
out:
sshbuf_free(copy);
sshkey_free(key);
free(xmss_name);
free(ktype);
free(curve);
free(pk);
#if defined(WITH_OPENSSL)
BN_clear_free(rsa_n);
BN_clear_free(rsa_e);
BN_clear_free(dsa_p);
BN_clear_free(dsa_q);
BN_clear_free(dsa_g);
BN_clear_free(dsa_pub_key);
# if defined(OPENSSL_HAS_ECC)
EC_POINT_free(q);
# endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
return ret;
}
int
sshkey_from_blob(const u_char *blob, size_t blen, struct sshkey **keyp)
{
struct sshbuf *b;
int r;
if ((b = sshbuf_from(blob, blen)) == NULL)
return SSH_ERR_ALLOC_FAIL;
r = sshkey_from_blob_internal(b, keyp, 1);
sshbuf_free(b);
return r;
}
int
sshkey_fromb(struct sshbuf *b, struct sshkey **keyp)
{
return sshkey_from_blob_internal(b, keyp, 1);
}
int
sshkey_froms(struct sshbuf *buf, struct sshkey **keyp)
{
struct sshbuf *b;
int r;
if ((r = sshbuf_froms(buf, &b)) != 0)
return r;
r = sshkey_from_blob_internal(b, keyp, 1);
sshbuf_free(b);
return r;
}
int
sshkey_get_sigtype(const u_char *sig, size_t siglen, char **sigtypep)
{
int r;
struct sshbuf *b = NULL;
char *sigtype = NULL;
if (sigtypep != NULL)
*sigtypep = NULL;
if ((b = sshbuf_from(sig, siglen)) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_get_cstring(b, &sigtype, NULL)) != 0)
goto out;
/* success */
if (sigtypep != NULL) {
*sigtypep = sigtype;
sigtype = NULL;
}
r = 0;
out:
free(sigtype);
sshbuf_free(b);
return r;
}
/*
*
* Checks whether a certificate's signature type is allowed.
* Returns 0 (success) if the certificate signature type appears in the
* "allowed" pattern-list, or the key is not a certificate to begin with.
* Otherwise returns a ssherr.h code.
*/
int
sshkey_check_cert_sigtype(const struct sshkey *key, const char *allowed)
{
if (key == NULL || allowed == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if (!sshkey_type_is_cert(key->type))
return 0;
if (key->cert == NULL || key->cert->signature_type == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if (match_pattern_list(key->cert->signature_type, allowed, 0) != 1)
return SSH_ERR_SIGN_ALG_UNSUPPORTED;
return 0;
}
/*
* Returns the expected signature algorithm for a given public key algorithm.
*/
const char *
sshkey_sigalg_by_name(const char *name)
{
const struct keytype *kt;
for (kt = keytypes; kt->type != -1; kt++) {
if (strcmp(kt->name, name) != 0)
continue;
if (kt->sigalg != NULL)
return kt->sigalg;
if (!kt->cert)
return kt->name;
return sshkey_ssh_name_from_type_nid(
sshkey_type_plain(kt->type), kt->nid);
}
return NULL;
}
/*
* Verifies that the signature algorithm appearing inside the signature blob
* matches that which was requested.
*/
int
sshkey_check_sigtype(const u_char *sig, size_t siglen,
const char *requested_alg)
{
const char *expected_alg;
char *sigtype = NULL;
int r;
if (requested_alg == NULL)
return 0;
if ((expected_alg = sshkey_sigalg_by_name(requested_alg)) == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if ((r = sshkey_get_sigtype(sig, siglen, &sigtype)) != 0)
return r;
r = strcmp(expected_alg, sigtype) == 0;
free(sigtype);
return r ? 0 : SSH_ERR_SIGN_ALG_UNSUPPORTED;
}
int
sshkey_sign(struct sshkey *key,
u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen,
const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
{
int was_shielded = sshkey_is_shielded(key);
int r2, r = SSH_ERR_INTERNAL_ERROR;
if (sigp != NULL)
*sigp = NULL;
if (lenp != NULL)
*lenp = 0;
if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE)
return SSH_ERR_INVALID_ARGUMENT;
if ((r = sshkey_unshield_private(key)) != 0)
return r;
switch (key->type) {
#ifdef WITH_OPENSSL
case KEY_DSA_CERT:
case KEY_DSA:
r = ssh_dss_sign(key, sigp, lenp, data, datalen, compat);
break;
# ifdef OPENSSL_HAS_ECC
case KEY_ECDSA_CERT:
case KEY_ECDSA:
r = ssh_ecdsa_sign(key, sigp, lenp, data, datalen, compat);
break;
# endif /* OPENSSL_HAS_ECC */
case KEY_RSA_CERT:
case KEY_RSA:
r = ssh_rsa_sign(key, sigp, lenp, data, datalen, alg);
break;
#endif /* WITH_OPENSSL */
case KEY_ED25519:
case KEY_ED25519_CERT:
r = ssh_ed25519_sign(key, sigp, lenp, data, datalen, compat);
break;
case KEY_ED25519_SK:
case KEY_ED25519_SK_CERT:
case KEY_ECDSA_SK_CERT:
case KEY_ECDSA_SK:
r = sshsk_sign(sk_provider, key, sigp, lenp, data,
datalen, compat, sk_pin);
break;
#ifdef WITH_XMSS
case KEY_XMSS:
case KEY_XMSS_CERT:
r = ssh_xmss_sign(key, sigp, lenp, data, datalen, compat);
break;
#endif /* WITH_XMSS */
default:
r = SSH_ERR_KEY_TYPE_UNKNOWN;
break;
}
if (was_shielded && (r2 = sshkey_shield_private(key)) != 0)
return r2;
return r;
}
/*
* ssh_key_verify returns 0 for a correct signature and < 0 on error.
* If "alg" specified, then the signature must use that algorithm.
*/
int
sshkey_verify(const struct sshkey *key,
const u_char *sig, size_t siglen,
const u_char *data, size_t dlen, const char *alg, u_int compat,
struct sshkey_sig_details **detailsp)
{
if (detailsp != NULL)
*detailsp = NULL;
if (siglen == 0 || dlen > SSH_KEY_MAX_SIGN_DATA_SIZE)
return SSH_ERR_INVALID_ARGUMENT;
switch (key->type) {
#ifdef WITH_OPENSSL
case KEY_DSA_CERT:
case KEY_DSA:
return ssh_dss_verify(key, sig, siglen, data, dlen, compat);
# ifdef OPENSSL_HAS_ECC
case KEY_ECDSA_CERT:
case KEY_ECDSA:
return ssh_ecdsa_verify(key, sig, siglen, data, dlen, compat);
case KEY_ECDSA_SK_CERT:
case KEY_ECDSA_SK:
return ssh_ecdsa_sk_verify(key, sig, siglen, data, dlen,
compat, detailsp);
# endif /* OPENSSL_HAS_ECC */
case KEY_RSA_CERT:
case KEY_RSA:
return ssh_rsa_verify(key, sig, siglen, data, dlen, alg);
#endif /* WITH_OPENSSL */
case KEY_ED25519:
case KEY_ED25519_CERT:
return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat);
case KEY_ED25519_SK:
case KEY_ED25519_SK_CERT:
return ssh_ed25519_sk_verify(key, sig, siglen, data, dlen,
compat, detailsp);
#ifdef WITH_XMSS
case KEY_XMSS:
case KEY_XMSS_CERT:
return ssh_xmss_verify(key, sig, siglen, data, dlen, compat);
#endif /* WITH_XMSS */
default:
return SSH_ERR_KEY_TYPE_UNKNOWN;
}
}
/* Convert a plain key to their _CERT equivalent */
int
sshkey_to_certified(struct sshkey *k)
{
int newtype;
switch (k->type) {
#ifdef WITH_OPENSSL
case KEY_RSA:
newtype = KEY_RSA_CERT;
break;
case KEY_DSA:
newtype = KEY_DSA_CERT;
break;
case KEY_ECDSA:
newtype = KEY_ECDSA_CERT;
break;
case KEY_ECDSA_SK:
newtype = KEY_ECDSA_SK_CERT;
break;
#endif /* WITH_OPENSSL */
case KEY_ED25519_SK:
newtype = KEY_ED25519_SK_CERT;
break;
case KEY_ED25519:
newtype = KEY_ED25519_CERT;
break;
#ifdef WITH_XMSS
case KEY_XMSS:
newtype = KEY_XMSS_CERT;
break;
#endif /* WITH_XMSS */
default:
return SSH_ERR_INVALID_ARGUMENT;
}
if ((k->cert = cert_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
k->type = newtype;
return 0;
}
/* Convert a certificate to its raw key equivalent */
int
sshkey_drop_cert(struct sshkey *k)
{
if (!sshkey_type_is_cert(k->type))
return SSH_ERR_KEY_TYPE_UNKNOWN;
cert_free(k->cert);
k->cert = NULL;
k->type = sshkey_type_plain(k->type);
return 0;
}
/* Sign a certified key, (re-)generating the signed certblob. */
int
sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
const char *sk_provider, const char *sk_pin,
sshkey_certify_signer *signer, void *signer_ctx)
{
struct sshbuf *principals = NULL;
u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32];
size_t i, ca_len, sig_len;
int ret = SSH_ERR_INTERNAL_ERROR;
struct sshbuf *cert = NULL;
char *sigtype = NULL;
#ifdef WITH_OPENSSL
const BIGNUM *rsa_n, *rsa_e, *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
#endif /* WITH_OPENSSL */
if (k == NULL || k->cert == NULL ||
k->cert->certblob == NULL || ca == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if (!sshkey_is_cert(k))
return SSH_ERR_KEY_TYPE_UNKNOWN;
if (!sshkey_type_is_valid_ca(ca->type))
return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
/*
* If no alg specified as argument but a signature_type was set,
* then prefer that. If both were specified, then they must match.
*/
if (alg == NULL)
alg = k->cert->signature_type;
else if (k->cert->signature_type != NULL &&
strcmp(alg, k->cert->signature_type) != 0)
return SSH_ERR_INVALID_ARGUMENT;
/*
* If no signing algorithm or signature_type was specified and we're
* using a RSA key, then default to a good signature algorithm.
*/
if (alg == NULL && ca->type == KEY_RSA)
alg = "rsa-sha2-512";
if ((ret = sshkey_to_blob(ca, &ca_blob, &ca_len)) != 0)
return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
cert = k->cert->certblob; /* for readability */
sshbuf_reset(cert);
if ((ret = sshbuf_put_cstring(cert, sshkey_ssh_name(k))) != 0)
goto out;
/* -v01 certs put nonce first */
arc4random_buf(&nonce, sizeof(nonce));
if ((ret = sshbuf_put_string(cert, nonce, sizeof(nonce))) != 0)
goto out;
/* XXX this substantially duplicates to_blob(); refactor */
switch (k->type) {
#ifdef WITH_OPENSSL
case KEY_DSA_CERT:
DSA_get0_pqg(k->dsa, &dsa_p, &dsa_q, &dsa_g);
DSA_get0_key(k->dsa, &dsa_pub_key, NULL);
if ((ret = sshbuf_put_bignum2(cert, dsa_p)) != 0 ||
(ret = sshbuf_put_bignum2(cert, dsa_q)) != 0 ||
(ret = sshbuf_put_bignum2(cert, dsa_g)) != 0 ||
(ret = sshbuf_put_bignum2(cert, dsa_pub_key)) != 0)
goto out;
break;
# ifdef OPENSSL_HAS_ECC
case KEY_ECDSA_CERT:
case KEY_ECDSA_SK_CERT:
if ((ret = sshbuf_put_cstring(cert,
sshkey_curve_nid_to_name(k->ecdsa_nid))) != 0 ||
(ret = sshbuf_put_ec(cert,
EC_KEY_get0_public_key(k->ecdsa),
EC_KEY_get0_group(k->ecdsa))) != 0)
goto out;
if (k->type == KEY_ECDSA_SK_CERT) {
if ((ret = sshbuf_put_cstring(cert,
k->sk_application)) != 0)
goto out;
}
break;
# endif /* OPENSSL_HAS_ECC */
case KEY_RSA_CERT:
RSA_get0_key(k->rsa, &rsa_n, &rsa_e, NULL);
if ((ret = sshbuf_put_bignum2(cert, rsa_e)) != 0 ||
(ret = sshbuf_put_bignum2(cert, rsa_n)) != 0)
goto out;
break;
#endif /* WITH_OPENSSL */
case KEY_ED25519_CERT:
case KEY_ED25519_SK_CERT:
if ((ret = sshbuf_put_string(cert,
k->ed25519_pk, ED25519_PK_SZ)) != 0)
goto out;
if (k->type == KEY_ED25519_SK_CERT) {
if ((ret = sshbuf_put_cstring(cert,
k->sk_application)) != 0)
goto out;
}
break;
#ifdef WITH_XMSS
case KEY_XMSS_CERT:
if (k->xmss_name == NULL) {
ret = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((ret = sshbuf_put_cstring(cert, k->xmss_name)) ||
(ret = sshbuf_put_string(cert,
k->xmss_pk, sshkey_xmss_pklen(k))) != 0)
goto out;
break;
#endif /* WITH_XMSS */
default:
ret = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((ret = sshbuf_put_u64(cert, k->cert->serial)) != 0 ||
(ret = sshbuf_put_u32(cert, k->cert->type)) != 0 ||
(ret = sshbuf_put_cstring(cert, k->cert->key_id)) != 0)
goto out;
if ((principals = sshbuf_new()) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
for (i = 0; i < k->cert->nprincipals; i++) {
if ((ret = sshbuf_put_cstring(principals,
k->cert->principals[i])) != 0)
goto out;
}
if ((ret = sshbuf_put_stringb(cert, principals)) != 0 ||
(ret = sshbuf_put_u64(cert, k->cert->valid_after)) != 0 ||
(ret = sshbuf_put_u64(cert, k->cert->valid_before)) != 0 ||
(ret = sshbuf_put_stringb(cert, k->cert->critical)) != 0 ||
(ret = sshbuf_put_stringb(cert, k->cert->extensions)) != 0 ||
(ret = sshbuf_put_string(cert, NULL, 0)) != 0 || /* Reserved */
(ret = sshbuf_put_string(cert, ca_blob, ca_len)) != 0)
goto out;
/* Sign the whole mess */
if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert),
sshbuf_len(cert), alg, sk_provider, sk_pin, 0, signer_ctx)) != 0)
goto out;
/* Check and update signature_type against what was actually used */
if ((ret = sshkey_get_sigtype(sig_blob, sig_len, &sigtype)) != 0)
goto out;
if (alg != NULL && strcmp(alg, sigtype) != 0) {
ret = SSH_ERR_SIGN_ALG_UNSUPPORTED;
goto out;
}
if (k->cert->signature_type == NULL) {
k->cert->signature_type = sigtype;
sigtype = NULL;
}
/* Append signature and we are done */
if ((ret = sshbuf_put_string(cert, sig_blob, sig_len)) != 0)
goto out;
ret = 0;
out:
if (ret != 0)
sshbuf_reset(cert);
free(sig_blob);
free(ca_blob);
free(sigtype);
sshbuf_free(principals);
return ret;
}
static int
default_key_sign(struct sshkey *key, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen,
const char *alg, const char *sk_provider, const char *sk_pin,
u_int compat, void *ctx)
{
if (ctx != NULL)
return SSH_ERR_INVALID_ARGUMENT;
return sshkey_sign(key, sigp, lenp, data, datalen, alg,
sk_provider, sk_pin, compat);
}
int
sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg,
const char *sk_provider, const char *sk_pin)
{
return sshkey_certify_custom(k, ca, alg, sk_provider, sk_pin,
default_key_sign, NULL);
}
int
sshkey_cert_check_authority(const struct sshkey *k,
int want_host, int require_principal, int wildcard_pattern,
const char *name, const char **reason)
{
u_int i, principal_matches;
time_t now = time(NULL);
if (reason == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if (!sshkey_is_cert(k)) {
*reason = "Key is not a certificate";
return SSH_ERR_KEY_CERT_INVALID;
}
if (want_host) {
if (k->cert->type != SSH2_CERT_TYPE_HOST) {
*reason = "Certificate invalid: not a host certificate";
return SSH_ERR_KEY_CERT_INVALID;
}
} else {
if (k->cert->type != SSH2_CERT_TYPE_USER) {
*reason = "Certificate invalid: not a user certificate";
return SSH_ERR_KEY_CERT_INVALID;
}
}
if (now < 0) {
/* yikes - system clock before epoch! */
*reason = "Certificate invalid: not yet valid";
return SSH_ERR_KEY_CERT_INVALID;
}
if ((u_int64_t)now < k->cert->valid_after) {
*reason = "Certificate invalid: not yet valid";
return SSH_ERR_KEY_CERT_INVALID;
}
if ((u_int64_t)now >= k->cert->valid_before) {
*reason = "Certificate invalid: expired";
return SSH_ERR_KEY_CERT_INVALID;
}
if (k->cert->nprincipals == 0) {
if (require_principal) {
*reason = "Certificate lacks principal list";
return SSH_ERR_KEY_CERT_INVALID;
}
} else if (name != NULL) {
principal_matches = 0;
for (i = 0; i < k->cert->nprincipals; i++) {
if (wildcard_pattern) {
if (match_pattern(k->cert->principals[i],
name)) {
principal_matches = 1;
break;
}
} else if (strcmp(name, k->cert->principals[i]) == 0) {
principal_matches = 1;
break;
}
}
if (!principal_matches) {
*reason = "Certificate invalid: name is not a listed "
"principal";
return SSH_ERR_KEY_CERT_INVALID;
}
}
return 0;
}
int
sshkey_cert_check_host(const struct sshkey *key, const char *host,
int wildcard_principals, const char *ca_sign_algorithms,
const char **reason)
{
int r;
if ((r = sshkey_cert_check_authority(key, 1, 0, wildcard_principals,
host, reason)) != 0)
return r;
if (sshbuf_len(key->cert->critical) != 0) {
*reason = "Certificate contains unsupported critical options";
return SSH_ERR_KEY_CERT_INVALID;
}
if (ca_sign_algorithms != NULL &&
(r = sshkey_check_cert_sigtype(key, ca_sign_algorithms)) != 0) {
*reason = "Certificate signed with disallowed algorithm";
return SSH_ERR_KEY_CERT_INVALID;
}
return 0;
}
size_t
sshkey_format_cert_validity(const struct sshkey_cert *cert, char *s, size_t l)
{
char from[32], to[32], ret[128];
time_t tt;
struct tm *tm;
*from = *to = '\0';
if (cert->valid_after == 0 &&
cert->valid_before == 0xffffffffffffffffULL)
return strlcpy(s, "forever", l);
if (cert->valid_after != 0) {
/* XXX revisit INT_MAX in 2038 :) */
tt = cert->valid_after > INT_MAX ?
INT_MAX : cert->valid_after;
tm = localtime(&tt);
strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm);
}
if (cert->valid_before != 0xffffffffffffffffULL) {
/* XXX revisit INT_MAX in 2038 :) */
tt = cert->valid_before > INT_MAX ?
INT_MAX : cert->valid_before;
tm = localtime(&tt);
strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm);
}
if (cert->valid_after == 0)
snprintf(ret, sizeof(ret), "before %s", to);
else if (cert->valid_before == 0xffffffffffffffffULL)
snprintf(ret, sizeof(ret), "after %s", from);
else
snprintf(ret, sizeof(ret), "from %s to %s", from, to);
return strlcpy(s, ret, l);
}
int
sshkey_private_serialize_opt(struct sshkey *key, struct sshbuf *buf,
enum sshkey_serialize_rep opts)
{
int r = SSH_ERR_INTERNAL_ERROR;
int was_shielded = sshkey_is_shielded(key);
struct sshbuf *b = NULL;
#ifdef WITH_OPENSSL
const BIGNUM *rsa_n, *rsa_e, *rsa_d, *rsa_iqmp, *rsa_p, *rsa_q;
const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key, *dsa_priv_key;
#endif /* WITH_OPENSSL */
if ((r = sshkey_unshield_private(key)) != 0)
return r;
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_cstring(b, sshkey_ssh_name(key))) != 0)
goto out;
switch (key->type) {
#ifdef WITH_OPENSSL
case KEY_RSA:
RSA_get0_key(key->rsa, &rsa_n, &rsa_e, &rsa_d);
RSA_get0_factors(key->rsa, &rsa_p, &rsa_q);
RSA_get0_crt_params(key->rsa, NULL, NULL, &rsa_iqmp);
if ((r = sshbuf_put_bignum2(b, rsa_n)) != 0 ||
(r = sshbuf_put_bignum2(b, rsa_e)) != 0 ||
(r = sshbuf_put_bignum2(b, rsa_d)) != 0 ||
(r = sshbuf_put_bignum2(b, rsa_iqmp)) != 0 ||
(r = sshbuf_put_bignum2(b, rsa_p)) != 0 ||
(r = sshbuf_put_bignum2(b, rsa_q)) != 0)
goto out;
break;
case KEY_RSA_CERT:
if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
RSA_get0_key(key->rsa, NULL, NULL, &rsa_d);
RSA_get0_factors(key->rsa, &rsa_p, &rsa_q);
RSA_get0_crt_params(key->rsa, NULL, NULL, &rsa_iqmp);
if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
(r = sshbuf_put_bignum2(b, rsa_d)) != 0 ||
(r = sshbuf_put_bignum2(b, rsa_iqmp)) != 0 ||
(r = sshbuf_put_bignum2(b, rsa_p)) != 0 ||
(r = sshbuf_put_bignum2(b, rsa_q)) != 0)
goto out;
break;
case KEY_DSA:
DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g);
DSA_get0_key(key->dsa, &dsa_pub_key, &dsa_priv_key);
if ((r = sshbuf_put_bignum2(b, dsa_p)) != 0 ||
(r = sshbuf_put_bignum2(b, dsa_q)) != 0 ||
(r = sshbuf_put_bignum2(b, dsa_g)) != 0 ||
(r = sshbuf_put_bignum2(b, dsa_pub_key)) != 0 ||
(r = sshbuf_put_bignum2(b, dsa_priv_key)) != 0)
goto out;
break;
case KEY_DSA_CERT:
if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
DSA_get0_key(key->dsa, NULL, &dsa_priv_key);
if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
(r = sshbuf_put_bignum2(b, dsa_priv_key)) != 0)
goto out;
break;
# ifdef OPENSSL_HAS_ECC
case KEY_ECDSA:
if ((r = sshbuf_put_cstring(b,
sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
(r = sshbuf_put_eckey(b, key->ecdsa)) != 0 ||
(r = sshbuf_put_bignum2(b,
EC_KEY_get0_private_key(key->ecdsa))) != 0)
goto out;
break;
case KEY_ECDSA_CERT:
if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
(r = sshbuf_put_bignum2(b,
EC_KEY_get0_private_key(key->ecdsa))) != 0)
goto out;
break;
case KEY_ECDSA_SK:
if ((r = sshbuf_put_cstring(b,
sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
(r = sshbuf_put_eckey(b, key->ecdsa)) != 0 ||
(r = sshbuf_put_cstring(b, key->sk_application)) != 0 ||
(r = sshbuf_put_u8(b, key->sk_flags)) != 0 ||
(r = sshbuf_put_stringb(b, key->sk_key_handle)) != 0 ||
(r = sshbuf_put_stringb(b, key->sk_reserved)) != 0)
goto out;
break;
case KEY_ECDSA_SK_CERT:
if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
(r = sshbuf_put_cstring(b, key->sk_application)) != 0 ||
(r = sshbuf_put_u8(b, key->sk_flags)) != 0 ||
(r = sshbuf_put_stringb(b, key->sk_key_handle)) != 0 ||
(r = sshbuf_put_stringb(b, key->sk_reserved)) != 0)
goto out;
break;
# endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
case KEY_ED25519:
if ((r = sshbuf_put_string(b, key->ed25519_pk,
ED25519_PK_SZ)) != 0 ||
(r = sshbuf_put_string(b, key->ed25519_sk,
ED25519_SK_SZ)) != 0)
goto out;
break;
case KEY_ED25519_CERT:
if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
(r = sshbuf_put_string(b, key->ed25519_pk,
ED25519_PK_SZ)) != 0 ||
(r = sshbuf_put_string(b, key->ed25519_sk,
ED25519_SK_SZ)) != 0)
goto out;
break;
case KEY_ED25519_SK:
if ((r = sshbuf_put_string(b, key->ed25519_pk,
ED25519_PK_SZ)) != 0 ||
(r = sshbuf_put_cstring(b, key->sk_application)) != 0 ||
(r = sshbuf_put_u8(b, key->sk_flags)) != 0 ||
(r = sshbuf_put_stringb(b, key->sk_key_handle)) != 0 ||
(r = sshbuf_put_stringb(b, key->sk_reserved)) != 0)
goto out;
break;
case KEY_ED25519_SK_CERT:
if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
(r = sshbuf_put_string(b, key->ed25519_pk,
ED25519_PK_SZ)) != 0 ||
(r = sshbuf_put_cstring(b, key->sk_application)) != 0 ||
(r = sshbuf_put_u8(b, key->sk_flags)) != 0 ||
(r = sshbuf_put_stringb(b, key->sk_key_handle)) != 0 ||
(r = sshbuf_put_stringb(b, key->sk_reserved)) != 0)
goto out;
break;
#ifdef WITH_XMSS
case KEY_XMSS:
if (key->xmss_name == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((r = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
(r = sshbuf_put_string(b, key->xmss_pk,
sshkey_xmss_pklen(key))) != 0 ||
(r = sshbuf_put_string(b, key->xmss_sk,
sshkey_xmss_sklen(key))) != 0 ||
(r = sshkey_xmss_serialize_state_opt(key, b, opts)) != 0)
goto out;
break;
case KEY_XMSS_CERT:
if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0 ||
key->xmss_name == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
(r = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
(r = sshbuf_put_string(b, key->xmss_pk,
sshkey_xmss_pklen(key))) != 0 ||
(r = sshbuf_put_string(b, key->xmss_sk,
sshkey_xmss_sklen(key))) != 0 ||
(r = sshkey_xmss_serialize_state_opt(key, b, opts)) != 0)
goto out;
break;
#endif /* WITH_XMSS */
default:
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
/*
* success (but we still need to append the output to buf after
* possibly re-shielding the private key)
*/
r = 0;
out:
if (was_shielded)
r = sshkey_shield_private(key);
if (r == 0)
r = sshbuf_putb(buf, b);
sshbuf_free(b);
return r;
}
int
sshkey_private_serialize(struct sshkey *key, struct sshbuf *b)
{
return sshkey_private_serialize_opt(key, b,
SSHKEY_SERIALIZE_DEFAULT);
}
int
sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
{
char *tname = NULL, *curve = NULL, *xmss_name = NULL;
char *expect_sk_application = NULL;
struct sshkey *k = NULL;
size_t pklen = 0, sklen = 0;
int type, r = SSH_ERR_INTERNAL_ERROR;
u_char *ed25519_pk = NULL, *ed25519_sk = NULL;
u_char *expect_ed25519_pk = NULL;
u_char *xmss_pk = NULL, *xmss_sk = NULL;
#ifdef WITH_OPENSSL
BIGNUM *exponent = NULL;
BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
BIGNUM *rsa_iqmp = NULL, *rsa_p = NULL, *rsa_q = NULL;
BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL;
BIGNUM *dsa_pub_key = NULL, *dsa_priv_key = NULL;
#endif /* WITH_OPENSSL */
if (kp != NULL)
*kp = NULL;
if ((r = sshbuf_get_cstring(buf, &tname, NULL)) != 0)
goto out;
type = sshkey_type_from_name(tname);
if (sshkey_type_is_cert(type)) {
/*
* Certificate key private keys begin with the certificate
* itself. Make sure this matches the type of the enclosing
* private key.
*/
if ((r = sshkey_froms(buf, &k)) != 0)
goto out;
if (k->type != type) {
r = SSH_ERR_KEY_CERT_MISMATCH;
goto out;
}
/* For ECDSA keys, the group must match too */
if (k->type == KEY_ECDSA &&
k->ecdsa_nid != sshkey_ecdsa_nid_from_name(tname)) {
r = SSH_ERR_KEY_CERT_MISMATCH;
goto out;
}
/*
* Several fields are redundant between certificate and
* private key body, we require these to match.
*/
expect_sk_application = k->sk_application;
expect_ed25519_pk = k->ed25519_pk;
k->sk_application = NULL;
k->ed25519_pk = NULL;
} else {
if ((k = sshkey_new(type)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
}
switch (type) {
#ifdef WITH_OPENSSL
case KEY_DSA:
if ((r = sshbuf_get_bignum2(buf, &dsa_p)) != 0 ||
(r = sshbuf_get_bignum2(buf, &dsa_q)) != 0 ||
(r = sshbuf_get_bignum2(buf, &dsa_g)) != 0 ||
(r = sshbuf_get_bignum2(buf, &dsa_pub_key)) != 0)
goto out;
if (!DSA_set0_pqg(k->dsa, dsa_p, dsa_q, dsa_g)) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
dsa_p = dsa_q = dsa_g = NULL; /* transferred */
if (!DSA_set0_key(k->dsa, dsa_pub_key, NULL)) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
dsa_pub_key = NULL; /* transferred */
/* FALLTHROUGH */
case KEY_DSA_CERT:
if ((r = sshbuf_get_bignum2(buf, &dsa_priv_key)) != 0)
goto out;
if (!DSA_set0_key(k->dsa, NULL, dsa_priv_key)) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
dsa_priv_key = NULL; /* transferred */
break;
# ifdef OPENSSL_HAS_ECC
case KEY_ECDSA:
if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((r = sshbuf_get_cstring(buf, &curve, NULL)) != 0)
goto out;
if (k->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
r = SSH_ERR_EC_CURVE_MISMATCH;
goto out;
}
k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
if (k->ecdsa == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if ((r = sshbuf_get_eckey(buf, k->ecdsa)) != 0)
goto out;
/* FALLTHROUGH */
case KEY_ECDSA_CERT:
if ((r = sshbuf_get_bignum2(buf, &exponent)) != 0)
goto out;
if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
EC_KEY_get0_public_key(k->ecdsa))) != 0 ||
(r = sshkey_ec_validate_private(k->ecdsa)) != 0)
goto out;
break;
case KEY_ECDSA_SK:
if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((r = sshbuf_get_cstring(buf, &curve, NULL)) != 0)
goto out;
if (k->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
r = SSH_ERR_EC_CURVE_MISMATCH;
goto out;
}
if ((k->sk_key_handle = sshbuf_new()) == NULL ||
(k->sk_reserved = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
if (k->ecdsa == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if ((r = sshbuf_get_eckey(buf, k->ecdsa)) != 0 ||
(r = sshbuf_get_cstring(buf, &k->sk_application,
NULL)) != 0 ||
(r = sshbuf_get_u8(buf, &k->sk_flags)) != 0 ||
(r = sshbuf_get_stringb(buf, k->sk_key_handle)) != 0 ||
(r = sshbuf_get_stringb(buf, k->sk_reserved)) != 0)
goto out;
if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
EC_KEY_get0_public_key(k->ecdsa))) != 0)
goto out;
break;
case KEY_ECDSA_SK_CERT:
if ((k->sk_key_handle = sshbuf_new()) == NULL ||
(k->sk_reserved = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_get_cstring(buf, &k->sk_application,
NULL)) != 0 ||
(r = sshbuf_get_u8(buf, &k->sk_flags)) != 0 ||
(r = sshbuf_get_stringb(buf, k->sk_key_handle)) != 0 ||
(r = sshbuf_get_stringb(buf, k->sk_reserved)) != 0)
goto out;
if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
EC_KEY_get0_public_key(k->ecdsa))) != 0)
goto out;
break;
# endif /* OPENSSL_HAS_ECC */
case KEY_RSA:
if ((r = sshbuf_get_bignum2(buf, &rsa_n)) != 0 ||
(r = sshbuf_get_bignum2(buf, &rsa_e)) != 0)
goto out;
if (!RSA_set0_key(k->rsa, rsa_n, rsa_e, NULL)) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
rsa_n = rsa_e = NULL; /* transferred */
/* FALLTHROUGH */
case KEY_RSA_CERT:
if ((r = sshbuf_get_bignum2(buf, &rsa_d)) != 0 ||
(r = sshbuf_get_bignum2(buf, &rsa_iqmp)) != 0 ||
(r = sshbuf_get_bignum2(buf, &rsa_p)) != 0 ||
(r = sshbuf_get_bignum2(buf, &rsa_q)) != 0)
goto out;
if (!RSA_set0_key(k->rsa, NULL, NULL, rsa_d)) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
rsa_d = NULL; /* transferred */
if (!RSA_set0_factors(k->rsa, rsa_p, rsa_q)) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
rsa_p = rsa_q = NULL; /* transferred */
if ((r = check_rsa_length(k->rsa)) != 0)
goto out;
if ((r = ssh_rsa_complete_crt_parameters(k, rsa_iqmp)) != 0)
goto out;
break;
#endif /* WITH_OPENSSL */
case KEY_ED25519:
case KEY_ED25519_CERT:
if ((r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 ||
(r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0)
goto out;
if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
k->ed25519_pk = ed25519_pk;
k->ed25519_sk = ed25519_sk;
ed25519_pk = ed25519_sk = NULL; /* transferred */
break;
case KEY_ED25519_SK:
case KEY_ED25519_SK_CERT:
if ((r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0)
goto out;
if (pklen != ED25519_PK_SZ) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((k->sk_key_handle = sshbuf_new()) == NULL ||
(k->sk_reserved = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_get_cstring(buf, &k->sk_application,
NULL)) != 0 ||
(r = sshbuf_get_u8(buf, &k->sk_flags)) != 0 ||
(r = sshbuf_get_stringb(buf, k->sk_key_handle)) != 0 ||
(r = sshbuf_get_stringb(buf, k->sk_reserved)) != 0)
goto out;
k->ed25519_pk = ed25519_pk;
ed25519_pk = NULL; /* transferred */
break;
#ifdef WITH_XMSS
case KEY_XMSS:
case KEY_XMSS_CERT:
if ((r = sshbuf_get_cstring(buf, &xmss_name, NULL)) != 0 ||
(r = sshbuf_get_string(buf, &xmss_pk, &pklen)) != 0 ||
(r = sshbuf_get_string(buf, &xmss_sk, &sklen)) != 0)
goto out;
if (type == KEY_XMSS &&
(r = sshkey_xmss_init(k, xmss_name)) != 0)
goto out;
if (pklen != sshkey_xmss_pklen(k) ||
sklen != sshkey_xmss_sklen(k)) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
k->xmss_pk = xmss_pk;
k->xmss_sk = xmss_sk;
xmss_pk = xmss_sk = NULL;
/* optional internal state */
if ((r = sshkey_xmss_deserialize_state_opt(k, buf)) != 0)
goto out;
break;
#endif /* WITH_XMSS */
default:
r = SSH_ERR_KEY_TYPE_UNKNOWN;
goto out;
}
#ifdef WITH_OPENSSL
/* enable blinding */
switch (k->type) {
case KEY_RSA:
case KEY_RSA_CERT:
if (RSA_blinding_on(k->rsa, NULL) != 1) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
break;
}
#endif /* WITH_OPENSSL */
if ((expect_sk_application != NULL && (k->sk_application == NULL ||
strcmp(expect_sk_application, k->sk_application) != 0)) ||
(expect_ed25519_pk != NULL && (k->ed25519_pk == NULL ||
- memcmp(expect_ed25519_pk, k->ed25519_pk, ED25519_PK_SZ) != 0))) {
+ memcmp(expect_ed25519_pk, k->ed25519_pk, ED25519_PK_SZ) != 0))) {
r = SSH_ERR_KEY_CERT_MISMATCH;
goto out;
}
/* success */
r = 0;
if (kp != NULL) {
*kp = k;
k = NULL;
}
out:
free(tname);
free(curve);
#ifdef WITH_OPENSSL
BN_clear_free(exponent);
BN_clear_free(dsa_p);
BN_clear_free(dsa_q);
BN_clear_free(dsa_g);
BN_clear_free(dsa_pub_key);
BN_clear_free(dsa_priv_key);
BN_clear_free(rsa_n);
BN_clear_free(rsa_e);
BN_clear_free(rsa_d);
BN_clear_free(rsa_p);
BN_clear_free(rsa_q);
BN_clear_free(rsa_iqmp);
#endif /* WITH_OPENSSL */
sshkey_free(k);
freezero(ed25519_pk, pklen);
freezero(ed25519_sk, sklen);
free(xmss_name);
freezero(xmss_pk, pklen);
freezero(xmss_sk, sklen);
free(expect_sk_application);
free(expect_ed25519_pk);
return r;
}
#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
int
sshkey_ec_validate_public(const EC_GROUP *group, const EC_POINT *public)
{
EC_POINT *nq = NULL;
BIGNUM *order = NULL, *x = NULL, *y = NULL, *tmp = NULL;
int ret = SSH_ERR_KEY_INVALID_EC_VALUE;
/*
* NB. This assumes OpenSSL has already verified that the public
* point lies on the curve. This is done by EC_POINT_oct2point()
* implicitly calling EC_POINT_is_on_curve(). If this code is ever
* reachable with public points not unmarshalled using
* EC_POINT_oct2point then the caller will need to explicitly check.
*/
/*
* We shouldn't ever hit this case because bignum_get_ecpoint()
* refuses to load GF2m points.
*/
if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
NID_X9_62_prime_field)
goto out;
/* Q != infinity */
if (EC_POINT_is_at_infinity(group, public))
goto out;
if ((x = BN_new()) == NULL ||
(y = BN_new()) == NULL ||
(order = BN_new()) == NULL ||
(tmp = BN_new()) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */
if (EC_GROUP_get_order(group, order, NULL) != 1 ||
EC_POINT_get_affine_coordinates_GFp(group, public,
x, y, NULL) != 1) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if (BN_num_bits(x) <= BN_num_bits(order) / 2 ||
BN_num_bits(y) <= BN_num_bits(order) / 2)
goto out;
/* nQ == infinity (n == order of subgroup) */
if ((nq = EC_POINT_new(group)) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (EC_POINT_mul(group, nq, NULL, public, order, NULL) != 1) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if (EC_POINT_is_at_infinity(group, nq) != 1)
goto out;
/* x < order - 1, y < order - 1 */
if (!BN_sub(tmp, order, BN_value_one())) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if (BN_cmp(x, tmp) >= 0 || BN_cmp(y, tmp) >= 0)
goto out;
ret = 0;
out:
BN_clear_free(x);
BN_clear_free(y);
BN_clear_free(order);
BN_clear_free(tmp);
EC_POINT_free(nq);
return ret;
}
int
sshkey_ec_validate_private(const EC_KEY *key)
{
BIGNUM *order = NULL, *tmp = NULL;
int ret = SSH_ERR_KEY_INVALID_EC_VALUE;
if ((order = BN_new()) == NULL || (tmp = BN_new()) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* log2(private) > log2(order)/2 */
if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, NULL) != 1) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if (BN_num_bits(EC_KEY_get0_private_key(key)) <=
BN_num_bits(order) / 2)
goto out;
/* private < order - 1 */
if (!BN_sub(tmp, order, BN_value_one())) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0)
goto out;
ret = 0;
out:
BN_clear_free(order);
BN_clear_free(tmp);
return ret;
}
void
sshkey_dump_ec_point(const EC_GROUP *group, const EC_POINT *point)
{
BIGNUM *x = NULL, *y = NULL;
if (point == NULL) {
fputs("point=(NULL)\n", stderr);
return;
}
if ((x = BN_new()) == NULL || (y = BN_new()) == NULL) {
fprintf(stderr, "%s: BN_new failed\n", __func__);
goto out;
}
if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
NID_X9_62_prime_field) {
fprintf(stderr, "%s: group is not a prime field\n", __func__);
goto out;
}
if (EC_POINT_get_affine_coordinates_GFp(group, point,
x, y, NULL) != 1) {
fprintf(stderr, "%s: EC_POINT_get_affine_coordinates_GFp\n",
__func__);
goto out;
}
fputs("x=", stderr);
BN_print_fp(stderr, x);
fputs("\ny=", stderr);
BN_print_fp(stderr, y);
fputs("\n", stderr);
out:
BN_clear_free(x);
BN_clear_free(y);
}
void
sshkey_dump_ec_key(const EC_KEY *key)
{
const BIGNUM *exponent;
sshkey_dump_ec_point(EC_KEY_get0_group(key),
EC_KEY_get0_public_key(key));
fputs("exponent=", stderr);
if ((exponent = EC_KEY_get0_private_key(key)) == NULL)
fputs("(NULL)", stderr);
else
BN_print_fp(stderr, EC_KEY_get0_private_key(key));
fputs("\n", stderr);
}
#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
static int
sshkey_private_to_blob2(struct sshkey *prv, struct sshbuf *blob,
const char *passphrase, const char *comment, const char *ciphername,
int rounds)
{
u_char *cp, *key = NULL, *pubkeyblob = NULL;
u_char salt[SALT_LEN];
char *b64 = NULL;
size_t i, pubkeylen, keylen, ivlen, blocksize, authlen;
u_int check;
int r = SSH_ERR_INTERNAL_ERROR;
struct sshcipher_ctx *ciphercontext = NULL;
const struct sshcipher *cipher;
const char *kdfname = KDFNAME;
struct sshbuf *encoded = NULL, *encrypted = NULL, *kdf = NULL;
if (rounds <= 0)
rounds = DEFAULT_ROUNDS;
if (passphrase == NULL || !strlen(passphrase)) {
ciphername = "none";
kdfname = "none";
} else if (ciphername == NULL)
ciphername = DEFAULT_CIPHERNAME;
if ((cipher = cipher_by_name(ciphername)) == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((kdf = sshbuf_new()) == NULL ||
(encoded = sshbuf_new()) == NULL ||
(encrypted = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
blocksize = cipher_blocksize(cipher);
keylen = cipher_keylen(cipher);
ivlen = cipher_ivlen(cipher);
authlen = cipher_authlen(cipher);
if ((key = calloc(1, keylen + ivlen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (strcmp(kdfname, "bcrypt") == 0) {
arc4random_buf(salt, SALT_LEN);
if (bcrypt_pbkdf(passphrase, strlen(passphrase),
salt, SALT_LEN, key, keylen + ivlen, rounds) < 0) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((r = sshbuf_put_string(kdf, salt, SALT_LEN)) != 0 ||
(r = sshbuf_put_u32(kdf, rounds)) != 0)
goto out;
} else if (strcmp(kdfname, "none") != 0) {
/* Unsupported KDF type */
r = SSH_ERR_KEY_UNKNOWN_CIPHER;
goto out;
}
if ((r = cipher_init(&ciphercontext, cipher, key, keylen,
key + keylen, ivlen, 1)) != 0)
goto out;
if ((r = sshbuf_put(encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC))) != 0 ||
(r = sshbuf_put_cstring(encoded, ciphername)) != 0 ||
(r = sshbuf_put_cstring(encoded, kdfname)) != 0 ||
(r = sshbuf_put_stringb(encoded, kdf)) != 0 ||
(r = sshbuf_put_u32(encoded, 1)) != 0 || /* number of keys */
(r = sshkey_to_blob(prv, &pubkeyblob, &pubkeylen)) != 0 ||
(r = sshbuf_put_string(encoded, pubkeyblob, pubkeylen)) != 0)
goto out;
/* set up the buffer that will be encrypted */
/* Random check bytes */
check = arc4random();
if ((r = sshbuf_put_u32(encrypted, check)) != 0 ||
(r = sshbuf_put_u32(encrypted, check)) != 0)
goto out;
/* append private key and comment*/
if ((r = sshkey_private_serialize_opt(prv, encrypted,
- SSHKEY_SERIALIZE_FULL)) != 0 ||
+ SSHKEY_SERIALIZE_FULL)) != 0 ||
(r = sshbuf_put_cstring(encrypted, comment)) != 0)
goto out;
/* padding */
i = 0;
while (sshbuf_len(encrypted) % blocksize) {
if ((r = sshbuf_put_u8(encrypted, ++i & 0xff)) != 0)
goto out;
}
/* length in destination buffer */
if ((r = sshbuf_put_u32(encoded, sshbuf_len(encrypted))) != 0)
goto out;
/* encrypt */
if ((r = sshbuf_reserve(encoded,
sshbuf_len(encrypted) + authlen, &cp)) != 0)
goto out;
if ((r = cipher_crypt(ciphercontext, 0, cp,
sshbuf_ptr(encrypted), sshbuf_len(encrypted), 0, authlen)) != 0)
goto out;
sshbuf_reset(blob);
/* assemble uuencoded key */
if ((r = sshbuf_put(blob, MARK_BEGIN, MARK_BEGIN_LEN)) != 0 ||
(r = sshbuf_dtob64(encoded, blob, 1)) != 0 ||
(r = sshbuf_put(blob, MARK_END, MARK_END_LEN)) != 0)
goto out;
/* success */
r = 0;
out:
sshbuf_free(kdf);
sshbuf_free(encoded);
sshbuf_free(encrypted);
cipher_free(ciphercontext);
explicit_bzero(salt, sizeof(salt));
if (key != NULL)
freezero(key, keylen + ivlen);
if (pubkeyblob != NULL)
freezero(pubkeyblob, pubkeylen);
if (b64 != NULL)
freezero(b64, strlen(b64));
return r;
}
static int
private2_uudecode(struct sshbuf *blob, struct sshbuf **decodedp)
{
const u_char *cp;
size_t encoded_len;
int r;
u_char last;
struct sshbuf *encoded = NULL, *decoded = NULL;
if (blob == NULL || decodedp == NULL)
return SSH_ERR_INVALID_ARGUMENT;
*decodedp = NULL;
if ((encoded = sshbuf_new()) == NULL ||
(decoded = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* check preamble */
cp = sshbuf_ptr(blob);
encoded_len = sshbuf_len(blob);
if (encoded_len < (MARK_BEGIN_LEN + MARK_END_LEN) ||
memcmp(cp, MARK_BEGIN, MARK_BEGIN_LEN) != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
cp += MARK_BEGIN_LEN;
encoded_len -= MARK_BEGIN_LEN;
/* Look for end marker, removing whitespace as we go */
while (encoded_len > 0) {
if (*cp != '\n' && *cp != '\r') {
if ((r = sshbuf_put_u8(encoded, *cp)) != 0)
goto out;
}
last = *cp;
encoded_len--;
cp++;
if (last == '\n') {
if (encoded_len >= MARK_END_LEN &&
memcmp(cp, MARK_END, MARK_END_LEN) == 0) {
/* \0 terminate */
if ((r = sshbuf_put_u8(encoded, 0)) != 0)
goto out;
break;
}
}
}
if (encoded_len == 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* decode base64 */
if ((r = sshbuf_b64tod(decoded, (char *)sshbuf_ptr(encoded))) != 0)
goto out;
/* check magic */
if (sshbuf_len(decoded) < sizeof(AUTH_MAGIC) ||
memcmp(sshbuf_ptr(decoded), AUTH_MAGIC, sizeof(AUTH_MAGIC))) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* success */
*decodedp = decoded;
decoded = NULL;
r = 0;
out:
sshbuf_free(encoded);
sshbuf_free(decoded);
return r;
}
static int
private2_decrypt(struct sshbuf *decoded, const char *passphrase,
struct sshbuf **decryptedp, struct sshkey **pubkeyp)
{
char *ciphername = NULL, *kdfname = NULL;
const struct sshcipher *cipher = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
size_t keylen = 0, ivlen = 0, authlen = 0, slen = 0;
struct sshbuf *kdf = NULL, *decrypted = NULL;
struct sshcipher_ctx *ciphercontext = NULL;
struct sshkey *pubkey = NULL;
u_char *key = NULL, *salt = NULL, *dp;
u_int blocksize, rounds, nkeys, encrypted_len, check1, check2;
if (decoded == NULL || decryptedp == NULL || pubkeyp == NULL)
return SSH_ERR_INVALID_ARGUMENT;
*decryptedp = NULL;
*pubkeyp = NULL;
if ((decrypted = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* parse public portion of key */
if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 ||
(r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 ||
(r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 ||
(r = sshbuf_froms(decoded, &kdf)) != 0 ||
(r = sshbuf_get_u32(decoded, &nkeys)) != 0)
goto out;
if (nkeys != 1) {
/* XXX only one key supported at present */
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((r = sshkey_froms(decoded, &pubkey)) != 0 ||
(r = sshbuf_get_u32(decoded, &encrypted_len)) != 0)
goto out;
if ((cipher = cipher_by_name(ciphername)) == NULL) {
r = SSH_ERR_KEY_UNKNOWN_CIPHER;
goto out;
}
if (strcmp(kdfname, "none") != 0 && strcmp(kdfname, "bcrypt") != 0) {
r = SSH_ERR_KEY_UNKNOWN_CIPHER;
goto out;
}
if (strcmp(kdfname, "none") == 0 && strcmp(ciphername, "none") != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((passphrase == NULL || strlen(passphrase) == 0) &&
strcmp(kdfname, "none") != 0) {
/* passphrase required */
r = SSH_ERR_KEY_WRONG_PASSPHRASE;
goto out;
}
/* check size of encrypted key blob */
blocksize = cipher_blocksize(cipher);
if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* setup key */
keylen = cipher_keylen(cipher);
ivlen = cipher_ivlen(cipher);
authlen = cipher_authlen(cipher);
if ((key = calloc(1, keylen + ivlen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (strcmp(kdfname, "bcrypt") == 0) {
if ((r = sshbuf_get_string(kdf, &salt, &slen)) != 0 ||
(r = sshbuf_get_u32(kdf, &rounds)) != 0)
goto out;
if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen,
key, keylen + ivlen, rounds) < 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
}
/* check that an appropriate amount of auth data is present */
if (sshbuf_len(decoded) < authlen ||
sshbuf_len(decoded) - authlen < encrypted_len) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* decrypt private portion of key */
if ((r = sshbuf_reserve(decrypted, encrypted_len, &dp)) != 0 ||
(r = cipher_init(&ciphercontext, cipher, key, keylen,
key + keylen, ivlen, 0)) != 0)
goto out;
if ((r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(decoded),
encrypted_len, 0, authlen)) != 0) {
/* an integrity error here indicates an incorrect passphrase */
if (r == SSH_ERR_MAC_INVALID)
r = SSH_ERR_KEY_WRONG_PASSPHRASE;
goto out;
}
if ((r = sshbuf_consume(decoded, encrypted_len + authlen)) != 0)
goto out;
/* there should be no trailing data */
if (sshbuf_len(decoded) != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* check check bytes */
if ((r = sshbuf_get_u32(decrypted, &check1)) != 0 ||
(r = sshbuf_get_u32(decrypted, &check2)) != 0)
goto out;
if (check1 != check2) {
r = SSH_ERR_KEY_WRONG_PASSPHRASE;
goto out;
}
/* success */
*decryptedp = decrypted;
decrypted = NULL;
*pubkeyp = pubkey;
pubkey = NULL;
r = 0;
out:
cipher_free(ciphercontext);
free(ciphername);
free(kdfname);
sshkey_free(pubkey);
if (salt != NULL) {
explicit_bzero(salt, slen);
free(salt);
}
if (key != NULL) {
explicit_bzero(key, keylen + ivlen);
free(key);
}
sshbuf_free(kdf);
sshbuf_free(decrypted);
return r;
}
/* Check deterministic padding after private key */
static int
private2_check_padding(struct sshbuf *decrypted)
{
u_char pad;
size_t i;
int r = SSH_ERR_INTERNAL_ERROR;
i = 0;
while (sshbuf_len(decrypted)) {
if ((r = sshbuf_get_u8(decrypted, &pad)) != 0)
goto out;
if (pad != (++i & 0xff)) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
}
/* success */
r = 0;
out:
explicit_bzero(&pad, sizeof(pad));
explicit_bzero(&i, sizeof(i));
return r;
}
static int
sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
struct sshkey **keyp, char **commentp)
{
char *comment = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
struct sshbuf *decoded = NULL, *decrypted = NULL;
struct sshkey *k = NULL, *pubkey = NULL;
if (keyp != NULL)
*keyp = NULL;
if (commentp != NULL)
*commentp = NULL;
/* Undo base64 encoding and decrypt the private section */
if ((r = private2_uudecode(blob, &decoded)) != 0 ||
(r = private2_decrypt(decoded, passphrase,
&decrypted, &pubkey)) != 0)
goto out;
if (type != KEY_UNSPEC &&
sshkey_type_plain(type) != sshkey_type_plain(pubkey->type)) {
r = SSH_ERR_KEY_TYPE_MISMATCH;
goto out;
}
/* Load the private key and comment */
if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 ||
(r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0)
goto out;
/* Check deterministic padding after private section */
if ((r = private2_check_padding(decrypted)) != 0)
goto out;
/* Check that the public key in the envelope matches the private key */
if (!sshkey_equal(pubkey, k)) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* success */
r = 0;
if (keyp != NULL) {
*keyp = k;
k = NULL;
}
if (commentp != NULL) {
*commentp = comment;
comment = NULL;
}
out:
free(comment);
sshbuf_free(decoded);
sshbuf_free(decrypted);
sshkey_free(k);
sshkey_free(pubkey);
return r;
}
static int
sshkey_parse_private2_pubkey(struct sshbuf *blob, int type,
struct sshkey **keyp)
{
int r = SSH_ERR_INTERNAL_ERROR;
struct sshbuf *decoded = NULL;
struct sshkey *pubkey = NULL;
u_int nkeys = 0;
if (keyp != NULL)
*keyp = NULL;
if ((r = private2_uudecode(blob, &decoded)) != 0)
goto out;
/* parse public key from unencrypted envelope */
if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 ||
(r = sshbuf_skip_string(decoded)) != 0 || /* cipher */
(r = sshbuf_skip_string(decoded)) != 0 || /* KDF alg */
(r = sshbuf_skip_string(decoded)) != 0 || /* KDF hint */
(r = sshbuf_get_u32(decoded, &nkeys)) != 0)
goto out;
if (nkeys != 1) {
/* XXX only one key supported at present */
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* Parse the public key */
if ((r = sshkey_froms(decoded, &pubkey)) != 0)
goto out;
if (type != KEY_UNSPEC &&
sshkey_type_plain(type) != sshkey_type_plain(pubkey->type)) {
r = SSH_ERR_KEY_TYPE_MISMATCH;
goto out;
}
/* success */
r = 0;
if (keyp != NULL) {
*keyp = pubkey;
pubkey = NULL;
}
out:
sshbuf_free(decoded);
sshkey_free(pubkey);
return r;
}
#ifdef WITH_OPENSSL
/* convert SSH v2 key to PEM or PKCS#8 format */
static int
sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf,
int format, const char *_passphrase, const char *comment)
{
int was_shielded = sshkey_is_shielded(key);
int success, r;
int blen, len = strlen(_passphrase);
u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
char *bptr;
BIO *bio = NULL;
struct sshbuf *blob;
EVP_PKEY *pkey = NULL;
if (len > 0 && len <= 4)
return SSH_ERR_PASSPHRASE_TOO_SHORT;
if ((blob = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
- if ((bio = BIO_new(BIO_s_mem())) == NULL) {
+ if ((bio = BIO_new(BIO_s_mem())) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (format == SSHKEY_PRIVATE_PKCS8 && (pkey = EVP_PKEY_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
- }
+ }
if ((r = sshkey_unshield_private(key)) != 0)
goto out;
switch (key->type) {
case KEY_DSA:
if (format == SSHKEY_PRIVATE_PEM) {
success = PEM_write_bio_DSAPrivateKey(bio, key->dsa,
cipher, passphrase, len, NULL, NULL);
} else {
success = EVP_PKEY_set1_DSA(pkey, key->dsa);
}
break;
#ifdef OPENSSL_HAS_ECC
case KEY_ECDSA:
if (format == SSHKEY_PRIVATE_PEM) {
success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
cipher, passphrase, len, NULL, NULL);
} else {
success = EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa);
}
break;
#endif
case KEY_RSA:
if (format == SSHKEY_PRIVATE_PEM) {
success = PEM_write_bio_RSAPrivateKey(bio, key->rsa,
cipher, passphrase, len, NULL, NULL);
} else {
success = EVP_PKEY_set1_RSA(pkey, key->rsa);
}
break;
default:
success = 0;
break;
}
if (success == 0) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if (format == SSHKEY_PRIVATE_PKCS8) {
if ((success = PEM_write_bio_PrivateKey(bio, pkey, cipher,
passphrase, len, NULL, NULL)) == 0) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
}
if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) {
r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
if ((r = sshbuf_put(blob, bptr, blen)) != 0)
goto out;
r = 0;
out:
if (was_shielded)
r = sshkey_shield_private(key);
if (r == 0)
r = sshbuf_putb(buf, blob);
EVP_PKEY_free(pkey);
sshbuf_free(blob);
BIO_free(bio);
return r;
}
#endif /* WITH_OPENSSL */
/* Serialise "key" to buffer "blob" */
int
sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob,
const char *passphrase, const char *comment,
int format, const char *openssh_format_cipher, int openssh_format_rounds)
{
switch (key->type) {
#ifdef WITH_OPENSSL
case KEY_DSA:
case KEY_ECDSA:
case KEY_RSA:
break; /* see below */
#endif /* WITH_OPENSSL */
case KEY_ED25519:
case KEY_ED25519_SK:
#ifdef WITH_XMSS
case KEY_XMSS:
#endif /* WITH_XMSS */
#ifdef WITH_OPENSSL
case KEY_ECDSA_SK:
#endif /* WITH_OPENSSL */
return sshkey_private_to_blob2(key, blob, passphrase,
comment, openssh_format_cipher, openssh_format_rounds);
default:
return SSH_ERR_KEY_TYPE_UNKNOWN;
}
#ifdef WITH_OPENSSL
switch (format) {
case SSHKEY_PRIVATE_OPENSSH:
return sshkey_private_to_blob2(key, blob, passphrase,
comment, openssh_format_cipher, openssh_format_rounds);
case SSHKEY_PRIVATE_PEM:
case SSHKEY_PRIVATE_PKCS8:
return sshkey_private_to_blob_pem_pkcs8(key, blob,
format, passphrase, comment);
default:
return SSH_ERR_INVALID_ARGUMENT;
}
#endif /* WITH_OPENSSL */
}
#ifdef WITH_OPENSSL
static int
translate_libcrypto_error(unsigned long pem_err)
{
int pem_reason = ERR_GET_REASON(pem_err);
switch (ERR_GET_LIB(pem_err)) {
case ERR_LIB_PEM:
switch (pem_reason) {
case PEM_R_BAD_PASSWORD_READ:
case PEM_R_PROBLEMS_GETTING_PASSWORD:
case PEM_R_BAD_DECRYPT:
return SSH_ERR_KEY_WRONG_PASSPHRASE;
default:
return SSH_ERR_INVALID_FORMAT;
}
case ERR_LIB_EVP:
switch (pem_reason) {
case EVP_R_BAD_DECRYPT:
return SSH_ERR_KEY_WRONG_PASSPHRASE;
#ifdef EVP_R_BN_DECODE_ERROR
case EVP_R_BN_DECODE_ERROR:
#endif
case EVP_R_DECODE_ERROR:
#ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR
case EVP_R_PRIVATE_KEY_DECODE_ERROR:
#endif
return SSH_ERR_INVALID_FORMAT;
default:
return SSH_ERR_LIBCRYPTO_ERROR;
}
case ERR_LIB_ASN1:
return SSH_ERR_INVALID_FORMAT;
}
return SSH_ERR_LIBCRYPTO_ERROR;
}
static void
clear_libcrypto_errors(void)
{
while (ERR_get_error() != 0)
;
}
/*
* Translate OpenSSL error codes to determine whether
* passphrase is required/incorrect.
*/
static int
convert_libcrypto_error(void)
{
/*
* Some password errors are reported at the beginning
* of the error queue.
*/
if (translate_libcrypto_error(ERR_peek_error()) ==
SSH_ERR_KEY_WRONG_PASSPHRASE)
return SSH_ERR_KEY_WRONG_PASSPHRASE;
return translate_libcrypto_error(ERR_peek_last_error());
}
static int
pem_passphrase_cb(char *buf, int size, int rwflag, void *u)
{
char *p = (char *)u;
size_t len;
if (p == NULL || (len = strlen(p)) == 0)
return -1;
if (size < 0 || len > (size_t)size)
return -1;
memcpy(buf, p, len);
return (int)len;
}
static int
sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
const char *passphrase, struct sshkey **keyp)
{
EVP_PKEY *pk = NULL;
struct sshkey *prv = NULL;
BIO *bio = NULL;
int r;
if (keyp != NULL)
*keyp = NULL;
if ((bio = BIO_new(BIO_s_mem())) == NULL || sshbuf_len(blob) > INT_MAX)
return SSH_ERR_ALLOC_FAIL;
if (BIO_write(bio, sshbuf_ptr(blob), sshbuf_len(blob)) !=
(int)sshbuf_len(blob)) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
clear_libcrypto_errors();
if ((pk = PEM_read_bio_PrivateKey(bio, NULL, pem_passphrase_cb,
(char *)passphrase)) == NULL) {
- /*
- * libcrypto may return various ASN.1 errors when attempting
- * to parse a key with an incorrect passphrase.
- * Treat all format errors as "incorrect passphrase" if a
- * passphrase was supplied.
- */
+ /*
+ * libcrypto may return various ASN.1 errors when attempting
+ * to parse a key with an incorrect passphrase.
+ * Treat all format errors as "incorrect passphrase" if a
+ * passphrase was supplied.
+ */
if (passphrase != NULL && *passphrase != '\0')
r = SSH_ERR_KEY_WRONG_PASSPHRASE;
else
r = convert_libcrypto_error();
goto out;
}
if (EVP_PKEY_base_id(pk) == EVP_PKEY_RSA &&
(type == KEY_UNSPEC || type == KEY_RSA)) {
if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
prv->rsa = EVP_PKEY_get1_RSA(pk);
prv->type = KEY_RSA;
#ifdef DEBUG_PK
RSA_print_fp(stderr, prv->rsa, 8);
#endif
if (RSA_blinding_on(prv->rsa, NULL) != 1) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if ((r = check_rsa_length(prv->rsa)) != 0)
goto out;
} else if (EVP_PKEY_base_id(pk) == EVP_PKEY_DSA &&
(type == KEY_UNSPEC || type == KEY_DSA)) {
if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
prv->dsa = EVP_PKEY_get1_DSA(pk);
prv->type = KEY_DSA;
#ifdef DEBUG_PK
DSA_print_fp(stderr, prv->dsa, 8);
#endif
#ifdef OPENSSL_HAS_ECC
} else if (EVP_PKEY_base_id(pk) == EVP_PKEY_EC &&
(type == KEY_UNSPEC || type == KEY_ECDSA)) {
if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
prv->type = KEY_ECDSA;
prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->ecdsa);
if (prv->ecdsa_nid == -1 ||
sshkey_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
sshkey_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
EC_KEY_get0_public_key(prv->ecdsa)) != 0 ||
sshkey_ec_validate_private(prv->ecdsa) != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
# ifdef DEBUG_PK
if (prv != NULL && prv->ecdsa != NULL)
sshkey_dump_ec_key(prv->ecdsa);
# endif
#endif /* OPENSSL_HAS_ECC */
} else {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
r = 0;
if (keyp != NULL) {
*keyp = prv;
prv = NULL;
}
out:
BIO_free(bio);
EVP_PKEY_free(pk);
sshkey_free(prv);
return r;
}
#endif /* WITH_OPENSSL */
int
sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
const char *passphrase, struct sshkey **keyp, char **commentp)
{
int r = SSH_ERR_INTERNAL_ERROR;
if (keyp != NULL)
*keyp = NULL;
if (commentp != NULL)
*commentp = NULL;
switch (type) {
case KEY_ED25519:
case KEY_XMSS:
/* No fallback for new-format-only keys */
return sshkey_parse_private2(blob, type, passphrase,
keyp, commentp);
default:
r = sshkey_parse_private2(blob, type, passphrase, keyp,
commentp);
/* Only fallback to PEM parser if a format error occurred. */
if (r != SSH_ERR_INVALID_FORMAT)
return r;
#ifdef WITH_OPENSSL
return sshkey_parse_private_pem_fileblob(blob, type,
passphrase, keyp);
#else
return SSH_ERR_INVALID_FORMAT;
#endif /* WITH_OPENSSL */
}
}
int
sshkey_parse_private_fileblob(struct sshbuf *buffer, const char *passphrase,
struct sshkey **keyp, char **commentp)
{
if (keyp != NULL)
*keyp = NULL;
if (commentp != NULL)
*commentp = NULL;
return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC,
passphrase, keyp, commentp);
}
void
sshkey_sig_details_free(struct sshkey_sig_details *details)
{
freezero(details, sizeof(*details));
}
int
sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob, int type,
struct sshkey **pubkeyp)
{
int r = SSH_ERR_INTERNAL_ERROR;
if (pubkeyp != NULL)
*pubkeyp = NULL;
/* only new-format private keys bundle a public key inside */
if ((r = sshkey_parse_private2_pubkey(blob, type, pubkeyp)) != 0)
return r;
return 0;
}
#ifdef WITH_XMSS
/*
* serialize the key with the current state and forward the state
* maxsign times.
*/
int
sshkey_private_serialize_maxsign(struct sshkey *k, struct sshbuf *b,
u_int32_t maxsign, int printerror)
{
int r, rupdate;
if (maxsign == 0 ||
sshkey_type_plain(k->type) != KEY_XMSS)
return sshkey_private_serialize_opt(k, b,
SSHKEY_SERIALIZE_DEFAULT);
if ((r = sshkey_xmss_get_state(k, printerror)) != 0 ||
(r = sshkey_private_serialize_opt(k, b,
SSHKEY_SERIALIZE_STATE)) != 0 ||
(r = sshkey_xmss_forward_state(k, maxsign)) != 0)
goto out;
r = 0;
out:
if ((rupdate = sshkey_xmss_update_state(k, printerror)) != 0) {
if (r == 0)
r = rupdate;
}
return r;
}
u_int32_t
sshkey_signatures_left(const struct sshkey *k)
{
if (sshkey_type_plain(k->type) == KEY_XMSS)
return sshkey_xmss_signatures_left(k);
return 0;
}
int
sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign)
{
if (sshkey_type_plain(k->type) != KEY_XMSS)
return SSH_ERR_INVALID_ARGUMENT;
return sshkey_xmss_enable_maxsign(k, maxsign);
}
int
sshkey_set_filename(struct sshkey *k, const char *filename)
{
if (k == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if (sshkey_type_plain(k->type) != KEY_XMSS)
return 0;
if (filename == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if ((k->xmss_filename = strdup(filename)) == NULL)
return SSH_ERR_ALLOC_FAIL;
return 0;
}
#else
int
sshkey_private_serialize_maxsign(struct sshkey *k, struct sshbuf *b,
u_int32_t maxsign, int printerror)
{
return sshkey_private_serialize_opt(k, b, SSHKEY_SERIALIZE_DEFAULT);
}
u_int32_t
sshkey_signatures_left(const struct sshkey *k)
{
return 0;
}
int
sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign)
{
return SSH_ERR_INVALID_ARGUMENT;
}
int
sshkey_set_filename(struct sshkey *k, const char *filename)
{
if (k == NULL)
return SSH_ERR_INVALID_ARGUMENT;
return 0;
}
#endif /* WITH_XMSS */
diff --git a/uidswap.c b/uidswap.c
index 40e1215039e3..6ed3024d0180 100644
--- a/uidswap.c
+++ b/uidswap.c
@@ -1,238 +1,238 @@
/* $OpenBSD: uidswap.c,v 1.42 2019/06/28 13:35:04 deraadt Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Code for uid-swapping.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#include "includes.h"
#include <errno.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <stdarg.h>
#include <stdlib.h>
#include <grp.h>
#include "log.h"
#include "uidswap.h"
#include "xmalloc.h"
/*
* Note: all these functions must work in all of the following cases:
* 1. euid=0, ruid=0
* 2. euid=0, ruid!=0
* 3. euid!=0, ruid!=0
* Additionally, they must work regardless of whether the system has
* POSIX saved uids or not.
*/
#if defined(_POSIX_SAVED_IDS) && !defined(BROKEN_SAVED_UIDS)
/* Lets assume that posix saved ids also work with seteuid, even though that
is not part of the posix specification. */
#define SAVED_IDS_WORK_WITH_SETEUID
/* Saved effective uid. */
-static uid_t saved_euid = 0;
+static uid_t saved_euid = 0;
static gid_t saved_egid = 0;
#endif
/* Saved effective uid. */
static int privileged = 0;
static int temporarily_use_uid_effective = 0;
static uid_t user_groups_uid;
static gid_t *saved_egroups = NULL, *user_groups = NULL;
static int saved_egroupslen = -1, user_groupslen = -1;
/*
* Temporarily changes to the given uid. If the effective user
* id is not root, this does nothing. This call cannot be nested.
*/
void
temporarily_use_uid(struct passwd *pw)
{
/* Save the current euid, and egroups. */
#ifdef SAVED_IDS_WORK_WITH_SETEUID
saved_euid = geteuid();
saved_egid = getegid();
debug("temporarily_use_uid: %u/%u (e=%u/%u)",
(u_int)pw->pw_uid, (u_int)pw->pw_gid,
(u_int)saved_euid, (u_int)saved_egid);
#ifndef HAVE_CYGWIN
if (saved_euid != 0) {
privileged = 0;
return;
}
#endif
#else
if (geteuid() != 0) {
privileged = 0;
return;
}
#endif /* SAVED_IDS_WORK_WITH_SETEUID */
privileged = 1;
temporarily_use_uid_effective = 1;
saved_egroupslen = getgroups(0, NULL);
if (saved_egroupslen == -1)
fatal("getgroups: %.100s", strerror(errno));
if (saved_egroupslen > 0) {
saved_egroups = xreallocarray(saved_egroups,
saved_egroupslen, sizeof(gid_t));
if (getgroups(saved_egroupslen, saved_egroups) == -1)
fatal("getgroups: %.100s", strerror(errno));
} else { /* saved_egroupslen == 0 */
free(saved_egroups);
saved_egroups = NULL;
}
/* set and save the user's groups */
if (user_groupslen == -1 || user_groups_uid != pw->pw_uid) {
if (initgroups(pw->pw_name, pw->pw_gid) == -1)
fatal("initgroups: %s: %.100s", pw->pw_name,
strerror(errno));
user_groupslen = getgroups(0, NULL);
if (user_groupslen == -1)
fatal("getgroups: %.100s", strerror(errno));
if (user_groupslen > 0) {
user_groups = xreallocarray(user_groups,
user_groupslen, sizeof(gid_t));
if (getgroups(user_groupslen, user_groups) == -1)
fatal("getgroups: %.100s", strerror(errno));
} else { /* user_groupslen == 0 */
free(user_groups);
user_groups = NULL;
}
user_groups_uid = pw->pw_uid;
}
/* Set the effective uid to the given (unprivileged) uid. */
if (setgroups(user_groupslen, user_groups) == -1)
fatal("setgroups: %.100s", strerror(errno));
#ifndef SAVED_IDS_WORK_WITH_SETEUID
/* Propagate the privileged gid to all of our gids. */
if (setgid(getegid()) == -1)
debug("setgid %u: %.100s", (u_int) getegid(), strerror(errno));
/* Propagate the privileged uid to all of our uids. */
if (setuid(geteuid()) == -1)
debug("setuid %u: %.100s", (u_int) geteuid(), strerror(errno));
#endif /* SAVED_IDS_WORK_WITH_SETEUID */
if (setegid(pw->pw_gid) == -1)
fatal("setegid %u: %.100s", (u_int)pw->pw_gid,
strerror(errno));
if (seteuid(pw->pw_uid) == -1)
fatal("seteuid %u: %.100s", (u_int)pw->pw_uid,
strerror(errno));
}
/*
* Restores to the original (privileged) uid.
*/
void
restore_uid(void)
{
/* it's a no-op unless privileged */
if (!privileged) {
debug("restore_uid: (unprivileged)");
return;
}
if (!temporarily_use_uid_effective)
fatal("restore_uid: temporarily_use_uid not effective");
#ifdef SAVED_IDS_WORK_WITH_SETEUID
debug("restore_uid: %u/%u", (u_int)saved_euid, (u_int)saved_egid);
/* Set the effective uid back to the saved privileged uid. */
if (seteuid(saved_euid) == -1)
fatal("seteuid %u: %.100s", (u_int)saved_euid, strerror(errno));
if (setegid(saved_egid) == -1)
fatal("setegid %u: %.100s", (u_int)saved_egid, strerror(errno));
#else /* SAVED_IDS_WORK_WITH_SETEUID */
/*
* We are unable to restore the real uid to its unprivileged value.
* Propagate the real uid (usually more privileged) to effective uid
* as well.
*/
if (setuid(getuid()) == -1)
fatal("%s: setuid failed: %s", __func__, strerror(errno));
if (setgid(getgid()) == -1)
fatal("%s: setgid failed: %s", __func__, strerror(errno));
#endif /* SAVED_IDS_WORK_WITH_SETEUID */
if (setgroups(saved_egroupslen, saved_egroups) == -1)
fatal("setgroups: %.100s", strerror(errno));
temporarily_use_uid_effective = 0;
}
/*
* Permanently sets all uids to the given uid. This cannot be
* called while temporarily_use_uid is effective.
*/
void
permanently_set_uid(struct passwd *pw)
{
#ifndef NO_UID_RESTORATION_TEST
uid_t old_uid = getuid();
gid_t old_gid = getgid();
#endif
if (pw == NULL)
fatal("permanently_set_uid: no user given");
if (temporarily_use_uid_effective)
fatal("permanently_set_uid: temporarily_use_uid effective");
debug("permanently_set_uid: %u/%u", (u_int)pw->pw_uid,
(u_int)pw->pw_gid);
if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1)
fatal("setresgid %u: %.100s", (u_int)pw->pw_gid, strerror(errno));
#ifdef __APPLE__
/*
* OS X requires initgroups after setgid to opt back into
* memberd support for >16 supplemental groups.
*/
if (initgroups(pw->pw_name, pw->pw_gid) == -1)
fatal("initgroups %.100s %u: %.100s",
pw->pw_name, (u_int)pw->pw_gid, strerror(errno));
#endif
if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
fatal("setresuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno));
#ifndef NO_UID_RESTORATION_TEST
/* Try restoration of GID if changed (test clearing of saved gid) */
if (old_gid != pw->pw_gid && pw->pw_uid != 0 &&
(setgid(old_gid) != -1 || setegid(old_gid) != -1))
fatal("%s: was able to restore old [e]gid", __func__);
#endif
/* Verify GID drop was successful */
if (getgid() != pw->pw_gid || getegid() != pw->pw_gid) {
fatal("%s: egid incorrect gid:%u egid:%u (should be %u)",
__func__, (u_int)getgid(), (u_int)getegid(),
(u_int)pw->pw_gid);
}
#ifndef NO_UID_RESTORATION_TEST
/* Try restoration of UID if changed (test clearing of saved uid) */
if (old_uid != pw->pw_uid &&
(setuid(old_uid) != -1 || seteuid(old_uid) != -1))
fatal("%s: was able to restore old [e]uid", __func__);
#endif
/* Verify UID drop was successful */
if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) {
fatal("%s: euid incorrect uid:%u euid:%u (should be %u)",
__func__, (u_int)getuid(), (u_int)geteuid(),
(u_int)pw->pw_uid);
}
}
diff --git a/umac.c b/umac.c
index 3d4e285bb17a..e5ec19f082cb 100644
--- a/umac.c
+++ b/umac.c
@@ -1,1282 +1,1282 @@
-/* $OpenBSD: umac.c,v 1.20 2020/03/13 03:17:07 djm Exp $ */
+/* $OpenBSD: umac.c,v 1.21 2021/04/03 06:58:30 djm Exp $ */
/* -----------------------------------------------------------------------
*
* umac.c -- C Implementation UMAC Message Authentication
*
* Version 0.93b of rfc4418.txt -- 2006 July 18
*
* For a full description of UMAC message authentication see the UMAC
* world-wide-web page at http://www.cs.ucdavis.edu/~rogaway/umac
* Please report bugs and suggestions to the UMAC webpage.
*
* Copyright (c) 1999-2006 Ted Krovetz
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and with or without fee, is hereby
* granted provided that the above copyright notice appears in all copies
* and in supporting documentation, and that the name of the copyright
* holder not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior permission.
*
* Comments should be directed to Ted Krovetz (tdk@acm.org)
*
* ---------------------------------------------------------------------- */
/* ////////////////////// IMPORTANT NOTES /////////////////////////////////
*
* 1) This version does not work properly on messages larger than 16MB
*
* 2) If you set the switch to use SSE2, then all data must be 16-byte
* aligned
*
* 3) When calling the function umac(), it is assumed that msg is in
* a writable buffer of length divisible by 32 bytes. The message itself
* does not have to fill the entire buffer, but bytes beyond msg may be
* zeroed.
*
* 4) Three free AES implementations are supported by this implementation of
* UMAC. Paulo Barreto's version is in the public domain and can be found
* at http://www.esat.kuleuven.ac.be/~rijmen/rijndael/ (search for
* "Barreto"). The only two files needed are rijndael-alg-fst.c and
* rijndael-alg-fst.h. Brian Gladman's version is distributed with the GNU
* Public license at http://fp.gladman.plus.com/AES/index.htm. It
* includes a fast IA-32 assembly version. The OpenSSL crypo library is
* the third.
*
* 5) With FORCE_C_ONLY flags set to 0, incorrect results are sometimes
* produced under gcc with optimizations set -O3 or higher. Dunno why.
*
/////////////////////////////////////////////////////////////////////// */
/* ---------------------------------------------------------------------- */
/* --- User Switches ---------------------------------------------------- */
/* ---------------------------------------------------------------------- */
#ifndef UMAC_OUTPUT_LEN
#define UMAC_OUTPUT_LEN 8 /* Alowable: 4, 8, 12, 16 */
#endif
#if UMAC_OUTPUT_LEN != 4 && UMAC_OUTPUT_LEN != 8 && \
UMAC_OUTPUT_LEN != 12 && UMAC_OUTPUT_LEN != 16
# error UMAC_OUTPUT_LEN must be defined to 4, 8, 12 or 16
#endif
/* #define FORCE_C_ONLY 1 ANSI C and 64-bit integers req'd */
/* #define AES_IMPLEMENTAION 1 1 = OpenSSL, 2 = Barreto, 3 = Gladman */
/* #define SSE2 0 Is SSE2 is available? */
/* #define RUN_TESTS 0 Run basic correctness/speed tests */
/* #define UMAC_AE_SUPPORT 0 Enable authenticated encryption */
/* ---------------------------------------------------------------------- */
/* -- Global Includes --------------------------------------------------- */
/* ---------------------------------------------------------------------- */
#include "includes.h"
#include <sys/types.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include "xmalloc.h"
#include "umac.h"
#include "misc.h"
/* ---------------------------------------------------------------------- */
/* --- Primitive Data Types --- */
/* ---------------------------------------------------------------------- */
/* The following assumptions may need change on your system */
typedef u_int8_t UINT8; /* 1 byte */
typedef u_int16_t UINT16; /* 2 byte */
typedef u_int32_t UINT32; /* 4 byte */
typedef u_int64_t UINT64; /* 8 bytes */
typedef unsigned int UWORD; /* Register */
/* ---------------------------------------------------------------------- */
/* --- Constants -------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
#define UMAC_KEY_LEN 16 /* UMAC takes 16 bytes of external key */
/* Message "words" are read from memory in an endian-specific manner. */
/* For this implementation to behave correctly, __LITTLE_ENDIAN__ must */
/* be set true if the host computer is little-endian. */
#if BYTE_ORDER == LITTLE_ENDIAN
#define __LITTLE_ENDIAN__ 1
#else
#define __LITTLE_ENDIAN__ 0
#endif
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ----- Architecture Specific ------------------------------------------ */
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ----- Primitive Routines --------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* --- 32-bit by 32-bit to 64-bit Multiplication ------------------------ */
/* ---------------------------------------------------------------------- */
#define MUL64(a,b) ((UINT64)((UINT64)(UINT32)(a) * (UINT64)(UINT32)(b)))
/* ---------------------------------------------------------------------- */
/* --- Endian Conversion --- Forcing assembly on some platforms */
/* ---------------------------------------------------------------------- */
#if (__LITTLE_ENDIAN__)
#define LOAD_UINT32_REVERSED(p) get_u32(p)
#define STORE_UINT32_REVERSED(p,v) put_u32(p,v)
#else
#define LOAD_UINT32_REVERSED(p) get_u32_le(p)
#define STORE_UINT32_REVERSED(p,v) put_u32_le(p,v)
#endif
#define LOAD_UINT32_LITTLE(p) (get_u32_le(p))
#define STORE_UINT32_BIG(p,v) put_u32(p, v)
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ----- Begin KDF & PDF Section ---------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* UMAC uses AES with 16 byte block and key lengths */
#define AES_BLOCK_LEN 16
/* OpenSSL's AES */
#ifdef WITH_OPENSSL
#include "openbsd-compat/openssl-compat.h"
#ifndef USE_BUILTIN_RIJNDAEL
# include <openssl/aes.h>
#endif
typedef AES_KEY aes_int_key[1];
#define aes_encryption(in,out,int_key) \
AES_encrypt((u_char *)(in),(u_char *)(out),(AES_KEY *)int_key)
#define aes_key_setup(key,int_key) \
AES_set_encrypt_key((const u_char *)(key),UMAC_KEY_LEN*8,int_key)
#else
#include "rijndael.h"
#define AES_ROUNDS ((UMAC_KEY_LEN / 4) + 6)
typedef UINT8 aes_int_key[AES_ROUNDS+1][4][4]; /* AES internal */
#define aes_encryption(in,out,int_key) \
rijndaelEncrypt((u32 *)(int_key), AES_ROUNDS, (u8 *)(in), (u8 *)(out))
#define aes_key_setup(key,int_key) \
rijndaelKeySetupEnc((u32 *)(int_key), (const unsigned char *)(key), \
UMAC_KEY_LEN*8)
#endif
/* The user-supplied UMAC key is stretched using AES in a counter
* mode to supply all random bits needed by UMAC. The kdf function takes
* an AES internal key representation 'key' and writes a stream of
* 'nbytes' bytes to the memory pointed at by 'bufp'. Each distinct
* 'ndx' causes a distinct byte stream.
*/
static void kdf(void *bufp, aes_int_key key, UINT8 ndx, int nbytes)
{
UINT8 in_buf[AES_BLOCK_LEN] = {0};
UINT8 out_buf[AES_BLOCK_LEN];
UINT8 *dst_buf = (UINT8 *)bufp;
int i;
/* Setup the initial value */
in_buf[AES_BLOCK_LEN-9] = ndx;
in_buf[AES_BLOCK_LEN-1] = i = 1;
while (nbytes >= AES_BLOCK_LEN) {
aes_encryption(in_buf, out_buf, key);
memcpy(dst_buf,out_buf,AES_BLOCK_LEN);
in_buf[AES_BLOCK_LEN-1] = ++i;
nbytes -= AES_BLOCK_LEN;
dst_buf += AES_BLOCK_LEN;
}
if (nbytes) {
aes_encryption(in_buf, out_buf, key);
memcpy(dst_buf,out_buf,nbytes);
}
explicit_bzero(in_buf, sizeof(in_buf));
explicit_bzero(out_buf, sizeof(out_buf));
}
/* The final UHASH result is XOR'd with the output of a pseudorandom
* function. Here, we use AES to generate random output and
* xor the appropriate bytes depending on the last bits of nonce.
* This scheme is optimized for sequential, increasing big-endian nonces.
*/
typedef struct {
UINT8 cache[AES_BLOCK_LEN]; /* Previous AES output is saved */
UINT8 nonce[AES_BLOCK_LEN]; /* The AES input making above cache */
aes_int_key prf_key; /* Expanded AES key for PDF */
} pdf_ctx;
static void pdf_init(pdf_ctx *pc, aes_int_key prf_key)
{
UINT8 buf[UMAC_KEY_LEN];
kdf(buf, prf_key, 0, UMAC_KEY_LEN);
aes_key_setup(buf, pc->prf_key);
/* Initialize pdf and cache */
memset(pc->nonce, 0, sizeof(pc->nonce));
aes_encryption(pc->nonce, pc->cache, pc->prf_key);
explicit_bzero(buf, sizeof(buf));
}
static void pdf_gen_xor(pdf_ctx *pc, const UINT8 nonce[8], UINT8 buf[8])
{
/* 'ndx' indicates that we'll be using the 0th or 1st eight bytes
* of the AES output. If last time around we returned the ndx-1st
* element, then we may have the result in the cache already.
*/
#if (UMAC_OUTPUT_LEN == 4)
#define LOW_BIT_MASK 3
#elif (UMAC_OUTPUT_LEN == 8)
#define LOW_BIT_MASK 1
#elif (UMAC_OUTPUT_LEN > 8)
#define LOW_BIT_MASK 0
#endif
union {
UINT8 tmp_nonce_lo[4];
UINT32 align;
} t;
#if LOW_BIT_MASK != 0
int ndx = nonce[7] & LOW_BIT_MASK;
#endif
*(UINT32 *)t.tmp_nonce_lo = ((const UINT32 *)nonce)[1];
t.tmp_nonce_lo[3] &= ~LOW_BIT_MASK; /* zero last bit */
if ( (((UINT32 *)t.tmp_nonce_lo)[0] != ((UINT32 *)pc->nonce)[1]) ||
(((const UINT32 *)nonce)[0] != ((UINT32 *)pc->nonce)[0]) )
{
((UINT32 *)pc->nonce)[0] = ((const UINT32 *)nonce)[0];
((UINT32 *)pc->nonce)[1] = ((UINT32 *)t.tmp_nonce_lo)[0];
aes_encryption(pc->nonce, pc->cache, pc->prf_key);
}
#if (UMAC_OUTPUT_LEN == 4)
*((UINT32 *)buf) ^= ((UINT32 *)pc->cache)[ndx];
#elif (UMAC_OUTPUT_LEN == 8)
*((UINT64 *)buf) ^= ((UINT64 *)pc->cache)[ndx];
#elif (UMAC_OUTPUT_LEN == 12)
((UINT64 *)buf)[0] ^= ((UINT64 *)pc->cache)[0];
((UINT32 *)buf)[2] ^= ((UINT32 *)pc->cache)[2];
#elif (UMAC_OUTPUT_LEN == 16)
((UINT64 *)buf)[0] ^= ((UINT64 *)pc->cache)[0];
((UINT64 *)buf)[1] ^= ((UINT64 *)pc->cache)[1];
#endif
}
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ----- Begin NH Hash Section ------------------------------------------ */
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* The NH-based hash functions used in UMAC are described in the UMAC paper
* and specification, both of which can be found at the UMAC website.
* The interface to this implementation has two
* versions, one expects the entire message being hashed to be passed
* in a single buffer and returns the hash result immediately. The second
* allows the message to be passed in a sequence of buffers. In the
- * muliple-buffer interface, the client calls the routine nh_update() as
+ * multiple-buffer interface, the client calls the routine nh_update() as
* many times as necessary. When there is no more data to be fed to the
* hash, the client calls nh_final() which calculates the hash output.
* Before beginning another hash calculation the nh_reset() routine
* must be called. The single-buffer routine, nh(), is equivalent to
* the sequence of calls nh_update() and nh_final(); however it is
* optimized and should be preferred whenever the multiple-buffer interface
* is not necessary. When using either interface, it is the client's
* responsibility to pass no more than L1_KEY_LEN bytes per hash result.
*
* The routine nh_init() initializes the nh_ctx data structure and
* must be called once, before any other PDF routine.
*/
/* The "nh_aux" routines do the actual NH hashing work. They
* expect buffers to be multiples of L1_PAD_BOUNDARY. These routines
* produce output for all STREAMS NH iterations in one call,
* allowing the parallel implementation of the streams.
*/
#define STREAMS (UMAC_OUTPUT_LEN / 4) /* Number of times hash is applied */
#define L1_KEY_LEN 1024 /* Internal key bytes */
#define L1_KEY_SHIFT 16 /* Toeplitz key shift between streams */
#define L1_PAD_BOUNDARY 32 /* pad message to boundary multiple */
#define ALLOC_BOUNDARY 16 /* Keep buffers aligned to this */
#define HASH_BUF_BYTES 64 /* nh_aux_hb buffer multiple */
typedef struct {
UINT8 nh_key [L1_KEY_LEN + L1_KEY_SHIFT * (STREAMS - 1)]; /* NH Key */
UINT8 data [HASH_BUF_BYTES]; /* Incoming data buffer */
int next_data_empty; /* Bookkeeping variable for data buffer. */
int bytes_hashed; /* Bytes (out of L1_KEY_LEN) incorporated. */
UINT64 state[STREAMS]; /* on-line state */
} nh_ctx;
#if (UMAC_OUTPUT_LEN == 4)
static void nh_aux(void *kp, const void *dp, void *hp, UINT32 dlen)
/* NH hashing primitive. Previous (partial) hash result is loaded and
* then stored via hp pointer. The length of the data pointed at by "dp",
* "dlen", is guaranteed to be divisible by L1_PAD_BOUNDARY (32). Key
* is expected to be endian compensated in memory at key setup.
*/
{
UINT64 h;
UWORD c = dlen / 32;
UINT32 *k = (UINT32 *)kp;
const UINT32 *d = (const UINT32 *)dp;
UINT32 d0,d1,d2,d3,d4,d5,d6,d7;
UINT32 k0,k1,k2,k3,k4,k5,k6,k7;
h = *((UINT64 *)hp);
do {
d0 = LOAD_UINT32_LITTLE(d+0); d1 = LOAD_UINT32_LITTLE(d+1);
d2 = LOAD_UINT32_LITTLE(d+2); d3 = LOAD_UINT32_LITTLE(d+3);
d4 = LOAD_UINT32_LITTLE(d+4); d5 = LOAD_UINT32_LITTLE(d+5);
d6 = LOAD_UINT32_LITTLE(d+6); d7 = LOAD_UINT32_LITTLE(d+7);
k0 = *(k+0); k1 = *(k+1); k2 = *(k+2); k3 = *(k+3);
k4 = *(k+4); k5 = *(k+5); k6 = *(k+6); k7 = *(k+7);
h += MUL64((k0 + d0), (k4 + d4));
h += MUL64((k1 + d1), (k5 + d5));
h += MUL64((k2 + d2), (k6 + d6));
h += MUL64((k3 + d3), (k7 + d7));
d += 8;
k += 8;
} while (--c);
*((UINT64 *)hp) = h;
}
#elif (UMAC_OUTPUT_LEN == 8)
static void nh_aux(void *kp, const void *dp, void *hp, UINT32 dlen)
/* Same as previous nh_aux, but two streams are handled in one pass,
* reading and writing 16 bytes of hash-state per call.
*/
{
UINT64 h1,h2;
UWORD c = dlen / 32;
UINT32 *k = (UINT32 *)kp;
const UINT32 *d = (const UINT32 *)dp;
UINT32 d0,d1,d2,d3,d4,d5,d6,d7;
UINT32 k0,k1,k2,k3,k4,k5,k6,k7,
k8,k9,k10,k11;
h1 = *((UINT64 *)hp);
h2 = *((UINT64 *)hp + 1);
k0 = *(k+0); k1 = *(k+1); k2 = *(k+2); k3 = *(k+3);
do {
d0 = LOAD_UINT32_LITTLE(d+0); d1 = LOAD_UINT32_LITTLE(d+1);
d2 = LOAD_UINT32_LITTLE(d+2); d3 = LOAD_UINT32_LITTLE(d+3);
d4 = LOAD_UINT32_LITTLE(d+4); d5 = LOAD_UINT32_LITTLE(d+5);
d6 = LOAD_UINT32_LITTLE(d+6); d7 = LOAD_UINT32_LITTLE(d+7);
k4 = *(k+4); k5 = *(k+5); k6 = *(k+6); k7 = *(k+7);
k8 = *(k+8); k9 = *(k+9); k10 = *(k+10); k11 = *(k+11);
h1 += MUL64((k0 + d0), (k4 + d4));
h2 += MUL64((k4 + d0), (k8 + d4));
h1 += MUL64((k1 + d1), (k5 + d5));
h2 += MUL64((k5 + d1), (k9 + d5));
h1 += MUL64((k2 + d2), (k6 + d6));
h2 += MUL64((k6 + d2), (k10 + d6));
h1 += MUL64((k3 + d3), (k7 + d7));
h2 += MUL64((k7 + d3), (k11 + d7));
k0 = k8; k1 = k9; k2 = k10; k3 = k11;
d += 8;
k += 8;
} while (--c);
((UINT64 *)hp)[0] = h1;
((UINT64 *)hp)[1] = h2;
}
#elif (UMAC_OUTPUT_LEN == 12)
static void nh_aux(void *kp, const void *dp, void *hp, UINT32 dlen)
/* Same as previous nh_aux, but two streams are handled in one pass,
* reading and writing 24 bytes of hash-state per call.
*/
{
UINT64 h1,h2,h3;
UWORD c = dlen / 32;
UINT32 *k = (UINT32 *)kp;
const UINT32 *d = (const UINT32 *)dp;
UINT32 d0,d1,d2,d3,d4,d5,d6,d7;
UINT32 k0,k1,k2,k3,k4,k5,k6,k7,
k8,k9,k10,k11,k12,k13,k14,k15;
h1 = *((UINT64 *)hp);
h2 = *((UINT64 *)hp + 1);
h3 = *((UINT64 *)hp + 2);
k0 = *(k+0); k1 = *(k+1); k2 = *(k+2); k3 = *(k+3);
k4 = *(k+4); k5 = *(k+5); k6 = *(k+6); k7 = *(k+7);
do {
d0 = LOAD_UINT32_LITTLE(d+0); d1 = LOAD_UINT32_LITTLE(d+1);
d2 = LOAD_UINT32_LITTLE(d+2); d3 = LOAD_UINT32_LITTLE(d+3);
d4 = LOAD_UINT32_LITTLE(d+4); d5 = LOAD_UINT32_LITTLE(d+5);
d6 = LOAD_UINT32_LITTLE(d+6); d7 = LOAD_UINT32_LITTLE(d+7);
k8 = *(k+8); k9 = *(k+9); k10 = *(k+10); k11 = *(k+11);
k12 = *(k+12); k13 = *(k+13); k14 = *(k+14); k15 = *(k+15);
h1 += MUL64((k0 + d0), (k4 + d4));
h2 += MUL64((k4 + d0), (k8 + d4));
h3 += MUL64((k8 + d0), (k12 + d4));
h1 += MUL64((k1 + d1), (k5 + d5));
h2 += MUL64((k5 + d1), (k9 + d5));
h3 += MUL64((k9 + d1), (k13 + d5));
h1 += MUL64((k2 + d2), (k6 + d6));
h2 += MUL64((k6 + d2), (k10 + d6));
h3 += MUL64((k10 + d2), (k14 + d6));
h1 += MUL64((k3 + d3), (k7 + d7));
h2 += MUL64((k7 + d3), (k11 + d7));
h3 += MUL64((k11 + d3), (k15 + d7));
k0 = k8; k1 = k9; k2 = k10; k3 = k11;
k4 = k12; k5 = k13; k6 = k14; k7 = k15;
d += 8;
k += 8;
} while (--c);
((UINT64 *)hp)[0] = h1;
((UINT64 *)hp)[1] = h2;
((UINT64 *)hp)[2] = h3;
}
#elif (UMAC_OUTPUT_LEN == 16)
static void nh_aux(void *kp, const void *dp, void *hp, UINT32 dlen)
/* Same as previous nh_aux, but two streams are handled in one pass,
* reading and writing 24 bytes of hash-state per call.
*/
{
UINT64 h1,h2,h3,h4;
UWORD c = dlen / 32;
UINT32 *k = (UINT32 *)kp;
const UINT32 *d = (const UINT32 *)dp;
UINT32 d0,d1,d2,d3,d4,d5,d6,d7;
UINT32 k0,k1,k2,k3,k4,k5,k6,k7,
k8,k9,k10,k11,k12,k13,k14,k15,
k16,k17,k18,k19;
h1 = *((UINT64 *)hp);
h2 = *((UINT64 *)hp + 1);
h3 = *((UINT64 *)hp + 2);
h4 = *((UINT64 *)hp + 3);
k0 = *(k+0); k1 = *(k+1); k2 = *(k+2); k3 = *(k+3);
k4 = *(k+4); k5 = *(k+5); k6 = *(k+6); k7 = *(k+7);
do {
d0 = LOAD_UINT32_LITTLE(d+0); d1 = LOAD_UINT32_LITTLE(d+1);
d2 = LOAD_UINT32_LITTLE(d+2); d3 = LOAD_UINT32_LITTLE(d+3);
d4 = LOAD_UINT32_LITTLE(d+4); d5 = LOAD_UINT32_LITTLE(d+5);
d6 = LOAD_UINT32_LITTLE(d+6); d7 = LOAD_UINT32_LITTLE(d+7);
k8 = *(k+8); k9 = *(k+9); k10 = *(k+10); k11 = *(k+11);
k12 = *(k+12); k13 = *(k+13); k14 = *(k+14); k15 = *(k+15);
k16 = *(k+16); k17 = *(k+17); k18 = *(k+18); k19 = *(k+19);
h1 += MUL64((k0 + d0), (k4 + d4));
h2 += MUL64((k4 + d0), (k8 + d4));
h3 += MUL64((k8 + d0), (k12 + d4));
h4 += MUL64((k12 + d0), (k16 + d4));
h1 += MUL64((k1 + d1), (k5 + d5));
h2 += MUL64((k5 + d1), (k9 + d5));
h3 += MUL64((k9 + d1), (k13 + d5));
h4 += MUL64((k13 + d1), (k17 + d5));
h1 += MUL64((k2 + d2), (k6 + d6));
h2 += MUL64((k6 + d2), (k10 + d6));
h3 += MUL64((k10 + d2), (k14 + d6));
h4 += MUL64((k14 + d2), (k18 + d6));
h1 += MUL64((k3 + d3), (k7 + d7));
h2 += MUL64((k7 + d3), (k11 + d7));
h3 += MUL64((k11 + d3), (k15 + d7));
h4 += MUL64((k15 + d3), (k19 + d7));
k0 = k8; k1 = k9; k2 = k10; k3 = k11;
k4 = k12; k5 = k13; k6 = k14; k7 = k15;
k8 = k16; k9 = k17; k10 = k18; k11 = k19;
d += 8;
k += 8;
} while (--c);
((UINT64 *)hp)[0] = h1;
((UINT64 *)hp)[1] = h2;
((UINT64 *)hp)[2] = h3;
((UINT64 *)hp)[3] = h4;
}
/* ---------------------------------------------------------------------- */
#endif /* UMAC_OUTPUT_LENGTH */
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
static void nh_transform(nh_ctx *hc, const UINT8 *buf, UINT32 nbytes)
/* This function is a wrapper for the primitive NH hash functions. It takes
* as argument "hc" the current hash context and a buffer which must be a
* multiple of L1_PAD_BOUNDARY. The key passed to nh_aux is offset
* appropriately according to how much message has been hashed already.
*/
{
UINT8 *key;
key = hc->nh_key + hc->bytes_hashed;
nh_aux(key, buf, hc->state, nbytes);
}
/* ---------------------------------------------------------------------- */
#if (__LITTLE_ENDIAN__)
static void endian_convert(void *buf, UWORD bpw, UINT32 num_bytes)
/* We endian convert the keys on little-endian computers to */
/* compensate for the lack of big-endian memory reads during hashing. */
{
UWORD iters = num_bytes / bpw;
if (bpw == 4) {
UINT32 *p = (UINT32 *)buf;
do {
*p = LOAD_UINT32_REVERSED(p);
p++;
} while (--iters);
} else if (bpw == 8) {
UINT32 *p = (UINT32 *)buf;
UINT32 t;
do {
t = LOAD_UINT32_REVERSED(p+1);
p[1] = LOAD_UINT32_REVERSED(p);
p[0] = t;
p += 2;
} while (--iters);
}
}
#define endian_convert_if_le(x,y,z) endian_convert((x),(y),(z))
#else
#define endian_convert_if_le(x,y,z) do{}while(0) /* Do nothing */
#endif
/* ---------------------------------------------------------------------- */
static void nh_reset(nh_ctx *hc)
/* Reset nh_ctx to ready for hashing of new data */
{
hc->bytes_hashed = 0;
hc->next_data_empty = 0;
hc->state[0] = 0;
#if (UMAC_OUTPUT_LEN >= 8)
hc->state[1] = 0;
#endif
#if (UMAC_OUTPUT_LEN >= 12)
hc->state[2] = 0;
#endif
#if (UMAC_OUTPUT_LEN == 16)
hc->state[3] = 0;
#endif
}
/* ---------------------------------------------------------------------- */
static void nh_init(nh_ctx *hc, aes_int_key prf_key)
/* Generate nh_key, endian convert and reset to be ready for hashing. */
{
kdf(hc->nh_key, prf_key, 1, sizeof(hc->nh_key));
endian_convert_if_le(hc->nh_key, 4, sizeof(hc->nh_key));
nh_reset(hc);
}
/* ---------------------------------------------------------------------- */
static void nh_update(nh_ctx *hc, const UINT8 *buf, UINT32 nbytes)
/* Incorporate nbytes of data into a nh_ctx, buffer whatever is not an */
/* even multiple of HASH_BUF_BYTES. */
{
UINT32 i,j;
j = hc->next_data_empty;
if ((j + nbytes) >= HASH_BUF_BYTES) {
if (j) {
i = HASH_BUF_BYTES - j;
memcpy(hc->data+j, buf, i);
nh_transform(hc,hc->data,HASH_BUF_BYTES);
nbytes -= i;
buf += i;
hc->bytes_hashed += HASH_BUF_BYTES;
}
if (nbytes >= HASH_BUF_BYTES) {
i = nbytes & ~(HASH_BUF_BYTES - 1);
nh_transform(hc, buf, i);
nbytes -= i;
buf += i;
hc->bytes_hashed += i;
}
j = 0;
}
memcpy(hc->data + j, buf, nbytes);
hc->next_data_empty = j + nbytes;
}
/* ---------------------------------------------------------------------- */
static void zero_pad(UINT8 *p, int nbytes)
{
/* Write "nbytes" of zeroes, beginning at "p" */
if (nbytes >= (int)sizeof(UWORD)) {
while ((ptrdiff_t)p % sizeof(UWORD)) {
*p = 0;
nbytes--;
p++;
}
while (nbytes >= (int)sizeof(UWORD)) {
*(UWORD *)p = 0;
nbytes -= sizeof(UWORD);
p += sizeof(UWORD);
}
}
while (nbytes) {
*p = 0;
nbytes--;
p++;
}
}
/* ---------------------------------------------------------------------- */
static void nh_final(nh_ctx *hc, UINT8 *result)
/* After passing some number of data buffers to nh_update() for integration
* into an NH context, nh_final is called to produce a hash result. If any
* bytes are in the buffer hc->data, incorporate them into the
* NH context. Finally, add into the NH accumulation "state" the total number
* of bits hashed. The resulting numbers are written to the buffer "result".
* If nh_update was never called, L1_PAD_BOUNDARY zeroes are incorporated.
*/
{
int nh_len, nbits;
if (hc->next_data_empty != 0) {
nh_len = ((hc->next_data_empty + (L1_PAD_BOUNDARY - 1)) &
~(L1_PAD_BOUNDARY - 1));
zero_pad(hc->data + hc->next_data_empty,
nh_len - hc->next_data_empty);
nh_transform(hc, hc->data, nh_len);
hc->bytes_hashed += hc->next_data_empty;
} else if (hc->bytes_hashed == 0) {
nh_len = L1_PAD_BOUNDARY;
zero_pad(hc->data, L1_PAD_BOUNDARY);
nh_transform(hc, hc->data, nh_len);
}
nbits = (hc->bytes_hashed << 3);
((UINT64 *)result)[0] = ((UINT64 *)hc->state)[0] + nbits;
#if (UMAC_OUTPUT_LEN >= 8)
((UINT64 *)result)[1] = ((UINT64 *)hc->state)[1] + nbits;
#endif
#if (UMAC_OUTPUT_LEN >= 12)
((UINT64 *)result)[2] = ((UINT64 *)hc->state)[2] + nbits;
#endif
#if (UMAC_OUTPUT_LEN == 16)
((UINT64 *)result)[3] = ((UINT64 *)hc->state)[3] + nbits;
#endif
nh_reset(hc);
}
/* ---------------------------------------------------------------------- */
static void nh(nh_ctx *hc, const UINT8 *buf, UINT32 padded_len,
UINT32 unpadded_len, UINT8 *result)
/* All-in-one nh_update() and nh_final() equivalent.
* Assumes that padded_len is divisible by L1_PAD_BOUNDARY and result is
* well aligned
*/
{
UINT32 nbits;
/* Initialize the hash state */
nbits = (unpadded_len << 3);
((UINT64 *)result)[0] = nbits;
#if (UMAC_OUTPUT_LEN >= 8)
((UINT64 *)result)[1] = nbits;
#endif
#if (UMAC_OUTPUT_LEN >= 12)
((UINT64 *)result)[2] = nbits;
#endif
#if (UMAC_OUTPUT_LEN == 16)
((UINT64 *)result)[3] = nbits;
#endif
nh_aux(hc->nh_key, buf, result, padded_len);
}
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ----- Begin UHASH Section -------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* UHASH is a multi-layered algorithm. Data presented to UHASH is first
* hashed by NH. The NH output is then hashed by a polynomial-hash layer
* unless the initial data to be hashed is short. After the polynomial-
* layer, an inner-product hash is used to produce the final UHASH output.
*
* UHASH provides two interfaces, one all-at-once and another where data
* buffers are presented sequentially. In the sequential interface, the
* UHASH client calls the routine uhash_update() as many times as necessary.
* When there is no more data to be fed to UHASH, the client calls
* uhash_final() which
* calculates the UHASH output. Before beginning another UHASH calculation
* the uhash_reset() routine must be called. The all-at-once UHASH routine,
* uhash(), is equivalent to the sequence of calls uhash_update() and
* uhash_final(); however it is optimized and should be
* used whenever the sequential interface is not necessary.
*
* The routine uhash_init() initializes the uhash_ctx data structure and
* must be called once, before any other UHASH routine.
*/
/* ---------------------------------------------------------------------- */
/* ----- Constants and uhash_ctx ---------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ----- Poly hash and Inner-Product hash Constants --------------------- */
/* ---------------------------------------------------------------------- */
/* Primes and masks */
#define p36 ((UINT64)0x0000000FFFFFFFFBull) /* 2^36 - 5 */
#define p64 ((UINT64)0xFFFFFFFFFFFFFFC5ull) /* 2^64 - 59 */
#define m36 ((UINT64)0x0000000FFFFFFFFFull) /* The low 36 of 64 bits */
/* ---------------------------------------------------------------------- */
typedef struct uhash_ctx {
nh_ctx hash; /* Hash context for L1 NH hash */
UINT64 poly_key_8[STREAMS]; /* p64 poly keys */
UINT64 poly_accum[STREAMS]; /* poly hash result */
UINT64 ip_keys[STREAMS*4]; /* Inner-product keys */
UINT32 ip_trans[STREAMS]; /* Inner-product translation */
UINT32 msg_len; /* Total length of data passed */
/* to uhash */
} uhash_ctx;
typedef struct uhash_ctx *uhash_ctx_t;
/* ---------------------------------------------------------------------- */
/* The polynomial hashes use Horner's rule to evaluate a polynomial one
* word at a time. As described in the specification, poly32 and poly64
* require keys from special domains. The following implementations exploit
* the special domains to avoid overflow. The results are not guaranteed to
* be within Z_p32 and Z_p64, but the Inner-Product hash implementation
* patches any errant values.
*/
static UINT64 poly64(UINT64 cur, UINT64 key, UINT64 data)
{
UINT32 key_hi = (UINT32)(key >> 32),
key_lo = (UINT32)key,
cur_hi = (UINT32)(cur >> 32),
cur_lo = (UINT32)cur,
x_lo,
x_hi;
UINT64 X,T,res;
X = MUL64(key_hi, cur_lo) + MUL64(cur_hi, key_lo);
x_lo = (UINT32)X;
x_hi = (UINT32)(X >> 32);
res = (MUL64(key_hi, cur_hi) + x_hi) * 59 + MUL64(key_lo, cur_lo);
T = ((UINT64)x_lo << 32);
res += T;
if (res < T)
res += 59;
res += data;
if (res < data)
res += 59;
return res;
}
/* Although UMAC is specified to use a ramped polynomial hash scheme, this
* implementation does not handle all ramp levels. Because we don't handle
* the ramp up to p128 modulus in this implementation, we are limited to
* 2^14 poly_hash() invocations per stream (for a total capacity of 2^24
* bytes input to UMAC per tag, ie. 16MB).
*/
static void poly_hash(uhash_ctx_t hc, UINT32 data_in[])
{
int i;
UINT64 *data=(UINT64*)data_in;
for (i = 0; i < STREAMS; i++) {
if ((UINT32)(data[i] >> 32) == 0xfffffffful) {
hc->poly_accum[i] = poly64(hc->poly_accum[i],
hc->poly_key_8[i], p64 - 1);
hc->poly_accum[i] = poly64(hc->poly_accum[i],
hc->poly_key_8[i], (data[i] - 59));
} else {
hc->poly_accum[i] = poly64(hc->poly_accum[i],
hc->poly_key_8[i], data[i]);
}
}
}
/* ---------------------------------------------------------------------- */
/* The final step in UHASH is an inner-product hash. The poly hash
* produces a result not necessarily WORD_LEN bytes long. The inner-
* product hash breaks the polyhash output into 16-bit chunks and
* multiplies each with a 36 bit key.
*/
static UINT64 ip_aux(UINT64 t, UINT64 *ipkp, UINT64 data)
{
t = t + ipkp[0] * (UINT64)(UINT16)(data >> 48);
t = t + ipkp[1] * (UINT64)(UINT16)(data >> 32);
t = t + ipkp[2] * (UINT64)(UINT16)(data >> 16);
t = t + ipkp[3] * (UINT64)(UINT16)(data);
return t;
}
static UINT32 ip_reduce_p36(UINT64 t)
{
/* Divisionless modular reduction */
UINT64 ret;
ret = (t & m36) + 5 * (t >> 36);
if (ret >= p36)
ret -= p36;
/* return least significant 32 bits */
return (UINT32)(ret);
}
/* If the data being hashed by UHASH is no longer than L1_KEY_LEN, then
* the polyhash stage is skipped and ip_short is applied directly to the
* NH output.
*/
static void ip_short(uhash_ctx_t ahc, UINT8 *nh_res, u_char *res)
{
UINT64 t;
UINT64 *nhp = (UINT64 *)nh_res;
t = ip_aux(0,ahc->ip_keys, nhp[0]);
STORE_UINT32_BIG((UINT32 *)res+0, ip_reduce_p36(t) ^ ahc->ip_trans[0]);
#if (UMAC_OUTPUT_LEN >= 8)
t = ip_aux(0,ahc->ip_keys+4, nhp[1]);
STORE_UINT32_BIG((UINT32 *)res+1, ip_reduce_p36(t) ^ ahc->ip_trans[1]);
#endif
#if (UMAC_OUTPUT_LEN >= 12)
t = ip_aux(0,ahc->ip_keys+8, nhp[2]);
STORE_UINT32_BIG((UINT32 *)res+2, ip_reduce_p36(t) ^ ahc->ip_trans[2]);
#endif
#if (UMAC_OUTPUT_LEN == 16)
t = ip_aux(0,ahc->ip_keys+12, nhp[3]);
STORE_UINT32_BIG((UINT32 *)res+3, ip_reduce_p36(t) ^ ahc->ip_trans[3]);
#endif
}
/* If the data being hashed by UHASH is longer than L1_KEY_LEN, then
* the polyhash stage is not skipped and ip_long is applied to the
* polyhash output.
*/
static void ip_long(uhash_ctx_t ahc, u_char *res)
{
int i;
UINT64 t;
for (i = 0; i < STREAMS; i++) {
/* fix polyhash output not in Z_p64 */
if (ahc->poly_accum[i] >= p64)
ahc->poly_accum[i] -= p64;
t = ip_aux(0,ahc->ip_keys+(i*4), ahc->poly_accum[i]);
STORE_UINT32_BIG((UINT32 *)res+i,
ip_reduce_p36(t) ^ ahc->ip_trans[i]);
}
}
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* Reset uhash context for next hash session */
static int uhash_reset(uhash_ctx_t pc)
{
nh_reset(&pc->hash);
pc->msg_len = 0;
pc->poly_accum[0] = 1;
#if (UMAC_OUTPUT_LEN >= 8)
pc->poly_accum[1] = 1;
#endif
#if (UMAC_OUTPUT_LEN >= 12)
pc->poly_accum[2] = 1;
#endif
#if (UMAC_OUTPUT_LEN == 16)
pc->poly_accum[3] = 1;
#endif
return 1;
}
/* ---------------------------------------------------------------------- */
/* Given a pointer to the internal key needed by kdf() and a uhash context,
* initialize the NH context and generate keys needed for poly and inner-
* product hashing. All keys are endian adjusted in memory so that native
* loads cause correct keys to be in registers during calculation.
*/
static void uhash_init(uhash_ctx_t ahc, aes_int_key prf_key)
{
int i;
UINT8 buf[(8*STREAMS+4)*sizeof(UINT64)];
/* Zero the entire uhash context */
memset(ahc, 0, sizeof(uhash_ctx));
/* Initialize the L1 hash */
nh_init(&ahc->hash, prf_key);
/* Setup L2 hash variables */
kdf(buf, prf_key, 2, sizeof(buf)); /* Fill buffer with index 1 key */
for (i = 0; i < STREAMS; i++) {
/* Fill keys from the buffer, skipping bytes in the buffer not
* used by this implementation. Endian reverse the keys if on a
* little-endian computer.
*/
memcpy(ahc->poly_key_8+i, buf+24*i, 8);
endian_convert_if_le(ahc->poly_key_8+i, 8, 8);
/* Mask the 64-bit keys to their special domain */
ahc->poly_key_8[i] &= ((UINT64)0x01ffffffu << 32) + 0x01ffffffu;
ahc->poly_accum[i] = 1; /* Our polyhash prepends a non-zero word */
}
/* Setup L3-1 hash variables */
kdf(buf, prf_key, 3, sizeof(buf)); /* Fill buffer with index 2 key */
for (i = 0; i < STREAMS; i++)
memcpy(ahc->ip_keys+4*i, buf+(8*i+4)*sizeof(UINT64),
4*sizeof(UINT64));
endian_convert_if_le(ahc->ip_keys, sizeof(UINT64),
sizeof(ahc->ip_keys));
for (i = 0; i < STREAMS*4; i++)
ahc->ip_keys[i] %= p36; /* Bring into Z_p36 */
/* Setup L3-2 hash variables */
/* Fill buffer with index 4 key */
kdf(ahc->ip_trans, prf_key, 4, STREAMS * sizeof(UINT32));
endian_convert_if_le(ahc->ip_trans, sizeof(UINT32),
STREAMS * sizeof(UINT32));
explicit_bzero(buf, sizeof(buf));
}
/* ---------------------------------------------------------------------- */
#if 0
static uhash_ctx_t uhash_alloc(u_char key[])
{
/* Allocate memory and force to a 16-byte boundary. */
uhash_ctx_t ctx;
u_char bytes_to_add;
aes_int_key prf_key;
ctx = (uhash_ctx_t)malloc(sizeof(uhash_ctx)+ALLOC_BOUNDARY);
if (ctx) {
if (ALLOC_BOUNDARY) {
bytes_to_add = ALLOC_BOUNDARY -
((ptrdiff_t)ctx & (ALLOC_BOUNDARY -1));
ctx = (uhash_ctx_t)((u_char *)ctx + bytes_to_add);
*((u_char *)ctx - 1) = bytes_to_add;
}
aes_key_setup(key,prf_key);
uhash_init(ctx, prf_key);
}
return (ctx);
}
#endif
/* ---------------------------------------------------------------------- */
#if 0
static int uhash_free(uhash_ctx_t ctx)
{
/* Free memory allocated by uhash_alloc */
u_char bytes_to_sub;
if (ctx) {
if (ALLOC_BOUNDARY) {
bytes_to_sub = *((u_char *)ctx - 1);
ctx = (uhash_ctx_t)((u_char *)ctx - bytes_to_sub);
}
free(ctx);
}
return (1);
}
#endif
/* ---------------------------------------------------------------------- */
static int uhash_update(uhash_ctx_t ctx, const u_char *input, long len)
/* Given len bytes of data, we parse it into L1_KEY_LEN chunks and
* hash each one with NH, calling the polyhash on each NH output.
*/
{
UWORD bytes_hashed, bytes_remaining;
UINT64 result_buf[STREAMS];
UINT8 *nh_result = (UINT8 *)&result_buf;
if (ctx->msg_len + len <= L1_KEY_LEN) {
nh_update(&ctx->hash, (const UINT8 *)input, len);
ctx->msg_len += len;
} else {
bytes_hashed = ctx->msg_len % L1_KEY_LEN;
if (ctx->msg_len == L1_KEY_LEN)
bytes_hashed = L1_KEY_LEN;
if (bytes_hashed + len >= L1_KEY_LEN) {
/* If some bytes have been passed to the hash function */
/* then we want to pass at most (L1_KEY_LEN - bytes_hashed) */
/* bytes to complete the current nh_block. */
if (bytes_hashed) {
bytes_remaining = (L1_KEY_LEN - bytes_hashed);
nh_update(&ctx->hash, (const UINT8 *)input, bytes_remaining);
nh_final(&ctx->hash, nh_result);
ctx->msg_len += bytes_remaining;
poly_hash(ctx,(UINT32 *)nh_result);
len -= bytes_remaining;
input += bytes_remaining;
}
/* Hash directly from input stream if enough bytes */
while (len >= L1_KEY_LEN) {
nh(&ctx->hash, (const UINT8 *)input, L1_KEY_LEN,
L1_KEY_LEN, nh_result);
ctx->msg_len += L1_KEY_LEN;
len -= L1_KEY_LEN;
input += L1_KEY_LEN;
poly_hash(ctx,(UINT32 *)nh_result);
}
}
/* pass remaining < L1_KEY_LEN bytes of input data to NH */
if (len) {
nh_update(&ctx->hash, (const UINT8 *)input, len);
ctx->msg_len += len;
}
}
return (1);
}
/* ---------------------------------------------------------------------- */
static int uhash_final(uhash_ctx_t ctx, u_char *res)
/* Incorporate any pending data, pad, and generate tag */
{
UINT64 result_buf[STREAMS];
UINT8 *nh_result = (UINT8 *)&result_buf;
if (ctx->msg_len > L1_KEY_LEN) {
if (ctx->msg_len % L1_KEY_LEN) {
nh_final(&ctx->hash, nh_result);
poly_hash(ctx,(UINT32 *)nh_result);
}
ip_long(ctx, res);
} else {
nh_final(&ctx->hash, nh_result);
ip_short(ctx,nh_result, res);
}
uhash_reset(ctx);
return (1);
}
/* ---------------------------------------------------------------------- */
#if 0
static int uhash(uhash_ctx_t ahc, u_char *msg, long len, u_char *res)
/* assumes that msg is in a writable buffer of length divisible by */
/* L1_PAD_BOUNDARY. Bytes beyond msg[len] may be zeroed. */
{
UINT8 nh_result[STREAMS*sizeof(UINT64)];
UINT32 nh_len;
int extra_zeroes_needed;
/* If the message to be hashed is no longer than L1_HASH_LEN, we skip
* the polyhash.
*/
if (len <= L1_KEY_LEN) {
if (len == 0) /* If zero length messages will not */
nh_len = L1_PAD_BOUNDARY; /* be seen, comment out this case */
else
nh_len = ((len + (L1_PAD_BOUNDARY - 1)) & ~(L1_PAD_BOUNDARY - 1));
extra_zeroes_needed = nh_len - len;
zero_pad((UINT8 *)msg + len, extra_zeroes_needed);
nh(&ahc->hash, (UINT8 *)msg, nh_len, len, nh_result);
ip_short(ahc,nh_result, res);
} else {
/* Otherwise, we hash each L1_KEY_LEN chunk with NH, passing the NH
* output to poly_hash().
*/
do {
nh(&ahc->hash, (UINT8 *)msg, L1_KEY_LEN, L1_KEY_LEN, nh_result);
poly_hash(ahc,(UINT32 *)nh_result);
len -= L1_KEY_LEN;
msg += L1_KEY_LEN;
} while (len >= L1_KEY_LEN);
if (len) {
nh_len = ((len + (L1_PAD_BOUNDARY - 1)) & ~(L1_PAD_BOUNDARY - 1));
extra_zeroes_needed = nh_len - len;
zero_pad((UINT8 *)msg + len, extra_zeroes_needed);
nh(&ahc->hash, (UINT8 *)msg, nh_len, len, nh_result);
poly_hash(ahc,(UINT32 *)nh_result);
}
ip_long(ahc, res);
}
uhash_reset(ahc);
return 1;
}
#endif
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ----- Begin UMAC Section --------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* The UMAC interface has two interfaces, an all-at-once interface where
* the entire message to be authenticated is passed to UMAC in one buffer,
* and a sequential interface where the message is presented a little at a
* time. The all-at-once is more optimaized than the sequential version and
* should be preferred when the sequential interface is not required.
*/
struct umac_ctx {
uhash_ctx hash; /* Hash function for message compression */
pdf_ctx pdf; /* PDF for hashed output */
void *free_ptr; /* Address to free this struct via */
} umac_ctx;
/* ---------------------------------------------------------------------- */
#if 0
int umac_reset(struct umac_ctx *ctx)
/* Reset the hash function to begin a new authentication. */
{
uhash_reset(&ctx->hash);
return (1);
}
#endif
/* ---------------------------------------------------------------------- */
int umac_delete(struct umac_ctx *ctx)
/* Deallocate the ctx structure */
{
if (ctx) {
if (ALLOC_BOUNDARY)
ctx = (struct umac_ctx *)ctx->free_ptr;
freezero(ctx, sizeof(*ctx) + ALLOC_BOUNDARY);
}
return (1);
}
/* ---------------------------------------------------------------------- */
struct umac_ctx *umac_new(const u_char key[])
/* Dynamically allocate a umac_ctx struct, initialize variables,
* generate subkeys from key. Align to 16-byte boundary.
*/
{
struct umac_ctx *ctx, *octx;
size_t bytes_to_add;
aes_int_key prf_key;
octx = ctx = xcalloc(1, sizeof(*ctx) + ALLOC_BOUNDARY);
if (ctx) {
if (ALLOC_BOUNDARY) {
bytes_to_add = ALLOC_BOUNDARY -
((ptrdiff_t)ctx & (ALLOC_BOUNDARY - 1));
ctx = (struct umac_ctx *)((u_char *)ctx + bytes_to_add);
}
ctx->free_ptr = octx;
aes_key_setup(key, prf_key);
pdf_init(&ctx->pdf, prf_key);
uhash_init(&ctx->hash, prf_key);
explicit_bzero(prf_key, sizeof(prf_key));
}
return (ctx);
}
/* ---------------------------------------------------------------------- */
int umac_final(struct umac_ctx *ctx, u_char tag[], const u_char nonce[8])
/* Incorporate any pending data, pad, and generate tag */
{
uhash_final(&ctx->hash, (u_char *)tag);
pdf_gen_xor(&ctx->pdf, (const UINT8 *)nonce, (UINT8 *)tag);
return (1);
}
/* ---------------------------------------------------------------------- */
int umac_update(struct umac_ctx *ctx, const u_char *input, long len)
/* Given len bytes of data, we parse it into L1_KEY_LEN chunks and */
/* hash each one, calling the PDF on the hashed output whenever the hash- */
/* output buffer is full. */
{
uhash_update(&ctx->hash, input, len);
return (1);
}
/* ---------------------------------------------------------------------- */
#if 0
int umac(struct umac_ctx *ctx, u_char *input,
long len, u_char tag[],
u_char nonce[8])
/* All-in-one version simply calls umac_update() and umac_final(). */
{
uhash(&ctx->hash, input, len, (u_char *)tag);
pdf_gen_xor(&ctx->pdf, (UINT8 *)nonce, (UINT8 *)tag);
return (1);
}
#endif
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ----- End UMAC Section ----------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
diff --git a/utf8.h b/utf8.h
index 9d6d9a32cd8a..09941d47180a 100644
--- a/utf8.h
+++ b/utf8.h
@@ -1,28 +1,28 @@
-/* $OpenBSD: utf8.h,v 1.3 2020/05/01 06:28:52 djm Exp $ */
+/* $OpenBSD: utf8.h,v 1.4 2021/04/03 06:18:41 djm Exp $ */
/*
* Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
int vasnmprintf(char **, size_t, int *, const char *, va_list);
int mprintf(const char *, ...)
- __attribute__((format(printf, 1, 2)));
+ __attribute__((format(printf, 1, 2)));
int fmprintf(FILE *, const char *, ...)
- __attribute__((format(printf, 2, 3)));
+ __attribute__((format(printf, 2, 3)));
int vfmprintf(FILE *, const char *, va_list);
int snmprintf(char *, size_t, int *, const char *, ...)
- __attribute__((format(printf, 4, 5)));
+ __attribute__((format(printf, 4, 5)));
int asmprintf(char **, size_t, int *, const char *, ...)
- __attribute__((format(printf, 4, 5)));
+ __attribute__((format(printf, 4, 5)));
void msetlocale(void);
diff --git a/version.h b/version.h
index 6b4fa3721e80..b1cdf851daee 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
-/* $OpenBSD: version.h,v 1.89 2021/03/02 01:48:18 djm Exp $ */
+/* $OpenBSD: version.h,v 1.90 2021/04/16 03:42:00 djm Exp $ */
-#define SSH_VERSION "OpenSSH_8.5"
+#define SSH_VERSION "OpenSSH_8.6"
#define SSH_PORTABLE "p1"
#define SSH_RELEASE SSH_VERSION SSH_PORTABLE
diff --git a/xmalloc.h b/xmalloc.h
index abaf7ada2c6c..a6b8d23bde8e 100644
--- a/xmalloc.h
+++ b/xmalloc.h
@@ -1,28 +1,27 @@
-/* $OpenBSD: xmalloc.h,v 1.19 2019/11/12 22:32:48 djm Exp $ */
+/* $OpenBSD: xmalloc.h,v 1.20 2021/04/03 06:18:41 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Created: Mon Mar 20 22:09:17 1995 ylo
*
* Versions of malloc and friends that check their results, and never return
* failure (they call fatal if they encounter an error).
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
void *xmalloc(size_t);
void *xcalloc(size_t, size_t);
void *xreallocarray(void *, size_t, size_t);
void *xrecallocarray(void *, size_t, size_t, size_t);
char *xstrdup(const char *);
int xasprintf(char **, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)))
- __attribute__((__nonnull__ (2)));
+ __attribute__((__format__ (printf, 2, 3))) __attribute__((__nonnull__ (2)));
int xvasprintf(char **, const char *, va_list)
- __attribute__((__nonnull__ (2)));
+ __attribute__((__nonnull__ (2)));

File Metadata

Mime Type
application/octet-stream
Expires
Fri, May 24, 2:31 PM (2 d)
Storage Engine
chunks
Storage Format
Chunks
Storage Handle
2Ah82uDav6m.
Default Alt Text
(4 MB)

Event Timeline