Page MenuHomeFreeBSD

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/.depend b/.depend
index cd38d15f8f52..fca83a67c970 100644
--- a/.depend
+++ b/.depend
@@ -1,182 +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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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 xmalloc.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-pubkeyfile.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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 log.h ssherr.h misc.h compat.h sshkey.h digest.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth-options.h authfile.h match.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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 misc.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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
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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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: 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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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 atomicio.h pathnames.h log.h ssherr.h misc.h progressmeter.h utf8.h sftp.h sftp-common.h sftp-client.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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 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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-usergroup.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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 log.h ssherr.h xmalloc.h sftp-common.h sftp-client.h openbsd-compat/glob.h sftp-usergroup.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-usergroup.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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 hostfile.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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 myproposal.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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_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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.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/.git_allowed_signers b/.git_allowed_signers
new file mode 100644
index 000000000000..0313c1ecd17f
--- /dev/null
+++ b/.git_allowed_signers
@@ -0,0 +1,5 @@
+dtucker@dtucker.net ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKecyjh9aNmD4rb8WblA8v91JjRb0Cd2JtkzqxcggGeG
+djm@mindrot.org sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBLnJo3ZVDENYZGXm5uO9lU7b0iDFq5gHpTu1MaHPWTEfPdvw+AjFQQ/q5YizuMJkXGsMdYmblJEJZYHpm9IS7ZkAAAAEc3NoOg==
+djm@mindrot.org sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBJoAXBTQalfg+kC5wy1vE7HkIHtVnmV6AUuuIo9KQ1P+70juHwvsFKpsGaqQbrHJkTVgYDGVP02XHj8+Fb18yBIAAAAEc3NoOg==
+djm@mindrot.org sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBH+z1I48s6ydOhP5SJmI02zVCLf0K15B+UMHgoTIKVfUIv5oDoVX7e9f+7QiRmTeEOdZfQydiaVqsfi7qPSve+0AAAAEc3NoOg==
+djm@mindrot.org sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBPM4BmUg/fMnsl42JwktTekk/mB8Be3M+yK2ayg6lqYsqEri8yhRx84gey51OHKVk1TwlGbJjcMHI4URreDBEMQAAAAEc3NoOg==
diff --git a/.git_allowed_signers.asc b/.git_allowed_signers.asc
new file mode 100644
index 000000000000..5fc6118ca9a6
--- /dev/null
+++ b/.git_allowed_signers.asc
@@ -0,0 +1,16 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEEcWi5g4FaXu9ZpK39Kj9BTnNgYLoFAmMMMiIACgkQKj9BTnNg
+YLpyGhAAhZ1RxmD62JnT0gnor1aD0inq1fGPRadaFvXH2OScPcxXMIZWx+otnyZ/
+H9s0bIti42dPHqurgh92KS2mDGVIW8Y8MvxFUr678+hdem1U7Xvjoo0uaveNhJhe
+GxuQDOvXKRmmfL2c6w3wnFChFA1o3K+JNshjCHhWz7u6+UmY0Q9yIxqbSi+vmEPP
+NfWPfGdu4h8r7q11UgTxRSUQkfZXMqpBtb367B9BLduGuKRFKEJNyi6WpjBrqy38
+BvEbAaL52KX8hEp3TKMjo38RbOK+veSoPV5zlLui0WlEwwasgljal3f4RkqCAJob
+hqpFJRogM5XNnA2e68TDTf3buJ3wRRjuK39/CusOJz5v4i6+VCdte+BET1Y4gD6y
+v8KV4pRyumcdbN3khFUkmaQsjo+fyQjWNrgOvv60J2xUWZdchn8lxHOxrfRVKnOi
+BD4bdks7tPQY/XsS5GNJIp21Ji9HGyBajjHo0BlesLodw7FEOf6YE18A3n9qzosR
+RliuP4Hs/Z4sCUuDTbpKtQiUVs40kBbkhEL8kS8FsXz3VO89hAWaUqNUYom8AkKv
+nfDjrZDBLXuVj1Mi8qNPXxqrB/1Cza2/W4U7SK4TlMFXfoXXWxxhefN5vIdMhAJB
+u9Mdz1pY9mowKbd0c0dR+3fauvjM133dzKuyeDHMqDa5JPyd59o=
+=kgnS
+-----END PGP SIGNATURE-----
diff --git a/.github/configs b/.github/configs
index 871a3d414d94..6bf1ab27f0ca 100755
--- a/.github/configs
+++ b/.github/configs
@@ -1,231 +1,290 @@
#!/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
+unset CC CFLAGS CPPFLAGS LDFLAGS LTESTS SUDO
+
TEST_TARGET="tests"
LTESTS=""
SKIP_LTESTS=""
SUDO=sudo # run with sudo by default
TEST_SSH_UNSAFE_PERMISSIONS=1
# Stop on first test failure to minimize logs
TEST_SSH_FAIL_FATAL=yes
CONFIGFLAGS=""
LIBCRYPTOFLAGS=""
case "$config" in
default|sol64)
;;
c89)
CC="gcc"
CFLAGS="-Wall -std=c89 -pedantic -Werror=vla"
CONFIGFLAGS="--without-zlib"
LIBCRYPTOFLAGS="--without-openssl"
TEST_TARGET=t-exec
;;
cygwin-release)
- CONFIGFLAGS="--with-libedit --with-xauth=/usr/bin/xauth --disable-strip --with-security-key-builtin"
+ # See https://cygwin.com/git/?p=git/cygwin-packages/openssh.git;a=blob;f=openssh.cygport;hb=HEAD
+ CONFIGFLAGS="--with-xauth=/usr/bin/xauth --with-security-key-builtin"
+ CONFIGFLAGS="$CONFIGFLAGS --with-kerberos5=/usr --with-libedit --disable-strip"
;;
clang-12-Werror)
CC="clang-12"
# clang's implicit-fallthrough requires that the code be annotated with
# __attribute__((fallthrough)) and does not understand /* FALLTHROUGH */
CFLAGS="-Wall -Wextra -O2 -Wno-error=implicit-fallthrough -Wno-error=unused-parameter"
CONFIGFLAGS="--with-pam --with-Werror"
;;
+ *-sanitize-*)
+ case "$config" in
+ gcc-*)
+ CC=gcc
+ ;;
+ clang-*)
+ # Find the newest available version of clang
+ for i in `seq 10 99`; do
+ clang="`which clang-$i 2>/dev/null`"
+ [ -x "$clang" ] && CC="$clang"
+ done
+ ;;
+ esac
+ # Put Sanitizer logs in regress dir.
+ SANLOGS=`pwd`/regress
+ # - We replace chroot with chdir so that the sanitizer in the preauth
+ # privsep process can read /proc.
+ # - clang does not recognizes explicit_bzero so we use bzero
+ # (see https://github.com/google/sanitizers/issues/1507
+ # - openssl and zlib trip ASAN.
+ # - sp_pwdp returned by getspnam trips ASAN, hence disabling shadow.
+ case "$config" in
+ *-sanitize-address)
+ CFLAGS="-fsanitize=address -fno-omit-frame-pointer"
+ LDFLAGS="-fsanitize=address"
+ CPPFLAGS='-Dchroot=chdir -Dexplicit_bzero=bzero -D_FORTIFY_SOURCE=0 -DASAN_OPTIONS=\"detect_leaks=0:log_path='$SANLOGS'/asan.log\"'
+ CONFIGFLAGS=""
+ TEST_TARGET="t-exec"
+ ;;
+ clang-sanitize-memory)
+ CFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer"
+ LDFLAGS="-fsanitize=memory"
+ CPPFLAGS='-Dchroot=chdir -Dexplicit_bzero=bzero -DMSAN_OPTIONS=\"log_path='$SANLOGS'/msan.log\"'
+ CONFIGFLAGS="--without-openssl --without-zlib --without-shadow"
+ TEST_TARGET="t-exec"
+ ;;
+ *-sanitize-undefined)
+ CFLAGS="-fsanitize=undefined"
+ LDFLAGS="-fsanitize=undefined"
+ ;;
+ *)
+ echo unknown sanitize option;
+ exit 1;;
+ esac
+ features="--disable-security-key --disable-pkcs11"
+ hardening="--without-sandbox --without-hardening --without-stackprotect"
+ privsep="--with-privsep-user=root"
+ CONFIGFLAGS="$CONFIGFLAGS $features $hardening $privsep"
+ # Because we hobble chroot we can't test it.
+ SKIP_LTESTS=sftp-chroot
+ ;;
gcc-11-Werror)
CC="gcc"
# -Wnoformat-truncation in gcc 7.3.1 20180130 fails on fmt_scaled
CFLAGS="-Wall -Wextra -O2 -Wno-format-truncation -Wimplicit-fallthrough=4 -Wno-unused-parameter"
CONFIGFLAGS="--with-pam --with-Werror"
;;
clang*|gcc*)
CC="$config"
;;
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"
;;
tcmalloc)
CONFIGFLAGS="--with-ldflags=-ltcmalloc"
;;
krb5|heimdal)
CONFIGFLAGS="--with-kerberos5"
;;
libedit)
CONFIGFLAGS="--with-libedit"
;;
musl)
CC="musl-gcc"
CONFIGFLAGS="--without-zlib"
LIBCRYPTOFLAGS="--without-openssl"
TEST_TARGET="t-exec"
;;
pam-krb5)
CONFIGFLAGS="--with-pam --with-kerberos5"
SSHD_CONFOPTS="UsePam yes"
;;
*pam)
CONFIGFLAGS="--with-pam"
SSHD_CONFOPTS="UsePam yes"
;;
libressl-*)
LIBCRYPTOFLAGS="--with-ssl-dir=/opt/libressl --with-rpath=-Wl,-rpath,"
;;
openssl-*)
LIBCRYPTOFLAGS="--with-ssl-dir=/opt/openssl --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-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 so split into three separate tests.
- tests2="rekey integrity try-ciphers sftp"
- tests3="krl forward-control sshsig agent-restrict kextype"
+ tests2="rekey integrity try-ciphers"
+ tests3="krl forward-control sshsig agent-restrict kextype sftp"
tests4="cert-userkey cert-hostkey kextype sftp-perm keygen-comment percent"
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}"
+ # and hostbased (since valgrind won't let ssh exec keysign).
+ # Slow ones are run separately to increase parallelism.
+ SKIP_LTESTS="agent-timeout hostbased ${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
aix*)
# These are slow real or virtual machines so skip the slowest tests
# (which tend to be thw ones that transfer lots of data) so that the
# test run does not time out.
# The agent-restrict test fails due to some quoting issue when run
# with sh or ksh so specify bash for now.
TEST_TARGET="t-exec TEST_SHELL=bash"
SKIP_LTESTS="rekey sftp"
;;
dfly58*|dfly60*)
# scp 3-way connection hangs on these so skip until sorted.
SKIP_LTESTS=scp3
;;
fbsd6)
# Native linker is not great with PIC so OpenSSL is built w/out.
CONFIGFLAGS="${CONFIGFLAGS} --disable-security-key"
;;
hurd)
SKIP_LTESTS="forwarding multiplex proxy-connect hostkey-agent agent-ptrace"
;;
minix3)
LIBCRYPTOFLAGS="--without-openssl --disable-security-key"
# Minix does not have a loopback interface so we have to skip any
# test that relies on one.
# Also, Minix seems to be very limited in the number of select()
# calls that can be operating concurrently, so prune additional tests for that.
T="addrmatch agent-restrict brokenkeys cfgmatch cfgmatchlisten cfgparse connect
connect-uri exit-status forward-control forwarding hostkey-agent
key-options keyscan knownhosts-command login-timeout multiplex
reconfigure reexec rekey scp scp-uri scp3 sftp sftp-badcmds
sftp-batch sftp-cmds sftp-glob sftp-perm sftp-uri stderr-data
transfer"
SKIP_LTESTS="$(echo $T)"
TEST_TARGET=t-exec
SUDO=""
;;
nbsd4)
# System compiler will ICE on some files with fstack-protector
# SHA256 functions in sha2.h conflict with OpenSSL's breaking sk-dummy
CONFIGFLAGS="${CONFIGFLAGS} --without-hardening --disable-security-key"
;;
openwrt-*)
CONFIGFLAGS="${CONFIGFLAGS} --without-openssl --without-zlib"
TEST_TARGET="t-exec"
;;
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"
;;
win10)
# No sudo on Windows.
SUDO=""
;;
esac
-# Unless specified otherwise, build without OpenSSL on Mac OS since
-# modern versions don't ship with libcrypto.
case "`./config.guess`" in
+*cygwin)
+ SUDO=""
+ ;;
*-darwin*)
+ # Unless specified otherwise, build without OpenSSL on Mac OS since
+ # modern versions don't ship with libcrypto.
LIBCRYPTOFLAGS="--without-openssl"
TEST_TARGET=t-exec
;;
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}"
if [ -x "$(which plink 2>/dev/null)" ]; then
REGRESS_INTEROP_PUTTY=yes
export REGRESS_INTEROP_PUTTY
fi
-export CC CFLAGS LTESTS SUDO
+export CC CFLAGS CPPFLAGS LDFLAGS LTESTS SUDO
export TEST_TARGET TEST_SSH_UNSAFE_PERMISSIONS TEST_SSH_FAIL_FATAL
diff --git a/.github/configure.sh b/.github/configure.sh
index 502bf5f0d407..bd0037702d6a 100755
--- a/.github/configure.sh
+++ b/.github/configure.sh
@@ -1,21 +1,21 @@
#!/bin/sh
. .github/configs $1
printf "$ "
if [ "x$CC" != "x" ]; then
printf "CC='$CC' "
fi
if [ "x$CFLAGS" != "x" ]; then
printf "CFLAGS='$CFLAGS' "
fi
if [ "x$CPPFLAGS" != "x" ]; then
printf "CPPFLAGS='$CPPFLAGS' "
fi
if [ "x$LDFLAGS" != "x" ]; then
printf "LDFLAGS='$LDFLAGS' "
fi
echo ./configure ${CONFIGFLAGS}
-./configure ${CONFIGFLAGS}
+./configure ${CONFIGFLAGS} 2>&1
diff --git a/.github/run_test.sh b/.github/run_test.sh
index adf2568ad1e2..8eeaf5e9b09d 100755
--- a/.github/run_test.sh
+++ b/.github/run_test.sh
@@ -1,34 +1,48 @@
#!/bin/sh
. .github/configs $1
[ -z "${SUDO}" ] || ${SUDO} mkdir -p /var/empty
set -ex
+# If we want to test hostbased auth, set up the host for it.
+if [ ! -z "$SUDO" ] && [ ! -z "$TEST_SSH_HOSTBASED_AUTH" ]; then
+ sshconf=/usr/local/etc
+ hostname | $SUDO tee $sshconf/shosts.equiv >/dev/null
+ echo "EnableSSHKeysign yes" | $SUDO tee $sshconf/ssh_config >/dev/null
+ $SUDO mkdir -p $sshconf
+ $SUDO cp -p /etc/ssh/ssh_host*key* $sshconf
+ $SUDO make install
+ for key in $sshconf/ssh_host*key*.pub; do
+ echo `hostname` `cat $key` | \
+ $SUDO tee -a $sshconf/ssh_known_hosts >/dev/null
+ done
+fi
+
output_failed_logs() {
for i in regress/failed*; do
if [ -f "$i" ]; then
echo -------------------------------------------------------------------------
echo LOGFILE $i
cat $i
echo -------------------------------------------------------------------------
fi
done
}
trap output_failed_logs 0
if [ -z "${LTESTS}" ]; then
make ${TEST_TARGET} SKIP_LTESTS="${SKIP_LTESTS}"
else
make ${TEST_TARGET} SKIP_LTESTS="${SKIP_LTESTS}" LTESTS="${LTESTS}"
fi
if [ ! -z "${SSHD_CONFOPTS}" ]; then
echo "rerunning t-exec with TEST_SSH_SSHD_CONFOPTS='${SSHD_CONFOPTS}'"
if [ -z "${LTESTS}" ]; then
make t-exec SKIP_LTESTS="${SKIP_LTESTS}" TEST_SSH_SSHD_CONFOPTS="${SSHD_CONFOPTS}"
else
make t-exec SKIP_LTESTS="${SKIP_LTESTS}" LTESTS="${LTESTS}" TEST_SSH_SSHD_CONFOPTS="${SSHD_CONFOPTS}"
fi
fi
diff --git a/.github/setup_ci.sh b/.github/setup_ci.sh
index a3bb8587eab1..044c4d1292b1 100755
--- a/.github/setup_ci.sh
+++ b/.github/setup_ci.sh
@@ -1,141 +1,188 @@
#!/bin/sh
+PACKAGES=""
+
. .github/configs $@
case "`./config.guess`" in
+*cygwin)
+ PACKAGER=setup
+ echo Setting CYGWIN sustem environment variable.
+ setx CYGWIN "binmode"
+ chmod -R go-rw /cygdrive/d/a
+ umask 077
+ PACKAGES="$PACKAGES,autoconf,automake,cygwin-devel,gcc-core"
+ PACKAGES="$PACKAGES,make,openssl-devel,zlib-devel"
+ ;;
*-darwin*)
+ PACKAGER=brew
brew install automake
exit 0
;;
+*)
+ PACKAGER=apt
esac
TARGETS=$@
-PACKAGES=""
INSTALL_FIDO_PPA="no"
export DEBIAN_FRONTEND=noninteractive
#echo "Setting up for '$TARGETS'"
set -ex
-lsb_release -a
+if [ -x "`which lsb_release 2>&1`" ]; then
+ lsb_release -a
+fi
+
+# Ubuntu 22.04 defaults to private home dirs which prevent the
+# agent-getpeerid test from running ssh-add as nobody. See
+# https://github.com/actions/runner-images/issues/6106
+if [ ! -z "$SUDO" ] && ! "$SUDO" -u nobody test -x ~; then
+ echo ~ is not executable by nobody, adding perms.
+ chmod go+x ~
+fi
if [ "${TARGETS}" = "kitchensink" ]; then
TARGETS="krb5 libedit pam sk selinux"
fi
for flag in $CONFIGFLAGS; do
case "$flag" in
- --with-pam) PACKAGES="${PACKAGES} libpam0g-dev" ;;
- --with-libedit) PACKAGES="${PACKAGES} libedit-dev" ;;
+ --with-pam) TARGETS="${TARGETS} pam" ;;
+ --with-libedit) TARGETS="${TARGETS} libedit" ;;
esac
done
for TARGET in $TARGETS; do
case $TARGET in
- default|without-openssl|without-zlib|c89|libedit|*pam)
+ default|without-openssl|without-zlib|c89)
# nothing to do
;;
+ clang-sanitize*)
+ PACKAGES="$PACKAGES clang-12"
+ ;;
+ cygwin-release)
+ PACKAGES="$PACKAGES libcrypt-devel libfido2-devel libkrb5-devel"
+ ;;
+ gcc-sanitize*)
+ ;;
clang-*|gcc-*)
compiler=$(echo $TARGET | sed 's/-Werror//')
PACKAGES="$PACKAGES $compiler"
;;
krb5)
PACKAGES="$PACKAGES libkrb5-dev"
;;
heimdal)
PACKAGES="$PACKAGES heimdal-dev"
;;
+ libedit)
+ case "$PACKAGER" in
+ setup) PACKAGES="$PACKAGES libedit-devel" ;;
+ apt) PACKAGES="$PACKAGES libedit-dev" ;;
+ esac
+ ;;
+ *pam)
+ PACKAGES="$PACKAGES libpam0g-dev"
+ ;;
sk)
INSTALL_FIDO_PPA="yes"
PACKAGES="$PACKAGES libfido2-dev libu2f-host-dev libcbor-dev"
;;
selinux)
PACKAGES="$PACKAGES libselinux1-dev selinux-policy-dev"
;;
hardenedmalloc)
INSTALL_HARDENED_MALLOC=yes
;;
musl)
PACKAGES="$PACKAGES musl-tools"
;;
tcmalloc)
PACKAGES="$PACKAGES libgoogle-perftools-dev"
;;
openssl-noec)
INSTALL_OPENSSL=OpenSSL_1_1_1k
SSLCONFOPTS="no-ec"
;;
openssl-*)
INSTALL_OPENSSL=$(echo ${TARGET} | cut -f2 -d-)
case ${INSTALL_OPENSSL} in
1.1.1_stable) INSTALL_OPENSSL="OpenSSL_1_1_1-stable" ;;
1.*) INSTALL_OPENSSL="OpenSSL_$(echo ${INSTALL_OPENSSL} | tr . _)" ;;
3.*) INSTALL_OPENSSL="openssl-${INSTALL_OPENSSL}" ;;
esac
PACKAGES="${PACKAGES} putty-tools"
;;
libressl-*)
INSTALL_LIBRESSL=$(echo ${TARGET} | cut -f2 -d-)
case ${INSTALL_LIBRESSL} in
master) ;;
*) INSTALL_LIBRESSL="$(echo ${TARGET} | cut -f2 -d-)" ;;
esac
PACKAGES="${PACKAGES} putty-tools"
;;
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 -qy software-properties-common
sudo apt-add-repository -y ppa:yubico/stable
fi
-if [ "x" != "x$PACKAGES" ]; then
- sudo apt update -qq
- sudo apt install -qy $PACKAGES
+if [ "x" != "x$PACKAGES" ]; then
+ case "$PACKAGER" in
+ apt)
+ sudo apt update -qq
+ sudo apt install -qy $PACKAGES
+ ;;
+ setup)
+ /cygdrive/c/setup.exe -q -P `echo "$PACKAGES" | tr ' ' ,`
+ ;;
+ esac
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 out/libhardened_malloc.so /usr/lib/)
fi
if [ ! -z "${INSTALL_OPENSSL}" ]; then
(cd ${HOME} &&
git clone https://github.com/openssl/openssl.git &&
cd ${HOME}/openssl &&
git checkout ${INSTALL_OPENSSL} &&
./config no-threads shared ${SSLCONFOPTS} \
--prefix=/opt/openssl &&
make && sudo make install_sw)
fi
if [ ! -z "${INSTALL_LIBRESSL}" ]; then
if [ "${INSTALL_LIBRESSL}" = "master" ]; then
(mkdir -p ${HOME}/libressl && cd ${HOME}/libressl &&
git clone https://github.com/libressl-portable/portable.git &&
cd ${HOME}/libressl/portable &&
git checkout ${INSTALL_LIBRESSL} &&
sh update.sh && sh autogen.sh &&
./configure --prefix=/opt/libressl &&
make -j2 && sudo make install)
else
LIBRESSL_URLBASE=https://cdn.openbsd.org/pub/OpenBSD/LibreSSL
(cd ${HOME} &&
wget ${LIBRESSL_URLBASE}/libressl-${INSTALL_LIBRESSL}.tar.gz &&
tar xfz libressl-${INSTALL_LIBRESSL}.tar.gz &&
cd libressl-${INSTALL_LIBRESSL} &&
./configure --prefix=/opt/libressl && make -j2 && sudo make install)
fi
fi
diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml
index b778c9804203..3cd1188fc572 100644
--- a/.github/workflows/c-cpp.yml
+++ b/.github/workflows/c-cpp.yml
@@ -1,104 +1,122 @@
name: C/C++ CI
on:
push:
- branches: [ master, ci ]
+ branches: [ master, ci, V_9_0 ]
+ paths: [ '**.c', '**.h', '**.m4', '**.sh', '.github/**', 'Makefile.in', 'configure.ac' ]
pull_request:
branches: [ master ]
+ paths: [ '**.c', '**.h', '**.m4', '**.sh', '.github/**', 'Makefile.in', 'configure.ac' ]
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, macos-10.15, macos-11.0]
+ os: [ubuntu-20.04, ubuntu-22.04, macos-11, macos-12, windows-2019, windows-2022]
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: windows-2019, configs: cygwin-release }
+ - { os: windows-2022, configs: cygwin-release }
- { 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: c89 }
- { os: ubuntu-20.04, configs: clang-6.0 }
- { os: ubuntu-20.04, configs: clang-8 }
- { os: ubuntu-20.04, configs: clang-9 }
- { os: ubuntu-20.04, configs: clang-10 }
- { os: ubuntu-20.04, configs: clang-11 }
- { os: ubuntu-20.04, configs: clang-12-Werror }
+ - { os: ubuntu-20.04, configs: clang-sanitize-address }
+ - { os: ubuntu-20.04, configs: clang-sanitize-undefined }
+ - { os: ubuntu-20.04, configs: gcc-sanitize-address }
+ - { os: ubuntu-20.04, configs: gcc-sanitize-undefined }
- { os: ubuntu-20.04, configs: gcc-7 }
- { os: ubuntu-20.04, configs: gcc-8 }
- { os: ubuntu-20.04, configs: gcc-10 }
- { os: ubuntu-20.04, configs: gcc-11-Werror }
- { os: ubuntu-20.04, configs: pam }
- { os: ubuntu-20.04, configs: kitchensink }
- { os: ubuntu-20.04, configs: hardenedmalloc }
- { os: ubuntu-20.04, configs: tcmalloc }
- { os: ubuntu-20.04, configs: musl }
- { os: ubuntu-latest, configs: libressl-master }
- { os: ubuntu-latest, configs: libressl-2.2.9 }
- { os: ubuntu-latest, configs: libressl-2.8.3 }
- { os: ubuntu-latest, configs: libressl-3.0.2 }
- { os: ubuntu-latest, configs: libressl-3.2.6 }
- - { os: ubuntu-latest, configs: libressl-3.3.4 }
- - { os: ubuntu-latest, configs: libressl-3.4.1 }
- - { os: ubuntu-latest, configs: libressl-3.5.0 }
+ - { os: ubuntu-latest, configs: libressl-3.3.6 }
+ - { os: ubuntu-latest, configs: libressl-3.4.3 }
+ - { os: ubuntu-latest, configs: libressl-3.5.3 }
- { os: ubuntu-latest, configs: openssl-master }
- { os: ubuntu-latest, configs: openssl-noec }
- { os: ubuntu-latest, configs: openssl-1.0.1 }
- { os: ubuntu-latest, configs: openssl-1.0.1u }
- { os: ubuntu-latest, configs: openssl-1.0.2u }
- { os: ubuntu-latest, configs: openssl-1.1.0h }
- { os: ubuntu-latest, configs: openssl-1.1.1 }
- { os: ubuntu-latest, configs: openssl-1.1.1k }
- - { os: ubuntu-latest, configs: openssl-1.1.1m }
+ - { os: ubuntu-latest, configs: openssl-1.1.1n }
+ - { os: ubuntu-latest, configs: openssl-1.1.1p }
- { os: ubuntu-latest, configs: openssl-3.0.0 }
- - { os: ubuntu-latest, configs: openssl-3.0.1 }
+ - { os: ubuntu-latest, configs: openssl-3.0.5 }
- { os: ubuntu-latest, configs: openssl-1.1.1_stable } # stable branch
- { os: ubuntu-latest, configs: openssl-3.0 } # stable branch
- - { os: ubuntu-18.04, configs: pam }
- - { os: ubuntu-18.04, configs: krb5 }
- - { os: ubuntu-18.04, configs: heimdal }
- - { 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: macos-10.15, configs: pam }
- - { os: macos-11.0, configs: pam }
+ - { os: ubuntu-22.04, configs: pam }
+ - { os: ubuntu-22.04, configs: krb5 }
+ - { os: ubuntu-22.04, configs: heimdal }
+ - { os: ubuntu-22.04, configs: libedit }
+ - { os: ubuntu-22.04, configs: sk }
+ - { os: ubuntu-22.04, configs: selinux }
+ - { os: ubuntu-22.04, configs: kitchensink }
+ - { os: ubuntu-22.04, configs: without-openssl }
+ - { os: macos-11, configs: pam }
+ - { os: macos-12, configs: pam }
runs-on: ${{ matrix.os }}
steps:
+ - name: set cygwin git params
+ if: ${{ startsWith(matrix.os, 'windows') }}
+ run: git config --global core.autocrlf input
+ - name: install cygwin
+ if: ${{ startsWith(matrix.os, 'windows') }}
+ uses: cygwin/cygwin-install-action@master
- uses: actions/checkout@v2
- name: setup CI system
- run: ./.github/setup_ci.sh ${{ matrix.configs }}
+ run: sh ./.github/setup_ci.sh ${{ matrix.configs }}
- name: autoreconf
- run: autoreconf
+ run: sh -c autoreconf
- name: configure
- run: ./.github/configure.sh ${{ matrix.configs }}
+ run: sh ./.github/configure.sh ${{ matrix.configs }}
- name: save config
uses: actions/upload-artifact@v2
with:
name: ${{ matrix.os }}-${{ matrix.configs }}-config
path: config.h
- name: make clean
run: make clean
- name: make
run: make -j2
- name: make tests
- run: ./.github/run_test.sh ${{ matrix.configs }}
+ run: sh ./.github/run_test.sh ${{ matrix.configs }}
env:
TEST_SSH_UNSAFE_PERMISSIONS: 1
+ TEST_SSH_HOSTBASED_AUTH: yes
- name: save logs
if: failure()
uses: actions/upload-artifact@v2
with:
name: ${{ matrix.os }}-${{ matrix.configs }}-logs
path: |
config.h
config.log
regress/*.log
regress/valgrind-out/
+ regress/asan.log.*
+ regress/msan.log.*
diff --git a/.github/workflows/selfhosted.yml b/.github/workflows/selfhosted.yml
index ec2c29825c85..c4bd1d9b24f7 100644
--- a/.github/workflows/selfhosted.yml
+++ b/.github/workflows/selfhosted.yml
@@ -1,108 +1,108 @@
name: C/C++ CI self-hosted
on:
push:
- branches: [ master, ci ]
+ branches: [ master, ci, V_9_0 ]
+ paths: [ '**.c', '**.h', '**.m4', '**.sh', '.github/**', 'Makefile.in', 'configure.ac' ]
jobs:
selfhosted:
if: github.repository == 'openssh/openssh-portable-selfhosted'
runs-on: ${{ matrix.os }}
env:
TARGET_HOST: ${{ matrix.os }}
strategy:
fail-fast: false
# We use a matrix in two parts: firstly all of the VMs are tested with the
# default config. "os" corresponds to a label associated with the worker.
matrix:
os:
- aix51
+ - ARM
- ARM64
- alpine
- - bbone
- debian-i386
+ - debian-riscv64
- dfly30
- dfly48
- dfly58
- dfly60
- - fbsd6
- fbsd10
- fbsd12
- fbsd13
# - hurd
- minix3
# - nbsd2
- nbsd3
- nbsd4
- nbsd8
- nbsd9
- obsd51
- obsd67
- obsd69
- obsd70
- obsdsnap
- openindiana
- openwrt-mips
- openwrt-mipsel
# - rocky84
- sol10
- sol11
- win10
configs:
- default
# Then we include any extra configs we want to test for specific VMs.
include:
- { os: ARM64, configs: pam }
- { os: debian-i386, configs: pam }
- { os: dfly30, configs: without-openssl}
- { os: dfly48, configs: pam }
- { os: dfly58, configs: pam }
- { os: dfly60, configs: pam }
- - { os: fbsd6, configs: pam }
- { os: fbsd10, configs: pam }
- { os: fbsd12, configs: pam }
- { os: fbsd13, configs: pam }
- { os: nbsd8, configs: pam }
- { os: nbsd9, configs: pam }
- { os: openindiana, configs: pam }
# - { os: rocky84, configs: pam }
- { os: sol10, configs: pam }
- { os: sol11, configs: pam-krb5 }
- { os: sol11, configs: sol64 }
# - { os: sol11, configs: sol64-pam }
- { os: win10, configs: cygwin-release }
steps:
+ - name: shutdown VM if running
+ run: vmshutdown
- 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
uses: actions/upload-artifact@v2
with:
name: ${{ matrix.os }}-${{ matrix.configs }}-config
path: config.h
- name: make clean
run: vmrun make clean
- name: make
run: vmrun make
- name: make tests
run: vmrun ./.github/run_test.sh ${{ matrix.configs }}
timeout-minutes: 600
- name: save logs
if: failure()
uses: actions/upload-artifact@v2
with:
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/.github/workflows/upstream.yml b/.github/workflows/upstream.yml
index b91083c65184..3cec069ede74 100644
--- a/.github/workflows/upstream.yml
+++ b/.github/workflows/upstream.yml
@@ -1,44 +1,47 @@
name: Upstream self-hosted
on:
push:
branches: [ master, ci ]
+ paths: [ '**.c', '**.h', '.github/**' ]
jobs:
selfhosted:
if: github.repository == 'openssh/openssh-portable-selfhosted'
runs-on: ${{ matrix.os }}
env:
TARGET_HOST: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ obsdsnap, obsdsnap-i386 ]
- configs: [ default, without-openssl ]
+ configs: [ default, without-openssl, ubsan ]
steps:
- uses: actions/checkout@v2
- name: shutdown VM if running
run: vmshutdown
- name: startup VM
run: vmstartup
- name: update source
run: vmrun "cd /usr/src && cvs up -dPA usr.bin/ssh regress/usr.bin/ssh"
- name: make clean
- run: vmrun "cd /usr/src/usr.bin/ssh && make obj && make clean"
+ run: vmrun "cd /usr/src/usr.bin/ssh && make obj && make clean && cd /usr/src/regress/usr.bin/ssh && make obj && make clean"
- name: make
- run: vmrun "cd /usr/src/usr.bin/ssh && if test '${{ matrix.configs }}' = 'without-openssl'; then make OPENSSL=no; else make; fi"
+ run: vmrun "cd /usr/src/usr.bin/ssh && case ${{ matrix.configs }} in without-openssl) make OPENSSL=no;; ubsan) make DEBUG='-fsanitize-minimal-runtime -fsanitize=undefined';; *) make; esac"
- name: make install
run: vmrun "cd /usr/src/usr.bin/ssh && sudo make install"
- - name: make tests
- run: vmrun "cd /usr/src/regress/usr.bin/ssh && make obj && make clean && if test '${{ matrix.configs }}' = 'without-openssl'; then make SUDO=sudo OPENSSL=no; else make SUDO=sudo; fi"
+ - name: make tests`
+ run: vmrun "cd /usr/src/regress/usr.bin/ssh && case ${{ matrix.configs }} in without-openssl) make OPENSSL=no;; ubsan) make DEBUG='-fsanitize-minimal-runtime -fsanitize=undefined';; *) make; esac"
+ env:
+ SUDO: sudo
timeout-minutes: 300
- name: save logs
if: failure()
uses: actions/upload-artifact@v2
with:
name: ${{ matrix.os }}-${{ matrix.configs }}-logs
path: |
/usr/obj/regress/usr.bin/ssh/*.log
- name: shutdown VM
if: always()
run: vmshutdown
diff --git a/.skipped-commit-ids b/.skipped-commit-ids
index c606eaee6c51..b639678939dd 100644
--- a/.skipped-commit-ids
+++ b/.skipped-commit-ids
@@ -1,52 +1,53 @@
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
6b52cd2b637f3d29ef543f0ce532a2bce6d86af5 makefile change
+f9a0726d957cf10692a231996a1f34e7f9cdfeb0 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 063b54769d53..02e11b023ca0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,11889 +1,11314 @@
-commit 94eb6858efecc1b4f02d8a6bd35e149f55c814c8
+commit 0ffb46f2ee2ffcc4daf45ee679e484da8fcf338c
Author: Damien Miller <djm@mindrot.org>
-Date: Wed Apr 6 10:47:48 2022 +1000
+Date: Tue Oct 4 01:51:42 2022 +1100
- update version numbers for release
+ update .depend
-commit 8e4a8eadf4fe74e65e6492f34250f8cf7d67e8da
+commit 657e676ff696c7bb787bffb0e249ea1be3b474e1
+Author: Damien Miller <djm@mindrot.org>
+Date: Tue Oct 4 01:45:52 2022 +1100
+
+ update release notes URL
+
+commit f059da2b29840c0f048448809c317ce2ae014da7
+Author: Damien Miller <djm@mindrot.org>
+Date: Tue Oct 4 01:45:41 2022 +1100
+
+ crank versions in RPM spec files
+
+commit b51f3f172d87cbdb80ca4eb7b2149e56a7647557
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Apr 4 22:45:25 2022 +0000
+Date: Mon Sep 26 22:18:40 2022 +0000
- upstream: openssh-9.0
+ upstream: openssh-9.1
- OpenBSD-Commit-ID: 0dfb461188f4513ec024c1534da8c1ce14c20b64
+ OpenBSD-Commit-ID: 5a467b2ee81da01a86adf1ad93b62b1728494e56
-commit a9f23ea2e3227f406880c2634d066f6f50fa5eaa
-Author: naddy@openbsd.org <naddy@openbsd.org>
-Date: Thu Mar 31 17:58:44 2022 +0000
+commit 4cf8d0c0f3030f594a238bab21a0695735515487
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Wed Sep 21 22:26:50 2022 +0000
- upstream: ssh: document sntrup761x25519-sha512@openssh.com as
-
- default KEX
+ upstream: Fix typo. From AlexanderStohr via github PR#343.
- OpenBSD-Commit-ID: 12545bfa10bcbf552d04d9d9520d0f4e98b0e171
+ OpenBSD-Commit-ID: a134c9b4039e48803fc6a87f955b0f4a03181497
-commit 9ec2713d122af79d66ebb9c1d6d9ae8621a8945f
-Author: naddy@openbsd.org <naddy@openbsd.org>
-Date: Thu Mar 31 17:27:27 2022 +0000
+commit 8179fed3264d5919899900ed8881d5f9bb57ca33
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Sep 19 21:39:16 2022 +0000
- upstream: man pages: add missing commas between subordinate and
-
- main clauses
+ upstream: add RequiredRSASize to the list of keywords accepted by
- jmc@ dislikes a comma before "then" in a conditional, so leave those
- untouched.
+ -o; spotted by jmc@
- ok jmc@
+ OpenBSD-Commit-ID: fe871408cf6f9d3699afeda876f8adbac86a035e
+
+commit 5f954929e9f173dd1e279e07d0e8b14fa845814d
+Author: Damien Miller <djm@mindrot.org>
+Date: Mon Sep 19 20:59:34 2022 +1000
+
+ no need for glob.h here
- OpenBSD-Commit-ID: 9520801729bebcb3c9fe43ad7f9776ab4dd05ea3
+ it also causes portability problems
-commit 3741df98ffaaff92b474ee70d8ef276b5882f85a
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Apr 4 23:52:11 2022 +1000
+commit 03d94a47207d58b3db37eba4f87eb6ae5a63168a
+Author: Damien Miller <djm@mindrot.org>
+Date: Mon Sep 19 20:59:04 2022 +1000
- Disable security key on fbsd6 test host.
+ avoid Wuninitialized false positive in gcc-12ish
-commit 32c12236f27ae83bfe6d2983b67c9bc67a83a417
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Apr 4 15:16:51 2022 +1000
+commit 9d952529113831fb3071ab6e408d2726fd72e771
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Sep 19 10:46:00 2022 +0000
- Specify TEST_SHELL=bash on AIX.
+ upstream: use users-groups-by-id@openssh.com sftp-server extension
- The system shells cause the agent-restrict test to fail due to some
- quoting so explicitly specify bash until we can get configure to
- autmatically work around that.
+ (when available) to fill in user/group names for directory listings.
+ Implement a client-side cache of see uid/gid=>user/group names. ok markus@
+
+ OpenBSD-Commit-ID: f239aeeadfa925a37ceee36ee8b256b8ccf4466e
-commit 90452c8b69d065b7c7c285ff78b81418a75bcd76
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 1 23:38:44 2022 +1100
+commit 8ff680368b0bccf88ae85d4c99de69387fbad7a6
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Sep 19 10:43:12 2022 +0000
- Only return events from ppoll that were requested.
+ upstream: sftp client library support for
- If the underlying system's select() returns bits that were not in the
- request set, our ppoll() implementation can return revents for events
- not requested, which can apparently cause a hang. Only return revents
- for activity in the requested event set. bz#3416, analysis and fix by
- yaroslav.kuzmin at vmssoftware com, ok djm@
+ users-groups-by-id@openssh.com; ok markus@
+
+ OpenBSD-Commit-ID: ddb2f33a2da6349a9a89a8b5bcb9ca7c999394de
-commit 6c49eb5fabc56f4865164ed818aa5112d09c31a8
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 1 23:21:40 2022 +1100
+commit 488f6e1c582212c2374a4bf8cd1b703d2e70fb8b
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Sep 19 10:41:58 2022 +0000
- Only run regression tests on slow VMs.
+ upstream: extend sftp-common.c:extend ls_file() to support supplied
+
+ user/group names; ok markus@
+
+ OpenBSD-Commit-ID: c70c70498b1fdcf158531117e405b6245863bfb0
-commit f67e47903977b42cb6abcd5565a61bd7293e4dc3
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 1 23:21:06 2022 +1100
+commit 74b77f7497dba3a58315c8f308883de448078057
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Sep 19 10:40:52 2022 +0000
- Increase test timeout to allow slow VMs to finish
+ upstream: sftp-server(8): add a "users-groups-by-id@openssh.com"
+
+ extension request that allows the client to obtain user/group names that
+ correspond to a set of uids/gids.
+
+ Will be used to make directory listings more useful and consistent
+ in sftp(1).
+
+ ok markus@
+
+ OpenBSD-Commit-ID: 7ebabde0bcb95ef949c4840fe89e697e30df47d3
-commit 02488c1b54065ddc4f25835dbd2618b2a2fe21f5
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 1 16:27:38 2022 +1100
+commit 231a346c0c67cc7ca098360f9a554fa7d4f1eddb
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Sep 19 08:49:50 2022 +0000
- Use bash or ksh if available for SH in Makefile.
+ upstream: better debugging for connect_next()
+
+ OpenBSD-Commit-ID: d16a307a0711499c971807f324484ed3a6036640
-commit 34c7018c316af4773e432066de28d0ef9d0888cd
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 1 14:56:54 2022 +1100
+commit 1875042c52a3b950ae5963c9ca3774a4cc7f0380
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Sep 17 10:34:29 2022 +0000
- Set Makefile SHELL as determined by configure.
+ upstream: Add RequiredRSASize for sshd(8); RSA keys that fall
- This should improve compatibility for users with non-POSIX shells. If
- using Makefile.in directly (eg make -f Makefile.in distprep) then SHELL
- will need to be specified on the command line (along with MANFMT in that
- particular case). ok djm@
+ beneath this limit will be ignored for user and host-based authentication.
+
+ Feedback deraadt@ ok markus@
+
+ OpenBSD-Commit-ID: 187931dfc19d51873df5930a04f2d972adf1f7f1
-commit 5b054d76402faab38c48377efd112426469553a0
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 1 13:16:47 2022 +1100
+commit 54b333d12e55e6560b328c737d514ff3511f1afd
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Sep 17 10:33:18 2022 +0000
- Skip slow tests on (very) slow test targets.
+ upstream: add a RequiredRSASize for checking RSA key length in
+
+ ssh(1). User authentication keys that fall beneath this limit will be
+ ignored. If a host presents a host key beneath this limit then the connection
+ will be terminated (unfortunately there are no fallbacks in the protocol for
+ host authentication).
+
+ feedback deraadt, Dmitry Belyavskiy; ok markus@
+
+ OpenBSD-Commit-ID: 430e339b2a79fa9ecc63f2837b06fdd88a7da13a
-commit b275818065b31a865142c48c2acf6a7c1655c542
-Author: Damien Miller <djm@mindrot.org>
-Date: Thu Mar 31 14:11:36 2022 +1100
+commit 07d8771bacfefbcfb37fa8a6dc6103bcc097e0ab
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Sep 17 10:30:45 2022 +0000
- depend
+ upstream: Add a sshkey_check_rsa_length() call for checking the
+
+ length of an RSA key; ok markus@
+
+ OpenBSD-Commit-ID: de77cd5b11594297eda82edc594b0d32b8535134
-commit 3fa539c3ffaabd6211995512d33e29150f88c5c5
+commit 3991a0cf947cf3ae0f0373bcec5a90e86a7152f5
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Mar 31 03:07:03 2022 +0000
+Date: Sat Sep 17 10:11:29 2022 +0000
- upstream: add a sftp client "cp" command that supports server-side
+ upstream: actually hook up restrict_websafe; the command-line flag
- copying of files. Useful for this task and for testing the copy-data
- extension. Patch from Mike Frysinger; ok dtucker@
+ was never actually used. Spotted by Matthew Garrett
- OpenBSD-Commit-ID: 1bb1b950af0d49f0d5425b1f267e197aa1b57444
+ OpenBSD-Commit-ID: 0b363518ac4c2819dbaa3dfad4028633ab9cdff1
-commit 7988bfc4b701c4b3fe9b36c8561a3d1c5d4c9a74
+commit 30b2a7e4291fb9e357f80a237931ff008d686d3b
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Mar 31 03:05:49 2022 +0000
+Date: Fri Sep 16 06:55:37 2022 +0000
- upstream: add support for the "corp-data" protocol extension to
-
- allow server-side copies to be performed without having to go via the client.
- Patch by Mike Frysinger, ok dtucker@
+ upstream: correct error value
- OpenBSD-Commit-ID: 00aa510940fedd66dab1843b58682de4eb7156d5
+ OpenBSD-Commit-ID: 780efcbad76281f11f14b2a5ff04eb6db3dfdad4
-commit 32dc1c29a4ac9c592ddfef0a4895eb36c1f567ba
+commit ac1ec9545947d9f9657259f55d04cb49d3a94c8a
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Mar 30 21:13:23 2022 +0000
+Date: Fri Sep 16 03:33:14 2022 +0000
- upstream: select post-quantum KEX
+ upstream: sftp: Be a bit more clever about completions
- sntrup761x25519-sha512@openssh.com as the default; ok markus@
+ There are commands (e.g. "get" or "put") that accept two
+ arguments, a local path and a remote path. However, the way
+ current completion is written doesn't take this distinction into
+ account and always completes remote or local paths.
- OpenBSD-Commit-ID: f02d99cbfce22dffec2e2ab1b60905fbddf48fb9
+ By expanding CMD struct and "cmds" array this distinction can be
+ reflected and with small adjustment to completer code the correct
+ path can be completed.
+
+ By Michal Privoznik, ok dtucker@
+
+ OpenBSD-Commit-ID: 1396d921c4eb1befd531f5c4a8ab47e7a74b610b
-commit d6556de1db0822c76ba2745cf5c097d9472adf7c
+commit 590db83384f9d99fc51c84505792d26d1ef60df9
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Mar 30 21:10:25 2022 +0000
+Date: Fri Sep 16 03:13:34 2022 +0000
- upstream: fix poll() spin when a channel's output fd closes without
+ upstream: sftp: Don't attempt to complete arguments for
- data in the channel buffer. Introduce more exact packing of channel fds into
- the pollfd array. fixes bz3405 and bz3411; ok deraadt@ markus@
+ non-existent commands
- OpenBSD-Commit-ID: 06740737849c9047785622ad5d472cb6a3907d10
+ If user entered a non-existent command (e.g. because they made a
+ typo) there is no point in trying to complete its arguments. Skip
+ calling complete_match() if that's the case.
+
+ From Michal Privoznik
+
+ OpenBSD-Commit-ID: cf39c811a68cde2aeb98fc85addea4000ef6b07a
-commit 8a74a96d25ca4d32fbf298f6c0ac5a148501777d
+commit ff9809fdfd1d9a91067bb14a77d176002edb153c
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Mar 30 04:33:09 2022 +0000
+Date: Wed Sep 14 00:14:37 2022 +0000
- upstream: ssh is almost out of getopt() characters; note the
+ upstream: sk_enroll: never drop SSH_SK_USER_VERIFICATION_REQD flag
- remaining remaining available ones in a comment
+ from response
- OpenBSD-Commit-ID: 48d38cef59d6bc8e84c6c066f6d601875d3253fd
+ Now that all FIDO signing calls attempt first without PIN and then
+ fall back to trying PIN only if that attempt fails, we can remove the
+ hack^wtrick that removed the UV flag from the keys returned during
+ enroll.
+
+ By Corinna Vinschen
+
+ OpenBSD-Commit-ID: 684517608c8491503bf80cd175425f0178d91d7f
-commit 6d4fc51adb9d8a42f67b5474f02f877422379de6
+commit 940dc10729cb5a95b7ee82c10184e2b9621c8a1d
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Mar 30 04:27:51 2022 +0000
+Date: Wed Sep 14 00:13:13 2022 +0000
- upstream: avoid NULL deref via ssh-keygen -Y find-principals.
+ upstream: a little extra debugging
- bz3409, reported by Mateusz Adamowski
+ OpenBSD-Commit-ID: edf1601c1d0905f6da4c713f4d9cecc7d1c0295a
+
+commit 4b5f91cb959358141181b934156513fcb8a6c1e3
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Sep 14 00:02:03 2022 +0000
+
+ upstream: ssh-agent: attempt FIDO key signing without PIN and use
- OpenBSD-Commit-ID: a3b2c02438052ee858e0ee18e5a288586b5df2c5
+ the error to determine whether a PIN is required and prompt only if
+ necessary. from Corinna Vinschen
+
+ OpenBSD-Commit-ID: dd6be6a0b7148608e834ee737c3479b3270b00dd
-commit e937514920335b92b543fd9be79cd6481d1eb0b6
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Mar 28 17:51:03 2022 +1100
+commit 113523bf0bc33600b07ebb083572c8c346b6fdf4
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Sun Sep 11 06:38:11 2022 +0000
- Add AIX 5.1 test target.
+ upstream: .Li -> .Vt where appropriate; from josiah frentsos,
+
+ tweaked by schwarze
+
+ ok schwarze
+
+ OpenBSD-Commit-ID: 565046e3ce68b46c2f440a93d67c2a92726de8ed
-commit 4bbe815ba974b4fd89cc3fc3e3ef1be847a0befe
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Mar 26 22:01:31 2022 +1100
+commit 86af013b56cecb5ee58ae0bd9d495cd586fc5918
+Author: jsg@openbsd.org <jsg@openbsd.org>
+Date: Sat Sep 10 08:50:53 2022 +0000
- Drop leading "v" from release version identifier.
+ upstream: fix repeated words ok miod@ jmc@
- It's present in the git tags but not in the release tarball names.
- Also drop extra "/" from URL path.
+ OpenBSD-Commit-ID: 6765daefe26a6b648cc15cadbbe337596af709b7
-commit f5cdd3b3c275dffaebfca91df782dca29975e9ac
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Mar 26 16:28:04 2022 +1100
+commit 0ba39b93b326a7d5dfab776cc9b9d326161a9b16
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Sep 9 03:31:42 2022 +0000
- Use tarballs when testing LibreSSL releases.
+ upstream: notifier_complete(NULL, ...) is a noop, so no need to test
- This means they'll still work when the combination of -portable and
- openbsd github repos no longer match.
+ that ctx!=NULL; from Corinna Vinschen
+
+ OpenBSD-Commit-ID: ade2f2e9cc519d01a586800c25621d910bce384a
-commit 24dc37d198f35a7cf71bf4d5384363c7ef4209d4
+commit be197635329feb839865fdc738e34e24afd1fca8
+Author: Sam James <sam@gentoo.org>
+Date: Thu Sep 8 02:49:29 2022 +0100
+
+ openbsd-compat/bsd-asprintf: add <stdio.h> include for vsnprintf
+
+ Fixes the following build failure with Clang 15 on musl:
+ ```
+ bsd-asprintf.c:51:8: error: call to undeclared library function 'vsnprintf' with type 'int (char *, unsigned long, const char *, struct __va_list_tag *)'; ISO C99 and laterclang -O2 -pipe -fdiagnostics-color=always -frecord-gcc-switches -pipe -Wunknown-warning-option -Qunused-arguments -Wall -Wpointer-arith -Wuninitialized -Wsign-compare -Wformat-security -Wsizeof-pointer-memaccess -Wno-pointer-sign -Wno-unused-result -Wmisleading-indentation -Wbitwise-instead-of-logical -fno-strict-aliasing -mretpoline -ftrapv -fzero-call-used-regs=all -fno-builtin-memset -fstack-protector-strong -fPIE -I. -I. -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_DEFAULT_SOURCE -DSSHDIR=\"/etc/ssh\" -D_PATH_SSH_PROGRAM=\"/usr/bin/ssh\" -D_PATH_SSH_ASKPASS_DEFAULT=\"/usr/lib/misc/ssh-askpass\" -D_PATH_SFTP_SERVER=\"/usr/lib/misc/sftp-server\" -D_PATH_SSH_KEY_SIGN=\"/usr/lib/misc/ssh-keysign\" -D_PATH_SSH_PKCS11_HELPER=\"/usr/lib/misc/ssh-pkcs11-helper\" -D_PATH_SSH_SK_HELPER=\"/usr/lib/misc/ssh-sk-helper\" -D_PATH_SSH_PIDDIR=\"/run\" -D_PATH_PRIVSEP_CHROOT_DIR=\"/var/empty\" -DHAVE_CONFIG_H -c cipher-aes.c -o cipher-aes.o
+ do not support
+ implicit function declarations [-Wimplicit-function-declaration]
+ ret = vsnprintf(string, INIT_SZ, fmt, ap2);
+ ^
+ bsd-asprintf.c:51:8: note: include the header <stdio.h> or explicitly provide a declaration for 'vsnprintf'
+ 1 error generated.
+ ```
+
+commit 6cb6f660bb35f77a0456dd2581ddf39c29398a5e
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Mar 26 15:02:45 2022 +1100
+Date: Fri Sep 2 16:43:27 2022 +1000
- Remove now-unused passwd variable.
+ Remove DEF_WEAK, it's already in defines.h.
-commit 5b467ceef2c356f0a77f5e8ab4eb0fac367e4d24
+commit ce39e7d8b70c4726defde5d3bc4cb7d40d131153
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Mar 26 13:15:44 2022 +1100
+Date: Fri Sep 2 14:28:14 2022 +1000
- Missing semicolon.
+ Resync arc4random with OpenBSD.
+
+ This brings us up to current, including djm's random-reseeding change,
+ as prompted by logan at cyberstorm.mu in bz#3467. It brings the
+ platform-specific hooks from LibreSSL Portable, simplified to match our
+ use case. ok djm@.
-commit 2923d026e55998133c0f6e5186dca2a3c0fa5ff5
+commit beaddde26f30e2195b8aa4f3193970e140e17305
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Mar 26 12:49:50 2022 +1100
+Date: Fri Sep 2 14:20:04 2022 +1000
- Factor out platform-specific locked account check.
+ Move OPENBSD ORIGINAL marker.
- Also fixes an incorrect free on platforms with both libiaf and shadow
- passwords (probably only Unixware). Prompted by github PR#284,
- originally from @c3h2_ctf and stoeckmann@.
+ Putting this after the copyright statement (which doesn't change)
+ instead of before the version identifier (which does) prevents merge
+ conflicts when resyncing changes.
-commit d23efe4b12886ffe416be10bc0a7da6ca8aa72d1
+commit c83e467ead67a8cb48ef4bec8085d6fb880a2ff4
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Mar 26 08:13:46 2022 +1100
+Date: Fri Sep 2 14:17:28 2022 +1000
- Add OpenWRT mips and mipsel test targets.
+ Remove arc4random_uniform from arc4random.c
+
+ This was previously moved into its own file (matching OpenBSD) which
+ prematurely committed in commit 73541f2.
-commit 16ea8b85838dd7a4dbeba4e51ac4f43fd68b1e5b
+commit 5f45c2395c60865e59fa44152ff1d003a128c5bc
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Mar 20 08:52:17 2022 +0000
+Date: Fri Sep 2 04:20:02 2022 +0000
- upstream: don't leak argument list; bz3404, reported by Balu
+ upstream: sk-usbhid: fix key_lookup() on tokens with built-in UV
- Gajjala ok dtucker@
+ explicitly test whether the token performs built-in UV (e.g. biometric
+ tokens) and enable UV in that case. From Pedro Martelletto via GHPR#388
- OpenBSD-Commit-ID: fddc32d74e5dd5cff1a49ddd6297b0867eae56a6
+ OpenBSD-Commit-ID: 007eb7e387d27cf3029ab06b88224e03eca62ccd
-commit a72bde294fe0518c9a44ba63864093a1ef2425e3
+commit 03277a4aa49b80af541a3e691f264c0c0d8f9cec
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Aug 31 20:26:30 2022 +1000
+
+ Move sftp from valgrind-2 to 3 to rebalance.
+
+commit fcf5365da69c516817321ba89c3a91df98d098df
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Mar 20 08:51:21 2022 +0000
+Date: Wed Aug 31 02:56:40 2022 +0000
- upstream: make addargs() and replacearg() a little more robust and
+ upstream: whitespace
- improve error reporting
+ OpenBSD-Commit-ID: c2bcbf93610d3d62ed206cdf9bf9ff98c6aaf232
+
+commit e60136a3d7a223dd8e84ba8a6895bc3142360993
+Author: Damien Miller <djm@mindrot.org>
+Date: Mon Aug 29 13:27:45 2022 +1000
+
+ additional keys
+
+commit 2b02dcb505288c462d1b5dd1ac04e603d01340eb
+Author: Damien Miller <djm@mindrot.org>
+Date: Mon Aug 29 13:23:43 2022 +1000
+
+ cross-sign allowed_signers with PGP key
- make freeargs(NULL) a noop like the other free functions
+ Provides continuity of trust from legacy PGP release key to
+ the SSHSIG signing keys that we will use henceforth for git
+ signing.
+
+commit 51b345f177ae981b8755f6bdf8358b1cc5e83d67
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Aug 27 21:49:27 2022 +1000
+
+ Add libcrypt-devel to cygwin-release deps.
- ok dtucker as part of bz3403
+ Based on feedback from vinschen at redhat.com.
+
+commit 9f81736cf16dd8dda1c8942f1973a5f80b8cd78c
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Aug 27 09:37:40 2022 +1000
+
+ Add Windows 2022 test targets.
+
+commit 85e1a69243f12be8520438ad6a3cfdc0b7fcbb2d
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Aug 26 16:26:06 2022 +1000
+
+ Add cygwin-release test target.
- OpenBSD-Commit-ID: 15f86da83176978b4d1d288caa24c766dfa2983d
+ This also moves the cygwin package install from the workflow file to
+ setup_ci.sh so that we can install different sets of Cygwin packages
+ for different test configs.
-commit 731087d2619fa7f01e675b23f57af10d745e8af2
+commit 92382dbe8bf9ea1225b16858f9b9b208c15c7e8d
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Mar 18 04:04:11 2022 +0000
+Date: Fri Aug 26 08:16:27 2022 +0000
- upstream: don't try to resolve ListenAddress directives in the sshd
-
- re-exec path - we're never going to use the result and if the operation fails
- then it can prevent connections from being accepted. Reported by Aaron
- Poffenberger; with / ok dtucker@
+ upstream: whitespace
- OpenBSD-Commit-ID: 44c53a43909a328e2f5ab26070fdef3594eded60
+ OpenBSD-Commit-ID: a5d015efbfd228dc598ffdef612d2da3a579e5d8
-commit 1c83c082128694ddd11ac05fdf31d70312ff1763
+commit 70a5de0a50e84d7250eb4e4537f765599f64c4af
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Mar 18 02:50:21 2022 +0000
+Date: Fri Aug 26 08:12:56 2022 +0000
- upstream: remove blank line
+ upstream: whitespace
- OpenBSD-Commit-ID: d5e0182965b2fbfb03ad5f256d1a1ce5706bcddf
+ OpenBSD-Commit-ID: d297e4387935d4aef091c5e9432578c2e513f538
-commit 807be68684da7a1fe969c399ddce2fafb7997dcb
+commit 3a683a19fd116ea15ebf8aa13d02646cceb302a9
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Aug 26 14:23:55 2022 +1000
+
+ initial list of allowed signers
+
+commit 6851f4b8c3fc1b3e1114c56106e4dc31369c8513
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Aug 19 17:22:18 2022 +1000
+
+ Install Cygwin packages based on OS not config.
+
+commit f96480906893ed93665df8cdf9065865c51c1475
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Mar 18 02:32:22 2022 +0000
+Date: Fri Aug 19 06:07:47 2022 +0000
- upstream: helpful comment
+ upstream: attemp FIDO key signing without PIN and use the error
- OpenBSD-Commit-ID: e3315a45cb04e7feeb614d76ec80a9fe4ca0e8c7
+ code returned to fall back only if necessary. Avoids PIN prompts for FIDO
+ tokens that don't require them; part of GHPR#302
+
+ OpenBSD-Commit-ID: 4f752aaf9f2e7c28bcaaf3d4f8fc290131bd038e
-commit a0b5816f8f1f645acdf74f7bc11b34455ec30bac
+commit 5453333b5d28e313284cb9aae82899704103f98d
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Mar 18 02:31:25 2022 +0000
+Date: Fri Aug 19 05:53:28 2022 +0000
- upstream: ssh-keygen -Y check-novalidate requires namespace or SEGV
+ upstream: remove incorrect check that can break enrolling a
- will ensue. Patch from Mateusz Adamowski via GHPR#307
+ resident key (introduced in r1.40)
- OpenBSD-Commit-ID: 99e8ec38f9feb38bce6de240335be34aedeba5fd
+ OpenBSD-Commit-ID: 4cab364d518470e29e624af3d3f9ffa9c92b6f01
-commit 5a252d54a63be30d5ba4be76210942d754a531c0
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Mar 15 05:27:37 2022 +0000
+commit ff89b1bed80721295555bd083b173247a9c0484e
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Aug 19 04:02:46 2022 +0000
- upstream: improve DEBUG_CHANNEL_POLL debugging message
+ upstream: Strictly enforce the maximum allowed SSH2 banner size in
- OpenBSD-Commit-ID: 2275eb7bc4707d019b1a0194b9c92c0b78da848f
+ ssh-keyscan and prevent a one-byte buffer overflow. Patch from Qualys, ok
+ djm@
+
+ OpenBSD-Commit-ID: 6ae664f9f4db6e8a0589425f74cd0bbf3aeef4e4
-commit ce324cf58ba2840e31afeb996935800780c8fa4b
-Author: cheloha@openbsd.org <cheloha@openbsd.org>
-Date: Sun Mar 13 23:27:54 2022 +0000
+commit 1b470b9036639cef4f32fb303bb35ea0b711178d
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Aug 19 15:18:09 2022 +1000
- upstream: ssh: xstrdup(): use memcpy(3)
-
- Copying the given string into the buffer with strlcpy(3) confers no
- benefit in this context because we have already determined the
- string's length with strlen(3) in order to allocate that buffer.
-
- Thread: https://marc.info/?l=openbsd-tech&m=164687525802691&w=2
-
- ok dtucker@ millert@
-
- OpenBSD-Commit-ID: f8bfc082e36e2d2dc4e1feece02fe274155ca11a
+ Fix cygwin conditional steps.
-commit 2893c5e764557f48f9d6a929e224ed49c59545db
+commit fd6ee741ab16714b7035d60aca924123ba28135a
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Mar 11 18:43:58 2022 +1100
+Date: Fri Aug 19 15:12:57 2022 +1000
- Resync fmt_scaled. with OpenBSD.
-
- Fixes underflow reported in bz#3401.
+ Add a bit more debug output.
-commit 5ae31a0fdd27855af29f48ff027491629fff5979
+commit a9305c4c739f4d91a3d3a92c0b6d4949404a36c5
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Mar 9 09:41:56 2022 +1100
+Date: Fri Aug 12 15:08:47 2022 +1000
- Provide killpg implementation.
+ Add Cygwin (on windows-2019) test target.
- Based on github PR#301 for Tandem NonStop.
+ In addition to installing the requisite Cygwin packages, we also need to
+ explicitly invoke "sh" for steps that run other scripts since the runner
+ environment doesn't understand #! paths.
-commit c41c84b439f4cd74d4fe44298a4b4037ddd7d2ae
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Mar 9 09:29:30 2022 +1100
+commit 5062ad48814b06162511c4f5924a33d97b6b2566
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Aug 19 03:06:30 2022 +0000
- Check for missing ftruncate prototype.
+ upstream: double free() in error path; from Eusgor via GHPR333
- From github PR#301 in conjunction with rsbeckerca.
+ OpenBSD-Commit-ID: 39f35e16ba878c8d02b4d01d8826d9b321be26d4
-commit 8cf5275452a950869cb90eeac7d220b01f77b12e
+commit 5a5c580b48fc6006bdfa731fc2f6d4945c2c0e4e
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Mar 8 20:04:06 2022 +1100
+Date: Thu Aug 18 21:36:39 2022 +1000
- Default to not using sandbox when cross compiling.
+ Check for perms to run agent-getpeereid test.
- On most systems poll(2) does not work when the number of FDs is reduced
- with setrlimit, so assume it doesn't when cross compiling and we can't
- run the test. bz#3398.
+ Ubuntu 22.04 defaults to private home dirs which prevents "nobody"
+ running ssh-add during the agent-getpeereid test. Check for this and
+ add the necessary permissions.
-commit 379b30120da53d7c84aa8299c26b18c51c2a0dac
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Mar 1 01:59:19 2022 +0000
+commit cd06a76b7ccc706e2bb4f1cc4aa9e9796a28a812
+Author: Damien Miller <djm@mindrot.org>
+Date: Wed Aug 17 16:04:16 2022 +1000
- upstream: pack pollfd array before server_accept_loop() ppoll()
+ on Cygwin, prefer WinHello FIDO device
- call, and terminate sshd if ppoll() returns errno==EINVAL
+ If no FIDO device was explictly specified, then prefer the
+ windows://hello FIDO device. An exception to this is when
+ probing resident FIDO keys, in which case hardware FIDO
+ devices are preferred.
+
+commit 47f72f534ac5cc2cd3027675a3df7b00a8f77575
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Aug 17 06:01:57 2022 +0000
+
+ upstream: add an extra flag to sk_probe() to indicate whether we're
- avoids spin in ppoll when MaxStartups > RLIMIT_NOFILE, reported by
- Daniel Micay
+ probing for a FIDO resident key or not. Unused here, but will make like
+ easier for portable
- feedback/ok deraadt
+ OpenBSD-Commit-ID: 432c8ff70e270378df9dbceb9bdeaa5b43b5a832
+
+commit edb0bcb3c79b16031dc87a8e57aecc3c4a3414f0
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Tue Aug 16 20:24:08 2022 +0000
+
+ upstream: use .Cm for "sign"; from josiah frentsos
- OpenBSD-Commit-ID: dbab1c24993ac977ec24d83283b8b7528f7c2c15
+ OpenBSD-Commit-ID: 7f80a53d54857ac6ae49ea6ad93c5bd12231d1e4
-commit eceafbe0bdbbd9bd2f3cf024ccb350666a9934dd
-Author: naddy@openbsd.org <naddy@openbsd.org>
-Date: Sun Feb 27 01:33:59 2022 +0000
+commit cccb011e130cbbac538b1689d10e4a067298df8b
+Author: Corinna Vinschen <vinschen@redhat.com>
+Date: Thu Aug 11 20:19:35 2022 +0200
- upstream: include rejected signature algorithm in error message and
+ Revert "check_sk_options: add temporary WinHello workaround"
- not the (useless) key type; ok djm@
+ Cygwin now comes with libfido2 1.11.0, so this workaround
+ isn't required anymore.
- OpenBSD-Commit-ID: d0c0f552a4d9161203e07e95d58a76eb602a76ff
+ This reverts commit 242c044ab111a37aad3b0775727c36a4c5f0102c.
+
+ Signed-off-by: Corinna Vinschen <vinschen@redhat.com>
-commit f2f3269423618a83157e18902385e720f9776007
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Feb 25 09:46:24 2022 +0000
+commit 9468cd7cf9d989dfa2ac20e2a0268ba6e93bfa5a
+Author: Corinna Vinschen <vinschen@redhat.com>
+Date: Thu Aug 11 20:18:17 2022 +0200
- upstream: Remove the char * casts from arguments to do_lstat,
+ fido_dev_is_winhello: return 0, not "false"
- do_readdir and do_stat paths since the underlying functions now take a const
- char *. Patch from vapier at gentoo.org.
+ "false" is not used anywhere in OpenSSH, so return 0 like
+ everywhere else.
- OpenBSD-Commit-ID: 9e4d964dbfb0ed683a2a2900711b88e7f1c0297b
+ Signed-off-by: Corinna Vinschen <vinschen@redhat.com>
-commit 4a66dac052c5ff5047161853f36904607649e4f9
+commit 730a80609472ee0451c99482d75c9c41f3ebc42d
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Feb 25 02:09:27 2022 +0000
+Date: Fri Aug 12 05:20:28 2022 +0000
- upstream: save an unneccessary alloc/free, based on patch from
+ upstream: sftp-server: support home-directory request
- Martin Vahlensieck; ok dtucker@
+ Add support to the sftp-server for the home-directory extension defined
+ in draft-ietf-secsh-filexfer-extensions-00. This overlaps a bit with the
+ existing expand-path@openssh.com, but uses a more official protocol name,
+ and so is a bit more likely to be implemented by non-OpenSSH clients.
- OpenBSD-Commit-ID: 90ffbf1f837e509742f2c31a1fbf2c0fd376fd5f
+ From Mike Frysinger, ok dtucker@
+
+ OpenBSD-Commit-ID: bfc580d05cc0c817831ae7ecbac4a481c23566ab
-commit 6f117cb151efe138ac57bdd8e26165f350328f5f
+commit 5e820bf79ce3ce99ef7e98b0ab642b0a0a4f396c
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Mar 1 09:02:06 2022 +1100
+Date: Fri Aug 12 14:56:55 2022 +1000
- Remove unused ivbits argument from chacha_keysetup
+ Replace deprecated ubuntu-18.04 runners with 22.04
-commit 15974235dd528aeab0ec67fb92a0a1d733f62be2
+commit 87b0d9c1b789d3ff958ec45df2ac912e24461bae
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Mar 1 09:00:20 2022 +1100
+Date: Thu Aug 11 22:48:23 2022 +1000
- Add OPENBSD ORIGINAL marker.
+ Add a timegm implementation from Heimdal via Samba.
+
+ Fixes build on (at least Solaris 10).
-commit f2ff669347d320532e7c1b63cdf5c62f46e73150
+commit d0c4fa58594577994921b593f10037c5282597ca
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Feb 28 22:21:36 2022 +1100
+Date: Thu Aug 11 14:23:58 2022 +1000
- No unused param warnings for clang-12 and gcc-11.
-
- These have too many false positives in -Werror tests on the github CI
- since we often provide empty stub functions for functionality not needed
- for particular configurations.
+ Rerun tests if any .github config file changes.
-commit 96558ecd87adac62efa9a2b5479f686ab86b0be1
+commit 113fe6c77ab43769fc61e953d07cb619fd7ea54b
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Feb 26 14:10:41 2022 +1100
+Date: Thu Aug 11 13:33:51 2022 +1000
- Add debian-i386 test target.
+ Skip hostbased during Valgrind tests.
+
+ Valgrind doesn't let ssh exec ssh-keysign (because it's setuid) so skip
+ it during the Valgrind based tests.
+
+ See https://bugs.kde.org/show_bug.cgi?id=119404 for a discussion of this
+ (ironically there the problematic binary was ssh(1) back when it could
+ still be setuid).
-commit 284b6e5394652d519e31782e3b3cdfd7b21d1a81
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Feb 26 14:06:14 2022 +1100
+commit b98a42afb69d60891eb0488935990df6ee571c4d
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Aug 11 01:57:50 2022 +0000
- Allow ppoll_time64 in seccomp sandbox.
+ upstream: add some tests for parse_absolute_time(), including cases
- Should fix sandbox violations on (some? at least i386 and armhf) 32bit
- Linux platforms. Patch from chutzpahu at gentoo.org and cjwatson at
- debian.org via bz#3396.
+ where it is forced to the UTC timezone. bz3468 ok dtucker
+
+ OpenBSD-Regress-ID: ea07ca31c2f3847a38df028ca632763ae44e8759
-commit 0132056efabc5edb85c3c7105d2fb6dee41843c6
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 25 19:47:48 2022 +1100
+commit ec1ddb72a146fd66d18df9cd423517453a5d8044
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Aug 11 01:56:51 2022 +0000
- Improve handling of _getshort and _getlong.
+ upstream: allow certificate validity intervals, sshsig verification
- If the system native ones are exactly as required then use them,
- otherwise use the local versions mapped to another name to prevent
- name collisions.
+ times and authorized_keys expiry-time options to accept dates in the UTC time
+ zone in addition to the default of interpreting them in the system time zone.
+ YYYYMMDD and YYMMDDHHMM[SS] dates/times will be interpreted as UTC if
+ suffixed with a 'Z' character.
+
+ Also allow certificate validity intervals to be specified in raw
+ seconds-since-epoch as hex value, e.g. -V 0x1234:0x4567890. This
+ is intended for use by regress tests and other tools that call
+ ssh-keygen as part of a CA workflow.
+
+ bz3468 ok dtucker
+
+ OpenBSD-Commit-ID: 454db1cdffa9fa346aea5211223a2ce0588dfe13
-commit 8e206e0dd6b9f757b07979e48f53ad5bf9b7b52b
+commit 4df246ec75751da7eb925e1880498300d8bda187
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 25 15:14:22 2022 +1100
+Date: Thu Aug 11 10:23:55 2022 +1000
- Constify utimes in compat library to match specs.
-
- Patch from vapier at chromium.org.
+ Fix conditional for running hostbased tests.
-commit 1b2920e3b63db2eddebeec7330ffe8b723055573
+commit 2580916e48721802220c61ce9e0df1297c00bc07
+Author: Damien Miller <djm@mindrot.org>
+Date: Thu Aug 11 08:58:28 2022 +1000
+
+ fix SANDBOX_SECCOMP_FILTER_DEBUG
+
+commit fdbd5bf507fc271ff813714fab8a72ff2c6cb5ca
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 25 13:50:56 2022 +1100
+Date: Wed Aug 10 17:35:52 2022 +1000
- ANSIfy getshort and getlong.
-
- These functions appear to have come from OpenBSD's lib/libc/net/res_comp.c
- which made this change in 2005.
+ Test hostbased auth on github runners.
-commit 54a86f4f6e1c43a2ca2be23ef799ab8910d4af70
+commit 7e2f51940ba48a1c0fae1107801ea643fa83c971
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 25 13:23:04 2022 +1100
+Date: Wed Aug 10 17:25:24 2022 +1000
- Use PICFLAG instead of hard coding -fPIC.
+ Rename our getentropy to prevent possible loops.
+
+ Since arc4random seeds from getentropy, and we use OpenSSL for that
+ if enabled, there's the possibility that if we build on a system that
+ does not have getentropy then run on a system that does have it, then
+ OpenSSL could end up calling our getentropy and getting stuck in a loop.
+ Pointed out by deraadt@, ok djm@
-commit 3016ba47035ac3561aabd48e2be70167fe157d6a
+commit 7a01f61be8d0aca0e975e7417f26371495fe7674
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 25 11:37:11 2022 +1100
+Date: Mon Aug 8 12:17:04 2022 +1000
- Add tests for latest releases of {Libre,Open}SSL.
+ Actually put HAVE_STDINT_H around the stdint.h.
-commit f107467179428a0e3ea9e4aa9738ac12ff02822d
-Author: Colin Watson <cjwatson@debian.org>
-Date: Thu Feb 24 16:04:18 2022 +0000
+commit 73541f29f0b50480da6c20dceb7a7191bd8ea7d3
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Aug 8 10:30:34 2022 +1000
- Improve detection of -fzero-call-used-regs=all support
+ Give unused param a name.
- GCC doesn't tell us whether this option is supported unless it runs into
- the situation where it would need to emit corresponding code.
+ Fixes builds on platforms that do have fido2 but don't have
+ fido_dev_is_winhello.
-commit 3383b2cac0e9275bc93c4b4760e6e048f537e1d6
+commit 2a108c0ea960381bd9b14ee0d84e818a23df4482
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Feb 23 21:21:49 2022 +0000
+Date: Fri Aug 5 05:01:40 2022 +0000
- upstream: free(3) wants stdlib.h
+ upstream: don't prompt for FIDO passphrase before attempting to enroll
- OpenBSD-Commit-ID: 227a8c70a95b4428c49e46863c9ef4bd318a3b8a
+ the credential, just let the enroll operating fail and we'll attempt to get a
+ PIN anyway. Might avoid some unneccessary PIN prompts.
+
+ Part of GHPR#302 from Corinna Vinschen; ok dtucker@
+
+ OpenBSD-Commit-ID: bd5342ffc353ee37d39617906867c305564d1ce2
-commit a4537e79ab4ac6db4493c5158744b9ebde5efcb0
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Feb 23 21:21:16 2022 +0000
+commit 2886975c0ad9244e60dc5e4be34fde3aa573a4b5
+Author: Corinna Vinschen <vinschen@redhat.com>
+Date: Fri Feb 11 14:33:41 2022 +0100
- upstream: put back the scp manpage changes for SFTP mode too
+ sk_sign: set FIDO2 uv attribute explicitely for WinHello
- OpenBSD-Commit-ID: 05dc53921f927e1b5e5694e1f3aa314549f2e768
+ WinHello via libfido2 performs user verification by default.
+ However, if we stick to that, there's no way to differentiate
+ between keys created with or without "-O verify-required".
+ Set FIDO2 uv attribute explicitely to FIDO_OPT_FALSE, then check
+ if user verification has been requested.
+
+ Signed-off-by: Corinna Vinschen <vinschen@redhat.com>
-commit 449bcb8403adfb9724805d02a51aea76046de185
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Wed Feb 23 19:01:00 2022 +0000
+commit 242c044ab111a37aad3b0775727c36a4c5f0102c
+Author: Corinna Vinschen <vinschen@redhat.com>
+Date: Tue Feb 15 11:28:08 2022 +0100
- upstream: and we go back to testing sftp-scp after the 8.9
+ check_sk_options: add temporary WinHello workaround
- release...
+ Up to libfido 1.10.0, WinHello advertises "clientPin" rather
+ than "uv" capability. This is fixed in 1.11.0. For the time
+ being, workaround it here.
- OpenBSD-Commit-ID: a80440168258adca543a4607b871327a279c569c
+ Signed-off-by: Corinna Vinschen <vinschen@redhat.com>
-commit 166456cedad3962b83b848b1e9caf80794831f0f
-Author: Damien Miller <djm@mindrot.org>
-Date: Wed Feb 23 22:31:11 2022 +1100
+commit 78774c08cc4b4997382975b0f414a86e06b6780c
+Author: Corinna Vinschen <vinschen@redhat.com>
+Date: Thu Feb 10 18:19:29 2022 +0100
- makedepend
+ compat code for fido_dev_is_winhello()
+
+ Signed-off-by: Corinna Vinschen <vinschen@redhat.com>
-commit 32ebaa0dbca5d0bb86e384e72bebc153f48413e4
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Feb 23 11:18:13 2022 +0000
+commit 3d3a932a019aedfb891e0779bb4990cd5008a390
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Aug 5 13:12:27 2022 +1000
- upstream: avoid integer overflow of auth attempts (harmless, caught
-
- by monitor)
+ Factor out getrnd() and rename to getentropy().
- OpenBSD-Commit-ID: 488ad570b003b21e0cd9e7a00349cfc1003b4d86
+ Factor out the arc4random seeding into its own file and change the
+ interface to match getentropy. Use native getentropy if available.
+ This will make it easier to resync OpenBSD changes to arc4random.
+ Prompted by bz#3467, ok djm@.
-commit 6e0258c64c901753df695e06498b26f9f4812ea6
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Feb 23 11:17:10 2022 +0000
+commit 9385d277b787403be9dfcb229cf372202496d2f3
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Aug 4 18:55:48 2022 +1000
- upstream: randomise the password used in fakepw
-
- OpenBSD-Commit-ID: 34e159f73b1fbf0a924a9c042d8d61edde293947
+ Include CHANNEL and FIDO2 libs in configure output
-commit bf114d6f0a9df0b8369823d9a0daa6c72b0c4cc9
+commit 141535b904b6fba01724444f38193a8599201f82
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Feb 23 11:15:57 2022 +0000
+Date: Mon Aug 1 11:09:26 2022 +0000
- upstream: use asprintf to construct .rhosts paths
+ upstream: avoid double-free in error path introduced in r1.70; report
- OpenBSD-Commit-ID: 8286e8d3d2c6ff916ff13d041d1713073f738a8b
+ and fix based on GHPR#332 by v-rzh ok dtucker@
+
+ OpenBSD-Commit-ID: 3d21aa127b1f37cfc5bdc21461db369a663a951f
-commit c07e154fbdc7285e9ec54e78d8a31f7325d43537
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Feb 23 11:07:09 2022 +0000
+commit dba7099ffcba3ca07b3946f017ba6a4c3158d9b1
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Jul 27 18:40:12 2022 +1000
- upstream: openssh-8.9
-
- OpenBSD-Commit-ID: 5c5f791c87c483cdab6d9266b43acdd9ca7bde0e
+ Remove deprecated MacOS 10.15 runners.
-commit bc16667b4a1c3cad7029304853c143a32ae04bd4
+commit 722a56439aa5972c830e4a9a724cf52aff4a950a
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Feb 22 15:29:22 2022 +1100
+Date: Wed Jul 27 18:31:14 2022 +1000
- Extend select+rlimit sanbox test to include poll.
-
- POSIX specifies that poll() shall fail if "nfds argument is greater
- than {OPEN_MAX}". The setrlimit sandbox sets this to effectively zero
- so this causes poll() to fail in the preauth privsep process.
+ Move stale-configure check as early as possible.
- This is likely the underlying cause for the previously observed similar
- behaviour of select() on plaforms where it is implement in userspace on
- top of poll().
+ We added a check in Makefile to catch the case where configure needs to
+ be rebuilt, however this did not happen until a build was attempted in
+ which case all of the work done by configure was wasted. Move this check
+ to the start of configure to catch it as early as possible. ok djm@
-commit 6520c488de95366be031d49287ed243620399e23
+commit 099d6b56288b421ba38531d26dc1bd6bb685e311
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Feb 22 13:08:59 2022 +1100
+Date: Fri Jul 22 10:47:19 2022 +1000
- Add Alpine Linux test VM.
+ Move libcrypto into CHANNELLIBS.
+
+ This will result in sftp, sftp-server and scp no longer being linked
+ against libcrypto. ok djm@
-commit a4b325a3fc82d11e0f5d61f62e7fde29415f7afb
+commit 1bdf86725b77733bb5f17c54888b88a10b2f6538
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Feb 22 12:27:07 2022 +1100
+Date: Fri Jul 22 10:45:47 2022 +1000
- Include sys/param.h if present.
+ Remove seed_rng calls from scp, sftp, sftp-server.
- Needed for howmany() on MUSL systems such as Alpine.
+ These binaries don't use OpenSSL's random functions. The next step
+ will be to stop linking them against libcrypto. ok djm@
-commit 5a102e9cb287a43bd7dfe594b775a89a8e94697c
+commit d73f77b8cb9b422f1ac4facee7890aa10ff2bc21
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Feb 22 12:25:52 2022 +1100
+Date: Fri Jul 22 09:51:51 2022 +1000
- Only include sys/poll.h if we don't have poll.h.
+ Group libcrypto and PRNGD checks together.
- Prevents warnings on MUSL based systems such as Alpine.
+ They're related more than the libcrypt or libiaf checks which are
+ currently between them. ok djm@
-commit 7c0d4ce911d5c58b6166b2db754a4e91f352adf5
-Author: Damien Miller <djm@mindrot.org>
-Date: Tue Feb 22 11:14:51 2022 +1100
+commit f117e372b3f42f2fbdb0a578d063b2609ab58e1f
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Jul 22 09:24:45 2022 +1000
- disable agent-restrict test on minix3
-
- Minix seems to have a platform-wide limit on the number of
- select(2) syscalls that can be concurrently issued. This test
- seems to exceed this limit.
+ Do not link scp, sftp and sftp-server w/ zlib.
- Refer to:
+ Some of our binaries (eg sftp, sftp-server, scp) do not interact with
+ the channels code and thus do use libraries such as zlib and libcrypto
+ although they are linked with them. This adds a CHANNELLIBS and starts
+ by moving zlib into it, which means the aformentioned binaries are no
+ longer linked against zlib. ok djm@
+
+commit 800c2483e68db38bd1566ff69677124be974aceb
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Jul 25 21:49:04 2022 +1000
+
+ Remove workarounds for OpenSSL missing AES-CTR.
- https://github.com/Stichting-MINIX-Research-Foundation/minix/blob/R3.3.0/minix/servers/vfs/select.c#L114
- https://github.com/Stichting-MINIX-Research-Foundation/minix/blob/R3.3.0/minix/servers/vfs/select.c#L30-L31
+ We have some compatibility hacks that were added to support OpenSSL
+ versions that do not support AES CTR mode. Since that time, however,
+ the minimum OpenSSL version that we support has moved to 1.0.1 which
+ *does* have CTR, so this is no longer needed. ok djm@
-commit 81d33d8e3cf7ea5ce3a5653c6102b623e019428a
+commit b7c56b65c12f51fe0dbae798d19c8f58224a5d95
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Feb 21 21:27:20 2022 +1100
+Date: Mon Jul 25 21:43:00 2022 +1000
- Skip agent-getpeereid when running as root.
+ Remove workarounds for OpenSSL missing AES-GCM.
+
+ We have some compatibility hacks that were added to support OpenSSL
+ versions that do not support AES GCM mode. Since that time, however,
+ the minimum OpenSSL version that we support has moved to 1.0.1 which
+ *does* have GCM, so this is no longer needed. ok djm@
-commit fbd772570a25436a33924d91c164d2b24021f010
+commit 5a4a9f7a968fbf92cc1eac519c65638e79ae9f1f
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sun Feb 20 03:47:26 2022 +0000
+Date: Mon Jul 25 07:12:45 2022 +0000
- upstream: Aproximate realpath on the expected output by deduping
+ upstream: Restore missing "!" in TEST_SSH_ELAPSED_TIMES test.
- leading slashes. Fixes test failure when user's home dir is / which is
- possible in some portable configurations.
-
- OpenBSD-Regress-ID: 53b8c53734f8893806961475c7106397f98d9f63
+ OpenBSD-Regress-ID: 38783f9676ec348c5a792caecee9a16e354b37b0
-commit 336685d223a59f893faeedf0a562e053fd84058e
+commit 0ff886be132299386cc29d87c2aa16ff68a1aa08
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sun Jul 24 23:29:10 2022 +0000
+
+ upstream: Test TEST_SSH_ELAPSED_TIMES for empty string not
+
+ executable. No-op on most platforms but should prevent warnings in -portable
+ on systems that don't have 'date %s'.
+
+ OpenBSD-Regress-ID: e39d79867b8065e33d0c5926fa1a31f85659d2a4
+
+commit f69319ad8ad1dd50f90bbcf5912e11cc8ed3e037
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sun Feb 20 13:30:52 2022 +1100
+Date: Sat Jul 23 14:38:22 2022 +1000
- Really move DSA to end of list.
+ Convert "have_prog" function into "which".
- In commit ad16a84e syncing from OpenBSD, RSA was accidentally moved to
- the end of the list instead of DSA. Spotted by andrew at fyfe.gb.net.
+ "which" and its behaviour is not standardized, so convert the existing
+ have_prog function into "which" so we can rely on it being available
+ and what its semantics are. Add a have_prog wrapper that maintains the
+ existing behaviour.
-commit 63bf4f49ed2fdf2da6f97136c9df0c8168546eb3
+commit ea7ecc2c3ae39fdf5c6ad97b7bc0b47a98847f43
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 18 12:12:21 2022 +1100
+Date: Sat Jul 23 14:36:38 2022 +1000
- Add test configs for MUSL C library.
+ Skip scp3 test if there's no scp on remote path.
+
+ scp -3 ends up using the scp that's in the remote path and will fail if
+ one is not available. Based on a patch from rapier at psc.edu.
-commit f7fc6a43f1173e8b2c38770bf6cee485a562d03b
+commit c46f6fed419167c1671e4227459e108036c760f8
Author: Damien Miller <djm@mindrot.org>
-Date: Thu Feb 17 22:54:19 2022 +1100
+Date: Wed Jul 20 13:39:14 2022 +1000
- minix needs BROKEN_POLL too; chokes on /dev/null
+ crank SSH_SK_VERSION_MAJOR in sk-dummy.so
-commit 667fec5d4fe4406745750a32f69b5d2e1a75e94b
+commit f208e3b9ffb5ee76cf9c95df7ff967adc7f51c7d
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Feb 17 10:58:27 2022 +0000
+Date: Wed Jul 20 03:33:22 2022 +0000
- upstream: check for EINTR/EAGAIN failures in the rfd fast-path; caught
+ upstream: ssh-keygen: fix touch prompt, pin retries;
- by dtucker's minix3 vm :) ok dtucker@
+ part of GHPR329 from Pedro Martelletto
- OpenBSD-Commit-ID: 2e2c895a3e82ef347aa6694394a76a438be91361
-
-commit 41417dbda9fb55a0af49a8236e3ef9d50d862644
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Feb 17 22:05:29 2022 +1100
-
- Comment hurd test, the VM is currently broken.
+ OpenBSD-Commit-ID: 75d1005bd2ef8f29fa834c90d2684e73556fffe8
-commit b2aee35a1f0dc798339b3fcf96136da71b7e3f6d
-Author: Damien Miller <djm@mindrot.org>
-Date: Thu Feb 17 21:15:16 2022 +1100
+commit 8638a2ce7e90c8a51d9af3143404282126c524f8
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Jul 20 03:31:42 2022 +0000
- find sk-dummy.so when build_dir != src_dir
+ upstream: sk-usbhid: preserve error code returned by key_lookup()
- spotted by Corinna Vinschen; feedback & ok dtucker@
+ it conveys useful information, such as the supplied pin being wrong.
+
+ Part of GHPR329 from Pedro Martelletto
+
+ OpenBSD-Commit-ID: c0647eb9290f793add363d81378439b273756c1b
-commit 62a2d4e50b2e89f2ef04576931895d5139a5d037
-Author: Damien Miller <djm@mindrot.org>
-Date: Wed Feb 16 16:26:17 2022 +1100
+commit 9ab929ca2d820520327b41929372bcb9e261534c
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Jul 20 03:29:14 2022 +0000
- update versions in preparation for 8.9 release
+ upstream: when enrolling a resident key on a security token, check
+
+ if a credential with matching application and user ID strings already exists.
+ if so, prompt the user for confirmation before overwriting the credential.
+
+ patch from Pedro Martelletto via GHPR329
+
+ NB. cranks SSH_SK_VERSION_MAJOR, so any third-party FIDO middleware
+ implementations will need to adjust
+
+ OpenBSD-Commit-ID: e45e9f1bf2b2f32d9850669e7a8dbd64acc5fca4
-commit dd6d3dded721ac653ea73c017325e5bfeeec837f
+commit 5bcfc788b38d5b64e4c347bdc04bd9a01bbc36da
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Feb 15 05:13:36 2022 +0000
+Date: Wed Jul 20 03:13:04 2022 +0000
- upstream: document the unbound/host-bound options to
+ upstream: pull passphrase reading and confirmation into a separate
- PubkeyAuthentication; spotted by HARUYAMA Seigo
+ function so it can be used for FIDO2 PINs; no functional change
- OpenBSD-Commit-ID: 298f681b66a9ecd498f0700082c7a6c46e948981
+ OpenBSD-Commit-ID: bf34f76b8283cc1d3f54633e0d4f13613d87bb2f
-commit df93529dd727fdf2fb290700cd4f1adb0c3c084b
+commit eb679e2959bdb15454eb94751930eb4c9110da94
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Feb 14 14:19:40 2022 +1100
+Date: Fri Jul 15 21:31:48 2022 +1000
- Test if sshd accidentally acquires controlling tty
+ Move vmshutdown to first step.
- When SSHD_ACQUIRES_CTTY is defined, test for the problematic behaviour
- in the STREAMS code before activating the workaround. ok djm@
+ If a previous run on a physical runner has failed to clean up, the next
+ run will fail because it'll try to check out the code to a broken
+ directory mount. Make cleanup the first step.
-commit 766176cfdbfd7ec38bb6118dde6e4daa0df34888
+commit 46b91b70ff3cb9c147e2875ef5dc609fd64c0c96
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Feb 12 10:24:56 2022 +1100
+Date: Fri Jul 15 20:25:27 2022 +1000
- Add cygwin-release test config.
-
- This tests the flags used to build the cygwin release binaries.
+ Rename bbone test target to ARM.
-commit b30698662b862f5397116d23688aac0764e0886e
+commit 751d22cdeffed9fe921db78eedc32a29f9e80510
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 11 21:00:35 2022 +1100
+Date: Fri Jul 15 13:37:29 2022 +1000
- Move SSHD_ACQUIRES_CTTY workaround into compat.
-
- On some (most? all?) SysV based systems with STREAMS based ptys,
- sshd could acquire a controlling terminal during pty setup when
- it pushed the "ptem" module, due to what is probably a bug in
- the STREAMS driver that's old enough to vote. Because it was the
- privileged sshd's controlling terminal, it was not available for
- the user's session, which ended up without one. This is known to
- affect at least Solaris <=10, derivatives such as OpenIndiana and
- several other SysV systems. See bz#245 for the backstory.
-
- In the we past worked around that by not calling setsid in the
- privileged sshd child, which meant it was not a session or process
- group leader. This solved controlling terminal problem because sshd
- was not eligble to acquire one, but had other side effects such as
- not cleaning up helper subprocesses in the SIGALRM handler since it
- was not PG leader. Recent cleanups in the signal handler uncovered
- this, resulting in the LoginGraceTime timer not cleaning up privsep
- unprivileged processes.
-
- This change moves the workaround into the STREAMS pty allocation code,
- by allocating a sacrificial pty to act as sshd's controlling terminal
- before allocating user ptys, so those are still available for users'
- sessions.
-
- On the down side:
- - this will waste a pty per ssh connection on affected platforms.
-
- On the up side:
- - it makes the process group behaviour consistent between platforms.
+ Add AUDIT_ARCH_PPC to supported seccomp arches.
- - it puts the workaround nearest the code that actually causes the
- problem and competely out of the mainline code.
+ Patch from dries.deschout at dodeco.eu.
+
+commit a061792a6e8d235fc40a9b5d4c22a1762bb75a7b
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Jul 14 19:20:24 2022 +1000
+
+ Remove unintended changes.
- - the workaround is only activated if you use the STREAMS code. If,
- say, Solaris 11 has the bug but also a working openpty() it doesn't
- matter that we defined SSHD_ACQUIRES_CTTY.
+ I inadvertently included a couple of local changes with the OpenSSL
+ 3.0.4 change. Revert, anything that should be there will be committed
+ separately.
+
+commit 527cb43fa1b4e55df661feabbac51b8e608b6519
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Jul 14 11:22:08 2022 +1000
+
+ Return ERANGE from getcwd() if buffer size is 1.
- - the workaround is only activated when the fist pty is allocated,
- ie in the post-auth privsep monitor. This means there's no risk
- of fd leaks to the unprivileged processes, and there's no effect on
- sessions that do not allocate a pty.
+ If getcwd() is supplied a buffer size of exactly 1 and a path of "/", it
+ could result in a nul byte being written out of array bounds. POSIX says
+ it should return ERANGE if the path will not fit in the available buffer
+ (with terminating nul). 1 byte cannot fit any possible path with its nul,
+ so immediately return ERANGE in that case.
- Based on analysis and work by djm@, ok djm@
+ OpenSSH never uses getcwd() with this buffer size, and all current
+ (and even quite old) platforms that we are currently known to work
+ on have a native getcwd() so this code is not used on those anyway.
+ Reported by Qualys, ok djm@
-commit cd00b48cf10f3565936a418c1e6d7e48b5c36140
+commit 36857fefd8849c4b0e877cfd9d1eb22f79b76650
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 11 20:09:32 2022 +1100
+Date: Thu Jul 14 10:02:35 2022 +1000
- Simplify handling of --with-ssl-dir.
+ Split README.platform into its own line.
- ok djm@
+ README.platform has general platform-specific information, having it
+ following text about FIDO2 on the same line could imply that it only
+ has information about FIDO2.
-commit ea13fc830fc0e0dce2459f1fab2ec5099f73bdf0
+commit 00a496c6c14f2d41f2a9365714d494dd5f3aac9f
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 11 13:39:29 2022 +1100
+Date: Thu Jul 14 09:56:01 2022 +1000
- Stop testing OpenBSD HEAD on 6.9 and 7.0.
+ Clarify README.md text.
- HEAD is not guaranteed to work on previous stable branches, and at the
- moment is broken due to libfido API changes.
+ Clarify the text about the implications of building without OpenSSL, and
+ prefix the "configure --help" example command with a "./" so it's likely
+ to work as-is in more shells. From bz#3461.
-commit 50b9e4a4514697ffb9592200e722de6b427cb9ff
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Feb 11 00:43:56 2022 +0000
+commit f40b52f21fbc52eb513279168a49d3285c65256c
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Jul 12 19:48:44 2022 +1000
- upstream: Always initialize delim before passing to hpdelim2 which
+ Remove special casing of crypt().
- might not set it. Found by the Valgrind tests on github, ok deraadt@
+ Configure goes to some lengths to pick crypt() from either libcrypt
+ or OpenSSL's libcrypto because they can more or less featureful (eg
+ supporting md5-style passwords).
- OpenBSD-Commit-ID: c830c0db185ca43beff3f41c19943c724b4f636d
+ OpenSSL removed its crypt() interface in 2002:
+ https://github.com/openssl/openssl/commit/69deec58 so these hijinks
+ should no longer be necessary. This also only links sshd with libcrypt
+ which is the only thing that needs it. ok djm@
-commit 6ee53064f476cf163acd5521da45b11b7c57321b
+commit 76f4e48631d7b09fb243b47d7b393d100d3741b7
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 11 10:03:06 2022 +1100
+Date: Wed Jul 13 13:17:47 2022 +1000
- Fix helper include path and remove excess code.
+ Only refuse to use OpenSSL 3.0.4 on x86_64.
- Looks like test_hpdelim.c was imported twice into the same file.
- Spotted by kevin.brott at gmail com and chris at cataclysmal org.
+ The potential RCE only impacts x86_64, so only refuse to use it if we're
+ targetting a potentially impacted architecture. ok djm@
-commit 9fa63a19f68bc87452d3cf5c577cafad2921b7a4
+commit e75bbc1d88491fa85e61b2cc8783d4bbd00cd131
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Feb 10 23:27:02 2022 +1100
+Date: Tue Jul 12 14:37:15 2022 +1000
- Put poll.h inside ifdef.
+ Capture stderr output from configure.
-commit 3ac00dfeb54b252c15dcbf1971582e9e3b946de6
+commit d9eaea4bea6271bcee6a2b9428f1271faf2d033b
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Feb 10 22:17:31 2022 +1100
+Date: Tue Jul 12 12:54:49 2022 +1000
- We now support POLLPRI so actually define it.
+ Refuse to use OpenSSL 3.0.4 due to potential RCE.
+
+ OpenSSL has a potential RCE in its RSA implementation (CVE-2022-2274)
+ so refuse to use that specific version.
-commit 25bd659cc72268f2858c5415740c442ee950049f
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sun Feb 6 22:58:33 2022 +0000
+commit fb2f3a61bf3d28fff285524535f7ffcd177c9235
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Jul 12 12:54:24 2022 +1000
- upstream: Add test for empty hostname with port.
-
- OpenBSD-Regress-ID: e19e89d3c432b68997667efea44cf015bbe2a7e3
+ Move unset to before we set anything.
-commit a29af853cff41c0635f0378c00fe91bf9c91dea4
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Feb 4 07:53:44 2022 +0000
+commit c483a5c0fb8e8b8915fad85c5f6113386a4341ca
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Jul 6 11:52:54 2022 +1000
- upstream: Add unit tests for hpdelim.
-
- OpenBSD-Regress-ID: be97b85c19895e6a1ce13c639765a3b48fd95018
+ Test against openssl-3.0.5.
-commit 9699151b039ecc5fad9ac6c6c02e9afdbd26f15f
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Feb 10 04:12:38 2022 +0000
+commit 669a56bcfe73f8b985f2bba476ba834d55253acf
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Jul 5 18:35:53 2022 +1000
- upstream: revert for imminent OpenSSH release, which wil ship with
-
- scp in RCP mode.
-
- > revision 1.106
- > date: 2021/10/15 14:46:46; author: deraadt; state: Exp; lines: +13 -9; commitid: w5n9B2RE38tFfggl;
- > openbsd 7.0 release shipped with the (hopefully last) scp that uses RCP
- > protocol for copying. Let's get back to testing the SFTP protocol.
-
- This will be put back once the OpenSSH release is done.
+ Update sanitizer test targets:
- OpenBSD-Commit-ID: 0c725481a78210aceecff1537322c0b2df03e768
+ - remove clang-sanitize-memory for now. It takes so long that the test
+ times out.
+ - add gcc sanitize-address and sanitize-undefined test targets.
-commit 45279abceb37c3cbfac8ba36dde8b2c8cdd63d32
+commit 48cc68b69118b3ce8d07fd4f82e00d58667d5379
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Jul 5 16:23:28 2022 +1000
+
+ Add GCC address sanitizer build/test.
+
+commit 55c60bdd39b82457e92efa77da8d16cfa6a49391
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Jul 5 12:02:33 2022 +1000
+
+ Move sanitizer logs into regress for collection.
+
+commit 35ef2b3b6ef198f8574904a45780487ec2f17858
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Feb 8 08:59:12 2022 +0000
+Date: Mon Jul 4 09:10:31 2022 +0000
- upstream: Switch hpdelim interface to accept only ":" as delimiter.
+ upstream: Add TEST_REGRESS_CACHE_DIR.
- Historicallly, hpdelim accepted ":" or "/" as a port delimiter between
- hosts (or addresses) and ports. These days most of the uses for "/"
- are no longer accepted, so there are several places where it checks the
- delimiter to disallow it. Make hpdelim accept only ":" and use hpdelim2
- in the other cases. ok djm@
+ If set, it is used to cache regress test names that have succeeded and
+ skip those on a re-run.
- OpenBSD-Commit-ID: 7e6420bd1be87590b6840973f5ad5305804e3102
+ OpenBSD-Regress-ID: a7570dd29a58df59f2cca647c3c2ec989b49f247
-commit a1bcbf04a7c2d81944141db7ecd0ba292d175a66
-Author: pedro martelletto <pedro@yubico.com>
-Date: Mon Feb 7 09:09:59 2022 +0100
+commit 7394ed80c4de8b228a43c8956cf2fa1b9c6b2622
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sun Jul 3 21:46:44 2022 +1000
- fix typos in previous
+ Add clang sanitizer tests.
-commit 56192518e329b39f063487bc2dc4d796f791eca0
-Author: Damien Miller <djm@mindrot.org>
-Date: Mon Feb 7 12:53:47 2022 +1100
+commit bfce0e66b6017a9bfab450b9dc7d4b16f90de817
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sun Jul 3 18:14:09 2022 +1000
- compat code for fido_assert_set_clientdata()
+ Skip all rlimit tests when sandboxing disabled.
+
+ The rlimit tests can hang when being run with some compiler sanitizers
+ so skip all of them if sandbox=no.
-commit d6b5aa08fdcf9b527f8b8f932432941d5b76b7ab
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Feb 7 01:25:12 2022 +0000
+commit 6208d611520f9ea94d5369f9da404b709930029d
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sun Jul 3 17:54:49 2022 +1000
- upstream: use libfido2 1.8.0+ fido_assert_set_clientdata() instead
+ Move checks for pollfd.fd and nfds_t.
- of manually hashing data outselves. Saves a fair bit of code and makes life
- easier for some -portable platforms.
-
- OpenBSD-Commit-ID: 351dfaaa5ab1ee928c0e623041fca28078cff0e0
+ Move the checks for struct pollfd.fd and nfds_t to before the sandboxing
+ checks. This groups all the sandbox checks together so we can skip them
+ all when sandboxing is disabled.
-commit 86cc93fd3c26b2e0c7663c6394995fb04ebfbf3b
-Author: jsg@openbsd.org <jsg@openbsd.org>
-Date: Sun Feb 6 00:29:03 2022 +0000
+commit 322964f8f2e9c321e77ebae1e4d2cd0ccc5c5a0b
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jul 1 05:08:23 2022 +0000
- upstream: remove please from manual pages ok jmc@ sthen@ millert@
+ upstream: Remove leftover line.
- OpenBSD-Commit-ID: 6543acb00f4f38a23472538e1685c013ca1a99aa
+ Remove extra line leftover from merge conflict. ok djm@
+
+ OpenBSD-Commit-ID: 460e2290875d7ae64971a7e669c244b1d1c0ae2e
-commit ad16a84e64a8cf1c69c63de3fb9008320a37009c
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Feb 4 02:49:17 2022 +0000
+commit 7ec81daad0e03a64e8d91c5590960c48c1a899a3
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jul 1 04:45:50 2022 +0000
- upstream: Since they are deprecated, move DSA to the end of the
+ upstream: use consistent field names (s/char/byte)
- default list of public keys so that they will be tried last. From github
- PR#295 from "ProBackup-nl", ok djm@
+ in format description
- OpenBSD-Commit-ID: 7e5d575cf4971d4e2de92e0b6d6efaba53598bf0
+ OpenBSD-Commit-ID: 3de33572733ee7fcfd7db33d37db23d2280254f0
-commit 253de42753de85dde266e061b6fec12ca6589f7d
-Author: Damien Miller <djm@mindrot.org>
-Date: Wed Feb 2 16:52:07 2022 +1100
+commit 32e82a392d9f263485effdd606ff5862d289a4a0
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Jul 1 13:55:19 2022 +1000
- portable-specific string array constification
+ Skip select+rlimit check if sandboxing is disabled
- from Mike Frysinger
+ It's not needed in that case, and the test can fail when being built
+ with some compiler memory sanitizer flags. bz#3441
-commit dfdcc2220cf359c492d5d34eb723370e8bd8a19e
+commit 4be7184ebe2a2ccef175983517a35ee06766e1b4
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Feb 1 23:37:15 2022 +0000
+Date: Fri Jul 1 03:52:57 2022 +0000
- upstream: test 'ssh-keygen -Y find-principals' with wildcard
+ upstream: bump up loglevel from debug to info when unable to open
- principals; from Fabian Stelzer
+ authorized keys/principals file for errno != ENOENT; bz2042 ok dtucker
- OpenBSD-Regress-ID: fbe4da5f0032e7ab496527a5bf0010fd700f8f40
+ OpenBSD-Commit-ID: e79aa550d91ade6a80f081bda689da24c086d66b
-commit 968e508967ef42480cebad8cf3172465883baa77
+commit 6c31ba10e97b6953c4f325f526f3e846dfea647a
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jan 21 02:54:41 2022 +0000
+Date: Fri Jul 1 03:39:44 2022 +0000
- upstream: Enable all supported ciphers and macs in the server
+ upstream: Don't leak the strings allocated by order_hostkeyalgs()
- before trying to benchmark them. Increase the data file size to get more
- signal.
+ and list_hostkey_types() that are passed to compat_pkalg_proposal(). Part of
+ github PR#324 from ZoltanFridrich, ok djm@
- OpenBSD-Regress-ID: dc3697d9f7defdfc51c608782c8e750128e46eb6
+ This is a roll-forward of the previous rollback now that the required
+ changes in compat.c have been done.
+
+ OpenBSD-Commit-ID: c7cd93730b3b9f53cdad3ae32462922834ef73eb
-commit 15b7199a1fd37eff4c695e09d573f3db9f4274b7
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Feb 1 23:34:47 2022 +0000
+commit 486c4dc3b83b4b67d663fb0fa62bc24138ec3946
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jul 1 03:35:45 2022 +0000
- upstream: allow 'ssh-keygen -Y find-principals' to match wildcard
+ upstream: Always return allocated strings from the kex filtering so
- principals in allowed_signers files; from Fabian Stelzer
+ that we can free them later. Fix one leak in compat_kex_proposal. Based on
+ github PR#324 from ZoltanFridrich with some simplications by me. ok djm@
- OpenBSD-Commit-ID: 1e970b9c025b80717dddff5018fe5e6f470c5098
+ OpenBSD-Commit-ID: 9171616da3307612d0ede086fd511142f91246e4
-commit 541667fe6dc26d7881e55f0bb3a4baa6f3171645
+commit 96faa0de6c673a2ce84736eba37fc9fb723d9e5c
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Feb 1 23:32:51 2022 +0000
+Date: Fri Jul 1 00:36:30 2022 +0000
- upstream: mark const string array contents const too, i.e. static
+ upstream: ignore SIGPIPE earlier in main(), specifically before
- const char *array => static const char * const array from Mike Frysinger
+ muxclient() which performs operations that could cause one; Reported by Noam
+ Lewis via bz3454, ok dtucker@
- OpenBSD-Commit-ID: a664e31ea6a795d7c81153274a5f47b22bdc9bc1
+ OpenBSD-Commit-ID: 63d8e13276869eebac6d7a05d5a96307f9026e47
-commit 8cfa73f8a2bde4c98773f33f974c650bdb40dd3c
+commit 33efac790f6b09d54894ba6c3e17dfb08b6fc7e1
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Tue Jun 28 06:09:14 2022 +0000
+
+ upstream: reflect the update to -D arg name in usage();
+
+ OpenBSD-Commit-ID: abdcde4f92b1ef094ae44210ee99d3b0155aad9c
+
+commit c71a1442d02f0a3586109dfe2cb366de36dee08e
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Jun 29 18:28:47 2022 +1000
+
+ Update OpenSSL tests to the most recent releases.
+
+commit 2a822f29300b2de7335fbff65f0b187a0c582304
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Feb 1 23:11:11 2022 +0000
+Date: Mon Jun 27 21:41:55 2022 +0000
- upstream: better match legacy scp behaviour: show un-expanded paths
+ upstream: allow arguments to sftp -D option, e.g. sftp -D
- in error messages. Spotted by and ok tb@
+ "/usr/libexec/sftp-server -el debug3"
- OpenBSD-Commit-ID: 866c8ffac5bd7d38ecbfc3357c8adfa58af637b7
+ ok markus@
+
+ OpenBSD-Commit-ID: 5a002b9f3a7aef2731fc0ffa9c921cf15f38ecce
-commit 4e62c13ab419b4b224c8bc6a761e91fcf048012d
+commit 2369a2810187e08f2af5d58b343956062fb96ee8
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Feb 1 07:57:32 2022 +0000
+Date: Fri Jun 24 10:45:06 2022 +0000
- upstream: Remove explicit kill of privsep preauth child's PID in
+ upstream: Roll back previous KEX changes as they aren't safe until
- SIGALRM handler. It's no longer needed since the child will get terminated by
- the SIGTERM to the process group that cleans up any auth helpers, it
- simplifies the signal handler and removes the risk of a race when updating
- the PID. Based on analysis by HerrSpace in github PR#289, ok djm@
+ compat_pkalg_proposal and friends always allocate their returned strings.
+ Reported by Qualys.
- OpenBSD-Commit-ID: 2be1ffa28b4051ad9e33bb4371e2ec8a31d6d663
+ OpenBSD-Commit-ID: 1c7a88a0d5033f42f88ab9bec58ef1cf72c81ad0
-commit 2a7ccd2ec4022917b745af7186f514f365b7ebe9
-Author: guenther@openbsd.org <guenther@openbsd.org>
-Date: Fri Jan 28 06:18:42 2022 +0000
+commit 646686136c34c2dbf6a01296dfaa9ebee029386d
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jun 24 04:37:00 2022 +0000
- upstream: When it's the possessive of 'it', it's spelled "its",
+ upstream: Don't leak the strings allocated by order_hostkeyalgs()
- without the apostrophe.
+ and list_hostkey_types() that are passed to compat_pkalg_proposal(). Part of
+ github PR#324 from ZoltanFridrich, ok djm@
- OpenBSD-Commit-ID: fb6ab9c65bd31de831da1eb4631ddac018c5fae7
+ OpenBSD-Commit-ID: b2f6e5f60f2bba293b831654328a8a0035ef4a1b
-commit 8a0848cdd3b25c049332cd56034186b7853ae754
-Author: Alex James <theracermaster@gmail.com>
-Date: Sun Jan 30 16:13:36 2022 -0600
+commit 193c6d8d905dde836b628fc07a7b9cf2d347e2a3
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Jun 25 12:16:15 2022 +1000
- sandbox-seccomp-filter: allow gettid
+ Zero out LIBFIDO2 when SK support not usable.
- Some allocators (such as Scudo) use gettid while tracing allocations [1].
- Allow gettid in preauth to prevent sshd from crashing with Scudo.
+ Prevents us from trying to link them into ssh-sk-helper and failing to
+ build.
+
+commit 40f5d849d25c60b4ae21261e78484d435f5cfd51
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Jun 25 11:47:28 2022 +1000
+
+ Disable SK support if FIDO libs not found.
+
+commit 5fd922ade1b25880fe8a8249f5c0385e413108f9
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Jun 24 14:43:54 2022 +1000
+
+ fix broken case statement in previous
+
+commit f51423bdaf0008d46b6af082bcfd7a22a87375f0
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Jun 24 14:40:42 2022 +1000
+
+ request 1.1x API compatibility for OpenSSL >=3.x
- [1]: https://github.com/llvm/llvm-project/blob/llvmorg-13.0.0/compiler-rt/lib/gwp_asan/common.cpp#L46
+ idea/patch from Pedro Martelletto via GHPR#322; ok dtucker@
-commit b30d32159dc3c7052f4bfdf36357996c905af739
+commit 455cee8d6c2e4c48c5af9faead3599c49948411e
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Jan 22 00:49:34 2022 +0000
+Date: Fri Jun 24 04:27:14 2022 +0000
- upstream: add a ssh_packet_process_read() function that reads from
+ upstream: make it clear that RekeyLimit applies to both transmitted
- a fd directly into the transport input buffer.
+ and received data. GHPR#328 from Jan Pazdziora
- Use this in the client and server mainloops to avoid unnecessary
- copying. It also lets us use a more greedy read size without penalty.
+ OpenBSD-Commit-ID: d180a905fec9ff418a75c07bb96ea41c9308c3f9
+
+commit 17904f05802988d0bb9ed3c8d1d37411e8f459c3
+Author: tobhe@openbsd.org <tobhe@openbsd.org>
+Date: Tue Jun 21 14:52:13 2022 +0000
+
+ upstream: Make sure not to fclose() the same fd twice in case of an
- Yields a 2-3% performance gain on cipher-speed.sh (in a fairly
- unscientific test tbf)
+ error.
- feedback dtucker@ ok markus@
+ ok dtucker@
- OpenBSD-Commit-ID: df4112125bf79d8e38e79a77113e1b373078e632
+ OpenBSD-Commit-ID: e384c4e05d5521e7866b3d53ca59acd2a86eef99
-commit a1a8efeaaa9cccb15cdc0a2bd7c347a149a3a7e3
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Jan 22 00:45:31 2022 +0000
+commit f29d6cf98c25bf044079032d22c1a57c63ab9d8e
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sat Jun 18 02:17:16 2022 +0000
- upstream: Use sshbuf_read() to read directly into the channel input
+ upstream: Don't attempt to fprintf a null identity comment. From
- buffer rather than into a stack buffer that needs to be copied again;
- Improves performance by about 1% on cipher-speed.sh feedback dtucker@ ok
- markus@
+ Martin Vahlensieck via tech@.
- OpenBSD-Commit-ID: bf5e6e3c821ac3546dc8241d8a94e70d47716572
+ OpenBSD-Commit-ID: 4c54d20a8e8e4e9912c38a7b4ef5bfc5ca2e05c2
-commit 29a76994e21623a1f84d68ebb9dc5a3c909fa3a7
+commit ad1762173bb38716a106e8979806149fd0f2753e
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jun 17 01:00:03 2022 +0000
+
+ upstream: Log an error if pipe() fails while accepting a
+
+ connection. bz#3447, from vincent-openssh at vinc17 net, ok djm@
+
+ OpenBSD-Commit-ID: 9d59f19872b94900a5c79da2d57850241ac5df94
+
+commit 9c59e7486cc8691401228b43b96a3edbb06e0412
Author: Damien Miller <djm@mindrot.org>
-Date: Tue Jan 25 11:52:34 2022 +1100
+Date: Fri Jun 24 14:20:43 2022 +1000
- depend
+ automatically enable built-in FIDO support
+
+ If libfido2 is found and usable, then enable the built-in
+ security key support unless --without-security-key-builtin
+ was requested.
+
+ ok dtucker@
-commit 754e0d5c7712296a7a3a83ace863812604c7bc4f
+commit 7d25b37fb2a5ff4dadabcbdac6087a97479434f5
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Jun 24 13:46:39 2022 +1000
+
+ fix possible NULL deref when built without FIDO
+
+ Analysis/fix from kircher in bz3443; ok dtucker@
+
+commit f5ba85daddfc2da6a8dab6038269e02c0695be44
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Jan 22 00:43:43 2022 +0000
+Date: Wed Jun 15 16:08:25 2022 +0000
- upstream: Add a sshbuf_read() that attempts to read(2) directly in
+ upstream: make sure that UseDNS hostname lookup happens in the monitor
- to a sshbuf; ok markus@
+ and not in the pledge(2)'d unprivileged process; fixes regression caused by
+ recent refactoring spotted by henning@
- OpenBSD-Commit-ID: 2d8f249040a4279f3bc23c018947384de8d4a45b
+ OpenBSD-Commit-ID: a089870b95101cd8881a2dff65b2f1627d13e88d
-commit c7964fb9829d9ae2ece8b51a76e4a02e8449338d
+commit acb2059febaddd71ee06c2ebf63dcf211d9ab9f2
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jan 21 07:04:19 2022 +0000
+Date: Fri Jun 3 04:47:21 2022 +0000
- upstream: add a helper for writing an error message to the
+ upstream: move auth_openprincipals() and auth_openkeyfile() over to
- stderr_buf and setting quit_pending; no functional change but saves a bunch
- of boilerplate
+ auth2-pubkeyfile.c too; they make more sense there.
- OpenBSD-Commit-ID: 0747657cad6b9eabd514a6732adad537568e232d
+ OpenBSD-Commit-ID: 9970d99f900e1117fdaab13e9e910a621b7c60ee
-commit d23b4f7fdb1bd87e2cd7a9ae7c198ae99d347916
+commit 3d9b0845f34510111cc693bb99a667662ca50cd8
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jan 21 06:58:06 2022 +0000
+Date: Fri Jun 3 04:31:54 2022 +0000
- upstream: correct comment and use local variable instead of long
+ upstream: test setenv in both client and server, test first-match-wins
- indirection; spotted by dtucker@
+ too
- OpenBSD-Commit-ID: 5f65f5f69db2b7d80a0a81b08f390a63f8845965
+ OpenBSD-Regress-ID: 4c8804f9db38a02db480b9923317457b377fe34b
-commit d069b020a02b6e3935080204ee44d233e8158ebb
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Fri Jan 21 00:53:40 2022 +0000
+commit 22e1a3a71ad6d108ff0c5f07f93c3fcbd30f8b40
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jun 3 04:30:46 2022 +0000
- upstream: When poll(2) returns -1, for some error conditions
+ upstream: Make SetEnv directives first-match-wins in both
- pfd[].revents is not cleared. There are subtle errors in various programs.
- In this particular case, the program should error out. ok djm millert
+ sshd_config and sshd_config; previously if the same name was reused then the
+ last would win (which is the opposite to how the config is supposed to work).
- OpenBSD-Commit-ID: 00f839b16861f7fb2adcf122e95e8a82fa6a375c
+ While there, make the ssh_config parsing more like sshd_config.
+
+ bz3438, ok dtucker
+
+ OpenBSD-Commit-ID: 797909c1e0262c0d00e09280459d7ab00f18273b
-commit e204b34337a965feb439826157c191919fd9ecf8
-Author: Damien Miller <djm@mindrot.org>
-Date: Sat Jan 22 11:38:21 2022 +1100
+commit 38ed6c57e9e592c08e020fa6e82b45b4e1040970
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jun 3 04:00:15 2022 +0000
- restore tty force-read hack
+ upstream: Add missing *-sk types to ssh-keyscan manpage. From
- This portable-specific hack fixes a hang on exit for ttyful sessions
- on Linux and some SysVish Unix variants. It was accidentally disabled
- in commit 5c79952dfe1a (a precursor to the mainloop poll(2) conversion).
+ skazi0 via github PR#294.
- Spotted by John in bz3383
+ OpenBSD-Commit-ID: fda2c869cdb871f3c90a89fb3f985370bb5d25c0
-commit 68085066b6bad43643b43f5957fcc5fd34782ccd
-Author: Corinna Vinschen <vinschen@redhat.com>
-Date: Fri Jan 21 03:22:56 2022 +1100
+commit ea97ec98c41ec2b755dfab459347db674ff9a5de
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jun 3 03:21:09 2022 +0000
- Fix signedness bug in Cygwin code
+ upstream: Add period at end of "not known by any other names"
- The Cygwin-specific pattern match code has a bug. It checks
- the size_t value returned by mbstowcs for being < 0. The right
- thing to do is to check against (size_t) -1. Fix that.
+ message. github PR#320 from jschauma, ok djm@
- Signed-off-by: Corinna Vinschen <vinschen@redhat.com>
+ OpenBSD-Commit-ID: bd60809803c4bfd3ebb7c5c4d918b10e275266f2
-commit 2e5cfed513e84444483baf1d8b31c40072b05103
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Jan 20 13:26:27 2022 +1100
+commit 88e376fcd67478ad1660d94bc73ab348ac9f4527
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jun 3 03:17:42 2022 +0000
- Improve compatibility of early exit trap handling.
+ upstream: ssh-keygen -A: do not generate DSA keys by default.
- Dash (as used by the github runners) has some differences in its trap
- builtin:
- - it doesn't have -p (which is fine, that's not in posix).
- - it doesn't work in a subshell (which turns out to be in compliance
- with posix, which means bash isn't).
- - it doesn't work in a pipeline, ie "trap|cat" produces no output.
+ Based on github PR#303 from jsegitz with man page text from jmc@, ok markus@
+ djm@
+
+ OpenBSD-Commit-ID: 5c4c57bdd7063ff03381cfb6696659dd3f9f5b9f
-commit 3fe6800b6027add478e648934cbb29d684e51943
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Jan 20 00:49:57 2022 +1100
+commit 6b3fb624675082a1e5aa615d1b8479873d8b5731
+Author: naddy@openbsd.org <naddy@openbsd.org>
+Date: Tue May 31 14:05:12 2022 +0000
- Move more tests out of valgrind-1 runner.
+ upstream: ssh-keygen: implement "verify-required" certificate option.
+
+ This was already documented when support for user-verified FIDO
+ keys was added, but the ssh-keygen(1) code was missing.
+
+ ok djm@
+
+ OpenBSD-Commit-ID: f660f973391b593fea4b7b25913c9a15c3eb8a06
-commit 20da6ed136dd76e6a0b229ca3036ef9c7c7ef798
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Jan 19 15:37:39 2022 +1100
+commit b7f86ffc301be105bba9a3e0618b6fab3ae379bd
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Sat May 28 05:57:56 2022 +0000
- Invoke EXIT handler early when using Valgrind.
+ upstream: keywords ref ssh_config.5;
- When using Valgrind, we need to wait for all invoked programs to
- complete before checking their valgrind logs. Some tests, notably
- agent-restrict, set an EXIT trap handler to clean up things like
- ssh-agent, but those do not get invoked until test-exec.sh exits.
- This causes the Valgrind wait to deadlock, so if present invoke
- the EXIT handler before checking the Valgrind logs.
+ from caspar schutijser
+
+ OpenBSD-Commit-ID: f146a19d7d5c9374c3b9c520da43b2732d7d1a4e
-commit ad2e0580c87b0714cf166bca9d926a95ddeee1c8
+commit dc7bc52372f2744fa39191577be5306ee57aacd4
+Author: Damien Miller <djm@mindrot.org>
+Date: Mon May 30 09:29:09 2022 +1000
+
+ fix some bugs in the fuzzer
+
+commit 1781f507c113667613351c19898efaf1e311a865
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Jan 18 12:55:21 2022 +1100
+Date: Fri May 27 18:19:48 2022 +1000
- Remove line leftover from upstream sync.
+ Test against OpenSSL 1.1.1o and 3.0.3.
-commit d1051c0f11a6b749027e26bbeb61b07df4b67e15
+commit c53906e0c59e569691b4095d3e8db79cf78fa058
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri May 27 18:18:31 2022 +1000
+
+ Test against LibreSSL 3.5.3.
+
+commit 9b3ad432ad2f19319bcc089370e356c6315d682f
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri May 27 17:00:43 2022 +1000
+
+ fuzzer for authorized_keys parsing
+
+ mostly redundant to authopt_fuzz, but it's sensitive code so IMO it
+ makes sense to test this layer too
+
+commit c83d8c4d6f3ccceef84d46de107f6b71cda06359
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Jan 17 22:56:04 2022 +0000
+Date: Fri May 27 05:02:46 2022 +0000
- upstream: when decompressing zlib compressed packets, use
+ upstream: split the low-level file handling functions out from
- Z_SYNC_FLUSH instead of Z_PARTIAL_FLUSH as the latter is not actually
- specified as a valid mode for inflate(). There should be no practical change
- in behaviour as the compression side ensures a flush that should make all
- data available to the receiver in all cases.
+ auth2-pubkey.c
- repoted by lamm AT ibm.com via bz3372; ok markus
+ Put them in a new auth2-pubkeyfile.c to make it easier to refer to them
+ (e.g. in unit/fuzz tests) without having to refer to everything else
+ pubkey auth brings in.
- OpenBSD-Commit-ID: 67cfc1fa8261feae6d2cc0c554711c97867cc81b
+ ok dtucker@
+
+ OpenBSD-Commit-ID: 3fdca2c61ad97dc1b8d4a7346816f83dc4ce2217
-commit d5981b1883746b1ae178a46229c26b53af99e37a
+commit 3b0b142d2a0767d8cd838e2f3aefde8a0aaa41e1
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Jan 17 21:41:04 2022 +0000
+Date: Fri May 27 05:01:25 2022 +0000
- upstream: make most of the sftp errors more idiomatic, following
+ upstream: refactor authorized_keys/principals handling
- the general form of "[local/remote] operation path: error message"; ok markus
+ remove "struct ssh *" from arguments - this was only used to pass the
+ remote host/address. These can be passed in instead and the resulting
+ code is less tightly coupled to ssh_api.[ch]
- OpenBSD-Commit-ID: 61364cd5f3a9fecaf8d63b4c38a42c0c91f8b571
+ ok dtucker@
+
+ OpenBSD-Commit-ID: 9d4373d013edc4cc4b5c21a599e1837ac31dda0d
-commit ac7c9ec894ed0825d04ef69c55babb49bab1d32e
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Jan 17 21:39:51 2022 +0000
+commit 2c334fd36f80cb91cc42e4b978b10aa35e0df236
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri May 27 04:29:40 2022 +0000
- upstream: when transferring multiple files in SFTP mode, create the
+ upstream: f sshpkt functions fail, then password is not cleared
- destination directory if it doesn't already exist to match olde-scp(1)
- behaviour. noticed by deraadt@ ok markus@
+ with freezero. Unconditionally call freezero to guarantee that password is
+ removed from RAM.
- OpenBSD-Commit-ID: cf44dfa231d4112f697c24ff39d7ecf2e6311407
+ From tobias@ and c3h2_ctf via github PR#286, ok djm@
+
+ OpenBSD-Commit-ID: 6b093619c9515328e25b0f8093779c52402c89cd
-commit 39d17e189f8e72c34c722579d8d4e701fa5132da
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jan 14 03:43:48 2022 +0000
+commit 5d3a77f4c5ae774c6796387266503f52c7cdc7c2
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri May 27 04:27:49 2022 +0000
- upstream: allow pin-required FIDO keys to be added to ssh-agent(1).
+ upstream: Avoid kill with -1 argument. The out_ctx label can be
- ssh-askpass will be used to request the PIN at authentication time.
+ reached before fork has been called. If this happens, then kill -1 would be
+ called, sending SIGTERM to all processes reachable by the current process.
- From Pedro Martelletto, ok djm
+ From tobias@ and c3h2_ctf via github PR#286, ok djm@
- OpenBSD-Commit-ID: de8189fcd35b45f632484864523c1655550e2950
+ OpenBSD-Commit-ID: 6277af1207d81202f5daffdccfeeaed4c763b1a8
-commit 52423f64e13db2bdc31a51b32e999cb1bfcf1263
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jan 14 03:35:10 2022 +0000
+commit 533b31cd08e4b97f455466f91c36915e2924c15a
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri May 27 04:13:24 2022 +0000
- upstream: ssh-sk: free a resident key's user id
+ upstream: Note that ProxyJump also accepts the same tokens as
- From Pedro Martelletto; ok dtucker & me
+ ProxyCommand. From pallxk via github PR#305.
- OpenBSD-Commit-ID: 47be40d602b7a6458c4c71114df9b53d149fc2e9
+ OpenBSD-Commit-ID: 7115ac351b129205f1f1ffa6bbfd62abd76be7c5
-commit 014e2f147a2788bfb3cc58d1b170dcf2bf2ee493
+commit 9d8c80f8a304babe61ca28f2e3fb5eb6dc9c39bf
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jan 14 03:34:00 2022 +0000
+Date: Wed May 25 06:03:44 2022 +0000
- upstream: sshsk_load_resident: don't preallocate resp
+ upstream: revert previous; it was broken (spotted by Theo)
- resp is allocated by client_converse(), at which point we lose
- the original pointer.
+ OpenBSD-Commit-ID: 457c79afaca2f89ec2606405c1059b98b30d8b0d
+
+commit 9e0d02ef7ce88b67643bfb1c2272c9f5f04cc680
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed May 25 00:31:13 2022 +0000
+
+ upstream: make SSHBUF_DBG/SSHBUF_TELL (off by default and only enabled
- From Pedro Martelletto; ok dtucker & me
+ via #define) dump to stderr rather than stdout
- OpenBSD-Commit-ID: 1f1b5ea3282017d6584dfed4f8370dc1db1f44b1
+ OpenBSD-Commit-ID: 10298513ee32db8390aecb0397d782d68cb14318
-commit c88265f207dfe0e8bdbaf9f0eda63ed6b33781cf
+commit 2487163630f28be28b7e2396b4bd6511b98f1d3e
+Author: Tim Rice <tim@multitalents.net>
+Date: Tue May 24 10:21:25 2022 -0700
+
+ configure.ac: Add missing AC_DEFINE for caph_cache_tzdata test causing
+ HAVE_CAPH_CACHE_TZDATA to be missing from config.h.in.
+ Spotted by Bryan Drewery
+
+commit bedb93415b60db3dfd704a3d525e82adb14a2481
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jan 14 03:32:52 2022 +0000
+Date: Sun May 15 23:48:07 2022 +0000
- upstream: sshsk_sign: trim call to sshkey_fingerprint()
+ upstream: regress test for in-place transfers and clobbering larger
- the resulting fingerprint doesn't appear to be used for anything,
- and we end up leaking it.
+ files with smaller ones; would have caught last regression in scp(1)
- from Pedro Martelletto; ok dtucker & me
+ OpenBSD-Regress-ID: 19de4e88dd3a4f7e5c1618c9be3c32415bd93bc2
+
+commit b4f0d719c2548cb74da509fb65f384dada4ebd37
+Author: anton@openbsd.org <anton@openbsd.org>
+Date: Fri Apr 22 05:08:43 2022 +0000
+
+ upstream: Only run agent-ptrace.sh if gdb is available as all
- OpenBSD-Commit-ID: 5625cf6c68f082bc2cbbd348e69a3ed731d2f9b7
+ architectures do not ship with gdb.
+
+ OpenBSD-Regress-ID: ec53e928803e6b87f9ac142d38888ca79a45348d
-commit 1cd1b2eac39661b849d5a4b4b56363e22bb5f61e
+commit 9b73345f80255a7f3048026462f2c0c6a241eeac
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jan 14 03:31:52 2022 +0000
+Date: Sun May 15 23:47:21 2022 +0000
- upstream: use status error message to communicate ~user expansion
-
- failures; provides better experience for scp in sftp mode, where ~user paths
- are more likely to be used; spotted jsg, feedback jsg & deraadt ok jsg &
- markus
+ upstream: fix in-place copies; r1.163 incorrectly skipped truncation in
- (forgot to include this file in previous commit)
+ all cases, not just at the start of a transfer. This could cause overwrites
+ of larger files to leave junk at the end. Spotted by tb@
- OpenBSD-Commit-ID: d37cc4c8c861ce48cd6ea9899e96aaac3476847b
+ OpenBSD-Commit-ID: b189f19cd68119548c8e24e39c79f61e115bf92c
-commit a1d42a6ce0398da3833bedf374ef2571af7fea50
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Jan 14 13:49:32 2022 +1100
+commit 56a0697fe079ff3e1ba30a2d5c26b5e45f7b71f8
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri May 13 06:31:50 2022 +0000
- fix edge case in poll(2) wrapper
+ upstream: arrange for scp, when in sftp mode, to not ftruncate(3) files
- Correct handling of select(2) exceptfds. These should only be consulted
- for POLLPRI flagged pfds and not unconditionally converted to POLLERR.
+ early
- with and ok dtucker@
+ previous behavious of unconditionally truncating the destination file
+ would cause "scp ~/foo localhost:" and "scp localhost:foo ~/" to
+ delete all the contents of their destination.
+
+ spotted by solene@ sthen@, also bz3431; ok dtucker@
+
+ OpenBSD-Commit-ID: ca39fdd39e0ec1466b9666f15cbcfddea6aaa179
-commit 976b9588b4b5babcaceec4767a241c11a67a5ccb
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jan 14 13:46:35 2022 +1100
+commit fbcef70c2832712f027bccea1aa9bc4b4103da93
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon May 9 08:25:27 2022 +0000
- Wrap OpenSSL includes in unit tests in ifdef.
+ upstream: Remove errant apostrophe. From haruyama at queen-ml org.
- Fixes unit test on systems that do not have OpenSSL headers installed.
+ OpenBSD-Commit-ID: dc6b294567cb84b384ad6ced9ca469f2bbf0bd10
-commit c171879374b2e8b07157503f5639ed0bce59ce89
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Jan 13 15:53:33 2022 +1100
+commit 0086a286ea6bbd11ca9b664ac3bb12b27443d6eb
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon May 9 03:09:53 2022 +0000
- Remove sort wrapper.
+ upstream: Allow existing -U (use agent) flag to work with "-Y sign"
- agent-restrict now takes care of this itself.
+ operations, where it will be interpreted to require that the private keys is
+ hosted in an agent; bz3429, suggested by Adam Szkoda; ok dtucker@
+
+ OpenBSD-Commit-ID: a7bc69873b99c32c42c7628ed9ea91565ba08c2f
-commit 9cc2654403f1a686bb26c07a6ac790edf334cef5
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Thu Jan 13 04:53:16 2022 +0000
+commit cb010744cc98f651b1029bb09efa986eb54e4ccf
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun May 8 22:58:35 2022 +0000
- upstream: Set LC_ALL in both local and remote shells so that sorted
+ upstream: improve error message when 'ssh-keygen -Y sign' is unable to
- output matches regardless of what the user's shell sets it to. ok djm@
+ load a private key; bz3429, reported by Adam Szkoda ok dtucker@
- OpenBSD-Regress-ID: 4e97dd69a68b05872033175a4c2315345d01837f
+ OpenBSD-Commit-ID: bb57b285e67bea536ef81b1055467be2fc380e74
-commit 7a75f748cb2dd2f771bf70ea72698aa027996ab1
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Thu Jan 13 04:22:10 2022 +0000
+commit aa61fc82c63d309a90c22ca74fb1da6c6f4372fd
+Author: Tobias Heider <me@tobhe.de>
+Date: Mon May 9 02:00:01 2022 +0200
- upstream: Avoid %'s in commands (not used in OpenBSD, but used in
+ Remove duplicate bcrypt_pbkdf.o from Makefile
- -portable's Valgrind test) being interpretted as printf format strings.
+ bcrypt_pbkdf.o is duplicated in the openbsd-compat Makefile's object
+ file list.
+
+commit deb506d00da8d11fb04c1e7b9b1e1cc379c1705c
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun May 8 22:32:36 2022 +0000
+
+ upstream: When performing operations that glob(3) a remote path, ensure
- OpenBSD-Regress-ID: dc8655db27ac4acd2c386c4681bf42a10d80b043
+ that the implicit working directory used to construct that path escapes
+ glob(3) characters.
+
+ This prevents glob characters from being processed in places they
+ shouldn't, e.g. "cd /tmp/a*/", "get *.txt" should have the get operation
+ treat the path "/tmp/a*" literally and not attempt to expand it.
+
+ Reported by Lusia Kundel; ok markus@
+
+ OpenBSD-Commit-ID: 4f647f58482cbad3d58b1eab7f6a1691433deeef
-commit 6c435bd4994d71442192001483a1cdb846e5ffcd
+commit f38cf74f20b5da113cfa823afd5bfb5c6ba65f3d
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Jan 12 16:58:13 2022 +1100
+Date: Fri May 6 14:50:18 2022 +1000
- Stop on first test failure to minimize logs.
+ Also retest OpenBSD upstream on .yml changes.
-commit 4bc2ba6095620a4484b708ece12842afd8c7685b
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Jan 12 07:18:37 2022 +0000
+commit f87a132800ba3710ab130d703448a31ef1128d77
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri May 6 14:46:09 2022 +1000
- upstream: Use egrep when searching for an anchored string.
-
- OpenBSD-Regress-ID: dd114a2ac27ac4b06f9e4a586d3f6320c54aeeb4
+ Note that, for now, we need variadic macros.
-commit 6bf2efa2679da1e8e60731f41677b2081dedae2c
+commit 217b518e0f7c52c4b909e935141a55344c61e644
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Jan 12 18:25:06 2022 +1100
+Date: Fri May 6 14:39:34 2022 +1000
- Add "rev" command replacement if needed.
+ Add ubsan minimal testcase on OpenBSD.
+
+ As suggested by djm@.
-commit 72bcd7993dadaf967bb3d8564ee31cbf38132b5d
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Jan 12 03:30:32 2022 +0000
+commit 457dce2cfef6a48f5442591cd8b21c7e8cba13f8
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu May 5 01:04:14 2022 +0000
- upstream: Don't log NULL hostname in restricted agent code,
+ upstream: sshkey_unshield_private() contains a exact duplicate of
- printf("%s", NULL) is not safe on all platforms. with & ok djm
+ the code in private2_check_padding(). Pull private2_check_padding() up so the
+ code can be reused. From Martin Vahlensieck, ok deraadt@
- OpenBSD-Commit-ID: faf10cdae4adde00cdd668cd1f6e05d0a0e32a02
+ OpenBSD-Commit-ID: 876884c3f0e62e8fd8d1594bab06900f971c9c85
-commit acabefe3f8fb58c867c99fed9bbf84dfa1771727
+commit 0e44db4d9cb313e68a59a44d27884af66c02356e
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jan 11 22:33:16 2022 +0000
+Date: Thu May 5 00:56:58 2022 +0000
- upstream: remove hardcoded domain and use window.location.host, so this
+ upstream: channel_new no longer frees remote_name. So update the
- can be run anywhere
+ comment accordingly. As remote_name is not modified, it can be const as
+ well. From Martin Vahlensieck
- OpenBSD-Regress-ID: 2ac2ade3b6227d9c547351d3ccdfe671e62b7f92
+ OpenBSD-Commit-ID: e4e10dc8dc9f40c166ea5a8e991942bedc75a76a
-commit 96da0946e44f34adc0397eb7caa6ec35a3e79891
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Jan 11 02:56:19 2022 +0000
+commit 37b62fd5caf19c85a48241535277cefff65adace
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu May 5 00:55:11 2022 +0000
- upstream: "void" functions should not return anything. From Tim Rice
+ upstream: mux.c: mark argument as const; from Martin Vahlensieck
- via -portable.
+ OpenBSD-Commit-ID: 69a1a93a55986c7c2ad9f733c093b46a47184341
+
+commit f4e67c0ad259b4cf10177277a5827fa5545bac53
+Author: markus@openbsd.org <markus@openbsd.org>
+Date: Wed May 4 07:31:22 2022 +0000
+
+ upstream: make sure stdout is non-blocking; ok djm@
- OpenBSD-Commit-ID: ce6616304f4c9881b46413e616b226c306830e2a
+ OpenBSD-Commit-ID: 64940fffbd1b882eda2d7c8c7a43c79368309c0d
-commit a882a09722c9f086c9edb65d0c4022fd965ec1ed
+commit e5c036d2092c00bef395e9161dc5ce42d4be9565
+Author: florian@openbsd.org <florian@openbsd.org>
+Date: Tue May 3 07:42:27 2022 +0000
+
+ upstream: Add FIDO AUTHENTICATOR section and explain a bit how FIDO
+
+ works. The wording came mostly from the 8.2 OpenSSH release notes, addapted
+ to fit the man page. Then move the -O bits into the new section as is already
+ done for CERTIFICATES and MODULI GENERATION. Finally we can explain the
+ trade-offs of resident keys. While here, consistently refer to the FIDO
+ thingies as "FIDO authenticators", not "FIDO tokens".
+
+ input & OK jmc, naddy
+
+ OpenBSD-Commit-ID: dd98748d7644df048f78dcf793b3b63db9ab1d25
+
+commit 575771bf79bef7127be6aaccddc46031ea15529e
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Mon May 2 05:40:37 2022 +0000
+
+ upstream: remove an obsolete rsa1 format example from an example;
+
+ from megan batty
+ ok djm
+
+ OpenBSD-Commit-ID: db2c89879c29bf083df996bd830abfb1e70d62bf
+
+commit 0bc6b4c8f04e292577bdb44d5dc6b630d3448087
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jan 11 01:26:47 2022 +0000
+Date: Sun May 1 23:20:30 2022 +0000
- upstream: suppress "Connection to xxx closed" messages at LogLevel >=
+ upstream: fix some integer overflows in sieve_large() that show up when
- error bz3378; ok dtucker@
+ trying to generate modp groups > 16k bits. Reported via GHPR#306 by Bertram
+ Felgenhauer, but fixed in a different way. feedback/ok tb@
- OpenBSD-Commit-ID: d5bf457d5d2eb927b81d0663f45248a31028265c
+ OpenBSD-Commit-ID: 81cbc6dd3a21c57bd6fadea10e44afe37bca558e
-commit 61a1a6af22e17fc94999a5d1294f27346e6c4668
-Author: Damien Miller <djm@mindrot.org>
-Date: Wed Jan 12 08:57:49 2022 +1100
+commit a45615cb172bc827e21ec76750de39dfb30ecc05
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Apr 29 04:55:07 2022 +0000
- OS X poll(2) is broken; use compat replacement
+ upstream: be stricter in which characters will be accepted in
- Darwin's poll(2) implementation is broken. For character-special
- devices like /dev/null, it returns POLLNVAL when polled with
- POLLIN.
+ specifying a mask length; allow only 0-9. From khaleesicodes via GHPR#278; ok
+ dtucker@
- Apparently this is Apple bug 3710161, which is AFAIK not public,
- but a websearch will find other OSS projects rediscovering it
- periodically since it was first identified in 2005 (!!)
+ OpenBSD-Commit-ID: e267746c047ea86665cdeccef795a8a56082eeb2
-commit 613a6545fc5a9542753b503cbe5906538a640b60
+commit 4835544d2dd31de6ffc7dba59f92093aea98155b
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Jan 11 20:56:01 2022 +1100
+Date: Sat Apr 30 10:56:41 2022 +1000
- libhardended_malloc.so moved into out dir.
+ Add Mac OS X 12 test target.
-commit 61761340be5e11046556623f8f5412b236cefa95
-Author: Tim Rice <tim@multitalents.net>
-Date: Mon Jan 10 11:07:04 2022 -0800
+commit 97a6a8b8c1f2da09712d0e72d0ef800e4edd34cd
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Apr 29 18:27:34 2022 +1000
- Make USL compilers happy
- UX:acomp: ERROR: "sftp-server.c", line 567: void function cannot return value
+ Only run tests when source files change.
+
+ Also run tests on changes to V_9_0 branch.
-commit 3ef403f351e80a59b6f7e9d43cb82c181855483c
+commit 6d0392b9ff4b50a56ac5685d1b9392e2cd432ca3
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Jan 10 21:07:38 2022 +1100
+Date: Fri Apr 29 18:22:34 2022 +1000
- Add wrapper for "sort" to set LC_ALL=C.
-
- Found by djm, this should make sorts stable and reduce test flakiness.
+ Remove now-empty int32_minmax.inc.
-commit bd69e29f5716090181dbe0b8272eb7eab1a383bb
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Jan 8 07:55:26 2022 +0000
+commit af59463553b5ad52d3b42c4455ee3c5600158bb7
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Apr 29 03:24:30 2022 +0000
- upstream: Remove errant "set -x" left over from debugging.
+ upstream: mention that the helpers are used by ssh(1), ssh-agent(1)
- OpenBSD-Regress-ID: cd989268e034264cec5df97be7581549032c87dc
+ and ssh-keygen(1). Previously only ssh(1) was mentioned. From Pedro
+ Martelletto
+
+ OpenBSD-Commit-ID: 30f880f989d4b329589c1c404315685960a5f153
-commit 1a7c88e26fd673813dc5f61c4ac278564845e004
+commit 3e26b3a6eebcee27be177207cc0846fb844b7a56
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Jan 8 07:01:13 2022 +0000
+Date: Fri Apr 29 03:16:48 2022 +0000
- upstream: Enable all supported hostkey algorithms (but no others).
+ upstream: Don't leak SK device. Patch from Pedro Martelletto via
- Allows hostbased test to pass when built without OpenSSL.
+ github PR#316. ok djm@
- OpenBSD-Regress-ID: 5ddd677a68b672517e1e78460dc6ca2ccc0a9562
+ OpenBSD-Commit-ID: 17d11327545022e727d95fd08b213171c5a4585d
-commit 12b457c2a42ff271e7967d9bedd068cebb048db9
+commit 247082b5013f0d4fcae8f97453f2a2f01bcda811
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Jan 8 07:37:32 2022 +0000
+Date: Fri Apr 29 03:13:32 2022 +0000
- upstream: use status error message to communicate ~user expansion
+ upstream: fix memleak on session-bind path; from Pedro Martelletto, ok
- failures; provides better experience for scp in sftp mode, where ~user paths
- are more likely to be used; spotted jsg, feedback jsg & deraadt ok jsg &
- markus
+ dtucker@
- OpenBSD-Commit-ID: fc610ce00ca0cdc2ecdabbd49ce7cb82033f905f
+ OpenBSD-Commit-ID: e85899a26ba402b4c0717b531317e8fc258f0a7e
-commit 63670d4e9030bcee490d5a9cce561373ac5b3b23
+commit e05522008092ceb86a87bdd4ad7878424315db89
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Jan 8 07:36:11 2022 +0000
+Date: Thu Apr 28 02:53:31 2022 +0000
- upstream: fix some corner-case bugs in scp sftp-mode handling of
+ upstream: avoid printing hash algorithm twice; from lucas AT sexy.is
- ~-prefixed paths; spotted by jsg; feedback jsg & deraadt, ok jsg & markus
+ OpenBSD-Commit-ID: 9d24671e10a84141b7c504396cabad600e47a941
+
+commit 0979e29356915261d69a9517a1e0aaade7c9fc75
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Wed Apr 27 11:08:55 2022 +0000
+
+ upstream: Add authfd path to debug output. ok markus@
- OpenBSD-Commit-ID: d1697dbaaa9f0f5649d69be897eab25c7d37c222
+ OpenBSD-Commit-ID: f735a17d1a6f2bee63bfc609d76ef8db8c090890
-commit e14940bbec57fc7d3ce0644dbefa35f5a8ec97d0
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Jan 8 07:34:57 2022 +0000
+commit 67b7c784769c74fd4d6b147d91e17e1ac1a8a96d
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Apr 26 07:41:44 2022 +0000
- upstream: more idiomatic error messages; spotted by jsg & deraadt
+ upstream: Check sshauthopt_new() for NULL. bz#3425, from
- ok jsg & markus
+ tessgauthier at microsoft.com. ok djm@
- OpenBSD-Commit-ID: 43618c692f3951747b4151c477c7df22afe2bcc8
+ OpenBSD-Commit-ID: af0315bc3e44aa406daa7e0ae7c2d719a974483f
-commit 9acddcd5918c623f7ebf454520ffe946a8f15e90
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Jan 8 07:33:54 2022 +0000
+commit d571314d14b919fbd7c84a61f9bf2065fc0a6841
+Author: millert@openbsd.org <millert@openbsd.org>
+Date: Wed Apr 20 16:00:25 2022 +0000
- upstream: add a variant of send_status() that allows overriding the
+ upstream: Remove unnecessary includes: openssl/hmac.h and
- default, generic error message. feedback/ok markus & jsg
+ openssl/evp.h. From Martin Vahlensieck.
- OpenBSD-Commit-ID: 81f251e975d759994131b717ee7c0b439659c40f
+ OpenBSD-Commit-ID: a6debb5fb0c8a44e43e8d5ca7cc70ad2f3ea31c3
-commit 961411337719d4cd78f1ab33e4ac549f3fa22f50
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Jan 8 07:32:45 2022 +0000
+commit da8dddf8cc1f2516ff894b8183e83a7c5ba3ef80
+Author: millert@openbsd.org <millert@openbsd.org>
+Date: Wed Apr 20 15:59:18 2022 +0000
- upstream: refactor tilde_expand_filename() and make it handle ~user
+ upstream: Add missing includes of stdlib.h and stdint.h. We need
- paths with no trailing slash; feedback/ok markus and jsg
+ stdlib.h for malloc(3) and stdint.h for SIZE_MAX. Unlike the other xmss
+ files, ssh-xmss.c does not include xmss_commons.h so ssh-xmss.c must include
+ those headers itself. From Martin Vahlensieck
- OpenBSD-Commit-ID: a2ab365598a902f0f14ba6a4f8fb2d07a9b5d51d
+ OpenBSD-Commit-ID: 70e28a9818cee3da1be2ef6503d4b396dd421e6b
-commit dc38236ab6827dec575064cac65c8e7035768773
+commit fe9d87a6800a7a33be08f4d5ab662a758055ced2
+Author: millert@openbsd.org <millert@openbsd.org>
+Date: Wed Apr 20 15:56:49 2022 +0000
+
+ upstream: Avoid an unnecessary xstrdup in rm_env() when matching
+
+ patterns. Since match_pattern() doesn't modify its arguments (they are
+ const), there is no need to make an extra copy of the strings in
+ options->send_env. From Martin Vahlensieck
+
+ OpenBSD-Commit-ID: 2c9db31e3f4d3403b49642c64ee048b2a0a39351
+
+commit 7bf2eb958fbb551e7d61e75c176bb3200383285d
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Apr 26 23:30:59 2022 +1000
+
+ Add debian-riscv64 test target.
+
+commit 3913c935523902482974c4c503bcff20bd850a6a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Apr 25 17:20:06 2022 +1000
+
+ Update OpenSSL and LibreSSL versions in tests.
+
+commit dcd8dca29bcdb193ff6be35b96fc55e6e30d37d9
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Apr 23 20:40:28 2022 +1000
+
+ Include stdlib.h for free() prototype.
+
+ ... which is used inside the CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG block.
+
+commit 4cc05de568e1c3edd7834ff3bd9d8214eb34861b
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Apr 23 20:17:26 2022 +1000
+
+ Cache timezone data in capsicum sandbox.
+
+ From emaste at freebsd.org, originally part of FreeBSD commit r339216
+ / fc3c19a9 with autoconf bits added by me.
+
+commit c31404426d212e2964ff9e5e58e1d0fce3d83f27
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Thu Jan 6 22:14:25 2022 +0000
+Date: Thu Apr 21 01:36:46 2022 +0000
- upstream: Don't explicitly set HostbasedAuthentication in
+ upstream: It looks like we can't completely avoid
- sshd_config. It defaults to "no", and not explicitly setting it allows us to
- enable it for the (optional) hostbased test.
+ waiting for processes to exit so retrieve the pid via controlmaster and
+ use that.
- OpenBSD-Regress-ID: aa8e3548eb5793721641d26e56c29f363b767c0c
+ OpenBSD-Regress-ID: 8246f00f22b14e49d2ff1744c94897ead33d457b
-commit e12d912ddf1c873cb72e5de9a197afbe0b6622d2
+commit d19b21afab5c8e2f3df6bd8aee9766bdad3d8c58
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Thu Jan 6 21:46:56 2022 +0000
+Date: Wed Apr 20 13:25:55 2022 +0000
- upstream: Add test for hostbased auth. It requires some external
+ upstream: Use ssh -f and ControlPersist ..
- setup (see comments at the top) and thus is disabled unless
- TEST_SSH_HOSTBASED_AUTH and SUDO are set.
+ to start up test forwards and ssh -O stop to shut them down intead of
+ sleep loops. This speeds up the test by an order of magnitude.
- OpenBSD-Regress-ID: 3ec8ba3750c5b595fc63e7845d13483065a4827a
+ OpenBSD-Regress-ID: eb3db5f805100919b092a3b2579c611fba3e83e7
-commit a48533a8da6a0f4f05ecd055dc8048047e53569e
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Jan 7 09:24:26 2022 +1100
+commit 5f76286a126721fa005de6edf3d1c7a265555f19
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Wed Apr 20 05:24:13 2022 +0000
- depend
+ upstream: Simplify forward-control test.
+
+ Since we no longer need to support SSH1 we don't need to run shell
+ commands on the other end of the connection and can use ssh -N instead.
+ This also makes the test less racy.
+
+ OpenBSD-Regress-ID: 32e94ce272820cc398f30b848b2b0f080d10302c
-commit d9dbb5d9a0326e252d3c7bc13beb9c2434f59409
+commit 687bbf23572d8bdf25cbbcdf8ac583514e1ba710
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Jan 6 22:06:51 2022 +0000
+Date: Thu Mar 31 03:07:33 2022 +0000
- upstream: allow hostbased auth to select RSA keys when only
+ upstream: regression test for sftp cp command
- RSA/SHA2 are configured (this is the default case); ok markus@
+ OpenBSD-Regress-ID: c96bea9edde3a384b254785e7f9b2b24a81cdf82
+
+commit f1233f19a6a9fe58f52946f50df4772f5b136761
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Wed Apr 20 01:13:47 2022 +0000
+
+ upstream: Import regenerated moduli
- OpenBSD-Commit-ID: 411c18c7bde40c60cc6dfb7017968577b4d4a827
+ OpenBSD-Commit-ID: f9a0726d957cf10692a231996a1f34e7f9cdfeb0
-commit fdb1d58d0d3888b042e5a500f6ce524486aaf782
+commit fec014785de198b9a325d1b94e324bb958c5fe7b
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Jan 6 22:05:42 2022 +0000
+Date: Wed Apr 20 04:19:11 2022 +0000
- upstream: add a helper function to match a key type to a list of
+ upstream: Try to continue running local I/O for channels in state
- signature algorithms. RSA keys can make signatures with multiple algorithms,
- so some special handling is required. ok markus@
+ OPEN during SSH transport rekeying. The most visible benefit is that it
+ should make ~-escapes work in the client (e.g. to exit) if the connection
+ happened to have stalled during a rekey event. Based work by and ok dtucker@
- OpenBSD-Commit-ID: 03b41b2bda06fa4cd9c84cef6095033b9e49b6ff
+ OpenBSD-Commit-ID: a66e8f254e92edd4ce09c9f750883ec8f1ea5f45
-commit 11e8c4309a5086a45fbbbc87d0af5323c6152914
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Jan 6 22:04:20 2022 +0000
+commit e68154b0d4f0f5085a050ea896955da1b1be6e30
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Wed Apr 20 01:13:47 2022 +0000
- upstream: log some details on hostkeys that ssh loads for
+ upstream: Import regenerated moduli
- hostbased authn ok markus@
+ OpenBSD-Commit-ID: f9a0726d957cf10692a231996a1f34e7f9cdfeb0
+
+commit 69928b106d8f0fa15b88cf3850d992ed81c44ae0
+Author: tj@openbsd.org <tj@openbsd.org>
+Date: Sat Apr 16 00:22:31 2022 +0000
+
+ upstream: list the correct version number
- OpenBSD-Commit-ID: da17061fa1f0e58cb31b88478a40643e18233e38
+ for when usage of the sftp protocol became default and fix a typo
+ from ed maste
+
+ OpenBSD-Commit-ID: 24e1795ed2283fdeacf16413c2f07503bcdebb31
-commit c6706f661739514a34125aa3136532a958929510
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Jan 6 22:03:59 2022 +0000
+commit 21042a05c0b304c16f655efeec97438249d2e2cc
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Apr 12 05:09:49 2022 +0000
- upstream: log signature algorithm during verification by monitor;
+ upstream: Correct path for system known hosts file in description
- ok markus
+ of IgnoreUserKnownHosts. Patch from Martin Vahlensieck via tech@
- OpenBSD-Commit-ID: 02b92bb42c4d4bf05a051702a56eb915151d9ecc
+ OpenBSD-Commit-ID: 9b7784f054fa5aa4d63cb36bd563889477127215
-commit 8832402bd500d1661ccc80a476fd563335ef6cdc
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Jan 6 22:02:52 2022 +0000
+commit 53f4aff60a7c1a08a23917bd47496f8901c471f5
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Apr 16 14:33:20 2022 +1000
- upstream: piece of UpdateHostkeys client strictification: when
+ Resync moduli.5 with upstream.
- updating known_hosts with new keys, ignore NULL keys (forgot to include in
- prior commit)
+ 1.18: remove duplicate publication year; carsten dot kunze at arcor dot de
+ 1.19: ssh-keygen's -G/-T have been replaced with -M generate/screen.
+
+commit d2b888762b9844eb0d8eb59909cdf5af5159f810
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Apr 16 14:31:13 2022 +1000
+
+ Retire fbsd6 test VM.
- OpenBSD-Commit-ID: 49d2eda6379490e1ceec40c3b670b973f63dea08
+ It's long since out of support, relatively slow (it's i686) and the
+ compiler has trouble with PIE.
-commit c2d9ced1da0276961d86690b3bd7ebdaca7fdbf7
+commit cd1f70009860a154b51230d367c55ea5f9a4504e
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Jan 6 22:01:14 2022 +0000
+Date: Mon Apr 11 22:52:08 2022 +0000
- upstream: include rejected signature algorithm in error message
+ upstream: clear io_want/io_ready flags at start of poll() cycle;
- and not the (useless) key type; ok markus
+ avoids plausible spin during rekeying if channel io_want flags are reused
+ across cycles. ok markus@ deraadt@
- OpenBSD-Commit-ID: 4180b5ec7ab347b43f84e00b1972515296dab023
+ OpenBSD-Commit-ID: 91034f855b7c73cd2591657c49ac30f10322b967
-commit 7aa7b096cf2bafe2777085abdeed5ce00581f641
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Jan 6 22:00:18 2022 +0000
+commit aa1920302778273f7f94c2091319aba199068ca0
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Apr 8 05:43:39 2022 +0000
- upstream: make ssh-keysign use the requested signature algorithm
+ upstream: Note that curve25519-sha256 was later published in
- and not the default for the keytype. Part of unbreaking hostbased auth for
- RSA/SHA2 keys. ok markus@
+ RFC8731. ok djm@
- OpenBSD-Commit-ID: b5639a14462948970da3a8020dc06f9a80ecccdc
+ OpenBSD-Commit-ID: 2ac2b5d642d4cf5918eaec8653cad9a4460b2743
-commit 291721bc7c840d113a49518f3fca70e86248b8e8
+commit 4673fa8f2be983f2f88d5afd754adb1a2a39ec9e
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Jan 6 21:57:28 2022 +0000
+Date: Fri Apr 8 04:40:40 2022 +0000
- upstream: stricter UpdateHostkey signature verification logic on
+ upstream: two defensive changes from Tobias Stoeckmann via GHPR287
- the client- side. Require RSA/SHA2 signatures for RSA hostkeys except when
- RSA/SHA1 was explicitly negotiated during initial KEX; bz3375
+ enforce stricter invarient for sshbuf_set_parent() - never allow
+ a buffer to have a previously-set parent changed.
- ok markus@
+ In sshbuf_reset(), if the reallocation fails, then zero the entire
+ buffer and not the (potentially smaller) default initial alloc size.
- OpenBSD-Commit-ID: 46e75e8dfa2c813781805b842580dcfbd888cf29
+ OpenBSD-Commit-ID: 14583203aa5d50ad38d2e209ae10abaf8955e6a9
-commit 0fa33683223c76289470a954404047bc762be84c
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Jan 6 21:55:23 2022 +0000
+commit 26eef015e2d2254375e13afaaf753b78932b1bf5
+Author: Damien Miller <djm@mindrot.org>
+Date: Mon Apr 11 16:07:09 2022 +1000
- upstream: Fix signature algorithm selection logic for
-
- UpdateHostkeys on the server side. The previous code tried to prefer RSA/SHA2
- for hostkey proofs of RSA keys, but missed some cases. This will use RSA/SHA2
- signatures for RSA keys if the client proposed these algorithms in initial
- KEX. bz3375
+ Revert "update build-aux files to match autoconf-2.71"
- Mostly by Dmitry Belyavskiy with some tweaks by me.
-
- ok markus@
+ This reverts commit 0a8ca39fac6ad19096b6c263436f8b2dd51606f2.
- OpenBSD-Commit-ID: c17ba0c3236340d2c6a248158ebed042ac6a8029
+ It turns out that the checked-in copies of these files are actually newer
+ than autoconf-2.71's copies, so this was effectively a downgrade.
+ Spotted by Bo Anderson via github
-commit 17877bc81db3846e6e7d4cfb124d966bb9c9296b
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Jan 6 21:48:38 2022 +0000
+commit 0a8ca39fac6ad19096b6c263436f8b2dd51606f2
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Apr 8 14:48:58 2022 +1000
- upstream: convert ssh, sshd mainloops from select() to poll();
-
- feedback & ok deraadt@ and markus@ has been in snaps for a few months
+ update build-aux files to match autoconf-2.71
- OpenBSD-Commit-ID: a77e16a667d5b194dcdb3b76308b8bba7fa7239c
+ i.e. config.guess, config.sub and install-sh
-commit 5c79952dfe1aa36105c93b3f383ce9be04dee384
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Jan 6 21:46:23 2022 +0000
+commit 94eb6858efecc1b4f02d8a6bd35e149f55c814c8
+Author: Damien Miller <djm@mindrot.org>
+Date: Wed Apr 6 10:47:48 2022 +1000
- upstream: prepare for conversion of ssh, sshd mainloop from
-
- select() to poll() by moving FD_SET construction out of channel handlers into
- separate functions. ok markus
-
- OpenBSD-Commit-ID: 937fbf2a4de12b19fb9d5168424e206124807027
+ update version numbers for release
-commit 24c5187edfef4651a625b7d5d692c8c7e794f71f
+commit 8e4a8eadf4fe74e65e6492f34250f8cf7d67e8da
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Jan 5 21:54:37 2022 +0000
+Date: Mon Apr 4 22:45:25 2022 +0000
- upstream: add a comment so I don't make this mistake again
+ upstream: openssh-9.0
- OpenBSD-Commit-ID: 69c7f2362f9de913bb29b6318580c5a1b52c921e
+ OpenBSD-Commit-ID: 0dfb461188f4513ec024c1534da8c1ce14c20b64
-commit 7369900441929058263a17f56aa67e05ff7ec628
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Jan 5 21:50:00 2022 +0000
+commit a9f23ea2e3227f406880c2634d066f6f50fa5eaa
+Author: naddy@openbsd.org <naddy@openbsd.org>
+Date: Thu Mar 31 17:58:44 2022 +0000
- upstream: fix cut-and-pasto in error message
+ upstream: ssh: document sntrup761x25519-sha512@openssh.com as
- OpenBSD-Commit-ID: 4cc5c619e4b456cd2e9bb760d17e3a9c84659198
+ default KEX
+
+ OpenBSD-Commit-ID: 12545bfa10bcbf552d04d9d9520d0f4e98b0e171
-commit 294c11b1c7d56d3fb61e329603a782315ed70c62
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Jan 5 08:25:05 2022 +0000
+commit 9ec2713d122af79d66ebb9c1d6d9ae8621a8945f
+Author: naddy@openbsd.org <naddy@openbsd.org>
+Date: Thu Mar 31 17:27:27 2022 +0000
- upstream: select all RSA hostkey algorithms for UpdateHostkeys tests,
+ upstream: man pages: add missing commas between subordinate and
- not just RSA-SHA1
+ main clauses
- OpenBSD-Regress-ID: b40e62b65863f2702a0c10aca583b2fe76772bd8
-
-commit 2ea1108c30e3edb6f872dfc1e6da10b041ddf2c0
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Jan 5 04:56:15 2022 +0000
-
- upstream: regress test both sshsig message hash algorithms, possible
+ jmc@ dislikes a comma before "then" in a conditional, so leave those
+ untouched.
- now because the algorithm is controllable via the CLI
+ ok jmc@
- OpenBSD-Regress-ID: 0196fa87acc3544b2b4fd98de844a571cb09a39f
+ OpenBSD-Commit-ID: 9520801729bebcb3c9fe43ad7f9776ab4dd05ea3
-commit 2327c306b5d4a2b7e71178e5a4d139af9902c2b0
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Jan 5 04:50:11 2022 +0000
+commit 3741df98ffaaff92b474ee70d8ef276b5882f85a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Apr 4 23:52:11 2022 +1000
- upstream: allow selection of hash at sshsig signing time; code
-
- already supported either sha512 (default) or sha256, but plumbing wasn't
- there mostly by Linus Nordberg
-
- OpenBSD-Commit-ID: 1b536404b9da74a84b3a1c8d0b05fd564cdc96cd
+ Disable security key on fbsd6 test host.
-commit 56e941d0a00d6d8bae88317717d5e1b7395c9529
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Jan 5 04:27:54 2022 +0000
+commit 32c12236f27ae83bfe6d2983b67c9bc67a83a417
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Apr 4 15:16:51 2022 +1000
- upstream: add missing -O option to usage() for ssh-keygen -Y sign;
-
- from Linus Nordberg
+ Specify TEST_SHELL=bash on AIX.
- OpenBSD-Commit-ID: 4e78feb4aa830727ab76bb2e3d940440ae1d7af0
+ The system shells cause the agent-restrict test to fail due to some
+ quoting so explicitly specify bash until we can get configure to
+ autmatically work around that.
-commit 141a14ec9b0924709c98df2dd8013bde5d8d12c7
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Jan 5 04:27:01 2022 +0000
+commit 90452c8b69d065b7c7c285ff78b81418a75bcd76
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Apr 1 23:38:44 2022 +1100
- upstream: move sig_process_opts() to before sig_sign(); no
-
- functional code change
+ Only return events from ppoll that were requested.
- OpenBSD-Commit-ID: da02d61f5464f72b4e8b299f83e93c3b657932f9
+ If the underlying system's select() returns bits that were not in the
+ request set, our ppoll() implementation can return revents for events
+ not requested, which can apparently cause a hang. Only return revents
+ for activity in the requested event set. bz#3416, analysis and fix by
+ yaroslav.kuzmin at vmssoftware com, ok djm@
-commit 37a14249ec993599a9051731e4fb0ac5e976aec1
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Jan 5 04:10:39 2022 +0000
+commit 6c49eb5fabc56f4865164ed818aa5112d09c31a8
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Apr 1 23:21:40 2022 +1100
- upstream: regression test for find-principals NULL deref; from Fabian
-
- Stelzer
-
- OpenBSD-Regress-ID: f845a8632a5a7d5ae26978004c93e796270fd3e5
+ Only run regression tests on slow VMs.
-commit eb1f042142fdaba93f6c9560cf6c91ae25f6884a
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Jan 5 04:02:42 2022 +0000
+commit f67e47903977b42cb6abcd5565a61bd7293e4dc3
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Apr 1 23:21:06 2022 +1100
- upstream: NULL deref when using find-principals when matching an
-
- allowed_signers line that contains a namespace restriction, but no
- restriction specified on the command-line; report and fix from Fabian Stelzer
-
- OpenBSD-Commit-ID: 4a201b86afb668c908d1a559c6af456a61f4b145
+ Increase test timeout to allow slow VMs to finish
-commit 8f3b18030579f395eca2181da31a5f945af12a59
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Jan 4 08:38:53 2022 +0000
+commit 02488c1b54065ddc4f25835dbd2618b2a2fe21f5
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Apr 1 16:27:38 2022 +1100
- upstream: Log command invocation while debugging.
-
- This will aid in manually reproducing failing commands.
-
- OpenBSD-Regress-ID: b4aba8d5ac5675ceebeeeefa3261ce344e67333a
+ Use bash or ksh if available for SH in Makefile.
-commit bbf285164df535f0d38c36237f007551bbdae27f
+commit 34c7018c316af4773e432066de28d0ef9d0888cd
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sun Dec 26 10:31:15 2021 +1100
+Date: Fri Apr 1 14:56:54 2022 +1100
- Always save config.h as build artifact.
+ Set Makefile SHELL as determined by configure.
- Should allow better comparison between failing and succeeding test
- platforms.
+ This should improve compatibility for users with non-POSIX shells. If
+ using Makefile.in directly (eg make -f Makefile.in distprep) then SHELL
+ will need to be specified on the command line (along with MANFMT in that
+ particular case). ok djm@
-commit 03bd4ed0db699687c5cd83405d26f81d2dc28d22
+commit 5b054d76402faab38c48377efd112426469553a0
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Dec 25 16:42:51 2021 +1100
+Date: Fri Apr 1 13:16:47 2022 +1100
- Add OpenBSD 7.0 target. Retire 6.8.
+ Skip slow tests on (very) slow test targets.
-commit c45a752f0de611afd87755c2887c8a24816d08ee
-Author: jsg@openbsd.org <jsg@openbsd.org>
-Date: Sat Jan 1 05:55:06 2022 +0000
+commit b275818065b31a865142c48c2acf6a7c1655c542
+Author: Damien Miller <djm@mindrot.org>
+Date: Thu Mar 31 14:11:36 2022 +1100
- upstream: spelling
-
- OpenBSD-Commit-ID: c63e43087a64d0727af13409c708938e05147b62
+ depend
-commit c672f83a89a756564db0d3af9934ba0e1cf8fa3e
+commit 3fa539c3ffaabd6211995512d33e29150f88c5c5
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jan 4 07:20:33 2022 +0000
+Date: Thu Mar 31 03:07:03 2022 +0000
- upstream: unbreak test: was picking up system ssh-add instead of the
+ upstream: add a sftp client "cp" command that supports server-side
- one supposedly being tested. Spotted by dtucker and using his VM zoo (which
- includes some systems old enough to lack ed25519 key support)
+ copying of files. Useful for this task and for testing the copy-data
+ extension. Patch from Mike Frysinger; ok dtucker@
- OpenBSD-Regress-ID: 7976eb3df11cc2ca3af91030a6a8c0cef1590bb5
+ OpenBSD-Commit-ID: 1bb1b950af0d49f0d5425b1f267e197aa1b57444
-commit a23698c3082ffe661abed14b020eac9b0c25eb9f
+commit 7988bfc4b701c4b3fe9b36c8561a3d1c5d4c9a74
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Jan 1 04:18:06 2022 +0000
+Date: Thu Mar 31 03:05:49 2022 +0000
- upstream: fix memleak in process_extension(); oss-fuzz issue #42719
+ upstream: add support for the "corp-data" protocol extension to
- OpenBSD-Commit-ID: d8d49f840162fb7b8949e3a5adb8107444b6de1e
+ allow server-side copies to be performed without having to go via the client.
+ Patch by Mike Frysinger, ok dtucker@
+
+ OpenBSD-Commit-ID: 00aa510940fedd66dab1843b58682de4eb7156d5
-commit cb885178f36b83d0f14cfe9f345d2068103feed0
-Author: jsg@openbsd.org <jsg@openbsd.org>
-Date: Sat Jan 1 01:55:30 2022 +0000
+commit 32dc1c29a4ac9c592ddfef0a4895eb36c1f567ba
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Mar 30 21:13:23 2022 +0000
- upstream: spelling ok dtucker@
+ upstream: select post-quantum KEX
- OpenBSD-Commit-ID: bfc7ba74c22c928de2e257328b3f1274a3dfdf19
+ sntrup761x25519-sha512@openssh.com as the default; ok markus@
+
+ OpenBSD-Commit-ID: f02d99cbfce22dffec2e2ab1b60905fbddf48fb9
-commit 6b977f8080a32c5b3cbb9edb634b9d5789fb79be
+commit d6556de1db0822c76ba2745cf5c097d9472adf7c
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 26 23:34:41 2021 +0000
+Date: Wed Mar 30 21:10:25 2022 +0000
- upstream: split method list search functionality from
+ upstream: fix poll() spin when a channel's output fd closes without
- authmethod_lookup() into a separate authmethod_byname(), for cases where we
- don't need to check whether a method is enabled, etc.
+ data in the channel buffer. Introduce more exact packing of channel fds into
+ the pollfd array. fixes bz3405 and bz3411; ok deraadt@ markus@
- use this to fix the "none" authentication method regression reported
- by Nam Nguyen via bugs@
+ OpenBSD-Commit-ID: 06740737849c9047785622ad5d472cb6a3907d10
+
+commit 8a74a96d25ca4d32fbf298f6c0ac5a148501777d
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Mar 30 04:33:09 2022 +0000
+
+ upstream: ssh is almost out of getopt() characters; note the
- ok deraadt@
+ remaining remaining available ones in a comment
- OpenBSD-Commit-ID: 8cd188dc3a83aa8abe5b7693e762975cd8ea8a17
+ OpenBSD-Commit-ID: 48d38cef59d6bc8e84c6c066f6d601875d3253fd
-commit 0074aa2c8d605ee7587279a22cdad4270b4ddd07
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Wed Dec 22 06:56:41 2021 +0000
+commit 6d4fc51adb9d8a42f67b5474f02f877422379de6
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Mar 30 04:27:51 2022 +0000
- upstream: sort -H and -h in SYNOPSIS/usage(); tweak the -H text;
+ upstream: avoid NULL deref via ssh-keygen -Y find-principals.
- ok djm
+ bz3409, reported by Mateusz Adamowski
- OpenBSD-Commit-ID: 90721643e41e9e09deb5b776aaa0443456ab0965
+ OpenBSD-Commit-ID: a3b2c02438052ee858e0ee18e5a288586b5df2c5
-commit 1c9853a68b2319f2e5f929179735e8fbb9988a67
+commit e937514920335b92b543fd9be79cd6481d1eb0b6
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Dec 22 19:33:10 2021 +1100
+Date: Mon Mar 28 17:51:03 2022 +1100
- Use SHA.*_HMAC_BLOCK_SIZE if needed.
-
- If the platform has a native SHA2, does not define SHA.*_BLOCK_LENGTH
- but does define SHA.*_HMAC_BLOCK_SIZE (eg Solaris) then use the latter.
- Should fix --without-openssl build on Solaris.
+ Add AIX 5.1 test target.
-commit 715c892f0a5295b391ae92c26ef4d6a86ea96e8e
-Author: Damien Miller <djm@mindrot.org>
-Date: Wed Dec 22 09:02:50 2021 +1100
+commit 4bbe815ba974b4fd89cc3fc3e3ef1be847a0befe
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Mar 26 22:01:31 2022 +1100
- remove sys/param.h in -portable, after upstream
+ Drop leading "v" from release version identifier.
+
+ It's present in the git tags but not in the release tarball names.
+ Also drop extra "/" from URL path.
-commit 7a7c69d8b4022b1e5c0afb169c416af8ce70f3e8
-Author: Damien Miller <djm@mindrot.org>
-Date: Mon Dec 20 13:05:20 2021 +1100
+commit f5cdd3b3c275dffaebfca91df782dca29975e9ac
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Mar 26 16:28:04 2022 +1100
- add agent-restrict.sh file, missed in last commit
+ Use tarballs when testing LibreSSL releases.
+
+ This means they'll still work when the combination of -portable and
+ openbsd github repos no longer match.
-commit f539136ca51a4976644db5d0be8158cc1914c72a
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:20:12 2021 +0000
+commit 24dc37d198f35a7cf71bf4d5384363c7ef4209d4
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Mar 26 15:02:45 2022 +1100
- upstream: regression test for destination restrictions in ssh-agent
-
- OpenBSD-Regress-ID: 3c799d91e736b1753b4a42d80c42fc40de5ad33d
+ Remove now-unused passwd variable.
-commit 6e4980eb8ef94c04874a79dd380c3f568e8416d6
-Author: anton@openbsd.org <anton@openbsd.org>
-Date: Sat Dec 18 06:53:59 2021 +0000
+commit 5b467ceef2c356f0a77f5e8ab4eb0fac367e4d24
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Mar 26 13:15:44 2022 +1100
- upstream: Make use of ntests variable, pointed out by clang 13.
-
- OpenBSD-Regress-ID: 4241a3d21bdfa1630ed429b6d4fee51038d1be72
+ Missing semicolon.
-commit 3eead8158393b697f663ec4301e3c7b6f24580b1
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Tue Dec 14 21:25:27 2021 +0000
+commit 2923d026e55998133c0f6e5186dca2a3c0fa5ff5
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Mar 26 12:49:50 2022 +1100
- upstream: sys/param.h cleanup, mostly using MINIMUM() and
-
- <limits.h> ok dtucker
+ Factor out platform-specific locked account check.
- OpenBSD-Regress-ID: 172a4c45d3bcf92fa6cdf6c4b9db3f1b3abe4db0
+ Also fixes an incorrect free on platforms with both libiaf and shadow
+ passwords (probably only Unixware). Prompted by github PR#284,
+ originally from @c3h2_ctf and stoeckmann@.
-commit 266678e19eb0e86fdf865b431b6e172e7a95bf48
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:15:42 2021 +0000
+commit d23efe4b12886ffe416be10bc0a7da6ca8aa72d1
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Mar 26 08:13:46 2022 +1100
- upstream: document host-bound publickey authentication
-
- OpenBSD-Commit-ID: ea6ed91779a81f06d961e30ecc49316b3d71961b
+ Add OpenWRT mips and mipsel test targets.
-commit 3d00024b3b156aa9bbd05d105f1deb9cb088f6f7
+commit 16ea8b85838dd7a4dbeba4e51ac4f43fd68b1e5b
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:15:21 2021 +0000
+Date: Sun Mar 20 08:52:17 2022 +0000
- upstream: document agent protocol extensions
+ upstream: don't leak argument list; bz3404, reported by Balu
- OpenBSD-Commit-ID: 09e8bb391bbaf24c409b75a4af44e0cac65405a7
+ Gajjala ok dtucker@
+
+ OpenBSD-Commit-ID: fddc32d74e5dd5cff1a49ddd6297b0867eae56a6
-commit c385abf76511451bcba78568167b1cd9e90587d5
+commit a72bde294fe0518c9a44ba63864093a1ef2425e3
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:14:47 2021 +0000
+Date: Sun Mar 20 08:51:21 2022 +0000
- upstream: PubkeyAuthentication=yes|no|unbound|host-bound
+ upstream: make addargs() and replacearg() a little more robust and
- Allow control over which pubkey methods are used. Added out of
- concern that some hardware devices may have difficulty signing
- the longer pubkey authentication challenges. This provides a
- way for them to disable the extension. It's also handy for
- testing.
+ improve error reporting
- feedback / ok markus@
+ make freeargs(NULL) a noop like the other free functions
- OpenBSD-Commit-ID: ee52580db95c355cf6d563ba89974c210e603b1a
+ ok dtucker as part of bz3403
+
+ OpenBSD-Commit-ID: 15f86da83176978b4d1d288caa24c766dfa2983d
-commit 34b1e9cc7654f41cd4c5b1cc290b999dcf6579bb
+commit 731087d2619fa7f01e675b23f57af10d745e8af2
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:14:12 2021 +0000
+Date: Fri Mar 18 04:04:11 2022 +0000
- upstream: document destination-constrained keys
+ upstream: don't try to resolve ListenAddress directives in the sshd
- feedback / ok markus@
+ re-exec path - we're never going to use the result and if the operation fails
+ then it can prevent connections from being accepted. Reported by Aaron
+ Poffenberger; with / ok dtucker@
- OpenBSD-Commit-ID: cd8c526c77268f6d91c06adbee66b014d22d672e
+ OpenBSD-Commit-ID: 44c53a43909a328e2f5ab26070fdef3594eded60
-commit a6d7677c4abcfba268053e5867f2acabe3aa371b
+commit 1c83c082128694ddd11ac05fdf31d70312ff1763
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:13:55 2021 +0000
+Date: Fri Mar 18 02:50:21 2022 +0000
- upstream: Use hostkey parsed from hostbound userauth request
-
- Require host-bound userauth requests for forwarded SSH connections.
-
- The hostkey parsed from the host-bound userauth request is now checked
- against the most recently bound session ID / hostkey on the agent socket
- and the signature refused if they do not match.
-
- ok markus@
+ upstream: remove blank line
- OpenBSD-Commit-ID: d69877c9a3bd8d1189a5dbdeceefa432044dae02
+ OpenBSD-Commit-ID: d5e0182965b2fbfb03ad5f256d1a1ce5706bcddf
-commit baaff0ff4357cc5a079621ba6e2d7e247b765061
+commit 807be68684da7a1fe969c399ddce2fafb7997dcb
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:13:33 2021 +0000
+Date: Fri Mar 18 02:32:22 2022 +0000
- upstream: agent support for parsing hostkey-bound signatures
-
- Allow parse_userauth_request() to work with blobs from
- publickey-hostbound-v00@openssh.com userauth attempts.
-
- Extract hostkey from these blobs.
-
- ok markus@
+ upstream: helpful comment
- OpenBSD-Commit-ID: 81c064255634c1109477dc65c3e983581d336df8
+ OpenBSD-Commit-ID: e3315a45cb04e7feeb614d76ec80a9fe4ca0e8c7
-commit 3e16365a79cdeb2d758cf1da6051b1c5266ceed7
+commit a0b5816f8f1f645acdf74f7bc11b34455ec30bac
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:13:12 2021 +0000
+Date: Fri Mar 18 02:31:25 2022 +0000
- upstream: EXT_INFO negotiation of hostbound pubkey auth
-
- the EXT_INFO packet gets a new publickey-hostbound@openssh.com to
- advertise the hostbound public key method.
-
- Client side support to parse this feature flag and set the kex->flags
- indicator if the expected version is offered (currently "0").
+ upstream: ssh-keygen -Y check-novalidate requires namespace or SEGV
- ok markus@
+ will ensue. Patch from Mateusz Adamowski via GHPR#307
- OpenBSD-Commit-ID: 4cdb2ca5017ec1ed7a9d33bda95c1d6a97b583b0
+ OpenBSD-Commit-ID: 99e8ec38f9feb38bce6de240335be34aedeba5fd
-commit 94ae0c6f0e35903b695e033bf4beacea1d376bb1
+commit 5a252d54a63be30d5ba4be76210942d754a531c0
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:12:54 2021 +0000
+Date: Tue Mar 15 05:27:37 2022 +0000
- upstream: client side of host-bound pubkey authentication
+ upstream: improve DEBUG_CHANNEL_POLL debugging message
- Add kex->flags member to enable the publickey-hostbound-v00@openssh.com
- authentication method.
+ OpenBSD-Commit-ID: 2275eb7bc4707d019b1a0194b9c92c0b78da848f
+
+commit ce324cf58ba2840e31afeb996935800780c8fa4b
+Author: cheloha@openbsd.org <cheloha@openbsd.org>
+Date: Sun Mar 13 23:27:54 2022 +0000
+
+ upstream: ssh: xstrdup(): use memcpy(3)
- Use the new hostbound method in client if the kex->flags flag was set,
- and include the inital KEX hostkey in the userauth request.
+ Copying the given string into the buffer with strlcpy(3) confers no
+ benefit in this context because we have already determined the
+ string's length with strlen(3) in order to allocate that buffer.
- Note: nothing in kex.c actually sets the new flag yet
+ Thread: https://marc.info/?l=openbsd-tech&m=164687525802691&w=2
- ok markus@
+ ok dtucker@ millert@
- OpenBSD-Commit-ID: 5a6fce8c6c8a77a80ee1526dc467d91036a5910d
+ OpenBSD-Commit-ID: f8bfc082e36e2d2dc4e1feece02fe274155ca11a
-commit 288fd0218dbfdcb05d9fbd1885904bed9b6d42e6
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:12:30 2021 +0000
+commit 2893c5e764557f48f9d6a929e224ed49c59545db
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Mar 11 18:43:58 2022 +1100
- upstream: sshd side of hostbound public key auth
-
- This is identical to the standard "publickey" method, but it also includes
- the initial server hostkey in the message signed by the client.
+ Resync fmt_scaled. with OpenBSD.
- feedback / ok markus@
+ Fixes underflow reported in bz#3401.
+
+commit 5ae31a0fdd27855af29f48ff027491629fff5979
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Mar 9 09:41:56 2022 +1100
+
+ Provide killpg implementation.
- OpenBSD-Commit-ID: 7ea01bb7238a560c1bfb426fda0c10a8aac07862
+ Based on github PR#301 for Tandem NonStop.
-commit dbb339f015c33d63484261d140c84ad875a9e548
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:12:07 2021 +0000
+commit c41c84b439f4cd74d4fe44298a4b4037ddd7d2ae
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Mar 9 09:29:30 2022 +1100
- upstream: prepare for multiple names for authmethods
+ Check for missing ftruncate prototype.
- allow authentication methods to have one additional name beyond their
- primary name.
+ From github PR#301 in conjunction with rsbeckerca.
+
+commit 8cf5275452a950869cb90eeac7d220b01f77b12e
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Mar 8 20:04:06 2022 +1100
+
+ Default to not using sandbox when cross compiling.
- allow lookup by this synonym
+ On most systems poll(2) does not work when the number of FDs is reduced
+ with setrlimit, so assume it doesn't when cross compiling and we can't
+ run the test. bz#3398.
+
+commit 379b30120da53d7c84aa8299c26b18c51c2a0dac
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Mar 1 01:59:19 2022 +0000
+
+ upstream: pack pollfd array before server_accept_loop() ppoll()
- Use primary name for authentication decisions, e.g. for
- PermitRootLogin=publickey
+ call, and terminate sshd if ppoll() returns errno==EINVAL
- Pass actual invoked name to the authmethods, so they can tell whether they
- were requested via the their primary name or synonym.
+ avoids spin in ppoll when MaxStartups > RLIMIT_NOFILE, reported by
+ Daniel Micay
- ok markus@
+ feedback/ok deraadt
- OpenBSD-Commit-ID: 9e613fcb44b8168823195602ed3d09ffd7994559
+ OpenBSD-Commit-ID: dbab1c24993ac977ec24d83283b8b7528f7c2c15
-commit 39f00dcf44915f20684160f0a88d3ef8a3278351
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:11:39 2021 +0000
+commit eceafbe0bdbbd9bd2f3cf024ccb350666a9934dd
+Author: naddy@openbsd.org <naddy@openbsd.org>
+Date: Sun Feb 27 01:33:59 2022 +0000
- upstream: ssh-agent side of destination constraints
+ upstream: include rejected signature algorithm in error message and
- Gives ssh-agent the ability to parse restrict-destination-v00@openssh.com
- constraints and to apply them to keys.
-
- Check constraints against the hostkeys recorded for a SocketEntry when
- attempting a signature, adding, listing or deleting keys. Note that
- the "delete all keys" request will remove constrained keys regardless of
- location.
-
- feedback Jann Horn & markus@
- ok markus@
+ not the (useless) key type; ok djm@
- OpenBSD-Commit-ID: 84a7fb81106c2d609a6ac17469436df16d196319
+ OpenBSD-Commit-ID: d0c0f552a4d9161203e07e95d58a76eb602a76ff
-commit ce943912df812c573a33d00bf9e5435b7fcca3f7
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:11:06 2021 +0000
+commit f2f3269423618a83157e18902385e720f9776007
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Feb 25 09:46:24 2022 +0000
- upstream: ssh-add side of destination constraints
-
- Have ssh-add accept a list of "destination constraints" that allow
- restricting where keys may be used in conjunction with a ssh-agent/ssh
- that supports session ID/hostkey binding.
-
- Constraints are specified as either "[user@]host-pattern" or
- "host-pattern>[user@]host-pattern".
-
- The first form permits a key to be used to authenticate as the
- specified user to the specified host.
-
- The second form permits a key that has previously been permitted
- for use at a host to be available via a forwarded agent to an
- additional host.
-
- For example, constraining a key with "user1@host_a" and
- "host_a>host_b". Would permit authentication as "user1" at
- "host_a", and allow the key to be available on an agent forwarded
- to "host_a" only for authentication to "host_b". The key would not
- be visible on agent forwarded to other hosts or usable for
- authentication there.
-
- Internally, destination constraints use host keys to identify hosts.
- The host patterns are used to obtain lists of host keys for that
- destination that are communicated to the agent. The user/hostkeys are
- encoded using a new restrict-destination-v00@openssh.com key
- constraint.
-
- host keys are looked up in the default client user/system known_hosts
- files. It is possible to override this set on the command-line.
+ upstream: Remove the char * casts from arguments to do_lstat,
- feedback Jann Horn & markus@
- ok markus@
+ do_readdir and do_stat paths since the underlying functions now take a const
+ char *. Patch from vapier at gentoo.org.
- OpenBSD-Commit-ID: 6b52cd2b637f3d29ef543f0ce532a2bce6d86af5
+ OpenBSD-Commit-ID: 9e4d964dbfb0ed683a2a2900711b88e7f1c0297b
-commit 5e950d765727ee0b20fc3d2cbb0c790b21ac2425
+commit 4a66dac052c5ff5047161853f36904607649e4f9
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:10:24 2021 +0000
+Date: Fri Feb 25 02:09:27 2022 +0000
- upstream: ssh-add side of destination constraints
-
- Have ssh-add accept a list of "destination constraints" that allow
- restricting where keys may be used in conjunction with a ssh-agent/ssh
- that supports session ID/hostkey binding.
-
- Constraints are specified as either "[user@]host-pattern" or
- "host-pattern>[user@]host-pattern".
-
- The first form permits a key to be used to authenticate as the
- specified user to the specified host.
-
- The second form permits a key that has previously been permitted
- for use at a host to be available via a forwarded agent to an
- additional host.
-
- For example, constraining a key with "user1@host_a" and
- "host_a>host_b". Would permit authentication as "user1" at
- "host_a", and allow the key to be available on an agent forwarded
- to "host_a" only for authentication to "host_b". The key would not
- be visible on agent forwarded to other hosts or usable for
- authentication there.
-
- Internally, destination constraints use host keys to identify hosts.
- The host patterns are used to obtain lists of host keys for that
- destination that are communicated to the agent. The user/hostkeys are
- encoded using a new restrict-destination-v00@openssh.com key
- constraint.
-
- host keys are looked up in the default client user/system known_hosts
- files. It is possible to override this set on the command-line.
+ upstream: save an unneccessary alloc/free, based on patch from
- feedback Jann Horn & markus@
- ok markus@
+ Martin Vahlensieck; ok dtucker@
- OpenBSD-Commit-ID: ef47fa9ec0e3c2a82e30d37ef616e245df73163e
+ OpenBSD-Commit-ID: 90ffbf1f837e509742f2c31a1fbf2c0fd376fd5f
-commit 4c1e3ce85e183a9d0c955c88589fed18e4d6a058
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:09:23 2021 +0000
+commit 6f117cb151efe138ac57bdd8e26165f350328f5f
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Mar 1 09:02:06 2022 +1100
- upstream: ssh-agent side of binding
-
- record session ID/hostkey/forwarding status for each active socket.
-
- Attempt to parse data-to-be-signed at signature request time and extract
- session ID from the blob if it is a pubkey userauth request.
-
- ok markus@
-
- OpenBSD-Commit-ID: a80fd41e292b18b67508362129e9fed549abd318
+ Remove unused ivbits argument from chacha_keysetup
-commit e9497ecf73f3c16667288bce48d4e3d7e746fea1
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:08:48 2021 +0000
+commit 15974235dd528aeab0ec67fb92a0a1d733f62be2
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Mar 1 09:00:20 2022 +1100
- upstream: ssh client side of binding
-
- send session ID, hostkey, signature and a flag indicating whether the
- agent connection is being forwarded to ssh agent each time a connection
- is opened via a new "session-bind@openssh.com" agent extension.
-
- ok markus@
-
- OpenBSD-Commit-ID: 2f154844fe13167d3ab063f830d7455fcaa99135
+ Add OPENBSD ORIGINAL marker.
-commit b42c61d6840d16ef392ed0f365e8c000734669aa
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 19 22:08:06 2021 +0000
+commit f2ff669347d320532e7c1b63cdf5c62f46e73150
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Feb 28 22:21:36 2022 +1100
- upstream: Record session ID, host key and sig at intital KEX
-
- These will be used later for agent session ID / hostkey binding
-
- ok markus@
+ No unused param warnings for clang-12 and gcc-11.
- OpenBSD-Commit-ID: a9af29e33772b18e3e867c6fa8ab35e1694a81fe
+ These have too many false positives in -Werror tests on the github CI
+ since we often provide empty stub functions for functionality not needed
+ for particular configurations.
-commit 26ca33d186473d58a32d812e19273ce078b6ffff
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Dec 7 22:06:45 2021 +0000
+commit 96558ecd87adac62efa9a2b5479f686ab86b0be1
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Feb 26 14:10:41 2022 +1100
- upstream: better error message for FIDO keys when we can't match
-
- them to a token
-
- OpenBSD-Commit-ID: 58255c2a1980088f4ed144db67d879ada2607650
+ Add debian-i386 test target.
-commit adb0ea006d7668190f0c42aafe3a2864d352e34a
+commit 284b6e5394652d519e31782e3b3cdfd7b21d1a81
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Dec 15 10:50:33 2021 +1100
+Date: Sat Feb 26 14:06:14 2022 +1100
- Correct value for IPTOS_DSCP_LE.
+ Allow ppoll_time64 in seccomp sandbox.
- It needs to allow for the preceeding two ECN bits. From daisuke.higashi
- at gmail.com via OpenSSH bz#3373, ok claudio@, job@, djm@.
+ Should fix sandbox violations on (some? at least i386 and armhf) 32bit
+ Linux platforms. Patch from chutzpahu at gentoo.org and cjwatson at
+ debian.org via bz#3396.
-commit 3dafd3fe220bd9046f11fcf5191a79ec8800819f
+commit 0132056efabc5edb85c3c7105d2fb6dee41843c6
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Dec 10 11:57:30 2021 +1100
+Date: Fri Feb 25 19:47:48 2022 +1100
- Increase timeout for test step.
+ Improve handling of _getshort and _getlong.
+
+ If the system native ones are exactly as required then use them,
+ otherwise use the local versions mapped to another name to prevent
+ name collisions.
-commit 5aefb05cd5b843e975b191d6ebb7ddf8de35c112
+commit 8e206e0dd6b9f757b07979e48f53ad5bf9b7b52b
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Dec 10 10:27:27 2021 +1100
+Date: Fri Feb 25 15:14:22 2022 +1100
- Update the list of tests that don't work on Minix.
+ Constify utimes in compat library to match specs.
- While there, remove CC (configure will now find clang) and make the test
- list easier to update via cut and paste.
+ Patch from vapier at chromium.org.
-commit 1c09bb1b2e207d091cec299c49416c23d24a1b31
+commit 1b2920e3b63db2eddebeec7330ffe8b723055573
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Dec 10 10:12:57 2021 +1100
+Date: Fri Feb 25 13:50:56 2022 +1100
- Add minix host tuple.
+ ANSIfy getshort and getlong.
- Define SETEUID_BREAKS_SETUID for it which should make privsep work.
+ These functions appear to have come from OpenBSD's lib/libc/net/res_comp.c
+ which made this change in 2005.
-commit a2188579032cf080213a78255373263466cb90cc
-Author: jsg@openbsd.org <jsg@openbsd.org>
-Date: Sun Dec 5 12:28:27 2021 +0000
+commit 54a86f4f6e1c43a2ca2be23ef799ab8910d4af70
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Feb 25 13:23:04 2022 +1100
- upstream: fix unintended sizeof pointer in debug path ok markus@
-
- OpenBSD-Commit-ID: b9c0481ffc0cd801e0840e342e6a282a85aac93c
+ Use PICFLAG instead of hard coding -fPIC.
-commit da40355234068c82f1a36196f2d18dd2d81aaafd
-Author: naddy@openbsd.org <naddy@openbsd.org>
-Date: Sat Dec 4 00:05:39 2021 +0000
+commit 3016ba47035ac3561aabd48e2be70167fe157d6a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Feb 25 11:37:11 2022 +1100
- upstream: RSA/SHA-1 is not used by default anymore on the server
-
- OpenBSD-Commit-ID: 64abef6cfc3e53088225f6b8a1dcd86d52dc8353
+ Add tests for latest releases of {Libre,Open}SSL.
-commit e9c71498a083a8b502aa831ea931ce294228eda0
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Dec 2 23:45:36 2021 +0000
+commit f107467179428a0e3ea9e4aa9738ac12ff02822d
+Author: Colin Watson <cjwatson@debian.org>
+Date: Thu Feb 24 16:04:18 2022 +0000
- upstream: hash full host:port when asked to hash output, fixes hashes
-
- for non- default ports. bz3367 ok dtucker@
+ Improve detection of -fzero-call-used-regs=all support
- OpenBSD-Commit-ID: 096021cc847da7318ac408742f2d0813ebe9aa73
+ GCC doesn't tell us whether this option is supported unless it runs into
+ the situation where it would need to emit corresponding code.
-commit b5601202145a03106012c22cb8980bcac2949f0b
+commit 3383b2cac0e9275bc93c4b4760e6e048f537e1d6
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Dec 2 23:23:13 2021 +0000
+Date: Wed Feb 23 21:21:49 2022 +0000
- upstream: improve the testing of credentials against inserted FIDO
-
- keys a little more: ask the token whether a particular key belongs to it in
- cases where the token support on-token user- verification (e.g. biometrics)
- rather than just assuming that it will accept it.
-
- Will reduce spurious "Confirm user presence" notifications for key
- handles that relate to FIDO keys that are not currently inserted in at
- least some cases.
-
- Motivated by bz3366; by Pedro Martelletto
+ upstream: free(3) wants stdlib.h
- OpenBSD-Commit-ID: ffac7f3215842397800e1ae2e20229671a55a63d
+ OpenBSD-Commit-ID: 227a8c70a95b4428c49e46863c9ef4bd318a3b8a
-commit ca709e27c41c90f4565b17282c48dca7756e083c
+commit a4537e79ab4ac6db4493c5158744b9ebde5efcb0
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Dec 2 22:40:05 2021 +0000
+Date: Wed Feb 23 21:21:16 2022 +0000
- upstream: move check_sk_options() up so we can use it earlier
+ upstream: put back the scp manpage changes for SFTP mode too
- OpenBSD-Commit-ID: 67fe98ba1c846d22035279782c4664c1865763b4
+ OpenBSD-Commit-ID: 05dc53921f927e1b5e5694e1f3aa314549f2e768
-commit b711bc01a7ec76bb6a285730990cbce9b8ca5773
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Thu Dec 2 22:35:05 2021 +0000
-
- upstream: ssh-rsa is no longer in the default for
-
- PubkeyAcceptedAlgorithms.
-
- OpenBSD-Commit-ID: 34a9e1bc30966fdcc922934ae00f09f2596cd73c
-
-commit dc91ceea33cd4a9f05be953e8d8062f732db5c8a
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Dec 2 02:44:44 2021 +0000
+commit 449bcb8403adfb9724805d02a51aea76046de185
+Author: deraadt@openbsd.org <deraadt@openbsd.org>
+Date: Wed Feb 23 19:01:00 2022 +0000
- upstream: don't put the tty into raw mode when SessionType=none, avoids
+ upstream: and we go back to testing sftp-scp after the 8.9
- ^c being unable to kill such a session. bz3360; ok dtucker@
+ release...
- OpenBSD-Commit-ID: 83960c433052303b643b4c380ae2f799ac896f65
+ OpenBSD-Commit-ID: a80440168258adca543a4607b871327a279c569c
-commit e6e7d2654a13ba10141da7b42ea683ea4eeb1f38
+commit 166456cedad3962b83b848b1e9caf80794831f0f
Author: Damien Miller <djm@mindrot.org>
-Date: Mon Nov 29 14:11:03 2021 +1100
-
- previous commit broke bcrypt_pbkdf()
-
- Accidentally reverted part of the conversion to use SHA512 from SUPERCOP
- instead of OpenBSD-style libc SHA512.
-
-commit c0459588b8d00b73e506c6095958ecfe62a4a7ba
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Nov 29 14:03:19 2021 +1100
+Date: Wed Feb 23 22:31:11 2022 +1100
- Fix typo in Neils' name.
+ makedepend
-commit 158bf854e2a22cf09064305f4a4e442670562685
-Author: Damien Miller <djm@mindrot.org>
-Date: Mon Nov 29 12:30:22 2021 +1100
+commit 32ebaa0dbca5d0bb86e384e72bebc153f48413e4
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Feb 23 11:18:13 2022 +0000
- sync bcrypt-related files with OpenBSD
+ upstream: avoid integer overflow of auth attempts (harmless, caught
- The main change is that Niels Provos kindly agreed to rescind the
- BSD license advertising clause, shifting them to the 3-term BSD
- license.
+ by monitor)
- This was the last thing in OpenSSH that used the advertising clause.
-
-commit e8976d92a42883ff6b8991438f07df60c2c0d82d
-Author: Damien Miller <djm@mindrot.org>
-Date: Mon Nov 29 12:29:29 2021 +1100
-
- depend
+ OpenBSD-Commit-ID: 488ad570b003b21e0cd9e7a00349cfc1003b4d86
-commit 8249afeec013e557fe7491a72ca3285de03e25b1
+commit 6e0258c64c901753df695e06498b26f9f4812ea6
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Nov 28 07:21:26 2021 +0000
+Date: Wed Feb 23 11:17:10 2022 +0000
- upstream: sshsig: return "key not found" when searching empty files
-
- rather than "internal error"
+ upstream: randomise the password used in fakepw
- OpenBSD-Commit-ID: e2ccae554c78d7a7cd33fc5d217f35be7e2507ed
+ OpenBSD-Commit-ID: 34e159f73b1fbf0a924a9c042d8d61edde293947
-commit 9e3227d4dbb5ad9c9091b4c14982cab4bba87b4d
+commit bf114d6f0a9df0b8369823d9a0daa6c72b0c4cc9
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Nov 28 07:15:10 2021 +0000
+Date: Wed Feb 23 11:15:57 2022 +0000
- upstream: ssh-keygen -Y match-principals doesn't accept any -O
-
- options at present, so don't say otherwise in SYNOPSIS; spotted jmc@
+ upstream: use asprintf to construct .rhosts paths
- OpenBSD-Commit-ID: 9cc43a18f4091010741930b48b3db2f2e4f1d35c
+ OpenBSD-Commit-ID: 8286e8d3d2c6ff916ff13d041d1713073f738a8b
-commit 56db1f4a4cf5039fc3b42e84c4b16291fdff32b1
+commit c07e154fbdc7285e9ec54e78d8a31f7325d43537
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Nov 28 07:14:29 2021 +0000
+Date: Wed Feb 23 11:07:09 2022 +0000
- upstream: fix indenting in last commit
+ upstream: openssh-8.9
- OpenBSD-Commit-ID: 8b9ba989815d0dec1fdf5427a4a4b58eb9cac4d2
+ OpenBSD-Commit-ID: 5c5f791c87c483cdab6d9266b43acdd9ca7bde0e
-commit 50bea24a9a9bdebad327c76e700def3261f5694e
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Nov 28 07:10:18 2021 +0000
+commit bc16667b4a1c3cad7029304853c143a32ae04bd4
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Feb 22 15:29:22 2022 +1100
- upstream: missing initialisation for oerrno
+ Extend select+rlimit sanbox test to include poll.
- OpenBSD-Commit-ID: 05d646bba238080259bec821c831a6f0b48d2a95
+ POSIX specifies that poll() shall fail if "nfds argument is greater
+ than {OPEN_MAX}". The setrlimit sandbox sets this to effectively zero
+ so this causes poll() to fail in the preauth privsep process.
+
+ This is likely the underlying cause for the previously observed similar
+ behaviour of select() on plaforms where it is implement in userspace on
+ top of poll().
-commit 5a0f4619041d09cd29f3a08da41db5040372bdd1
+commit 6520c488de95366be031d49287ed243620399e23
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sun Nov 28 15:31:37 2021 +1100
+Date: Tue Feb 22 13:08:59 2022 +1100
- Correct ifdef to activate poll() only if needed.
+ Add Alpine Linux test VM.
-commit d4035c81a71237f690edd7eda32bef7d63fd9528
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Nov 27 07:23:35 2021 +0000
+commit a4b325a3fc82d11e0f5d61f62e7fde29415f7afb
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Feb 22 12:27:07 2022 +1100
- upstream: whitespac e
+ Include sys/param.h if present.
- OpenBSD-Regress-ID: b9511d41568056bda489e13524390167889908f8
+ Needed for howmany() on MUSL systems such as Alpine.
-commit a443491e6782ef0f5a8bb87a5536c8ee4ff233a1
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Nov 27 07:20:58 2021 +0000
+commit 5a102e9cb287a43bd7dfe594b775a89a8e94697c
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Feb 22 12:25:52 2022 +1100
- upstream: regression test for match-principals. Mostly by Fabian
-
- Stelzer
+ Only include sys/poll.h if we don't have poll.h.
- OpenBSD-Regress-ID: ced0bec89af90935103438986bbbc4ad1df9cfa7
+ Prevents warnings on MUSL based systems such as Alpine.
-commit 78230b3ec8cbabc1e7de68732dc5cbd4837c6675
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Nov 27 07:14:46 2021 +0000
+commit 7c0d4ce911d5c58b6166b2db754a4e91f352adf5
+Author: Damien Miller <djm@mindrot.org>
+Date: Tue Feb 22 11:14:51 2022 +1100
- upstream: Add ssh-keygen -Y match-principals operation to perform
-
- matching of principals names against an allowed signers file.
+ disable agent-restrict test on minix3
- Requested by and mostly written by Fabian Stelzer, towards a TOFU
- model for SSH signatures in git. Some tweaks by me.
+ Minix seems to have a platform-wide limit on the number of
+ select(2) syscalls that can be concurrently issued. This test
+ seems to exceed this limit.
- "doesn't bother me" deraadt@
+ Refer to:
- OpenBSD-Commit-ID: 8d1b71f5a4127bc5e10a880c8ea6053394465247
+ https://github.com/Stichting-MINIX-Research-Foundation/minix/blob/R3.3.0/minix/servers/vfs/select.c#L114
+ https://github.com/Stichting-MINIX-Research-Foundation/minix/blob/R3.3.0/minix/servers/vfs/select.c#L30-L31
-commit 15db86611baaafb24c40632784dabf82e3ddb1a7
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Nov 25 23:02:24 2021 +0000
+commit 81d33d8e3cf7ea5ce3a5653c6102b623e019428a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Feb 21 21:27:20 2022 +1100
- upstream: debug("func: ...") -> debug_f("...")
+ Skip agent-getpeereid when running as root.
+
+commit fbd772570a25436a33924d91c164d2b24021f010
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sun Feb 20 03:47:26 2022 +0000
+
+ upstream: Aproximate realpath on the expected output by deduping
- OpenBSD-Commit-ID: d58494dc05c985326a895adfbe16fbd5bcc54347
+ leading slashes. Fixes test failure when user's home dir is / which is
+ possible in some portable configurations.
+
+ OpenBSD-Regress-ID: 53b8c53734f8893806961475c7106397f98d9f63
-commit b7ffbb17e37f59249c31f1ff59d6c5d80888f689
+commit 336685d223a59f893faeedf0a562e053fd84058e
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Nov 19 18:53:46 2021 +1100
+Date: Sun Feb 20 13:30:52 2022 +1100
- Allow for fd = -1 in compat ppoll overflow check.
+ Really move DSA to end of list.
- Fixes tests on at least FreeBSD 6, possibly others.
+ In commit ad16a84e syncing from OpenBSD, RSA was accidentally moved to
+ the end of the list instead of DSA. Spotted by andrew at fyfe.gb.net.
-commit 04b172da5b96a51b0d55c905b423ababff9f4e0b
+commit 63bf4f49ed2fdf2da6f97136c9df0c8168546eb3
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Nov 19 16:01:51 2021 +1100
+Date: Fri Feb 18 12:12:21 2022 +1100
- Don't auto-enable Capsicum sandbox on FreeBSD 9/10.
-
- Since we changed from select() to ppoll() tests have been failing.
- This seems to be because FreeBSD 10 (and presumably 9) do not allow
- ppoll() in the privsep process and sshd will fail with "Not permitted in
- capability mode". Setting CAP_EVENT on the FDs doesn't help, but weirdly,
- poll() works without that. Those versions are EOL so this situation is
- unlikely to change.
+ Add test configs for MUSL C library.
-commit a823f39986e7b879f26412e64c15630e1cfa0dc5
+commit f7fc6a43f1173e8b2c38770bf6cee485a562d03b
+Author: Damien Miller <djm@mindrot.org>
+Date: Thu Feb 17 22:54:19 2022 +1100
+
+ minix needs BROKEN_POLL too; chokes on /dev/null
+
+commit 667fec5d4fe4406745750a32f69b5d2e1a75e94b
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Nov 18 03:53:48 2021 +0000
+Date: Thu Feb 17 10:58:27 2022 +0000
- upstream: regression test for ssh-keygen -Y find-principals fix; from
+ upstream: check for EINTR/EAGAIN failures in the rfd fast-path; caught
- Fabian Stelzer ok djm markus
+ by dtucker's minix3 vm :) ok dtucker@
- OpenBSD-Regress-ID: 34fe4088854c1a2eb4c0c51cc4676ba24096bac4
+ OpenBSD-Commit-ID: 2e2c895a3e82ef347aa6694394a76a438be91361
-commit 199c4df66c0e39dd5c3333b162af274678c0501d
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Nov 18 21:32:11 2021 +0000
+commit 41417dbda9fb55a0af49a8236e3ef9d50d862644
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Feb 17 22:05:29 2022 +1100
- upstream: less confusing debug message; bz#3365
-
- OpenBSD-Commit-ID: 836268d3642c2cdc84d39b98d65837f5241e4a50
+ Comment hurd test, the VM is currently broken.
-commit 97f9b6e61316c97a32dad94b7a37daa9b5f6b836
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Nov 18 21:11:01 2021 +0000
+commit b2aee35a1f0dc798339b3fcf96136da71b7e3f6d
+Author: Damien Miller <djm@mindrot.org>
+Date: Thu Feb 17 21:15:16 2022 +1100
- upstream: avoid xmalloc(0) for PKCS#11 keyid for ECDSA keys (we
-
- already did this for RSA keys). Avoids fatal errors for PKCS#11 libraries
- that return empty keyid, e.g. Microchip ATECC608B "cryptoauthlib"; bz#3364
+ find sk-dummy.so when build_dir != src_dir
- OpenBSD-Commit-ID: 054d4dc1d6a99a2e6f8eebc48207b534057c154d
+ spotted by Corinna Vinschen; feedback & ok dtucker@
-commit c74aa0eb73bd1edf79947d92d9c618fc3424c4a6
+commit 62a2d4e50b2e89f2ef04576931895d5139a5d037
+Author: Damien Miller <djm@mindrot.org>
+Date: Wed Feb 16 16:26:17 2022 +1100
+
+ update versions in preparation for 8.9 release
+
+commit dd6d3dded721ac653ea73c017325e5bfeeec837f
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Nov 18 03:50:41 2021 +0000
+Date: Tue Feb 15 05:13:36 2022 +0000
- upstream: ssh-keygen -Y find-principals was verifying key validity
-
- when using ca certs but not with simple key lifetimes within the allowed
- signers file.
-
- Since it returns the first keys principal it finds this could
- result in a principal with an expired key even though a valid
- one is just below.
+ upstream: document the unbound/host-bound options to
- patch from Fabian Stelzer; feedback/ok djm markus
+ PubkeyAuthentication; spotted by HARUYAMA Seigo
- OpenBSD-Commit-ID: b108ed0a76b813226baf683ab468dc1cc79e0905
+ OpenBSD-Commit-ID: 298f681b66a9ecd498f0700082c7a6c46e948981
-commit d902d728dfd81622454260e23bc09d5e5a9a795e
+commit df93529dd727fdf2fb290700cd4f1adb0c3c084b
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Nov 18 23:44:07 2021 +1100
+Date: Mon Feb 14 14:19:40 2022 +1100
- Correct calculation of tv_nsec in poll().
+ Test if sshd accidentally acquires controlling tty
+
+ When SSHD_ACQUIRES_CTTY is defined, test for the problematic behaviour
+ in the STREAMS code before activating the workaround. ok djm@
-commit 21dd5a9a3fb35e8299a1fbcf8d506f1f6b752b85
+commit 766176cfdbfd7ec38bb6118dde6e4daa0df34888
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Nov 18 23:11:37 2021 +1100
+Date: Sat Feb 12 10:24:56 2022 +1100
- Add compat implementation of ppoll using pselect.
+ Add cygwin-release test config.
+
+ This tests the flags used to build the cygwin release binaries.
-commit b544ce1ad4afb7ee2b09f714aa63efffc73fa93a
+commit b30698662b862f5397116d23688aac0764e0886e
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Nov 18 23:05:34 2021 +1100
+Date: Fri Feb 11 21:00:35 2022 +1100
- Put poll.h inside ifdef HAVE_POLL_H.
+ Move SSHD_ACQUIRES_CTTY workaround into compat.
+
+ On some (most? all?) SysV based systems with STREAMS based ptys,
+ sshd could acquire a controlling terminal during pty setup when
+ it pushed the "ptem" module, due to what is probably a bug in
+ the STREAMS driver that's old enough to vote. Because it was the
+ privileged sshd's controlling terminal, it was not available for
+ the user's session, which ended up without one. This is known to
+ affect at least Solaris <=10, derivatives such as OpenIndiana and
+ several other SysV systems. See bz#245 for the backstory.
+
+ In the we past worked around that by not calling setsid in the
+ privileged sshd child, which meant it was not a session or process
+ group leader. This solved controlling terminal problem because sshd
+ was not eligble to acquire one, but had other side effects such as
+ not cleaning up helper subprocesses in the SIGALRM handler since it
+ was not PG leader. Recent cleanups in the signal handler uncovered
+ this, resulting in the LoginGraceTime timer not cleaning up privsep
+ unprivileged processes.
+
+ This change moves the workaround into the STREAMS pty allocation code,
+ by allocating a sacrificial pty to act as sshd's controlling terminal
+ before allocating user ptys, so those are still available for users'
+ sessions.
+
+ On the down side:
+ - this will waste a pty per ssh connection on affected platforms.
+
+ On the up side:
+ - it makes the process group behaviour consistent between platforms.
+
+ - it puts the workaround nearest the code that actually causes the
+ problem and competely out of the mainline code.
+
+ - the workaround is only activated if you use the STREAMS code. If,
+ say, Solaris 11 has the bug but also a working openpty() it doesn't
+ matter that we defined SSHD_ACQUIRES_CTTY.
+
+ - the workaround is only activated when the fist pty is allocated,
+ ie in the post-auth privsep monitor. This means there's no risk
+ of fd leaks to the unprivileged processes, and there's no effect on
+ sessions that do not allocate a pty.
+
+ Based on analysis and work by djm@, ok djm@
-commit 875408270c5a7dd69ed5449e5d85bd7120c88f70
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Nov 18 03:31:44 2021 +0000
+commit cd00b48cf10f3565936a418c1e6d7e48b5c36140
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Feb 11 20:09:32 2022 +1100
- upstream: check for POLLHUP wherever we check for POLLIN
+ Simplify handling of --with-ssl-dir.
- OpenBSD-Commit-ID: 6aa6f3ec6b17c3bd9bfec672a917f003a76d93e5
+ ok djm@
-commit 36b5e37030d35bbaa18ba56825b1af55971d18a0
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Nov 18 03:07:59 2021 +0000
+commit ea13fc830fc0e0dce2459f1fab2ec5099f73bdf0
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Feb 11 13:39:29 2022 +1100
- upstream: fd leak in sshd listen loop error path; from Gleb
+ Stop testing OpenBSD HEAD on 6.9 and 7.0.
- Smirnoff
+ HEAD is not guaranteed to work on previous stable branches, and at the
+ moment is broken due to libfido API changes.
+
+commit 50b9e4a4514697ffb9592200e722de6b427cb9ff
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Feb 11 00:43:56 2022 +0000
+
+ upstream: Always initialize delim before passing to hpdelim2 which
- OpenBSD-Commit-ID: a7a2be27a690a74bf2381bc16cea38e265657412
+ might not set it. Found by the Valgrind tests on github, ok deraadt@
+
+ OpenBSD-Commit-ID: c830c0db185ca43beff3f41c19943c724b4f636d
-commit b99498d0c93f1edd04857b318308a66b28316bd8
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Nov 18 03:07:20 2021 +0000
+commit 6ee53064f476cf163acd5521da45b11b7c57321b
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Feb 11 10:03:06 2022 +1100
- upstream: check for POLLHUP as well as POLLIN in sshd listen loop;
+ Fix helper include path and remove excess code.
- ok deraadt millert
+ Looks like test_hpdelim.c was imported twice into the same file.
+ Spotted by kevin.brott at gmail com and chris at cataclysmal org.
+
+commit 9fa63a19f68bc87452d3cf5c577cafad2921b7a4
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Feb 10 23:27:02 2022 +1100
+
+ Put poll.h inside ifdef.
+
+commit 3ac00dfeb54b252c15dcbf1971582e9e3b946de6
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Feb 10 22:17:31 2022 +1100
+
+ We now support POLLPRI so actually define it.
+
+commit 25bd659cc72268f2858c5415740c442ee950049f
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sun Feb 6 22:58:33 2022 +0000
+
+ upstream: Add test for empty hostname with port.
- OpenBSD-Commit-ID: a4f1244c5a9c2b08dac4f3b1dc22e9d1dc60c587
+ OpenBSD-Regress-ID: e19e89d3c432b68997667efea44cf015bbe2a7e3
-commit 1f3055d788e8cf80851eb1728b535d57eb0dba6a
+commit a29af853cff41c0635f0378c00fe91bf9c91dea4
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Feb 4 07:53:44 2022 +0000
+
+ upstream: Add unit tests for hpdelim.
+
+ OpenBSD-Regress-ID: be97b85c19895e6a1ce13c639765a3b48fd95018
+
+commit 9699151b039ecc5fad9ac6c6c02e9afdbd26f15f
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Nov 18 03:06:03 2021 +0000
+Date: Thu Feb 10 04:12:38 2022 +0000
- upstream: check for POLLHUP as well as POLLIN, handle transient IO
+ upstream: revert for imminent OpenSSH release, which wil ship with
- errors as well as half-close on the output side; ok deraadt millert
+ scp in RCP mode.
- OpenBSD-Commit-ID: de5c5b9939a37476d256328cbb96305bdecf511e
+ > revision 1.106
+ > date: 2021/10/15 14:46:46; author: deraadt; state: Exp; lines: +13 -9; commitid: w5n9B2RE38tFfggl;
+ > openbsd 7.0 release shipped with the (hopefully last) scp that uses RCP
+ > protocol for copying. Let's get back to testing the SFTP protocol.
+
+ This will be put back once the OpenSSH release is done.
+
+ OpenBSD-Commit-ID: 0c725481a78210aceecff1537322c0b2df03e768
-commit 9778a15fa6dbdac6a95bf15865c2688b4bd6944e
-Author: Damien Miller <djm@mindrot.org>
-Date: Thu Nov 18 10:16:55 2021 +1100
+commit 45279abceb37c3cbfac8ba36dde8b2c8cdd63d32
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Feb 8 08:59:12 2022 +0000
- adjust seccomp filter for select->poll conversion
+ upstream: Switch hpdelim interface to accept only ":" as delimiter.
- Needed to add ppoll syscall but also to relax the fallback rlimit
- sandbox. Linux poll() fails with EINVAL if npfds > RLIMIT_NOFILE,
- so we have to allow a single fd in the rlimit.
+ Historicallly, hpdelim accepted ":" or "/" as a port delimiter between
+ hosts (or addresses) and ports. These days most of the uses for "/"
+ are no longer accepted, so there are several places where it checks the
+ delimiter to disallow it. Make hpdelim accept only ":" and use hpdelim2
+ in the other cases. ok djm@
+
+ OpenBSD-Commit-ID: 7e6420bd1be87590b6840973f5ad5305804e3102
-commit fcd8d895bbb849c64f0aed934e3303d37f696f5d
-Author: Damien Miller <djm@mindrot.org>
-Date: Thu Nov 18 10:16:44 2021 +1100
+commit a1bcbf04a7c2d81944141db7ecd0ba292d175a66
+Author: pedro martelletto <pedro@yubico.com>
+Date: Mon Feb 7 09:09:59 2022 +0100
- update depends
+ fix typos in previous
-commit 76292787a1e93e668f10e36b4bf59ce0ae28e156
+commit 56192518e329b39f063487bc2dc4d796f791eca0
Author: Damien Miller <djm@mindrot.org>
-Date: Thu Nov 18 09:26:20 2021 +1100
+Date: Mon Feb 7 12:53:47 2022 +1100
- compat for timespecsub() and friends
+ compat code for fido_assert_set_clientdata()
-commit fd7e7de4ddb4399c7e929b44f2bbfc118eddfcf8
+commit d6b5aa08fdcf9b527f8b8f932432941d5b76b7ab
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Nov 17 21:06:39 2021 +0000
+Date: Mon Feb 7 01:25:12 2022 +0000
- upstream: set num_listen_socks to 0 on close-all instead of -1,
+ upstream: use libfido2 1.8.0+ fido_assert_set_clientdata() instead
- which interferes with the new poll()-based listen loop; spotted and debugged
- by anton@+deraadt@
+ of manually hashing data outselves. Saves a fair bit of code and makes life
+ easier for some -portable platforms.
- OpenBSD-Commit-ID: f7ab8ab124f615a2e0c45fee14c38d2f2abbabbd
+ OpenBSD-Commit-ID: 351dfaaa5ab1ee928c0e623041fca28078cff0e0
-commit fd9343579afac30a971f06643a669733d9acb407
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Sun Nov 14 18:47:43 2021 +0000
+commit 86cc93fd3c26b2e0c7663c6394995fb04ebfbf3b
+Author: jsg@openbsd.org <jsg@openbsd.org>
+Date: Sun Feb 6 00:29:03 2022 +0000
- upstream: use ppoll() instead of pselect() with djm
+ upstream: remove please from manual pages ok jmc@ sthen@ millert@
- OpenBSD-Commit-ID: 980f87c9564d5d2ad55722b7a6f44f21284cd215
+ OpenBSD-Commit-ID: 6543acb00f4f38a23472538e1685c013ca1a99aa
-commit 092d29b232ef1a19609a5316ed7e4d896bb2e696
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Sun Nov 14 06:15:36 2021 +0000
+commit ad16a84e64a8cf1c69c63de3fb9008320a37009c
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Feb 4 02:49:17 2022 +0000
- upstream: match .events with .fd better
+ upstream: Since they are deprecated, move DSA to the end of the
- OpenBSD-Commit-ID: 77eef212ca0add905949532af390164489c5984b
+ default list of public keys so that they will be tried last. From github
+ PR#295 from "ProBackup-nl", ok djm@
+
+ OpenBSD-Commit-ID: 7e5d575cf4971d4e2de92e0b6d6efaba53598bf0
-commit 8d642c9a90fa4ed5a3effd785fb3591e14de00cd
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Sun Nov 14 03:25:10 2021 +0000
+commit 253de42753de85dde266e061b6fec12ca6589f7d
+Author: Damien Miller <djm@mindrot.org>
+Date: Wed Feb 2 16:52:07 2022 +1100
- upstream: convert select() to poll() ok djm
+ portable-specific string array constification
- OpenBSD-Commit-ID: b53e4940ff10dd24f8d16e8db8ef1970015d7ead
+ from Mike Frysinger
-commit 6582a31c388968f4073af2bd8621880735c3d42b
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Sat Nov 13 21:14:13 2021 +0000
+commit dfdcc2220cf359c492d5d34eb723370e8bd8a19e
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Feb 1 23:37:15 2022 +0000
- upstream: replace select() with ppoll(), including converting
+ upstream: test 'ssh-keygen -Y find-principals' with wildcard
- timeval's to timespec's to make things easier. back and forth and ok; djm
+ principals; from Fabian Stelzer
- OpenBSD-Commit-ID: 89d3b23c60875da919e7820f9de6213286ffbec9
+ OpenBSD-Regress-ID: fbe4da5f0032e7ab496527a5bf0010fd700f8f40
-commit 7c025c005550c86a40200a2bcdd355d09413d61a
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Sat Nov 13 17:26:13 2021 +0000
+commit 968e508967ef42480cebad8cf3172465883baa77
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jan 21 02:54:41 2022 +0000
- upstream: It really looks like pledge "stdio dns" is possible
+ upstream: Enable all supported ciphers and macs in the server
- earlier. Discussed with mestre
+ before trying to benchmark them. Increase the data file size to get more
+ signal.
- OpenBSD-Commit-ID: 610873de63a593e0ac7bbbcb7a0f2894d36f4c01
+ OpenBSD-Regress-ID: dc3697d9f7defdfc51c608782c8e750128e46eb6
-commit 06acb04c20ee483fe4757bd12aec870cc4bb1076
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Fri Nov 12 05:23:49 2021 +0000
+commit 15b7199a1fd37eff4c695e09d573f3db9f4274b7
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Feb 1 23:34:47 2022 +0000
- upstream: aggressively pre-fill the pollfd array with fd=-1
-
- OpenBSD-Commit-ID: c2a525de8f83c1a04405bd79122c424140552a5b
-
-commit 7eec76793dec06e8f06b6cf71f9473141c69d109
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Thu Nov 11 15:32:32 2021 +0000
-
- upstream: Convert from select() to ppoll(). Along the way, I
-
- observed that the select() code was using exceptfds incorrectly.. ok millert
+ upstream: allow 'ssh-keygen -Y find-principals' to match wildcard
- OpenBSD-Commit-ID: 548e05bfc31b2af02319eb3d051286d4128dec96
-
-commit e665ed2d0c24fe11d5470ce72fa1e187377d3fc4
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Nov 12 22:55:27 2021 +1100
-
- Switch from LibreSSL 3.4.0 to 3.4.1.
+ principals in allowed_signers files; from Fabian Stelzer
- The LibreSSL 3.4.0 release has an OPENBSD_BRANCH that points to
- "master" and that branch no longer has the files LibreSSL expects
- and thus it will no longer build, breaking the test.
+ OpenBSD-Commit-ID: 1e970b9c025b80717dddff5018fe5e6f470c5098
-commit 21b6b5a06c8c53c548d25e6074c5240e88e2ef34
+commit 541667fe6dc26d7881e55f0bb3a4baa6f3171645
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Nov 10 06:29:25 2021 +0000
+Date: Tue Feb 1 23:32:51 2022 +0000
- upstream: add the sntrup761x25519-sha512@openssh.com hybrid
-
- ECDH/x25519 + Streamlined NTRU Prime post-quantum KEX to the default
- KEXAlgorithms list (after the ECDH methods but before the prime-group DH
- ones).
+ upstream: mark const string array contents const too, i.e. static
- ok markus@
+ const char *array => static const char * const array from Mike Frysinger
- OpenBSD-Commit-ID: 22b77e27a04e497a10e22f138107579652854210
+ OpenBSD-Commit-ID: a664e31ea6a795d7c81153274a5f47b22bdc9bc1
-commit 239da797cbf07a640d7b1ea02d3f99ace3ef792d
+commit 8cfa73f8a2bde4c98773f33f974c650bdb40dd3c
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Nov 10 06:25:08 2021 +0000
+Date: Tue Feb 1 23:11:11 2022 +0000
- upstream: fix ssh-keysign for KEX algorithms that use SHA384/512
+ upstream: better match legacy scp behaviour: show un-expanded paths
- exchange hashes; feedback/ok markus@
+ in error messages. Spotted by and ok tb@
- OpenBSD-Commit-ID: 09a8fda1c081f5de1e3128df64f28b7bdadee239
+ OpenBSD-Commit-ID: 866c8ffac5bd7d38ecbfc3357c8adfa58af637b7
-commit 6997a592ecb1013df0c6d7f8df3e6517827aef11
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Nov 8 21:32:49 2021 +0000
+commit 4e62c13ab419b4b224c8bc6a761e91fcf048012d
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Feb 1 07:57:32 2022 +0000
- upstream: improve error message when trying to expand a ~user path
-
- for a user that doesn't exist; better matches what the shell does
+ upstream: Remove explicit kill of privsep preauth child's PID in
- ok deraadt@
+ SIGALRM handler. It's no longer needed since the child will get terminated by
+ the SIGTERM to the process group that cleans up any auth helpers, it
+ simplifies the signal handler and removes the risk of a race when updating
+ the PID. Based on analysis by HerrSpace in github PR#289, ok djm@
- OpenBSD-Commit-ID: 1ddefa3c3a78b69ce13d1b8f67bc9f2cefd23ad6
+ OpenBSD-Commit-ID: 2be1ffa28b4051ad9e33bb4371e2ec8a31d6d663
-commit 10b899a15c88eb40eb5f73cd0fa84ef0966f79c9
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Nov 10 12:34:25 2021 +1100
+commit 2a7ccd2ec4022917b745af7186f514f365b7ebe9
+Author: guenther@openbsd.org <guenther@openbsd.org>
+Date: Fri Jan 28 06:18:42 2022 +0000
- Don't trust closefrom() on Linux.
+ upstream: When it's the possessive of 'it', it's spelled "its",
- glibc's closefrom implementation does not work in a chroot when the kernel
- does not have close_range. It tries to read from /proc/self/fd and when
- that fails dies with an assertion of sorts. Instead, call close_range
- ourselves from our compat code and fall back if that fails. bz#3349,
- with william.wilson at canonical.com and fweimer at redhat.com.
+ without the apostrophe.
+
+ OpenBSD-Commit-ID: fb6ab9c65bd31de831da1eb4631ddac018c5fae7
-commit eb1f63195a9a38b519536a5b398d9939261ec081
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Nov 6 10:13:39 2021 +0000
+commit 8a0848cdd3b25c049332cd56034186b7853ae754
+Author: Alex James <theracermaster@gmail.com>
+Date: Sun Jan 30 16:13:36 2022 -0600
- upstream: Plug a couple of minor mem leaks. From beldmit at
+ sandbox-seccomp-filter: allow gettid
- gmail.com via github PR#283, ok markus@
+ Some allocators (such as Scudo) use gettid while tracing allocations [1].
+ Allow gettid in preauth to prevent sshd from crashing with Scudo.
- OpenBSD-Commit-ID: ec1fa7d305d46226861c3ca6fb9c9beb2ada2892
+ [1]: https://github.com/llvm/llvm-project/blob/llvmorg-13.0.0/compiler-rt/lib/gwp_asan/common.cpp#L46
-commit e4f501bf1d3b53f1cc23d9521fd7c5163307b760
+commit b30d32159dc3c7052f4bfdf36357996c905af739
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Nov 5 03:10:58 2021 +0000
+Date: Sat Jan 22 00:49:34 2022 +0000
- upstream: move cert_filter_principals() to earlier in the file for
+ upstream: add a ssh_packet_process_read() function that reads from
- reuse; no code change
+ a fd directly into the transport input buffer.
- OpenBSD-Commit-ID: 598fa9528b656b2f38bcc3cf5b6f3869a8c115cf
-
-commit 59c60f96fee321c7f38f00372826d37f289534af
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Wed Nov 3 22:00:56 2021 +0000
-
- upstream: Many downstreams expect ssh to compile as non-C99...
+ Use this in the client and server mainloops to avoid unnecessary
+ copying. It also lets us use a more greedy read size without penalty.
- OpenBSD-Commit-ID: e6aa3e08bda68e5fb838fc8a49b1d2dfc38ee783
+ Yields a 2-3% performance gain on cipher-speed.sh (in a fairly
+ unscientific test tbf)
+
+ feedback dtucker@ ok markus@
+
+ OpenBSD-Commit-ID: df4112125bf79d8e38e79a77113e1b373078e632
-commit 7a78fe63b0b28ef7231913dfefe9d08f9bc41c61
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Nov 6 21:07:03 2021 +1100
+commit a1a8efeaaa9cccb15cdc0a2bd7c347a149a3a7e3
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Jan 22 00:45:31 2022 +0000
- Skip getline() on HP-UX 10.x.
+ upstream: Use sshbuf_read() to read directly into the channel input
- HP-UX 10.x has a getline() implementation in libc that does not behave
- as we expect so don't use it. With correction from Thorsten Glaser and
- typo fix from Larkin Nickle.
+ buffer rather than into a stack buffer that needs to be copied again;
+ Improves performance by about 1% on cipher-speed.sh feedback dtucker@ ok
+ markus@
+
+ OpenBSD-Commit-ID: bf5e6e3c821ac3546dc8241d8a94e70d47716572
-commit 343ae252ebb35c6ecae26b447bf1551a7666720e
+commit 29a76994e21623a1f84d68ebb9dc5a3c909fa3a7
Author: Damien Miller <djm@mindrot.org>
-Date: Wed Nov 3 12:08:21 2021 +1100
+Date: Tue Jan 25 11:52:34 2022 +1100
- basic SECURITY.md (refers people to the website)
+ depend
-commit ed45a0168638319e0a710633f6085b96b9cec656
+commit 754e0d5c7712296a7a3a83ace863812604c7bc4f
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Nov 2 22:57:27 2021 +0000
+Date: Sat Jan 22 00:43:43 2022 +0000
- upstream: crank SSH_SK_VERSION_MAJOR to match recent change in
+ upstream: Add a sshbuf_read() that attempts to read(2) directly in
- usr/bin/ssh
+ to a sshbuf; ok markus@
- OpenBSD-Regress-ID: 113d181c7e3305e138db9b688cdb8b0a0019e552
+ OpenBSD-Commit-ID: 2d8f249040a4279f3bc23c018947384de8d4a45b
-commit f3c34df860c4c1ebddacb973954e58167d9dbade
+commit c7964fb9829d9ae2ece8b51a76e4a02e8449338d
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Nov 2 22:56:40 2021 +0000
+Date: Fri Jan 21 07:04:19 2022 +0000
- upstream: Better handle FIDO keys on tokens that provide user
-
- verification (UV) on the device itself, including biometric keys.
-
- Query the token during key creation to determine whether it supports
- on-token UV and, if so, clear the SSH_SK_USER_VERIFICATION_REQD flag
- in the key so that ssh(1) doesn't automatically prompty for PIN later.
-
- When making signatures with the key, query the token's capabilities
- again and check whether the token is able (right now) to perform user-
- verification without a PIN. If it is then the PIN prompt is bypassed
- and user verification delegated to the token. If not (e.g. the token
- is biometric capable, but no biometric are enrolled), then fall back
- to user verification via the usual PIN prompt.
-
- Work by Pedro Martelletto; ok myself and markus@
+ upstream: add a helper for writing an error message to the
- NB. cranks SSH_SK_VERSION_MAJOR
+ stderr_buf and setting quit_pending; no functional change but saves a bunch
+ of boilerplate
- OpenBSD-Commit-ID: e318a8c258d9833a0b7eb0236cdb68b5143b2f27
+ OpenBSD-Commit-ID: 0747657cad6b9eabd514a6732adad537568e232d
-commit 0328a081f38c09d2d4d650e94461a47fb5eef536
+commit d23b4f7fdb1bd87e2cd7a9ae7c198ae99d347916
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Oct 29 03:03:06 2021 +0000
+Date: Fri Jan 21 06:58:06 2022 +0000
- upstream: sshsig: add tests for signing key validity and
+ upstream: correct comment and use local variable instead of long
- find-principals
+ indirection; spotted by dtucker@
- - adds generic find-principals tests (this command had none before)
- - tests certs with a timeboxed validity both with and without a
- restriced lifetime for the CA
- - test for a revoked CA cert
+ OpenBSD-Commit-ID: 5f65f5f69db2b7d80a0a81b08f390a63f8845965
+
+commit d069b020a02b6e3935080204ee44d233e8158ebb
+Author: deraadt@openbsd.org <deraadt@openbsd.org>
+Date: Fri Jan 21 00:53:40 2022 +0000
+
+ upstream: When poll(2) returns -1, for some error conditions
- by Fabian Stelzer
+ pfd[].revents is not cleared. There are subtle errors in various programs.
+ In this particular case, the program should error out. ok djm millert
- OpenBSD-Regress-ID: 9704b2c6df5b8ccfbdf2c06c5431f5f8cad280c9
+ OpenBSD-Commit-ID: 00f839b16861f7fb2adcf122e95e8a82fa6a375c
-commit ccd358e1e25e25c13f0825996283cbf7a1647a3b
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Oct 29 02:48:19 2021 +0000
+commit e204b34337a965feb439826157c191919fd9ecf8
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Jan 22 11:38:21 2022 +1100
- upstream: avoid signedness warning; spotted in -portable
+ restore tty force-read hack
- OpenBSD-Regress-ID: 4cacc126086487c0ea7f3d86b42dec458cf0d0c6
+ This portable-specific hack fixes a hang on exit for ttyful sessions
+ on Linux and some SysVish Unix variants. It was accidentally disabled
+ in commit 5c79952dfe1a (a precursor to the mainloop poll(2) conversion).
+
+ Spotted by John in bz3383
-commit 2741f52beb11490d7033a25e56ed0496f0c78006
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Oct 29 03:20:46 2021 +0000
+commit 68085066b6bad43643b43f5957fcc5fd34782ccd
+Author: Corinna Vinschen <vinschen@redhat.com>
+Date: Fri Jan 21 03:22:56 2022 +1100
- upstream: ssh-keygen: make verify-time argument parsing optional
+ Fix signedness bug in Cygwin code
- From Fabian Stelzer
+ The Cygwin-specific pattern match code has a bug. It checks
+ the size_t value returned by mbstowcs for being < 0. The right
+ thing to do is to check against (size_t) -1. Fix that.
- OpenBSD-Commit-ID: 1ff35e4c366a45a073663df90381be6a8ef4d370
+ Signed-off-by: Corinna Vinschen <vinschen@redhat.com>
-commit a1217d363b88b32cfe54c4f02c6c1cf4bdefdd23
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Oct 29 13:48:34 2021 +1100
+commit 2e5cfed513e84444483baf1d8b31c40072b05103
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Jan 20 13:26:27 2022 +1100
- unbreak fuzz harness for recent changes
+ Improve compatibility of early exit trap handling.
+
+ Dash (as used by the github runners) has some differences in its trap
+ builtin:
+ - it doesn't have -p (which is fine, that's not in posix).
+ - it doesn't work in a subshell (which turns out to be in compliance
+ with posix, which means bash isn't).
+ - it doesn't work in a pipeline, ie "trap|cat" produces no output.
-commit 68e522ed8183587c9367fa3842c5b75f64f3d12b
+commit 3fe6800b6027add478e648934cbb29d684e51943
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Oct 29 13:32:24 2021 +1100
+Date: Thu Jan 20 00:49:57 2022 +1100
- Use -Wbitwise-instead-of-logical if supported.
+ Move more tests out of valgrind-1 runner.
-commit be28b23012aa3fa323be7ec84863cf238927c078
-Author: Damien Miller <djm@mindrot.org>
-Date: Thu Oct 28 16:24:53 2021 +1100
+commit 20da6ed136dd76e6a0b229ca3036ef9c7c7ef798
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Jan 19 15:37:39 2022 +1100
- use -Wmisleading-indentation cflag if available
+ Invoke EXIT handler early when using Valgrind.
- ok dtucker@
+ When using Valgrind, we need to wait for all invoked programs to
+ complete before checking their valgrind logs. Some tests, notably
+ agent-restrict, set an EXIT trap handler to clean up things like
+ ssh-agent, but those do not get invoked until test-exec.sh exits.
+ This causes the Valgrind wait to deadlock, so if present invoke
+ the EXIT handler before checking the Valgrind logs.
-commit 2e6f5f24dd2f9217f4ab8b737ed428d5d5278f91
-Author: Damien Miller <djm@mindrot.org>
-Date: Thu Oct 28 16:24:44 2021 +1100
+commit ad2e0580c87b0714cf166bca9d926a95ddeee1c8
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Jan 18 12:55:21 2022 +1100
- depend
+ Remove line leftover from upstream sync.
-commit a5ab4882348d26addc9830a44e053238dfa2cb58
-Author: Damien Miller <djm@mindrot.org>
-Date: Thu May 6 10:08:30 2021 +1000
+commit d1051c0f11a6b749027e26bbeb61b07df4b67e15
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Jan 17 22:56:04 2022 +0000
- remove built-in support for md5crypt()
+ upstream: when decompressing zlib compressed packets, use
- Users of MD5-hashed password should arrange for ./configure to link
- against libxcrypt or similar. Though it would be better to avoid use
- of MD5 password hashing entirely, it's arguably worse than DEScrypt.
+ Z_SYNC_FLUSH instead of Z_PARTIAL_FLUSH as the latter is not actually
+ specified as a valid mode for inflate(). There should be no practical change
+ in behaviour as the compression side ensures a flush that should make all
+ data available to the receiver in all cases.
- feedback and ok dtucker@
+ repoted by lamm AT ibm.com via bz3372; ok markus
+
+ OpenBSD-Commit-ID: 67cfc1fa8261feae6d2cc0c554711c97867cc81b
-commit c5de1fffa6328b8246b87da28fa9df05813f76a3
+commit d5981b1883746b1ae178a46229c26b53af99e37a
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Oct 28 02:55:30 2021 +0000
+Date: Mon Jan 17 21:41:04 2022 +0000
- upstream: increment SSH_SK_VERSION_MAJOR to match last change
+ upstream: make most of the sftp errors more idiomatic, following
- OpenBSD-Regress-ID: 17873814d1cbda97f49c8528d7b5ac9cadf6ddc0
+ the general form of "[local/remote] operation path: error message"; ok markus
+
+ OpenBSD-Commit-ID: 61364cd5f3a9fecaf8d63b4c38a42c0c91f8b571
-commit 0001d04e55802d5bd9d6dece1081a99aa4ba2828
+commit ac7c9ec894ed0825d04ef69c55babb49bab1d32e
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Oct 28 02:54:18 2021 +0000
+Date: Mon Jan 17 21:39:51 2022 +0000
- upstream: When downloading resident keys from a FIDO token, pass
+ upstream: when transferring multiple files in SFTP mode, create the
- back the user ID that was used when the key was created and append it to the
- filename the key is written to (if it is not the default).
+ destination directory if it doesn't already exist to match olde-scp(1)
+ behaviour. noticed by deraadt@ ok markus@
- Avoids keys being clobbered if the user created multiple
- resident keys with the same application string but different
- user IDs.
+ OpenBSD-Commit-ID: cf44dfa231d4112f697c24ff39d7ecf2e6311407
+
+commit 39d17e189f8e72c34c722579d8d4e701fa5132da
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jan 14 03:43:48 2022 +0000
+
+ upstream: allow pin-required FIDO keys to be added to ssh-agent(1).
- feedback Pedro Martelletto; ok markus
+ ssh-askpass will be used to request the PIN at authentication time.
- NB. increments SSH_SK_VERSION_MAJOR
+ From Pedro Martelletto, ok djm
- OpenBSD-Commit-ID: dbd658b5950f583106d945641a634bc6562dd3a3
+ OpenBSD-Commit-ID: de8189fcd35b45f632484864523c1655550e2950
-commit d4bed5445646e605c383a4374fa962e23bf9e3a3
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Sun Oct 24 21:24:17 2021 +0000
+commit 52423f64e13db2bdc31a51b32e999cb1bfcf1263
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jan 14 03:35:10 2022 +0000
- upstream: For open/openat, if the flags parameter does not contain
+ upstream: ssh-sk: free a resident key's user id
- O_CREAT, the 3rd (variadic) mode_t parameter is irrelevant. Many developers
- in the past have passed mode_t (0, 044, 0644, or such), which might lead
- future people to copy this broken idiom, and perhaps even believe this
- parameter has some meaning or implication or application. Delete them all.
- This comes out of a conversation where tb@ noticed that a strange (but
- intentional) pledge behaviour is to always knock-out high-bits from mode_t on
- a number of system calls as a safety factor, and his bewilderment that this
- appeared to be happening against valid modes (at least visually), but no
- sorry, they are all irrelevant junk. They could all be 0xdeafbeef. ok
- millert
+ From Pedro Martelletto; ok dtucker & me
- OpenBSD-Commit-ID: 503d11633497115688c0c6952686524f01f53121
-
-commit d575cf44895104e0fcb0629920fb645207218129
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Oct 22 23:27:41 2021 +1100
-
- kitchensink test target now needs krb5.
-
-commit 4ae39cada214e955bcfd3448ff28f0ed18886706
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Oct 22 22:54:33 2021 +1100
-
- Test both MIT KRB5 and Heimdal.
+ OpenBSD-Commit-ID: 47be40d602b7a6458c4c71114df9b53d149fc2e9
-commit 22b2681d88619e5247dc53c9f112058a7e248d48
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Oct 22 10:51:57 2021 +0000
+commit 014e2f147a2788bfb3cc58d1b170dcf2bf2ee493
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jan 14 03:34:00 2022 +0000
- upstream: Plug mem addrinfo mem leaks.
+ upstream: sshsk_load_resident: don't preallocate resp
- Prevent mem leaks in the (unlikely) event that getaddrinfo returns
- no addresses. ALso, remove an unneeded NULL check in addr_ntop. From
- khaleesicodes via github PR#281, ok deraadt@
+ resp is allocated by client_converse(), at which point we lose
+ the original pointer.
- OpenBSD-Commit-ID: e8a5afc686376637c355c5f7e122dc4b080b9c1a
+ From Pedro Martelletto; ok dtucker & me
+
+ OpenBSD-Commit-ID: 1f1b5ea3282017d6584dfed4f8370dc1db1f44b1
-commit 27c8c343b610263f83ac2328735feeb881c6c92f
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Oct 22 09:22:04 2021 +0000
+commit c88265f207dfe0e8bdbaf9f0eda63ed6b33781cf
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jan 14 03:32:52 2022 +0000
- upstream: Remove unnecessary semicolons
+ upstream: sshsk_sign: trim call to sshkey_fingerprint()
- ... in case statements. From khaleesicodes via github PR#280.
+ the resulting fingerprint doesn't appear to be used for anything,
+ and we end up leaking it.
- OpenBSD-Commit-ID: e1e89360b65775cff83e77ce040b342015caf4ed
+ from Pedro Martelletto; ok dtucker & me
+
+ OpenBSD-Commit-ID: 5625cf6c68f082bc2cbbd348e69a3ed731d2f9b7
-commit e7eb73b8d1fe1008d92433ea949491ce654bfaba
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Oct 22 09:19:34 2021 +0000
+commit 1cd1b2eac39661b849d5a4b4b56363e22bb5f61e
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jan 14 03:31:52 2022 +0000
- upstream: Fix typos in comments.
+ upstream: use status error message to communicate ~user expansion
- From khaleesicodes via github PR#280.
+ failures; provides better experience for scp in sftp mode, where ~user paths
+ are more likely to be used; spotted jsg, feedback jsg & deraadt ok jsg &
+ markus
- OpenBSD-Commit-ID: 26fdd83652c40f098bf7c685e8ebb9eb72cc45fc
+ (forgot to include this file in previous commit)
+
+ OpenBSD-Commit-ID: d37cc4c8c861ce48cd6ea9899e96aaac3476847b
-commit 052a9d8494175e24312daa6c132665e58c17fe6e
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Fri Oct 15 14:46:46 2021 +0000
+commit a1d42a6ce0398da3833bedf374ef2571af7fea50
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Jan 14 13:49:32 2022 +1100
- upstream: switch scp(1) back to sftp protocol.
+ fix edge case in poll(2) wrapper
- openbsd 7.0 release shipped with the (hopefully last) scp that uses RCP
- protocol for copying. Let's get back to testing the SFTP protocol.
+ Correct handling of select(2) exceptfds. These should only be consulted
+ for POLLPRI flagged pfds and not unconditionally converted to POLLERR.
- OpenBSD-Commit-ID: 9eaa35d95fd547b78b0a043b3f518e135f151f30
-
-commit a07664646bf6d293f5bbd45a5de54f3c36bb85da
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Oct 22 14:00:05 2021 +1100
-
- Source configs script so setup_ci can use settings
+ with and ok dtucker@
-commit 34df52c201c6b47e5a46b50c215e4d98a8bf6587
+commit 976b9588b4b5babcaceec4767a241c11a67a5ccb
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Oct 22 09:42:14 2021 +1100
+Date: Fri Jan 14 13:46:35 2022 +1100
- Install libedit and pam based on config flags.
+ Wrap OpenSSL includes in unit tests in ifdef.
+
+ Fixes unit test on systems that do not have OpenSSL headers installed.
-commit 8c626cc563e8d21d844d06f9971a9ee01de6aa2a
+commit c171879374b2e8b07157503f5639ed0bce59ce89
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Oct 21 16:53:39 2021 +1100
+Date: Thu Jan 13 15:53:33 2022 +1100
- Don't use 'here string", it's not POSIX.
+ Remove sort wrapper.
+
+ agent-restrict now takes care of this itself.
-commit 086a4b5977472aefa3de918b88efad0faf83b2b1
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Oct 21 15:33:27 2021 +1100
+commit 9cc2654403f1a686bb26c07a6ac790edf334cef5
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Thu Jan 13 04:53:16 2022 +0000
- Remove -Werror from compiler package to install.
+ upstream: Set LC_ALL in both local and remote shells so that sorted
+
+ output matches regardless of what the user's shell sets it to. ok djm@
+
+ OpenBSD-Regress-ID: 4e97dd69a68b05872033175a4c2315345d01837f
-commit 5a7a4687507d057f9b5e7497f3d3f82e64753c02
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Oct 21 15:00:53 2021 +1100
+commit 7a75f748cb2dd2f771bf70ea72698aa027996ab1
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Thu Jan 13 04:22:10 2022 +0000
- Build with -Werror on most recent gcc and clang.
+ upstream: Avoid %'s in commands (not used in OpenBSD, but used in
+
+ -portable's Valgrind test) being interpretted as printf format strings.
+
+ OpenBSD-Regress-ID: dc8655db27ac4acd2c386c4681bf42a10d80b043
-commit 4d2cbdb525d673acf941d48a7044fcf03125611a
+commit 6c435bd4994d71442192001483a1cdb846e5ffcd
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Oct 15 12:59:06 2021 +1100
+Date: Wed Jan 12 16:58:13 2022 +1100
- Include string.h and stdio.h for strerror.
+ Stop on first test failure to minimize logs.
-commit fff13aaa262b7b3ec83ed21e29674cbf331780a7
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Oct 15 12:43:36 2021 +1100
+commit 4bc2ba6095620a4484b708ece12842afd8c7685b
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Wed Jan 12 07:18:37 2022 +0000
- Include error reason if trace disabling fails.
+ upstream: Use egrep when searching for an anchored string.
+
+ OpenBSD-Regress-ID: dd114a2ac27ac4b06f9e4a586d3f6320c54aeeb4
-commit d4b38144c02f3faa5271e5fb35df93507e06f1b4
+commit 6bf2efa2679da1e8e60731f41677b2081dedae2c
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Oct 12 22:55:51 2021 +1100
+Date: Wed Jan 12 18:25:06 2022 +1100
- Add tcmalloc test target.
+ Add "rev" command replacement if needed.
-commit 002d65b0a30063c6e49bf8a53e709d8d5a0d45c1
+commit 72bcd7993dadaf967bb3d8564ee31cbf38132b5d
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Oct 9 10:52:42 2021 +0000
+Date: Wed Jan 12 03:30:32 2022 +0000
- upstream: Document that CASignatureAlgorithms, ExposeAuthInfo and
+ upstream: Don't log NULL hostname in restricted agent code,
- PubkeyAuthOptions can be used in a Match block. Patch from eehakkin via
- github PR#277.
+ printf("%s", NULL) is not safe on all platforms. with & ok djm
- OpenBSD-Commit-ID: c0a63f5f52e918645967ac022b28392da4b866aa
-
-commit 40bd3709dddaae3a1b6113748bec3faa6a607531
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Oct 7 15:55:49 2021 +1100
+ OpenBSD-Commit-ID: faf10cdae4adde00cdd668cd1f6e05d0a0e32a02
- Skip SK unit tests when built without security-key
+commit acabefe3f8fb58c867c99fed9bbf84dfa1771727
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Jan 11 22:33:16 2022 +0000
-commit 482f73be10f10b93f818df19fcc8a912c0c371fc
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Oct 7 15:55:04 2021 +1100
+ upstream: remove hardcoded domain and use window.location.host, so this
+
+ can be run anywhere
+
+ OpenBSD-Regress-ID: 2ac2ade3b6227d9c547351d3ccdfe671e62b7f92
- Include relevant env vars on command line.
+commit 96da0946e44f34adc0397eb7caa6ec35a3e79891
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Jan 11 02:56:19 2022 +0000
+
+ upstream: "void" functions should not return anything. From Tim Rice
- Makes it easier to reproduce a build by cut/pasting the configure line.
+ via -portable.
+
+ OpenBSD-Commit-ID: ce6616304f4c9881b46413e616b226c306830e2a
-commit ef5916b8acd9b1d2f39fad4951dae03b00dbe390
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Oct 7 14:28:02 2021 +1100
+commit a882a09722c9f086c9edb65d0c4022fd965ec1ed
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Jan 11 01:26:47 2022 +0000
- Only enable sk-* key types if ENABLE_SK is defined
+ upstream: suppress "Connection to xxx closed" messages at LogLevel >=
+
+ error bz3378; ok dtucker@
+
+ OpenBSD-Commit-ID: d5bf457d5d2eb927b81d0663f45248a31028265c
-commit 52d4232b493a9858fe616e28a8bbcc89afa2ad4d
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Oct 6 18:14:37 2021 +1100
+commit 61a1a6af22e17fc94999a5d1294f27346e6c4668
+Author: Damien Miller <djm@mindrot.org>
+Date: Wed Jan 12 08:57:49 2022 +1100
- Disable security key on minix3.
+ OS X poll(2) is broken; use compat replacement
- The test doesn't work so disable.
+ Darwin's poll(2) implementation is broken. For character-special
+ devices like /dev/null, it returns POLLNVAL when polled with
+ POLLIN.
+
+ Apparently this is Apple bug 3710161, which is AFAIK not public,
+ but a websearch will find other OSS projects rediscovering it
+ periodically since it was first identified in 2005 (!!)
-commit 7cd062c3a29669b8d7dc2a97e6575f4dcb7d35a2
+commit 613a6545fc5a9542753b503cbe5906538a640b60
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Oct 6 17:45:28 2021 +1100
+Date: Tue Jan 11 20:56:01 2022 +1100
- Add USE_LIBC_SHA2 for (at least) NetBSD 9.
+ libhardended_malloc.so moved into out dir.
-commit 639c440f6c3c2a8216a5eb9455ef13bf4204089c
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Oct 6 17:09:31 2021 +1100
+commit 61761340be5e11046556623f8f5412b236cefa95
+Author: Tim Rice <tim@multitalents.net>
+Date: Mon Jan 10 11:07:04 2022 -0800
- Define OPENSSL_NO_SHA including OpenSSL from test.
-
- We don't use SHA256 from OpenSSL in the sk-dummy module and the
- definitions can conflict with system sha2.h (eg on NetBSD) so define
- OPENSSL_NO_SHA so we don't attempt to redefine them.
+ Make USL compilers happy
+ UX:acomp: ERROR: "sftp-server.c", line 567: void function cannot return value
-commit 8f4be526a338d06624f146fa26007bb9dd3a4f7b
+commit 3ef403f351e80a59b6f7e9d43cb82c181855483c
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Oct 6 15:40:58 2021 +1100
+Date: Mon Jan 10 21:07:38 2022 +1100
- Disable security key on NetBSD4 test.
+ Add wrapper for "sort" to set LC_ALL=C.
- sk-dummy used for the security key test includes both sha2.h and OpenSSL
- causing the definitions conflict so disable security key support on this
- platform.
+ Found by djm, this should make sorts stable and reduce test flakiness.
-commit 3b353ae58aa07a1cbbeb1da3ace21fc0dcccd66a
-Author: Damien Miller <djm@mindrot.org>
-Date: Wed Oct 6 15:07:01 2021 +1100
+commit bd69e29f5716090181dbe0b8272eb7eab1a383bb
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sat Jan 8 07:55:26 2022 +0000
- clean regress/misc/sk-dummy in cleandir target
+ upstream: Remove errant "set -x" left over from debugging.
+
+ OpenBSD-Regress-ID: cd989268e034264cec5df97be7581549032c87dc
-commit 57680a2ab43518c5ccbd8242c40482106cde6ac1
+commit 1a7c88e26fd673813dc5f61c4ac278564845e004
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Oct 2 03:17:01 2021 +0000
+Date: Sat Jan 8 07:01:13 2022 +0000
- upstream: Dynamically allocate encoded HashKnownHosts and free as
+ upstream: Enable all supported hostkey algorithms (but no others).
- appropriate. Saves 1k of static storage and prevents snprintf "possible
- truncation" warnings from newer compilers (although in this case it's false
- positive since the actual sizes are limited by the output size of the SHA1).
- ok djm@
+ Allows hostbased test to pass when built without OpenSSL.
- OpenBSD-Commit-ID: e254ae723f7e3dce352c7d5abc4b6d87faf61bf4
+ OpenBSD-Regress-ID: 5ddd677a68b672517e1e78460dc6ca2ccc0a9562
-commit e3e62deb549fde215b777d95276c304f84bf00c6
+commit 12b457c2a42ff271e7967d9bedd068cebb048db9
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Oct 6 03:35:13 2021 +0000
+Date: Sat Jan 8 07:37:32 2022 +0000
- upstream: use libc SHA256 functions; make this work when compiled
+ upstream: use status error message to communicate ~user expansion
- !WITH_OPENSSL
+ failures; provides better experience for scp in sftp mode, where ~user paths
+ are more likely to be used; spotted jsg, feedback jsg & deraadt ok jsg &
+ markus
- OpenBSD-Regress-ID: fda0764c1097cd42f979ace29b07eb3481259890
+ OpenBSD-Commit-ID: fc610ce00ca0cdc2ecdabbd49ce7cb82033f905f
-commit 12937d867019469ebce83c2ff614cdc6688fc2d8
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Oct 1 05:20:20 2021 +0000
+commit 63670d4e9030bcee490d5a9cce561373ac5b3b23
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Jan 8 07:36:11 2022 +0000
- upstream: Add test for ssh hashed known_hosts handling.
+ upstream: fix some corner-case bugs in scp sftp-mode handling of
- OpenBSD-Regress-ID: bcef3b3cd5a1ad9899327b4b2183de2541aaf9cf
+ ~-prefixed paths; spotted by jsg; feedback jsg & deraadt, ok jsg & markus
+
+ OpenBSD-Commit-ID: d1697dbaaa9f0f5649d69be897eab25c7d37c222
-commit 5a37cc118f464416d08cd0291a9b1611d8de9943
-Author: Damien Miller <djm@mindrot.org>
-Date: Wed Oct 6 13:16:21 2021 +1100
+commit e14940bbec57fc7d3ce0644dbefa35f5a8ec97d0
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Jan 8 07:34:57 2022 +0000
- fix broken OPENSSL_HAS_ECC test
+ upstream: more idiomatic error messages; spotted by jsg & deraadt
- spotted by dtucker
+ ok jsg & markus
+
+ OpenBSD-Commit-ID: 43618c692f3951747b4151c477c7df22afe2bcc8
-commit 16a25414f303cd6790eb967aeb962040e32c9c7a
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Oct 1 22:40:06 2021 +1000
+commit 9acddcd5918c623f7ebf454520ffe946a8f15e90
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Jan 8 07:33:54 2022 +0000
- make sk-dummy.so work without libcrypto installed
+ upstream: add a variant of send_status() that allows overriding the
+
+ default, generic error message. feedback/ok markus & jsg
+
+ OpenBSD-Commit-ID: 81f251e975d759994131b717ee7c0b439659c40f
-commit dee22129bbc61e25b1003adfa2bc584c5406ef2d
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Oct 1 16:35:49 2021 +1000
+commit 961411337719d4cd78f1ab33e4ac549f3fa22f50
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Jan 8 07:32:45 2022 +0000
- make OPENSSL_HAS_ECC checks more thorough
+ upstream: refactor tilde_expand_filename() and make it handle ~user
- ok dtucker
+ paths with no trailing slash; feedback/ok markus and jsg
+
+ OpenBSD-Commit-ID: a2ab365598a902f0f14ba6a4f8fb2d07a9b5d51d
-commit 872595572b6c9a584ed754165e8b7c4c9e7e1d61
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Oct 1 16:35:05 2021 +1000
+commit dc38236ab6827dec575064cac65c8e7035768773
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Thu Jan 6 22:14:25 2022 +0000
- fix FIDO key support for !OPENSSL_HAS_ECC case
+ upstream: Don't explicitly set HostbasedAuthentication in
- ok dtucker
+ sshd_config. It defaults to "no", and not explicitly setting it allows us to
+ enable it for the (optional) hostbased test.
+
+ OpenBSD-Regress-ID: aa8e3548eb5793721641d26e56c29f363b767c0c
-commit 489741dc68366940d369ac670b210b4834a6c272
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Oct 1 14:51:37 2021 +1000
+commit e12d912ddf1c873cb72e5de9a197afbe0b6622d2
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Thu Jan 6 21:46:56 2022 +0000
- enable security key support for --without-openssl
+ upstream: Add test for hostbased auth. It requires some external
+
+ setup (see comments at the top) and thus is disabled unless
+ TEST_SSH_HOSTBASED_AUTH and SUDO are set.
+
+ OpenBSD-Regress-ID: 3ec8ba3750c5b595fc63e7845d13483065a4827a
-commit c978565c8589acfe4ea37ab5099d39c84158c713
+commit a48533a8da6a0f4f05ecd055dc8048047e53569e
Author: Damien Miller <djm@mindrot.org>
-Date: Fri Oct 1 13:27:50 2021 +1000
+Date: Fri Jan 7 09:24:26 2022 +1100
- need stdlib.h for free(3)
+ depend
-commit 76a398edfb51951b2d65d522d7b02c72304db300
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Thu Sep 30 05:26:26 2021 +0000
+commit d9dbb5d9a0326e252d3c7bc13beb9c2434f59409
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Jan 6 22:06:51 2022 +0000
- upstream: Fix up whitespace left by previous
+ upstream: allow hostbased auth to select RSA keys when only
- change removing privsep. No other changes.
+ RSA/SHA2 are configured (this is the default case); ok markus@
- OpenBSD-Regress-ID: 87adec225d8afaee4d6a91b2b71203f52bf14b15
+ OpenBSD-Commit-ID: 411c18c7bde40c60cc6dfb7017968577b4d4a827
-commit ddcb53b7a7b29be65d57562302b2d5f41733e8dd
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Thu Sep 30 05:20:08 2021 +0000
+commit fdb1d58d0d3888b042e5a500f6ce524486aaf782
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Jan 6 22:05:42 2022 +0000
- upstream: Remove references to privsep.
+ upstream: add a helper function to match a key type to a list of
- This removes several do..while loops but does not change the
- indentation of the now-shallower loops, which will be done in a separate
- whitespace-only commit to keep changes of style and substance separate.
+ signature algorithms. RSA keys can make signatures with multiple algorithms,
+ so some special handling is required. ok markus@
- OpenBSD-Regress-ID: 4bed1a0249df7b4a87c965066ce689e79472a8f7
+ OpenBSD-Commit-ID: 03b41b2bda06fa4cd9c84cef6095033b9e49b6ff
-commit ece2fbe486164860de8df3f8b943cccca3085eff
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Thu Sep 30 04:22:50 2021 +0000
+commit 11e8c4309a5086a45fbbbc87d0af5323c6152914
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Jan 6 22:04:20 2022 +0000
- upstream: Use "skip" instead of "fatal"
+ upstream: log some details on hostkeys that ssh loads for
- if SUDO isn't set for the *-command tests. This means running "make tests"
- without SUDO set will perform all of the tests that it can instead of
- failing on the ones it cannot run.
+ hostbased authn ok markus@
- OpenBSD-Regress-ID: bd4dbbb02f34b2e8c890558ad4a696248def763a
+ OpenBSD-Commit-ID: da17061fa1f0e58cb31b88478a40643e18233e38
-commit bb754b470c360e787a99fb4e88e2668198e97b41
+commit c6706f661739514a34125aa3136532a958929510
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Oct 1 04:50:36 2021 +0000
+Date: Thu Jan 6 22:03:59 2022 +0000
- upstream: unbreak FIDO sk-ed25519 key enrollment for OPENSSL=no builds;
+ upstream: log signature algorithm during verification by monitor;
- ok dtucker@
+ ok markus
- OpenBSD-Commit-ID: 6323a5241728626cbb2bf0452cf6a5bcbd7ff709
-
-commit 207648d7a6415dc915260ca75850404dbf9f0a0b
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 29 20:03:58 2021 +1000
+ OpenBSD-Commit-ID: 02b92bb42c4d4bf05a051702a56eb915151d9ecc
- Include stdlib.h for arc4random_uniform prototype.
+commit 8832402bd500d1661ccc80a476fd563335ef6cdc
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Jan 6 22:02:52 2022 +0000
-commit 696aadc854582c164d5fc04933d2f3e212dc0e06
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 29 20:00:30 2021 +1000
+ upstream: piece of UpdateHostkeys client strictification: when
+
+ updating known_hosts with new keys, ignore NULL keys (forgot to include in
+ prior commit)
+
+ OpenBSD-Commit-ID: 49d2eda6379490e1ceec40c3b670b973f63dea08
- Look for clang after cc and gcc.
-
-commit a3c6375555026d85dbf811fab566b9f76f196144
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 29 19:30:59 2021 +1000
-
- Use backticks instead of $(..) for portability.
-
- Older shells (eg /bin/sh on Solaris 10) don't support $() syntax.
-
-commit 958aaa0387133d51f84fe9c8f30bca03025f2867
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 29 18:53:32 2021 +1000
+commit c2d9ced1da0276961d86690b3bd7ebdaca7fdbf7
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Jan 6 22:01:14 2022 +0000
- Skip file-based tests by default on Mac OS.
+ upstream: include rejected signature algorithm in error message
- The file-based tests need OpenSSL so skip them.
-
-commit 55c8bdf6e9afb0f9fa8e4f10c25c7f0081b48fd0
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 29 18:42:47 2021 +1000
-
- Build without OpenSSL on Mac OS.
+ and not the (useless) key type; ok markus
- Modern versions don't ship enough libcrypto to build against.
+ OpenBSD-Commit-ID: 4180b5ec7ab347b43f84e00b1972515296dab023
-commit c9172193ea975415facf0afb356d87df21535f88
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 29 18:33:38 2021 +1000
+commit 7aa7b096cf2bafe2777085abdeed5ce00581f641
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Jan 6 22:00:18 2022 +0000
- Remove TEST_SSH_ECC.
+ upstream: make ssh-keysign use the requested signature algorithm
- Convert the only remaining user of it to runtime detection using ssh -Q.
-
-commit 5e6d28b7874b0deae95d2c68947c45212d32e599
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 29 17:48:09 2021 +1000
-
- Split c89 test openssl setting out.
-
-commit c4ac7f98e230e83c015678dc958b1ffe828564ad
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 29 17:40:50 2021 +1000
-
- Expand TEST_SHELL consistently with other vars.
-
-commit cfe5f7b0eb7621bfb0a756222de0431315c2ab8b
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 29 17:26:50 2021 +1000
-
- Replace `pwd` with make variable in regress cmd.
-
-commit 899be59da5fbc3372444bd0fbe74af48313bed33
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 29 17:14:33 2021 +1000
-
- Get BUILDDIR from autoconf.
+ and not the default for the keytype. Part of unbreaking hostbased auth for
+ RSA/SHA2 keys. ok markus@
- Use this to replace `pwd`s in regress test command line.
-
-commit c8d92d3d4f7d560146f2f936156ec4dac3fc5811
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 29 13:28:56 2021 +1000
-
- Add make clean step to tests.
-
-commit 360fb41ef8359619ab90b0d131c914494e55d3dd
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 29 11:36:13 2021 +1000
-
- Test all available clang and gcc versions.
+ OpenBSD-Commit-ID: b5639a14462948970da3a8020dc06f9a80ecccdc
-commit 4fb49899d7da22952d35a4bc4c9bdb2311087893
+commit 291721bc7c840d113a49518f3fca70e86248b8e8
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Sep 29 01:32:21 2021 +0000
+Date: Thu Jan 6 21:57:28 2022 +0000
- upstream: Test certificate hostkeys held in ssh-agent too. Would have
+ upstream: stricter UpdateHostkey signature verification logic on
- caught regression fixed in sshd r1.575
+ the client- side. Require RSA/SHA2 signatures for RSA hostkeys except when
+ RSA/SHA1 was explicitly negotiated during initial KEX; bz3375
ok markus@
- OpenBSD-Regress-ID: 1f164d7bd89f83762db823eec4ddf2d2556145ed
+ OpenBSD-Commit-ID: 46e75e8dfa2c813781805b842580dcfbd888cf29
-commit ce4854e12e749a05646e5775e9deb8cfaf49a755
+commit 0fa33683223c76289470a954404047bc762be84c
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Sep 29 01:33:32 2021 +0000
+Date: Thu Jan 6 21:55:23 2022 +0000
- upstream: add some debug output showing how many key file/command lines
+ upstream: Fix signature algorithm selection logic for
- were processed. Useful to see whether a file or command actually has keys
- present
+ UpdateHostkeys on the server side. The previous code tried to prefer RSA/SHA2
+ for hostkey proofs of RSA keys, but missed some cases. This will use RSA/SHA2
+ signatures for RSA keys if the client proposed these algorithms in initial
+ KEX. bz3375
- OpenBSD-Commit-ID: 0bd9ff94e84e03a22df8e6c12f6074a95d27f23c
-
-commit 15abdd523501c349b703d9a27e2bb4252ad921ef
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Sep 28 11:14:50 2021 +0000
-
- upstream: Make prototype for rijndaelEncrypt match function
+ Mostly by Dmitry Belyavskiy with some tweaks by me.
- including the bounds. Fixes error in portable where GCC>=11 takes notice of
- the bounds. ok deraadt@
+ ok markus@
- OpenBSD-Commit-ID: cdd2f05fd1549e1786a70871e513cf9e9cf099a6
+ OpenBSD-Commit-ID: c17ba0c3236340d2c6a248158ebed042ac6a8029
-commit d1d29ea1d1ef1a1a54b209f062ec1dcc8399cf03
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Sep 28 11:10:05 2021 +0000
+commit 17877bc81db3846e6e7d4cfb124d966bb9c9296b
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Jan 6 21:48:38 2022 +0000
- upstream: Import regenerated moduli.
+ upstream: convert ssh, sshd mainloops from select() to poll();
- OpenBSD-Commit-ID: 4bec5db13b736b64b06a0fca704cbecc2874c8e1
+ feedback & ok deraadt@ and markus@ has been in snaps for a few months
+
+ OpenBSD-Commit-ID: a77e16a667d5b194dcdb3b76308b8bba7fa7239c
-commit 39f2111b1d5f00206446257377dcce58cc72369f
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 29 10:53:55 2021 +1000
+commit 5c79952dfe1aa36105c93b3f383ce9be04dee384
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Jan 6 21:46:23 2022 +0000
- Add new compiler hardening flags.
+ upstream: prepare for conversion of ssh, sshd mainloop from
- Add -fzero-call-used-regs and -ftrivial-auto-var-init to the list of
- compiler hardening flags that configure checks for. These are supported
- by clang and gcc, and make ROP gadgets less useful and mitigate
- stack-based infoleaks respectively. ok djm@
+ select() to poll() by moving FD_SET construction out of channel handlers into
+ separate functions. ok markus
+
+ OpenBSD-Commit-ID: 937fbf2a4de12b19fb9d5168424e206124807027
-commit bf944e3794eff5413f2df1ef37cddf96918c6bde
-Author: Damien Miller <djm@mindrot.org>
-Date: Mon Sep 27 00:03:19 2021 +1000
+commit 24c5187edfef4651a625b7d5d692c8c7e794f71f
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Jan 5 21:54:37 2022 +0000
- initgroups needs grp.h
+ upstream: add a comment so I don't make this mistake again
+
+ OpenBSD-Commit-ID: 69c7f2362f9de913bb29b6318580c5a1b52c921e
-commit 8c5b5655149bd76ea21026d7fe73ab387dbc3bc7
+commit 7369900441929058263a17f56aa67e05ff7ec628
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Sep 26 14:01:11 2021 +0000
+Date: Wed Jan 5 21:50:00 2022 +0000
- upstream: openssh-8.8
+ upstream: fix cut-and-pasto in error message
- OpenBSD-Commit-ID: 12357794602ac979eb7312a1fb190c453f492ec4
+ OpenBSD-Commit-ID: 4cc5c619e4b456cd2e9bb760d17e3a9c84659198
-commit f3cbe43e28fe71427d41cfe3a17125b972710455
+commit 294c11b1c7d56d3fb61e329603a782315ed70c62
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Sep 26 14:01:03 2021 +0000
+Date: Wed Jan 5 08:25:05 2022 +0000
- upstream: need initgroups() before setresgid(); reported by anton@,
+ upstream: select all RSA hostkey algorithms for UpdateHostkeys tests,
- ok deraadt@
+ not just RSA-SHA1
- OpenBSD-Commit-ID: 6aa003ee658b316960d94078f2a16edbc25087ce
-
-commit 8acaff41f7518be40774c626334157b1b1c5583c
-Author: Damien Miller <djm@mindrot.org>
-Date: Sun Sep 26 22:16:36 2021 +1000
-
- update version numbers for release
+ OpenBSD-Regress-ID: b40e62b65863f2702a0c10aca583b2fe76772bd8
-commit d39039ddc0010baa91c70a0fa0753a2699bbf435
-Author: kn@openbsd.org <kn@openbsd.org>
-Date: Sat Sep 25 09:40:33 2021 +0000
+commit 2ea1108c30e3edb6f872dfc1e6da10b041ddf2c0
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Jan 5 04:56:15 2022 +0000
- upstream: RSA/SHA-1 is not used by default anymore
+ upstream: regress test both sshsig message hash algorithms, possible
- OK dtucker deraadt djm
+ now because the algorithm is controllable via the CLI
- OpenBSD-Commit-ID: 055c51a221c3f099dd75c95362f902da1b8678c6
+ OpenBSD-Regress-ID: 0196fa87acc3544b2b4fd98de844a571cb09a39f
-commit 9b2ee74e3aa8c461eb5552a6ebf260449bb06f7e
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Sep 24 11:08:03 2021 +1000
+commit 2327c306b5d4a2b7e71178e5a4d139af9902c2b0
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Jan 5 04:50:11 2022 +0000
- Move the fgrep replacement to hostkey-rotate.sh.
+ upstream: allow selection of hash at sshsig signing time; code
- The fgrep replacement for buggy greps doesn't work in the sftp-glob test
- so move it to just where we know it's needed.
-
-commit f7039541570d4b66d76e6f574544db176d8d5c02
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Sep 24 08:04:14 2021 +1000
-
- Replacement function for buggy fgrep.
+ already supported either sha512 (default) or sha256, but plumbing wasn't
+ there mostly by Linus Nordberg
- GNU (f)grep <=2.18, as shipped by FreeBSD<=12 and NetBSD<=9 will
- occasionally fail to find ssh host keys in the hostkey-rotate test.
- If we have those versions, use awk instead.
-
-commit f6a660e5bf28a01962af87568e118a2d2e79eaa0
-Author: David Manouchehri <david.manouchehri@riseup.net>
-Date: Thu Sep 23 17:03:18 2021 -0400
-
- Don't prompt for yes/no questions.
+ OpenBSD-Commit-ID: 1b536404b9da74a84b3a1c8d0b05fd564cdc96cd
-commit 7ed1a3117c09f8c3f1add35aad77d3ebe1b85b4d
+commit 56e941d0a00d6d8bae88317717d5e1b7395c9529
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Sep 20 06:53:56 2021 +0000
+Date: Wed Jan 5 04:27:54 2022 +0000
- upstream: fix missing -s in SYNOPSYS and usage() as well as a
+ upstream: add missing -O option to usage() for ssh-keygen -Y sign;
- capitalisation mistake; spotted by jmc@
+ from Linus Nordberg
- OpenBSD-Commit-ID: 0ed8ee085c7503c60578941d8b45f3a61d4c9710
+ OpenBSD-Commit-ID: 4e78feb4aa830727ab76bb2e3d940440ae1d7af0
-commit 8c07170135dde82a26886b600a8bf6fb290b633d
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Sep 20 04:02:13 2021 +0000
+commit 141a14ec9b0924709c98df2dd8013bde5d8d12c7
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Jan 5 04:27:01 2022 +0000
- upstream: Fix "Allocated port" debug message
+ upstream: move sig_process_opts() to before sig_sign(); no
- for unix domain sockets. From peder.stray at gmail.com via github PR#272,
- ok deraadt@
+ functional code change
- OpenBSD-Commit-ID: 8d5ef3fbdcdd29ebb0792b5022a4942db03f017e
+ OpenBSD-Commit-ID: da02d61f5464f72b4e8b299f83e93c3b657932f9
-commit 277d3c6adfb128b4129db08e3d65195d94b55fe7
+commit 37a14249ec993599a9051731e4fb0ac5e976aec1
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Sep 20 01:55:42 2021 +0000
+Date: Wed Jan 5 04:10:39 2022 +0000
- upstream: Switch scp back to use the old protocol by default, ahead of
+ upstream: regression test for find-principals NULL deref; from Fabian
- release. We'll wait a little longer for people to pick up sftp-server(8) that
- supports the extension that scp needs for ~user paths to continue working in
- SFTP protocol mode. Discussed with deraadt@
+ Stelzer
- OpenBSD-Commit-ID: f281f603a705fba317ff076e7b11bcf2df941871
+ OpenBSD-Regress-ID: f845a8632a5a7d5ae26978004c93e796270fd3e5
-commit ace19b34cc15bea3482be90450c1ed0cd0dd0669
+commit eb1f042142fdaba93f6c9560cf6c91ae25f6884a
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Sep 18 02:03:25 2021 +0000
+Date: Wed Jan 5 04:02:42 2022 +0000
- upstream: better error message for ~user failures when the
+ upstream: NULL deref when using find-principals when matching an
- sftp-server lacks the expand-path extension; ok deraadt@
+ allowed_signers line that contains a namespace restriction, but no
+ restriction specified on the command-line; report and fix from Fabian Stelzer
- OpenBSD-Commit-ID: 9c1d965d389411f7e86f0a445158bf09b8f9e4bc
+ OpenBSD-Commit-ID: 4a201b86afb668c908d1a559c6af456a61f4b145
-commit 6b1238ba971ee722a310d95037b498ede5539c03
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Sep 16 15:22:22 2021 +0000
+commit 8f3b18030579f395eca2181da31a5f945af12a59
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Jan 4 08:38:53 2022 +0000
- upstream: make some more scp-in-SFTP mode better match Unix idioms
+ upstream: Log command invocation while debugging.
- suggested by deraadt@
+ This will aid in manually reproducing failing commands.
- OpenBSD-Commit-ID: 0f2439404ed4cf0b0be8bf49a1ee734836e1ac87
+ OpenBSD-Regress-ID: b4aba8d5ac5675ceebeeeefa3261ce344e67333a
-commit e694f8ac4409931e67d08ac44ed251b20b10a957
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Sep 16 15:11:19 2021 +0000
+commit bbf285164df535f0d38c36237f007551bbdae27f
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sun Dec 26 10:31:15 2021 +1100
- upstream: allow log_stderr==2 to prefix log messages with argv[0]
-
- use this to make scp's SFTP mode error messages more scp-like
-
- prompted by and ok deraadt@
+ Always save config.h as build artifact.
- OpenBSD-Commit-ID: 0e821dbde423fc2280e47414bdc22aaa5b4e0733
+ Should allow better comparison between failing and succeeding test
+ platforms.
-commit 8a7a06ee505cb833e613f74a07392e9296286c30
+commit 03bd4ed0db699687c5cd83405d26f81d2dc28d22
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Sep 17 13:03:31 2021 +1000
+Date: Sat Dec 25 16:42:51 2021 +1100
- Test against LibreSSL 3.2.6, 3.3.4, 3.4.0.
+ Add OpenBSD 7.0 target. Retire 6.8.
-commit c25c84074a47f700dd6534995b4af4b456927150
+commit c45a752f0de611afd87755c2887c8a24816d08ee
+Author: jsg@openbsd.org <jsg@openbsd.org>
+Date: Sat Jan 1 05:55:06 2022 +0000
+
+ upstream: spelling
+
+ OpenBSD-Commit-ID: c63e43087a64d0727af13409c708938e05147b62
+
+commit c672f83a89a756564db0d3af9934ba0e1cf8fa3e
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Sep 16 05:36:03 2021 +0000
+Date: Tue Jan 4 07:20:33 2022 +0000
- upstream: missing space character in ssh -G output broke the
+ upstream: unbreak test: was picking up system ssh-add instead of the
- t-sshcfgparse regression test; spotted by anton@
+ one supposedly being tested. Spotted by dtucker and using his VM zoo (which
+ includes some systems old enough to lack ed25519 key support)
- OpenBSD-Commit-ID: bcc36fae2f233caac4baa8e58482da4aa350eed0
+ OpenBSD-Regress-ID: 7976eb3df11cc2ca3af91030a6a8c0cef1590bb5
-commit a4bee1934bf5e5575fea486628f4123d6a29dff8
+commit a23698c3082ffe661abed14b020eac9b0c25eb9f
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Sep 15 06:56:01 2021 +0000
+Date: Sat Jan 1 04:18:06 2022 +0000
- upstream: allow CanonicalizePermittedCNAMEs=none in ssh_config; ok
+ upstream: fix memleak in process_extension(); oss-fuzz issue #42719
- markus@
+ OpenBSD-Commit-ID: d8d49f840162fb7b8949e3a5adb8107444b6de1e
+
+commit cb885178f36b83d0f14cfe9f345d2068103feed0
+Author: jsg@openbsd.org <jsg@openbsd.org>
+Date: Sat Jan 1 01:55:30 2022 +0000
+
+ upstream: spelling ok dtucker@
- OpenBSD-Commit-ID: 668a82ba8e56d731b26ffc5703213bfe071df623
+ OpenBSD-Commit-ID: bfc7ba74c22c928de2e257328b3f1274a3dfdf19
-commit d0fffc88c8fe90c1815c6f4097bc8cbcabc0f3dd
-Author: mbuhl@openbsd.org <mbuhl@openbsd.org>
-Date: Tue Sep 14 11:04:21 2021 +0000
+commit 6b977f8080a32c5b3cbb9edb634b9d5789fb79be
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Dec 26 23:34:41 2021 +0000
- upstream: put back the mux_ctx memleak fix for SSH_CHANNEL_MUX_CLIENT
+ upstream: split method list search functionality from
- OK mfriedl@
+ authmethod_lookup() into a separate authmethod_byname(), for cases where we
+ don't need to check whether a method is enabled, etc.
- OpenBSD-Commit-ID: 1aba1da828956cacaadb81a637338734697d9798
+ use this to fix the "none" authentication method regression reported
+ by Nam Nguyen via bugs@
+
+ ok deraadt@
+
+ OpenBSD-Commit-ID: 8cd188dc3a83aa8abe5b7693e762975cd8ea8a17
-commit 19b3d846f06697c85957ab79a63454f57f8e22d6
-Author: schwarze@openbsd.org <schwarze@openbsd.org>
-Date: Sat Sep 11 09:05:50 2021 +0000
+commit 0074aa2c8d605ee7587279a22cdad4270b4ddd07
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Wed Dec 22 06:56:41 2021 +0000
- upstream: Do not ignore SIGINT while waiting for input if editline(3)
+ upstream: sort -H and -h in SYNOPSIS/usage(); tweak the -H text;
- is not used. Instead, in non-interactive mode, exit sftp(1), like for other
- serious errors. As pointed out by dtucker@, when compiled without editline(3)
- support in portable OpenSSH, the el == NULL branch is also used for
- interactive mode. In that case, discard the input line and provide a fresh
- prompt to the user just like in the case where editline(3) is used. OK djm@
+ ok djm
- OpenBSD-Commit-ID: 7d06f4d3ebba62115527fafacf38370d09dfb393
+ OpenBSD-Commit-ID: 90721643e41e9e09deb5b776aaa0443456ab0965
-commit ba61123eef9c6356d438c90c1199a57a0d7bcb0a
+commit 1c9853a68b2319f2e5f929179735e8fbb9988a67
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Dec 22 19:33:10 2021 +1100
+
+ Use SHA.*_HMAC_BLOCK_SIZE if needed.
+
+ If the platform has a native SHA2, does not define SHA.*_BLOCK_LENGTH
+ but does define SHA.*_HMAC_BLOCK_SIZE (eg Solaris) then use the latter.
+ Should fix --without-openssl build on Solaris.
+
+commit 715c892f0a5295b391ae92c26ef4d6a86ea96e8e
+Author: Damien Miller <djm@mindrot.org>
+Date: Wed Dec 22 09:02:50 2021 +1100
+
+ remove sys/param.h in -portable, after upstream
+
+commit 7a7c69d8b4022b1e5c0afb169c416af8ce70f3e8
+Author: Damien Miller <djm@mindrot.org>
+Date: Mon Dec 20 13:05:20 2021 +1100
+
+ add agent-restrict.sh file, missed in last commit
+
+commit f539136ca51a4976644db5d0be8158cc1914c72a
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Sep 11 00:40:24 2021 +0000
+Date: Sun Dec 19 22:20:12 2021 +0000
- upstream: when using SFTP protocol, continue transferring files after a
+ upstream: regression test for destination restrictions in ssh-agent
- transfer error occurs. This matches original scp/rcp behaviour. ok dtucker@
+ OpenBSD-Regress-ID: 3c799d91e736b1753b4a42d80c42fc40de5ad33d
+
+commit 6e4980eb8ef94c04874a79dd380c3f568e8416d6
+Author: anton@openbsd.org <anton@openbsd.org>
+Date: Sat Dec 18 06:53:59 2021 +0000
+
+ upstream: Make use of ntests variable, pointed out by clang 13.
- OpenBSD-Commit-ID: dfe4558d71dd09707e9b5d6e7d2e53b793da69fa
+ OpenBSD-Regress-ID: 4241a3d21bdfa1630ed429b6d4fee51038d1be72
-commit b0ec59a708b493c6f3940336b1a537bcb64dd2a7
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Sep 10 11:38:38 2021 +0000
+commit 3eead8158393b697f663ec4301e3c7b6f24580b1
+Author: deraadt@openbsd.org <deraadt@openbsd.org>
+Date: Tue Dec 14 21:25:27 2021 +0000
- upstream: Document that non-interactive commands are run via the user's
+ upstream: sys/param.h cleanup, mostly using MINIMUM() and
- shell using the -c flag. ok jmc@
+ <limits.h> ok dtucker
- OpenBSD-Commit-ID: 4f0d912077732eead10423afd1acf4fc0ceec477
+ OpenBSD-Regress-ID: 172a4c45d3bcf92fa6cdf6c4b9db3f1b3abe4db0
-commit 66a658b5d9e009ea11f8a0ca6e69c7feb2d851ea
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Sep 10 10:26:02 2021 +0000
+commit 266678e19eb0e86fdf865b431b6e172e7a95bf48
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Dec 19 22:15:42 2021 +0000
- upstream: Document behaviour of arguments following non-interactive
+ upstream: document host-bound publickey authentication
- commands. Prompted by github PR#139 from EvanTheB, feedback & ok djm@ jmc@
+ OpenBSD-Commit-ID: ea6ed91779a81f06d961e30ecc49316b3d71961b
+
+commit 3d00024b3b156aa9bbd05d105f1deb9cb088f6f7
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Dec 19 22:15:21 2021 +0000
+
+ upstream: document agent protocol extensions
- OpenBSD-Commit-ID: fc758d1fe0471dfab4304fcad6cd4ecc3d79162a
+ OpenBSD-Commit-ID: 09e8bb391bbaf24c409b75a4af44e0cac65405a7
-commit 1d47e28e407d1f95fdf8f799be23f48dcfa5206b
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Sep 10 07:11:11 2021 +0000
+commit c385abf76511451bcba78568167b1cd9e90587d5
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Dec 19 22:14:47 2021 +0000
- upstream: Clarify which file's attributes -p preserves, and that
+ upstream: PubkeyAuthentication=yes|no|unbound|host-bound
- it's specifically the file mode bits. bz#3340 from calestyo at scientia.net,
- ok djm@ jmc@
+ Allow control over which pubkey methods are used. Added out of
+ concern that some hardware devices may have difficulty signing
+ the longer pubkey authentication challenges. This provides a
+ way for them to disable the extension. It's also handy for
+ testing.
- OpenBSD-Commit-ID: f09e6098ed1c4be00c730873049825f8ee7cb884
+ feedback / ok markus@
+
+ OpenBSD-Commit-ID: ee52580db95c355cf6d563ba89974c210e603b1a
-commit b344db7a413478e4c21e4cadba4a970ad3e6128a
+commit 34b1e9cc7654f41cd4c5b1cc290b999dcf6579bb
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Sep 10 05:46:09 2021 +0000
+Date: Sun Dec 19 22:14:12 2021 +0000
- upstream: openssh-7.4 was incorrectly listed twice; spotted by
+ upstream: document destination-constrained keys
- Dmitry Belyavskiy, ok dtucker@
+ feedback / ok markus@
- OpenBSD-Commit-ID: 4b823ae448f6e899927ce7b04225ac9e489f58ef
+ OpenBSD-Commit-ID: cd8c526c77268f6d91c06adbee66b014d22d672e
-commit 9136d6239ad7a4a293e0418a49b69e70c76d58b8
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Thu Sep 9 06:17:39 2021 +0000
+commit a6d7677c4abcfba268053e5867f2acabe3aa371b
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Dec 19 22:13:55 2021 +0000
- upstream: - move CAVEATS to its correct order - use the term
+ upstream: Use hostkey parsed from hostbound userauth request
- "legacy" protocol rather than "original", as the latter made the text
- misleading - uppercase SCP
+ Require host-bound userauth requests for forwarded SSH connections.
- ok djm
+ The hostkey parsed from the host-bound userauth request is now checked
+ against the most recently bound session ID / hostkey on the agent socket
+ and the signature refused if they do not match.
- OpenBSD-Commit-ID: 8479255746d5fa76a358ee59e7340fecf4245ff0
-
-commit 2d678c5e3bdc2f5c99f7af5122e9d054925d560d
-Author: David Carlier <devnexen@gmail.com>
-Date: Wed Sep 8 19:49:54 2021 +0100
-
- Disable tracing on FreeBSD using procctl.
+ ok markus@
- Placed at the start of platform_disable_tracing() to prevent declaration
- after code errors from strict C89 compilers (in the unlikely event that
- more than one method is enabled).
+ OpenBSD-Commit-ID: d69877c9a3bd8d1189a5dbdeceefa432044dae02
-commit 73050fa38fb36ae3326d768b574806352b97002d
+commit baaff0ff4357cc5a079621ba6e2d7e247b765061
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Sep 8 23:31:39 2021 +0000
+Date: Sun Dec 19 22:13:33 2021 +0000
- upstream: Use the SFTP protocol by default. The original scp/rcp
+ upstream: agent support for parsing hostkey-bound signatures
- protocol remains available via the -O flag.
+ Allow parse_userauth_request() to work with blobs from
+ publickey-hostbound-v00@openssh.com userauth attempts.
- Note that ~user/ prefixed paths in SFTP mode require a protocol extension
- that was first shipped in OpenSSH 8.7.
+ Extract hostkey from these blobs.
- ok deraadt, after baking in snaps for a while without incident
+ ok markus@
- OpenBSD-Commit-ID: 23588976e28c281ff5988da0848cb821fec9213c
-
-commit c4565e69ffa2485cff715aa842ea7a350296bfb6
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 8 21:09:49 2021 +1000
+ OpenBSD-Commit-ID: 81c064255634c1109477dc65c3e983581d336df8
- Really fix test on OpenSSL 1.1.1 stable.
+commit 3e16365a79cdeb2d758cf1da6051b1c5266ceed7
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Dec 19 22:13:12 2021 +0000
-commit 79f1bb5f56cef3ae9276207316345b8309248478
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 8 18:51:39 2021 +1000
-
- Correct OpenSSL 1.1.1 stable identifier.
-
-commit b6255593ed5ccbe5e7d3d4b26b2ad31ad4afc232
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 8 18:39:44 2021 +1000
-
- Increment nfds when coming from startup_pipe.
-
- If we have to increase nfds because startup_pipe[0] is above any of the
- descriptors passed in the fd_sets, we also need to add 1 to nfds since
- select takes highest FD number plus one. bz#3345 from yaroslav.kuzmin
- at vmssoftware.com.
-
-commit a3e92a6794817df6012ac8546aea19652cc91b61
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Sep 8 13:45:10 2021 +1000
-
- Tests for OpenSSL 3.0.0 release & 1.1.1 branch.
-
-commit 4afe431da98ec1cf6a2933fe5658f4fd68dee9e2
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Sep 8 03:23:44 2021 +0000
-
- upstream: correct my mistake in previous fix; spotted by halex
-
- OpenBSD-Commit-ID: 3cc62d92e3f70006bf02468fc146bfc36fffa183
-
-commit ca0e455b9331213ff9505a21b94c38e34faa2bba
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Sep 7 06:03:51 2021 +0000
-
- upstream: avoid NULL deref in -Y find-principals. Report and fix
-
- from Carlo Marcelo Arenas Belón
- MIME-Version: 1.0
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
-
- OpenBSD-Commit-ID: 6238486f8ecc888d6ccafcd9ad99e621bb41f1e0
-
-commit 37616807f150fb46610bbd5031c31af4857ad1e9
-Author: millert@openbsd.org <millert@openbsd.org>
-Date: Mon Sep 6 00:36:01 2021 +0000
-
- upstream: revision 1.381 neglected to remove
-
- sChallengeResponseAuthentication from the enum. Noticed by
- christos@zoulas.com. OK dtucker@
-
- OpenBSD-Commit-ID: b533283a4dd6d04a867da411a4c7a8fbc90e34ff
-
-commit 7acb3578cdfec0b3d34501408071f7a96c1684ea
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sun Sep 5 20:45:42 2021 +1000
-
- Correct version_num for OpenSSL dev branch.
-
-commit 65bb01111320dfd0d25e21e1fd4d3f2b77532669
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sun Sep 5 19:37:39 2021 +1000
-
- Test against OpenSSL 3 branch as well as dev.
-
- Now that OpenSSL development has moved to 3.1, test against the most
- recent version of the openssl-3.0 branch too.
-
-commit 864ed0d5e04a503b97202c776b7cf3f163f3eeaa
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sun Sep 5 19:33:22 2021 +1000
-
- OpenSSL development is now 3.1.*
-
-commit a60209a586a928f92ab323bf23bd07f57093342e
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Sep 3 07:43:23 2021 +0000
-
- upstream: Use .Cm instead of .Dq in StrictHostKeyChecking list for
-
- consistency. Patch from scop via github PR#257, ok jmc@
-
- OpenBSD-Commit-ID: 3652a91564570779431802c31224fb4a9cf39872
-
-commit 8d1d9eb6de37331e872700e9e399a3190cca1242
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Sep 3 07:27:03 2021 +0000
-
- upstream: Mention using ssh -i for specifying the public key file
-
- in the case where the private key is loaded into ssh-agent but is not present
- locally. Based on patch from rafork via github PR#215, ok jmc@
-
- OpenBSD-Commit-ID: 2282e83b0ff78d2efbe705883b67240745fa5bb2
-
-commit eb4362e5e3aa7ac26138b11e44d8c191910aff64
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Sep 3 05:25:50 2021 +0000
-
- upstream: Refer to KEX "algorithms" instead of "methods" to match
-
- other references and improve consistency. Patch from scop via github PR#241,
- ok djm@
-
- OpenBSD-Commit-ID: 840bc94ff6861b28d8603c8e8c16499bfb65e32c
-
-commit b3318946ce5725da43c4bf7eeea1b73129c47d2a
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Sep 3 05:12:25 2021 +0000
-
- upstream: Remove redundant attrib_clear in upload_dir_internal.
-
- The subsequent call to stat_to_attrib clears the struct as its first step
- anyway. From pmeinhardt via github PR#220, ok djm@
-
- OpenBSD-Commit-ID: f5234fc6d7425b607e179acb3383f21716f3029e
-
-commit 7cc3fe28896e653956a6a2eed0a25d551b83a029
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Sep 3 04:11:13 2021 +0000
-
- upstream: Add test for client termination status on signal.
-
- Based on patch from Alexxz via github PR#235 with some tweaks, to
- match patch in bz#3281.
-
- OpenBSD-Regress-ID: d87c7446fb8b5f8b45894fbbd6875df326e729e2
-
-commit 5428b0d239f6b516c81d1dd15aa9fe9e60af75d4
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Thu Sep 2 21:03:54 2021 +0000
-
- upstream: sys/param.h is not needed for any visible reason
-
- OpenBSD-Commit-ID: 8bdea2d0c75692e4c5777670ac039d4b01c1f368
-
-commit 1ff38f34b4c4545eb28106629cafa1e0496bc726
-Author: Shchelkunov Artem <a.shchelkunov@ideco.ru>
-Date: Wed Aug 11 18:07:58 2021 +0500
-
- Fix memory leak in error path.
-
- *info is allocated via xstrdup but was leaked in the PAM_AUTH_ERR path.
- From github PR#266.
-
-commit cb37e2f0c0ca4fef844ed7edc5d0e3b7d0e83f6a
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Sep 1 03:16:06 2021 +0000
-
- upstream: Fix ssh-rsa fallback for old PuTTY interop tests.
-
- OpenBSD-Regress-ID: a19ac929da604843a5b5f0f48d2c0eb6e0773d37
-
-commit 8b02ef0f28dc24cda8cbcd8b7eb02bda8f8bbe59
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Sep 1 00:50:27 2021 +0000
-
- upstream: Add a function to skip remaining tests.
-
- Many tests skip tests for various reasons but not in a consistent way and
- don't always clean up, so add that and switch the tests that do that over.
-
- OpenBSD-Regress-ID: 72d2ec90a3ee8849486956a808811734281af735
-
-commit d486845c07324c04240f1674ac513985bd356f66
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Aug 31 07:13:59 2021 +0000
-
- upstream: Specify path to PuTTY keys.
-
- Portable needs this and it makes no difference on OpenBSD, so resync
- them. (Id sync only, Portable already had this.)
-
- OpenBSD-Regress-ID: 33f6f66744455886d148527af8368811e4264162
-
-commit d22b299115e27606e846b23490746f69fdd4fb38
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Aug 31 06:13:23 2021 +0000
-
- upstream: Better compat tests with old PuTTY.
-
- When running PuTTY interop tests and using a PuTTY version older than
- 0.76, re-enable the ssh-rsa host key algorithm (the 256 and 512 variants
- of RSA were added some time between 0.73 and 0.76).
-
- OpenBSD-Regress-ID: e6138d6987aa705fa1e4f216db0bb386e1ff38e1
-
-commit 87ad70d605c3e39c9b8aa275db27120d7cc09b77
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Aug 31 17:04:50 2021 +1000
-
- Resync PuTTY interop tests.
-
- Resync behaviour when REGRESS_INTEROP_PUTTY is not set with OpenBSD.
-
-commit e47b82a7bf51021afac218bf59a3be121827653d
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Aug 31 01:25:27 2021 +0000
-
- upstream: Specify hostkeyalgorithms in SSHFP test.
-
- Specify host key algorithms in sshd's default set for the SSHFP test,
- from djm@. Make the reason for when the test is skipped a bit clearer.
-
- OpenBSD-Regress-ID: 4f923dfc761480d5411de17ea6f0b30de3e32cea
-
-commit 7db3e0a9e8477c018757b59ee955f7372c0b55fb
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Aug 30 01:15:45 2021 +0000
-
- upstream: adapt to RSA/SHA1 deprectation
-
- OpenBSD-Regress-ID: 952397c39a22722880e4de9d1c50bb1a14f907bb
-
-commit 2344750250247111a6c3c6a4fe84ed583a61cc11
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Aug 29 23:53:10 2021 +0000
-
- upstream: After years of forewarning, disable the RSA/SHA-1
-
- signature algorithm by default. It is feasible to create colliding SHA1
- hashes, so we need to deprecate its use.
-
- RSA/SHA-256/512 remains available and will be transparently selected
- instead of RSA/SHA1 for most SSH servers released in the last five+
- years. There is no need to regenerate RSA keys.
-
- The use of RSA/SHA1 can be re-enabled by adding "ssh-rsa" to the
- PubkeyAcceptedAlgorithms directives on the client and server.
-
- ok dtucker deraadt
-
- OpenBSD-Commit-ID: 189bcc4789c7254e09e23734bdd5def8354ff1d5
-
-commit 56c4455d3b54b7d481c77c82115c830b9c8ce328
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Aug 29 23:44:07 2021 +0000
-
- upstream: wrap at 80 columns
-
- OpenBSD-Commit-ID: 47ca2286d6b52a9747f34da16d742879e1a37bf0
-
-commit 95401eea8503943449f712e5f3de52fc0bc612c5
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Aug 20 18:14:13 2021 +1000
-
- Replace shell function with ssh-keygen -A.
-
- Prevents the init script in the SysV package from trying (and failing)
- to generate unsupported key types. Remove now-unused COMMENT_OUT_ECC.
- ok tim@
-
-commit d83ec9ed995a76ed1d5c65cf10b447222ec86131
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Aug 20 15:39:05 2021 +1000
-
- Remove obsolete Redhat PAM config and init script.
-
-commit e1a596186c81e65a34ce13076449712d3bf97eb4
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Aug 20 14:03:49 2021 +1000
-
- depend
-
-commit 5450606c8f7f7a0d70211cea78bc2dab74ab35d1
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Aug 20 13:59:43 2021 +1000
-
- update version numbers
-
-commit feee2384ab8d694c770b7750cfa76a512bdf8246
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Aug 20 03:22:55 2021 +0000
-
- upstream: openssh-8.7
-
- OpenBSD-Commit-ID: 8769dff0fd76ae3193d77bf83b439adee0f300cd
-
-commit 9a2ed62173cc551b2b5f479460bb015b19499de8
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Aug 20 10:48:13 2021 +1000
-
- Also check pid in pselect_notify_setup.
-
- Spotted by djm@.
-
-commit deaadcb93ca15d4f38aa38fb340156077792ce87
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Aug 20 08:39:33 2021 +1000
-
- Prefix pselect functions to clarify debug messages
-
-commit 10e45654cff221ca60fd35ee069df67208fcf415
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Aug 20 08:30:42 2021 +1000
-
- Fix race in pselect replacement code.
-
- On the second and subsequent calls to pselect the notify_pipe was not
- added to the select readset, opening up a race that om G. Christensen
- discovered on multiprocessor Solaris <=9 systems.
-
- Also reinitialize notify_pipe if the pid changes. This will prevent a
- parent and child from using the same FD, although this is not an issue
- in the current structure it might be in future.
-
-commit 464ba22f1e38d25402e5ec79a9b8d34a32df5a3f
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Aug 18 12:51:30 2021 +1000
-
- Check compiler for c99 declarations after code.
-
- The sntrup761 reference code contains c99-style declarations after code
- so don't try to build that if the compiler doesn't support it.
-
-commit 7d878679a4b155a359d32104ff473f789501748d
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Aug 17 15:12:04 2021 +1000
-
- Remove trailing backslash on regress-unit-binaries
-
-commit b71b2508f17c68c5d9dbbe537686d81cedb9a781
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Aug 17 07:59:27 2021 +1000
-
- Put stdint.h inside HAVE_STDINT_H.
-
- From Tom G. Christensen.
-
-commit 6a24567a29bd7b4ab64e1afad859ea845cbc6b8c
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Aug 16 14:13:02 2021 +1000
-
- Improve github test driver script.
-
- - use a trap to always output any failed regress logs (since the script
- sets -e, the existing log output is never invoked).
- - pass LTESTS and SKIP_LTESTS when re-running with sshd options (eg.
- UsePAM).
-
-commit b467cf13705f59ed348b620722ac098fe31879b7
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Aug 16 11:32:23 2021 +1000
-
- Remove deprecated ubuntu-16.04 test targets.
-
- Github has deprecated ubuntu-16.04 and it will be removed on 20
- September.
-
-commit 20e6eefcdf78394f05e453d456c1212ffaa6b6a4
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sun Aug 15 23:25:26 2021 +1000
-
- Skip agent ptrace test on hurd.
-
-commit 7c9115bbbf958fbf85259a061c1122e2d046aabf
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sun Aug 15 19:37:22 2021 +1000
-
- Add hurd test target.
-
-commit 7909a566f6c6a78fcd30708dc49f4e4f9bb80ce3
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sun Aug 15 12:45:10 2021 +1000
-
- Skip scp3 tests on all dfly58 and 60 configs.
-
-commit e65198e52cb03534e8c846d1bca74c310b1526de
-Author: Tim Rice <tim@multitalents.net>
-Date: Sat Aug 14 13:08:07 2021 -0700
-
- openbsd-compat/openbsd-compat.h: put bsd-signal.h before bsd-misc.h
- to get sigset_t from signal.h needed for the pselect replacement.
-
-commit e50635640f79920d9375e0155cb3f4adb870eee5
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Aug 13 13:21:00 2021 +1000
-
- Test OpenSSH from OpenBSD head on 6.8 and 6.9.
-
-commit e0ba38861c490c680117b7fe0a1d61a181cd00e7
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Aug 13 13:00:14 2021 +1000
-
- Skip scp3 test on dragonfly 58 and 60.
-
- The tests hang, so skip until we figure them out.
-
-commit dcce2a2bcf007bf817a2fb0dce3db83fa9201e92
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Aug 12 23:59:25 2021 +0000
-
- upstream: mention that CASignatureAlgorithms accepts +/- similarly to
-
- the other algorithm list directives; ok jmc bz#3335
-
- OpenBSD-Commit-ID: 0d46b53995817052c78e2dce9dbd133963b073d9
-
-commit 090a82486e5d7a8f7f16613d67e66a673a40367f
-Author: schwarze@openbsd.org <schwarze@openbsd.org>
-Date: Thu Aug 12 09:59:00 2021 +0000
-
- upstream: In the editline(3) branch of the sftp(1) event loop,
-
- handle SIGINT rather than ignoring it, such that the user can use Ctrl-C to
- discard the currently edited command line and get a fresh prompt, just like
- in ftp(1), bc(1), and in shells.
-
- It is critical to not use ssl_signal() for this particular case
- because that function unconditionally sets SA_RESTART, but here we
- need the signal to interrupt the read(2) in the el_gets(3) event loop.
-
- OK dtucker@ deraadt@
-
- OpenBSD-Commit-ID: 8025115a773f52e9bb562eaab37ea2e021cc7299
-
-commit e1371e4f58404d6411d9f95eb774b444cea06a26
-Author: naddy@openbsd.org <naddy@openbsd.org>
-Date: Wed Aug 11 14:07:54 2021 +0000
-
- upstream: scp: tweak man page and error message for -3 by default
-
- Now that the -3 option is enabled by default, flip the documentation
- and error message logic from "requires -3" to "blocked by -R".
-
- ok djm@
-
- OpenBSD-Commit-ID: a872592118444fb3acda5267b2a8c3d4c4252020
-
-commit 49f46f6d77328a3d10a758522b670a3e8c2235e7
-Author: naddy@openbsd.org <naddy@openbsd.org>
-Date: Wed Aug 11 14:05:19 2021 +0000
-
- upstream: scp: do not spawn ssh with two -s flags for
-
- remote-to-remote copies
-
- Do not add another "-s" to the argument vector every time an SFTP
- connection is initiated. Instead, introduce a subsystem flag to
- do_cmd() and add "-s" when the flag is set.
-
- ok djm@
-
- OpenBSD-Commit-ID: 25df69759f323661d31b2e1e790faa22e27966c1
-
-commit 2a2cd00783e1da45ee730b7f453408af1358ef5b
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Aug 11 08:55:04 2021 +0000
-
- upstream: test -Oprint-pubkey
-
- OpenBSD-Regress-ID: 3d51afb6d1f287975fb6fddd7a2c00a3bc5094e0
-
-commit b9f4635ea5bc33ed5ebbacf332d79bae463b0f54
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Aug 11 08:54:17 2021 +0000
-
- upstream: when verifying sshsig signatures, support an option
-
- (-Oprint-pubkey) to dump the full public key to stdout; based on patch from
- Fabian Stelzer; ok markus@
-
- OpenBSD-Commit-ID: 0598000e5b9adfb45d42afa76ff80daaa12fc3e2
-
-commit 750c1a45ba4e8ad63793d49418a0780e77947b9b
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Aug 11 05:21:32 2021 +0000
-
- upstream: oops, missed one more %p
-
- OpenBSD-Commit-ID: e7e62818d1564cc5cd9086eaf7a51cbd1a9701eb
-
-commit b5aa27b69ab2e1c13ac2b5ad3f8f7d389bad7489
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Aug 11 05:20:17 2021 +0000
-
- upstream: remove a bunch of %p in format strings; leftovers of
-
- debuggings past. prompted by Michael Forney, ok dtucker@
-
- OpenBSD-Commit-ID: 4853a0d6c9cecaba9ecfcc19066e52d3a8dcb2ac
-
-commit 419aa01123db5ff5dbc68b2376ef23b222862338
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Aug 11 09:21:09 2021 +1000
-
- Add includes.h to compat tests.
-
- On platforms where closefrom returns void (eg glibc>=2.34) the prototype
- for closefrom in its compat tests would cause compile errors. Remove
- this and have the tests pull in the compat headers in the same way as
- the main code. bz#3336.
-
-commit 931f592f26239154eea3eb35a086585897b1a185
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Aug 10 03:35:45 2021 +0000
-
- upstream: adapt to scp -M flag change; make scp3.sh test SFTP mode too
-
- OpenBSD-Regress-ID: 43fea26704a0f0b962b53c1fabcb68179638f9c0
-
-commit 391ca67fb978252c48d20c910553f803f988bd37
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Aug 10 03:33:34 2021 +0000
-
- upstream: Prepare for a future where scp(1) uses the SFTP protocol by
-
- default. Replace recently added -M option to select the protocol with -O
- (olde) and -s (SFTP) flags, and label the -s flag with a clear warning that
- it will be removed in the near future (so no, don't use it in scripts!).
-
- prompted by/feedback from deraadt@
-
- OpenBSD-Commit-ID: 92ad72cc6f0023c9be9e316d8b30eb6d8d749cfc
-
-commit bfdd4b722f124a4fa9173d20dd64dd0fc69856be
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Aug 9 23:56:36 2021 +0000
-
- upstream: make scp -3 the default for remote-to-remote copies. It
-
- provides a much better and more intuitive user experience and doesn't require
- exposing credentials to the source host.
-
- thanks naddy@ for catching the missing argument in usage()
-
- "Yes please!" - markus@
- "makes a lot of sense" - deraadt@
- "the right thing to do" - dtucker@
-
- OpenBSD-Commit-ID: d0d2af5f0965c5192ba5b2fa461c9f9b130e5dd9
-
-commit 2f7a3b51cef689ad9e93d0c6c17db5a194eb5555
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Aug 9 23:49:31 2021 +0000
-
- upstream: make scp in SFTP mode try to use relative paths as much
-
- as possible. Previosuly, it would try to make relative and ~/-rooted paths
- absolute before requesting transfers.
-
- prompted by and much discussion deraadt@
- ok markus@
-
- OpenBSD-Commit-ID: 46639d382ea99546a4914b545fa7b00fa1be5566
-
-commit 2ab864010e0a93c5dd95116fb5ceaf430e2fc23c
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Aug 9 23:47:44 2021 +0000
-
- upstream: SFTP protocol extension to allow the server to expand
-
- ~-prefixed paths, in particular ~user ones. Allows scp in sftp mode to accept
- these paths, like scp in rcp mode does.
-
- prompted by and much discussion deraadt@
- ok markus@
-
- OpenBSD-Commit-ID: 7d794def9e4de348e1e777f6030fc9bafdfff392
-
-commit 41b019ac067f1d1f7d99914d0ffee4d2a547c3d8
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Aug 9 23:44:32 2021 +0000
-
- upstream: when scp is in SFTP mode, try to deal better with ~
-
- prefixed paths. ~user paths aren't supported, but ~/ paths will be accepted
- and prefixed with the SFTP server starting directory (more to come)
-
- prompted by and discussed with deraadt@
- ok markus@
-
- OpenBSD-Commit-ID: 263a071f14555c045fd03132a8fb6cbd983df00d
-
-commit b4b3f3da6cdceb3fd168b5fab69d11fba73bd0ae
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Aug 9 07:21:01 2021 +0000
-
- upstream: on fatal errors, make scp wait for ssh connection before
-
- exiting avoids LogLevel=verbose (or greater) messages from ssh appearing
- after scp has returned exited and control has returned to the shell; ok
- markus@
-
- (this was originally committed as r1.223 along with unrelated stuff that
- I rolled back in r1.224)
-
- OpenBSD-Commit-ID: 1261fd667ad918484889ed3d7aec074f3956a74b
-
-commit 2ae7771749e0b4cecb107f9d4860bec16c3f4245
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Aug 9 07:19:12 2021 +0000
-
- upstream: rever r1.223 - I accidentally committed unrelated changes
-
- OpenBSD-Commit-ID: fb73f3865b2647a27dd94db73d6589506a9625f9
-
-commit 986abe94d481a1e82a01747360bd767b96b41eda
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Aug 9 07:16:09 2021 +0000
-
- upstream: show only the final path component in the progress meter;
-
- more useful with long paths (that may truncate) and better matches
- traditional scp behaviour; spotted by naddy@ ok deraadt@
-
- OpenBSD-Commit-ID: 26b544d0074f03ebb8a3ebce42317d8d7ee291a3
-
-commit 2b67932bb3176dee4fd447af4368789e04a82b93
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Aug 9 07:13:54 2021 +0000
-
- upstream: on fatal errors, make scp wait for ssh connection before
-
- exiting avoids LogLevel=verbose (or greater) messages from ssh appearing
- after scp has returned exited and control has returned to the shell; ok
- markus@
-
- OpenBSD-Commit-ID: ef9dab5ef5ae54a6a4c3b15d380568e94263456c
-
-commit 724eb900ace30661d45db2ba01d0f924d95ecccb
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sun Aug 8 08:49:09 2021 +0000
-
- upstream: xstrdup environment variable used by ForwardAgent. bz#3328
-
- from goetze at dovetail.com, ok djm@ deraadt@
-
- OpenBSD-Commit-ID: 760320dac1c3b26904284ba417a7d63fccc5e742
-
-commit 86b4cb3a884846b358305aad17a6ef53045fa41f
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sun Aug 8 08:27:28 2021 +0000
-
- upstream: Although it's POSIX, not all shells used in Portable support
-
- the implicit 'in "$@"' after 'for i'.
-
- OpenBSD-Regress-ID: 3c9aec6bca4868f85d2742b6ba5223fce110bdbc
-
-commit f2ccf6c9f395923695f22345e626dfd691227aaf
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sun Aug 8 17:39:56 2021 +1000
-
- Move portable specific settings down.
-
- This brings the top hunk of the file back in sync with OpenBSD
- so patches to the CVS Id should apply instead of always being
- rejected.
-
-commit 71b0eb997e220b0fc9331635af409ad84979f2af
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sun Aug 8 07:27:52 2021 +0000
-
- upstream: Move setting of USER further down the startup In portable
-
- we have to change this and having it in the same hunk as the CVS Id string
- means applying changes fails every. single. time.
-
- OpenBSD-Regress-ID: 87cd603eb6db58c9b430bf90adacb7f90864429b
-
-commit f0aca2706c710a0da1a4be705f825a807cd15400
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sun Aug 8 06:38:33 2021 +0000
-
- upstream: Drop -q in ssh-log-wrapper.sh to preserve logs.
-
- scp and sftp like to add -q to the command line passed to ssh which
- overrides the LogLevel we set in the config files and suppresses output
- to the debug logs so drop any "-q" from the invoked ssh. In the one
- case where we actually want to use -q in the banner test, call the ssh
- binary directly bypassing the logging wrapper.
-
- OpenBSD-Regress-ID: e2c97d3c964bda33a751374c56f65cdb29755b75
-
-commit cf27810a649c5cfae60f8ce66eeb25caa53b13bc
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Aug 7 01:57:08 2021 +0000
-
- upstream: Fix prototype mismatch for do_cmd. ok djm@
-
- OpenBSD-Commit-ID: 1c1598bb5237a7ae0be99152f185e0071163714d
-
-commit 85de69f64665245786e28c81ab01fe18b0e2a149
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Aug 7 01:55:01 2021 +0000
-
- upstream: sftp-client.c needs poll.h
-
- remove unused variable
-
- OpenBSD-Commit-ID: 233ac6c012cd23af62f237167a661db391055a16
-
-commit 397c4d72e50023af5fe3aee5cc2ad407a6eb1073
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Aug 7 11:30:57 2021 +1000
-
- Include poll.h and friends for struct pollfd.
-
-commit a9e2c533195f28627f205682482d9da384c4c52e
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Aug 7 00:14:17 2021 +0000
-
- upstream: do_upload() used a near-identical structure for
-
- tracking expected status replies from the server to what do_download() was
- using.
-
- Refactor it to use the same structure and factor out some common
- code into helper functions.
-
- OpenBSD-Commit-ID: 0c167df8ab6df4a5292c32421922b0cf379e9054
-
-commit 7b1cbcb7599d9f6a3bbad79d412604aa1203b5ee
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Aug 7 00:12:09 2021 +0000
-
- upstream: make scp(1) in SFTP mode follow symlinks like
-
- traditional scp(1) ok markus@
-
- OpenBSD-Commit-ID: 97255e55be37e8e26605e4ba1e69f9781765d231
-
-commit 133b44e500422df68c9c25c3b6de35c0263132f1
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Aug 7 00:10:49 2021 +0000
-
- upstream: fix incorrect directory permissions on scp -3
-
- transfers; ok markus@
-
- OpenBSD-Commit-ID: 64b2abaa5635a2be65ee2e77688ad9bcebf576c2
-
-commit 98b59244ca10e62ff67a420856770cb700164f59
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Aug 7 00:09:57 2021 +0000
-
- upstream: a bit more debugging of file attributes being
-
- sent/received over the wire
-
- OpenBSD-Commit-ID: f68c4e207b08ef95200a8b2de499d422808e089b
-
-commit c677e65365d6f460c084e41e0c4807bb8a9cf601
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Aug 7 00:08:52 2021 +0000
-
- upstream: make scp(1) in SFTP mode output better match original
-
- scp(1) by suppressing "Retrieving [path]" lines that were emitted to support
- the interactive sftp(1) client. ok markus@
-
- OpenBSD-Commit-ID: 06be293df5f156a18f366079be2f33fa68001acc
-
-commit 48cd39b7a4e5e7c25101c6d1179f98fe544835cd
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Aug 7 00:07:18 2021 +0000
-
- upstream: factor out a structure duplicated between downloading
+ upstream: EXT_INFO negotiation of hostbound pubkey auth
- and crossloading; ok markus@
+ the EXT_INFO packet gets a new publickey-hostbound@openssh.com to
+ advertise the hostbound public key method.
- OpenBSD-Commit-ID: 96eede24d520569232086a129febe342e4765d39
-
-commit 318c06bb04ee21a0cfa6b6022a201eacaa53f388
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Aug 7 00:06:30 2021 +0000
-
- upstream: use sftp_client crossloading to implement scp -3
+ Client side support to parse this feature flag and set the kex->flags
+ indicator if the expected version is offered (currently "0").
- feedback/ok markus@
+ ok markus@
- OpenBSD-Commit-ID: 7db4c0086cfc12afc9cfb71d4c2fd3c7e9416ee9
+ OpenBSD-Commit-ID: 4cdb2ca5017ec1ed7a9d33bda95c1d6a97b583b0
-commit de7115b373ba0be3861c65de9b606a3e0e9d29a3
+commit 94ae0c6f0e35903b695e033bf4beacea1d376bb1
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Aug 7 00:02:41 2021 +0000
+Date: Sun Dec 19 22:12:54 2021 +0000
- upstream: support for "cross"-loading files/directories, i.e.
+ upstream: client side of host-bound pubkey authentication
- downloading from one SFTP server while simultaneously uploading to another.
+ Add kex->flags member to enable the publickey-hostbound-v00@openssh.com
+ authentication method.
- feedback & ok markus@
+ Use the new hostbound method in client if the kex->flags flag was set,
+ and include the inital KEX hostkey in the userauth request.
- OpenBSD-Commit-ID: 3982878e29d8df0fa4ddc502f5ff6126ac714235
-
-commit a50bd0367ff2063bbc70a387740a2aa6914de094
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Aug 7 00:01:29 2021 +0000
-
- upstream: factor our SSH2_FXP_OPEN calls into their own function;
+ Note: nothing in kex.c actually sets the new flag yet
- "looks fine" markus@
+ ok markus@
- OpenBSD-Commit-ID: d3dea2153f08855c6d9dacc01973248944adeffb
+ OpenBSD-Commit-ID: 5a6fce8c6c8a77a80ee1526dc467d91036a5910d
-commit e3c0ba05873cf3d3f7d19d595667a251026b2d84
+commit 288fd0218dbfdcb05d9fbd1885904bed9b6d42e6
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Aug 7 00:00:33 2021 +0000
+Date: Sun Dec 19 22:12:30 2021 +0000
- upstream: prepare for scp -3 implemented via sftp
+ upstream: sshd side of hostbound public key auth
- OpenBSD-Commit-ID: 194aac0dd87cb175334b71c2a30623a5ad55bb44
-
-commit 395d8fbdb094497211e1461cf0e2f80af5617e0a
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Aug 6 09:00:18 2021 +0000
-
- upstream: Make diff invocation more portable.
+ This is identical to the standard "publickey" method, but it also includes
+ the initial server hostkey in the message signed by the client.
- POSIX does not require diff to have -N, so compare in both directions
- with just -r, which should catch missing files in either directory.
+ feedback / ok markus@
- OpenBSD-Regress-ID: 0e2ec8594556a6f369ed5a0a90c6806419b845f7
+ OpenBSD-Commit-ID: 7ea01bb7238a560c1bfb426fda0c10a8aac07862
-commit d247a73ce27b460138599648d9c637c6f2b77605
+commit dbb339f015c33d63484261d140c84ad875a9e548
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Aug 4 21:28:00 2021 +0000
-
- upstream: regression test for scp -3
-
- OpenBSD-Regress-ID: b44375d125c827754a1f722ec6b6b75b634de05d
-
-commit 35c8e41a6f6d8ad76f8d1cd81ac2ea23d0d993b2
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Aug 6 05:04:42 2021 +0000
+Date: Sun Dec 19 22:12:07 2021 +0000
- upstream: Document "ProxyJump none". bz#3334.
+ upstream: prepare for multiple names for authmethods
- OpenBSD-Commit-ID: f78cc6f55731f2cd35c3a41d5352ac1ee419eba7
-
-commit 911ec6411821bda535d09778df7503b92f0eafab
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Aug 4 01:34:55 2021 +0000
-
- upstream: Allow for different (but POSIX compliant) behaviour of
+ allow authentication methods to have one additional name beyond their
+ primary name.
- basename(3) and prevent a use-after-free in that case in the new sftp-compat
- code.
+ allow lookup by this synonym
- POSIX allows basename(3) to either return a pointer to static storage
- or modify the passed string and return a pointer to that. OpenBSD does
- the former and works as is, but on other platforms "filename" points
- into "tmp" which was just freed. This makes the freeing of tmp
- consistent with the other variable in the loop.
+ Use primary name for authentication decisions, e.g. for
+ PermitRootLogin=publickey
- Pinpointed by the -portable Valgrind regress test. ok djm@ deraadt@
+ Pass actual invoked name to the authmethods, so they can tell whether they
+ were requested via the their primary name or synonym.
- OpenBSD-Commit-ID: 750f3c19bd4440e4210e30dd5d7367386e833374
-
-commit 6df1fecb5d3e51f3a8027a74885c3a44f6cbfcbd
-Author: Damien Miller <djm@mindrot.org>
-Date: Wed Aug 4 11:05:11 2021 +1000
-
- use openbsd-compat glob.h is required
-
-commit 9ebd1828881dfc9014a344587934a5ce7db6fa1b
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Aug 3 21:03:23 2021 +1000
-
- Missing space between macro arg and punctuation.
+ ok markus@
- From jmc@
-
-commit 0fd3f62eddc7cf54dcc9053be6f58998f3eb926a
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Aug 3 21:02:33 2021 +1000
-
- Avoid lines >80 chars. From jmc@
+ OpenBSD-Commit-ID: 9e613fcb44b8168823195602ed3d09ffd7994559
-commit af5d8094d8b755e1daaf2e20ff1dc252800b4c9b
+commit 39f00dcf44915f20684160f0a88d3ef8a3278351
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Aug 3 01:05:24 2021 +0000
+Date: Sun Dec 19 22:11:39 2021 +0000
- upstream: regression tests for scp SFTP protocol support; mostly by
-
- Jakub Jelen in GHPR#194 ok markus
+ upstream: ssh-agent side of destination constraints
- OpenBSD-Regress-ID: 36f1458525bcb111741ec8547eaf58b13cddc715
-
-commit e4673b7f67ae7740131a4ecea29a846593049a91
-Author: anton@openbsd.org <anton@openbsd.org>
-Date: Thu Jul 29 15:34:09 2021 +0000
-
- upstream: Treat doas with arguments as a valid SUDO variable.
+ Gives ssh-agent the ability to parse restrict-destination-v00@openssh.com
+ constraints and to apply them to keys.
- Allows one to specify SUDO="doas -n" which I do while running make regress.
+ Check constraints against the hostkeys recorded for a SocketEntry when
+ attempting a signature, adding, listing or deleting keys. Note that
+ the "delete all keys" request will remove constrained keys regardless of
+ location.
- ok dtucker@
+ feedback Jann Horn & markus@
+ ok markus@
- OpenBSD-Regress-ID: 4fe5814b5010dbf0885500d703bea06048d11005
+ OpenBSD-Commit-ID: 84a7fb81106c2d609a6ac17469436df16d196319
-commit 197e29f1cca190d767c4b2b63a662f9a9e5da0b3
+commit ce943912df812c573a33d00bf9e5435b7fcca3f7
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Aug 2 23:38:27 2021 +0000
+Date: Sun Dec 19 22:11:06 2021 +0000
- upstream: support for using the SFTP protocol for file transfers in
+ upstream: ssh-add side of destination constraints
- scp, via a new "-M sftp" option. Marked as experimental for now.
+ Have ssh-add accept a list of "destination constraints" that allow
+ restricting where keys may be used in conjunction with a ssh-agent/ssh
+ that supports session ID/hostkey binding.
- Some corner-cases exist, in particular there is no attempt to
- provide bug-compatibility with scp's weird "double shell" quoting
- rules.
+ Constraints are specified as either "[user@]host-pattern" or
+ "host-pattern>[user@]host-pattern".
- Mostly by Jakub Jelen in GHPR#194 with some tweaks by me. ok markus@
- Thanks jmc@ for improving the scp.1 bits.
+ The first form permits a key to be used to authenticate as the
+ specified user to the specified host.
- OpenBSD-Commit-ID: 6ce4c9157ff17b650ace571c9f7793d92874051c
-
-commit dd533c7ab79d61a7796b77b64bd81b098e0d7f9f
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Fri Jul 30 14:28:13 2021 +0000
-
- upstream: fix a formatting error and add some Xr; from debian at
+ The second form permits a key that has previously been permitted
+ for use at a host to be available via a forwarded agent to an
+ additional host.
- helgefjell de
+ For example, constraining a key with "user1@host_a" and
+ "host_a>host_b". Would permit authentication as "user1" at
+ "host_a", and allow the key to be available on an agent forwarded
+ to "host_a" only for authentication to "host_b". The key would not
+ be visible on agent forwarded to other hosts or usable for
+ authentication there.
- removed references to rlogin etc. as no longer relevant;
- suggested by djm
+ Internally, destination constraints use host keys to identify hosts.
+ The host patterns are used to obtain lists of host keys for that
+ destination that are communicated to the agent. The user/hostkeys are
+ encoded using a new restrict-destination-v00@openssh.com key
+ constraint.
- ok djm dtucker
+ host keys are looked up in the default client user/system known_hosts
+ files. It is possible to override this set on the command-line.
- OpenBSD-Commit-ID: 3c431c303068d3aec5bb18573a0bd5e0cd77c5ae
+ feedback Jann Horn & markus@
+ ok markus@
+
+ OpenBSD-Commit-ID: 6b52cd2b637f3d29ef543f0ce532a2bce6d86af5
-commit c7cd347a8823819411222c1e10a0d26747d0fd5c
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Fri Jul 30 14:25:01 2021 +0000
+commit 5e950d765727ee0b20fc3d2cbb0c790b21ac2425
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Dec 19 22:10:24 2021 +0000
- upstream: fix a formatting error and mark up known_hosts
-
- consistently; issues reported by debian at helgefjell de
+ upstream: ssh-add side of destination constraints
- ok djm dtucker
+ Have ssh-add accept a list of "destination constraints" that allow
+ restricting where keys may be used in conjunction with a ssh-agent/ssh
+ that supports session ID/hostkey binding.
- OpenBSD-Commit-ID: a1fd8d21dc77f507685443832df0c9700481b0ce
-
-commit 4455aec2e4fc90f64ae4fc47e78ebc9c18721738
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Wed Jul 28 05:57:42 2021 +0000
-
- upstream: no need to talk about version 2 with the -Q option, so
+ Constraints are specified as either "[user@]host-pattern" or
+ "host-pattern>[user@]host-pattern".
- rewrite the text to read better;
+ The first form permits a key to be used to authenticate as the
+ specified user to the specified host.
- issue reported by debian at helgefjell de
- ok djm dtucker
+ The second form permits a key that has previously been permitted
+ for use at a host to be available via a forwarded agent to an
+ additional host.
- OpenBSD-Commit-ID: 59fe2e8219c37906740ad062e0fdaea487dbe9cf
-
-commit bec429338e9b30d2c7668060e82608286a8a4777
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Tue Jul 27 14:28:46 2021 +0000
-
- upstream: word fix; reported by debian at helgefjell de
+ For example, constraining a key with "user1@host_a" and
+ "host_a>host_b". Would permit authentication as "user1" at
+ "host_a", and allow the key to be available on an agent forwarded
+ to "host_a" only for authentication to "host_b". The key would not
+ be visible on agent forwarded to other hosts or usable for
+ authentication there.
- OpenBSD-Commit-ID: 0c6fd22142422a25343c5bd1a618f31618f41ece
-
-commit efad4deb5a1f1cf79ebefd63c6625059060bfbe1
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Tue Jul 27 14:14:25 2021 +0000
-
- upstream: standardise the grammar in the options list; issue
+ Internally, destination constraints use host keys to identify hosts.
+ The host patterns are used to obtain lists of host keys for that
+ destination that are communicated to the agent. The user/hostkeys are
+ encoded using a new restrict-destination-v00@openssh.com key
+ constraint.
- reported by debian at helgefjell de
+ host keys are looked up in the default client user/system known_hosts
+ files. It is possible to override this set on the command-line.
- ok dtucker djm
+ feedback Jann Horn & markus@
+ ok markus@
- OpenBSD-Commit-ID: 7ac15575045d82f4b205a42cc7d5207fe4c3f8e6
-
-commit 1e11fb24066f3fc259ee30db3dbb2a3127e05956
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Aug 2 18:56:29 2021 +1000
-
- Check for RLIMIT_NOFILE before trying to use it.
+ OpenBSD-Commit-ID: ef47fa9ec0e3c2a82e30d37ef616e245df73163e
-commit 0f494236b49fb48c1ef33669f14822ca4f3ce2f4
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Jul 27 17:45:34 2021 +1000
+commit 4c1e3ce85e183a9d0c955c88589fed18e4d6a058
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Dec 19 22:09:23 2021 +0000
- lastenv is only used in setenv.
+ upstream: ssh-agent side of binding
- Prevents an unused variable warning on platforms that have setenv but
- not unsetenv.
-
-commit a1f78e08bdb3eaa88603ba3c6e01de7c8671e28a
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Jul 26 12:45:30 2021 +1000
-
- Move SUDO to "make test" command line.
+ record session ID/hostkey/forwarding status for each active socket.
- Environment variables don't get passed by vmrun, so move to command
- line.
-
-commit 02e624273b9c78a49a01239159b8c09b8409b1a0
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sun Jul 25 23:26:36 2021 +1000
-
- Set SUDO for tests and cleanup.
-
-commit 460ae5d93051bab70239ad823dd784822d58baad
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sun Jul 25 22:37:55 2021 +1000
-
- Pass OPENSSL=no to make tests too.
-
-commit b398f499c68d74ebe3298b73757cf3f36e14e0cb
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sun Jul 25 12:27:37 2021 +0000
-
- upstream: Skip unit and makefile-based key conversion tests when
+ Attempt to parse data-to-be-signed at signature request time and extract
+ session ID from the blob if it is a pubkey userauth request.
- we're building with OPENSSL=no.
+ ok markus@
- OpenBSD-Regress-ID: 20455ed9a977c93f846059d1fcb48e29e2c8d732
+ OpenBSD-Commit-ID: a80fd41e292b18b67508362129e9fed549abd318
-commit 727ce36c8c5941bde99216d27109405907caae4f
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sun Jul 25 12:13:03 2021 +0000
+commit e9497ecf73f3c16667288bce48d4e3d7e746fea1
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Dec 19 22:08:48 2021 +0000
- upstream: Replace OPENSSL as the variable that points to the
+ upstream: ssh client side of binding
- openssl binary with OPENSSL_BIN. This will allow us to use the OPENSSL
- variable from mk.conf or the make(1) command line indicating if we're
- building with our without OpenSSL, and ultimately get the regress tests
- working in the OPENSSL=no configuration.
+ send session ID, hostkey, signature and a flag indicating whether the
+ agent connection is being forwarded to ssh agent each time a connection
+ is opened via a new "session-bind@openssh.com" agent extension.
- OpenBSD-Regress-ID: 2d788fade3264d7803e5b54cae8875963f688c4e
+ ok markus@
+
+ OpenBSD-Commit-ID: 2f154844fe13167d3ab063f830d7455fcaa99135
-commit 55e17101a9075f6a63af724261c5744809dcb95c
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Jul 24 02:57:28 2021 +0000
+commit b42c61d6840d16ef392ed0f365e8c000734669aa
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Dec 19 22:08:06 2021 +0000
- upstream: Skip RFC4716 format import and export tests when built
+ upstream: Record session ID, host key and sig at intital KEX
- without OpenSSL.
+ These will be used later for agent session ID / hostkey binding
- OpenBSD-Regress-ID: d2c2d5d38c1acc2b88cc99cfe00a2eb8bb39dfa4
+ ok markus@
+
+ OpenBSD-Commit-ID: a9af29e33772b18e3e867c6fa8ab35e1694a81fe
-commit f5ccb5895d39cd627ad9e7b2c671d2587616100d
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Jul 24 02:51:14 2021 +0000
+commit 26ca33d186473d58a32d812e19273ce078b6ffff
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Dec 7 22:06:45 2021 +0000
- upstream: Don't omit ssh-keygen -y from usage when built without
+ upstream: better error message for FIDO keys when we can't match
- OpenSSL. It is actually available, albeit only for ed25519 keys.
+ them to a token
- OpenBSD-Commit-ID: 7a254c33d0e6a55c30c6b016a8d298d3cb7a7674
+ OpenBSD-Commit-ID: 58255c2a1980088f4ed144db67d879ada2607650
-commit 819d57ac23469f1f03baa8feb38ddefbada90fdc
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Jul 24 02:08:13 2021 +0000
+commit adb0ea006d7668190f0c42aafe3a2864d352e34a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Dec 15 10:50:33 2021 +1100
- upstream: Exclude key conversion options from usage when built
-
- without OpenSSL since those are not available, similar to what we currently
- do with the moduli screening options. We can also use this to skip the
- conversion regression tests in this case.
+ Correct value for IPTOS_DSCP_LE.
- OpenBSD-Commit-ID: 3c82caa398cf99cd4518c23bba5a2fc66b16bafe
+ It needs to allow for the preceeding two ECN bits. From daisuke.higashi
+ at gmail.com via OpenSSH bz#3373, ok claudio@, job@, djm@.
-commit b6673b1d2ee90b4690ee84f634efe40225423c38
+commit 3dafd3fe220bd9046f11fcf5191a79ec8800819f
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Jul 24 13:02:51 2021 +1000
+Date: Fri Dec 10 11:57:30 2021 +1100
- Test OpenBSD upstream with and without OpenSSL.
+ Increase timeout for test step.
-commit 9d38074b5453c1abbdf888e80828c278d3b886ac
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Jul 24 01:54:23 2021 +0000
+commit 5aefb05cd5b843e975b191d6ebb7ddf8de35c112
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Dec 10 10:27:27 2021 +1100
- upstream: test for first-match-wins in authorized_keys environment=
-
- options
+ Update the list of tests that don't work on Minix.
- OpenBSD-Regress-ID: 1517c90276fe84b5dc5821c59f88877fcc34c0e8
+ While there, remove CC (configure will now find clang) and make the test
+ list easier to update via cut and paste.
-commit 2b76f1dd19787e784711ea297ad8fc938b4484fd
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jul 23 05:53:02 2021 +0000
+commit 1c09bb1b2e207d091cec299c49416c23d24a1b31
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Dec 10 10:12:57 2021 +1100
- upstream: Simplify keygen-convert by using $SSH_KEYTYPES directly.
+ Add minix host tuple.
- OpenBSD-Regress-ID: cdbe408ec3671ea9ee9b55651ee551370d2a4108
+ Define SETEUID_BREAKS_SETUID for it which should make privsep work.
-commit 7d64a9fb587ba9592f027f7a2264226c713d6579
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Jul 24 01:55:19 2021 +0000
+commit a2188579032cf080213a78255373263466cb90cc
+Author: jsg@openbsd.org <jsg@openbsd.org>
+Date: Sun Dec 5 12:28:27 2021 +0000
- upstream: don't leak environment= variable when it is not the first
+ upstream: fix unintended sizeof pointer in debug path ok markus@
- match
+ OpenBSD-Commit-ID: b9c0481ffc0cd801e0840e342e6a282a85aac93c
+
+commit da40355234068c82f1a36196f2d18dd2d81aaafd
+Author: naddy@openbsd.org <naddy@openbsd.org>
+Date: Sat Dec 4 00:05:39 2021 +0000
+
+ upstream: RSA/SHA-1 is not used by default anymore on the server
- OpenBSD-Commit-ID: 7fbdc3dfe0032deaf003fd937eeb4d434ee4efe0
+ OpenBSD-Commit-ID: 64abef6cfc3e53088225f6b8a1dcd86d52dc8353
-commit db2130e2340bf923e41c791aa9cd27b9e926042c
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Fri Jul 23 06:01:17 2021 +0000
+commit e9c71498a083a8b502aa831ea931ce294228eda0
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Dec 2 23:45:36 2021 +0000
- upstream: punctuation;
+ upstream: hash full host:port when asked to hash output, fixes hashes
- OpenBSD-Commit-ID: 64be152e378c45975073ab1c07e0db7eddd15806
+ for non- default ports. bz3367 ok dtucker@
+
+ OpenBSD-Commit-ID: 096021cc847da7318ac408742f2d0813ebe9aa73
-commit 03190d10980c6fc9124e988cb2df13101f266507
+commit b5601202145a03106012c22cb8980bcac2949f0b
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jul 23 05:56:47 2021 +0000
+Date: Thu Dec 2 23:23:13 2021 +0000
- upstream: mention in comment that read_passphrase(..., RP_ALLOW_STDIN)
+ upstream: improve the testing of credentials against inserted FIDO
- will try to use askpass first. bz3314
+ keys a little more: ask the token whether a particular key belongs to it in
+ cases where the token support on-token user- verification (e.g. biometrics)
+ rather than just assuming that it will accept it.
- convert a couple of debug() -> debug_f() while here
+ Will reduce spurious "Confirm user presence" notifications for key
+ handles that relate to FIDO keys that are not currently inserted in at
+ least some cases.
- OpenBSD-Commit-ID: c7e812aebc28fcc5db06d4710e0f73613dee545c
+ Motivated by bz3366; by Pedro Martelletto
+
+ OpenBSD-Commit-ID: ffac7f3215842397800e1ae2e20229671a55a63d
-commit 1653ece6832b2b304d46866b262d5f69880a9ec7
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jul 23 05:07:16 2021 +0000
+commit ca709e27c41c90f4565b17282c48dca7756e083c
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Dec 2 22:40:05 2021 +0000
- upstream: Test conversion of ed25519 and ecdsa keys too.
+ upstream: move check_sk_options() up so we can use it earlier
- OpenBSD-Regress-ID: 3676d2d00e58e0d6d37f2878f108cc2b83bbe4bb
+ OpenBSD-Commit-ID: 67fe98ba1c846d22035279782c4664c1865763b4
-commit 8b7af02dcf9d2b738787efd27da7ffda9859bed2
+commit b711bc01a7ec76bb6a285730990cbce9b8ca5773
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jul 23 04:56:21 2021 +0000
+Date: Thu Dec 2 22:35:05 2021 +0000
- upstream: Add test for exporting pubkey from a passphrase-protected
+ upstream: ssh-rsa is no longer in the default for
- private key.
+ PubkeyAcceptedAlgorithms.
- OpenBSD-Regress-ID: da99d93e7b235fbd5b5aaa01efc411225e6ba8ac
+ OpenBSD-Commit-ID: 34a9e1bc30966fdcc922934ae00f09f2596cd73c
-commit 441095d4a3e5048fe3c87a6c5db5bc3383d767fb
+commit dc91ceea33cd4a9f05be953e8d8062f732db5c8a
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jul 23 03:54:55 2021 +0000
+Date: Thu Dec 2 02:44:44 2021 +0000
- upstream: regression test for time-limited signature keys
+ upstream: don't put the tty into raw mode when SessionType=none, avoids
- OpenBSD-Regress-ID: 2a6f3bd900dbee0a3c96f1ff23e032c93ab392bc
+ ^c being unable to kill such a session. bz3360; ok dtucker@
+
+ OpenBSD-Commit-ID: 83960c433052303b643b4c380ae2f799ac896f65
-commit 9e1882ef6489a7dd16b6d7794af96629cae61a53
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jul 23 05:24:02 2021 +0000
+commit e6e7d2654a13ba10141da7b42ea683ea4eeb1f38
+Author: Damien Miller <djm@mindrot.org>
+Date: Mon Nov 29 14:11:03 2021 +1100
- upstream: note successful authentication method in final "Authenticated
-
- to ..." message and partial auth success messages (all at LogLevel=verbose)
- ok dtucker@
+ previous commit broke bcrypt_pbkdf()
- OpenBSD-Commit-ID: 06834b89ceb89f8f16c5321d368a66c08f441984
+ Accidentally reverted part of the conversion to use SHA512 from SUPERCOP
+ instead of OpenBSD-style libc SHA512.
-commit a917e973a1b90b40ff1e950df083364b48fc6c78
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jul 23 04:04:52 2021 +0000
+commit c0459588b8d00b73e506c6095958ecfe62a4a7ba
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Nov 29 14:03:19 2021 +1100
- upstream: Add a ForkAfterAuthentication ssh_config(5) counterpart
-
- to the ssh(1) -f flag. Last part of GHPR231 from Volker Diels-Grabsch. ok
- dtucker
-
- OpenBSD-Commit-ID: b18aeda12efdebe2093d55263c90fe4ea0bce0d3
+ Fix typo in Neils' name.
-commit e0c5088f1c96a145eb6ea1dee438010da78f9ef5
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jul 23 04:00:59 2021 +0000
+commit 158bf854e2a22cf09064305f4a4e442670562685
+Author: Damien Miller <djm@mindrot.org>
+Date: Mon Nov 29 12:30:22 2021 +1100
- upstream: Add a StdinNull directive to ssh_config(5) that allows
+ sync bcrypt-related files with OpenBSD
- the config file to do the same thing as -n does on the ssh(1) commandline.
- Patch from Volker Diels-Grabsch via GHPR231; ok dtucker
+ The main change is that Niels Provos kindly agreed to rescind the
+ BSD license advertising clause, shifting them to the 3-term BSD
+ license.
- OpenBSD-Commit-ID: 66ddf3f15c76796d4dcd22ff464aed1edd62468e
+ This was the last thing in OpenSSH that used the advertising clause.
-commit e3957e21ffdc119d6d04c0b1686f8e2fe052f5ea
+commit e8976d92a42883ff6b8991438f07df60c2c0d82d
+Author: Damien Miller <djm@mindrot.org>
+Date: Mon Nov 29 12:29:29 2021 +1100
+
+ depend
+
+commit 8249afeec013e557fe7491a72ca3285de03e25b1
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jul 23 03:57:20 2021 +0000
+Date: Sun Nov 28 07:21:26 2021 +0000
- upstream: make authorized_keys environment="..." directives
-
- first-match-wins and more strictly limit their maximum number; prompted by
- OOM reported by OSS-fuzz (35470).
+ upstream: sshsig: return "key not found" when searching empty files
- feedback and ok dtucker@
+ rather than "internal error"
- OpenBSD-Commit-ID: 01f63fc10dcd995e7aed9c378ad879161af83121
+ OpenBSD-Commit-ID: e2ccae554c78d7a7cd33fc5d217f35be7e2507ed
-commit d0bb1ce731762c55acb95817df4d5fab526c7ecd
+commit 9e3227d4dbb5ad9c9091b4c14982cab4bba87b4d
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jul 23 03:37:52 2021 +0000
+Date: Sun Nov 28 07:15:10 2021 +0000
- upstream: Let allowed signers files used by ssh-keygen(1)
+ upstream: ssh-keygen -Y match-principals doesn't accept any -O
- signatures support key lifetimes, and allow the verification mode to specify
- a signature time to check at. This is intended for use by git to support
- signing objects using ssh keys. ok dtucker@
+ options at present, so don't say otherwise in SYNOPSIS; spotted jmc@
- OpenBSD-Commit-ID: 3e2c67b7dcd94f0610194d1e8e4907829a40cf31
+ OpenBSD-Commit-ID: 9cc43a18f4091010741930b48b3db2f2e4f1d35c
-commit 44142068dc7ef783d135e91ff954e754d2ed432e
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jul 19 08:48:33 2021 +0000
+commit 56db1f4a4cf5039fc3b42e84c4b16291fdff32b1
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Nov 28 07:14:29 2021 +0000
- upstream: Use SUDO when setting up hostkey.
+ upstream: fix indenting in last commit
- OpenBSD-Regress-ID: 990cf4481cab8dad62e90818a9b4b36c533851a7
+ OpenBSD-Commit-ID: 8b9ba989815d0dec1fdf5427a4a4b58eb9cac4d2
-commit 6b67f3f1d1d187597e54a139cc7785c0acebd9a2
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jul 19 05:08:54 2021 +0000
+commit 50bea24a9a9bdebad327c76e700def3261f5694e
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Nov 28 07:10:18 2021 +0000
- upstream: Increase time margin for rekey tests. Should help
-
- reliability on very heavily loaded hosts.
+ upstream: missing initialisation for oerrno
- OpenBSD-Regress-ID: 4c28a0fce3ea89ebde441d7091464176e9730533
+ OpenBSD-Commit-ID: 05d646bba238080259bec821c831a6f0b48d2a95
-commit 7953e1bfce9e76bec41c1331a29bc6cff9d416b8
+commit 5a0f4619041d09cd29f3a08da41db5040372bdd1
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Jul 19 13:47:51 2021 +1000
+Date: Sun Nov 28 15:31:37 2021 +1100
- Add sshfp-connect.sh file missed in previous.
+ Correct ifdef to activate poll() only if needed.
-commit b75a80fa8369864916d4c93a50576155cad4df03
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jul 19 03:13:28 2021 +0000
+commit d4035c81a71237f690edd7eda32bef7d63fd9528
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Nov 27 07:23:35 2021 +0000
- upstream: Ensure that all returned SSHFP records for the specified host
-
- name and hostkey type match instead of only one. While there, simplify the
- code somewhat and add some debugging. Based on discussion in bz#3322, ok
- djm@.
+ upstream: whitespac e
- OpenBSD-Commit-ID: 0a6a0a476eb7f9dfe8fe2c05a1a395e3e9b22ee4
+ OpenBSD-Regress-ID: b9511d41568056bda489e13524390167889908f8
-commit 1cc1fd095393663cd72ddac927d82c6384c622ba
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jul 19 02:21:50 2021 +0000
+commit a443491e6782ef0f5a8bb87a5536c8ee4ff233a1
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Nov 27 07:20:58 2021 +0000
- upstream: Id sync only, -portable already has this.
+ upstream: regression test for match-principals. Mostly by Fabian
- Put dh_set_moduli_file call inside ifdef WITH_OPENSSL. Fixes
- build with OPENSSL=no.
+ Stelzer
- OpenBSD-Commit-ID: af54abbebfb12bcde6219a44d544e18204defb15
+ OpenBSD-Regress-ID: ced0bec89af90935103438986bbbc4ad1df9cfa7
-commit 33abbe2f4153f5ca5c874582f6a7cc91ae167485
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jul 19 02:46:34 2021 +0000
+commit 78230b3ec8cbabc1e7de68732dc5cbd4837c6675
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Nov 27 07:14:46 2021 +0000
- upstream: Add test for host key verification via SSHFP records. This
+ upstream: Add ssh-keygen -Y match-principals operation to perform
- requires some external setup to operate so is disabled by default (see
- comments in sshfp-connect.sh).
+ matching of principals names against an allowed signers file.
- OpenBSD-Regress-ID: c52c461bd1df3a803d17498917d156ef64512fd9
+ Requested by and mostly written by Fabian Stelzer, towards a TOFU
+ model for SSH signatures in git. Some tweaks by me.
+
+ "doesn't bother me" deraadt@
+
+ OpenBSD-Commit-ID: 8d1b71f5a4127bc5e10a880c8ea6053394465247
-commit f0cd000d8e3afeb0416dce1c711c3d7c28d89bdd
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jul 19 02:29:28 2021 +0000
+commit 15db86611baaafb24c40632784dabf82e3ddb1a7
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Nov 25 23:02:24 2021 +0000
- upstream: Add ed25519 key and test SSHFP export of it. Only test
+ upstream: debug("func: ...") -> debug_f("...")
- RSA SSHFP export if we have RSA functionality compiled in.
+ OpenBSD-Commit-ID: d58494dc05c985326a895adfbe16fbd5bcc54347
+
+commit b7ffbb17e37f59249c31f1ff59d6c5d80888f689
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Nov 19 18:53:46 2021 +1100
+
+ Allow for fd = -1 in compat ppoll overflow check.
- OpenBSD-Regress-ID: b4ff5181b8c9a5862e7f0ecdd96108622333a9af
+ Fixes tests on at least FreeBSD 6, possibly others.
-commit 0075511e27e5394faa28edca02bfbf13b9a6693e
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jul 19 00:16:26 2021 +0000
+commit 04b172da5b96a51b0d55c905b423ababff9f4e0b
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Nov 19 16:01:51 2021 +1100
- upstream: Group keygen tests together.
+ Don't auto-enable Capsicum sandbox on FreeBSD 9/10.
- OpenBSD-Regress-ID: 07e2d25c527bb44f03b7c329d893a1f2d6c5c40c
+ Since we changed from select() to ppoll() tests have been failing.
+ This seems to be because FreeBSD 10 (and presumably 9) do not allow
+ ppoll() in the privsep process and sshd will fail with "Not permitted in
+ capability mode". Setting CAP_EVENT on the FDs doesn't help, but weirdly,
+ poll() works without that. Those versions are EOL so this situation is
+ unlikely to change.
-commit 034828820c7e62652e7c48f9ee6b67fb7ba6fa26
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sun Jul 18 23:10:10 2021 +0000
+commit a823f39986e7b879f26412e64c15630e1cfa0dc5
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Nov 18 03:53:48 2021 +0000
- upstream: Add test for ssh-keygen printing of SSHFP records.
+ upstream: regression test for ssh-keygen -Y find-principals fix; from
- OpenBSD-Regress-ID: fde9566b56eeb980e149bbe157a884838507c46b
+ Fabian Stelzer ok djm markus
+
+ OpenBSD-Regress-ID: 34fe4088854c1a2eb4c0c51cc4676ba24096bac4
-commit 52c3b6985ef1d5dadb4c4fe212f8b3a78ca96812
+commit 199c4df66c0e39dd5c3333b162af274678c0501d
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Jul 17 00:38:11 2021 +0000
+Date: Thu Nov 18 21:32:11 2021 +0000
- upstream: wrap some long lines
+ upstream: less confusing debug message; bz#3365
- OpenBSD-Commit-ID: 4f5186b1466656762dae37d3e569438d900c350d
+ OpenBSD-Commit-ID: 836268d3642c2cdc84d39b98d65837f5241e4a50
-commit 43ec991a782791d0b3f42898cd789f99a07bfaa4
+commit 97f9b6e61316c97a32dad94b7a37daa9b5f6b836
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Jul 17 00:36:53 2021 +0000
+Date: Thu Nov 18 21:11:01 2021 +0000
- upstream: fix sftp on ControlPersist connections, broken by recent
+ upstream: avoid xmalloc(0) for PKCS#11 keyid for ECDSA keys (we
- SessionType change; spotted by sthen@
+ already did this for RSA keys). Avoids fatal errors for PKCS#11 libraries
+ that return empty keyid, e.g. Microchip ATECC608B "cryptoauthlib"; bz#3364
- OpenBSD-Commit-ID: 4c5ddc5698790ae6ff50d2a4f8f832f0eeeaa234
+ OpenBSD-Commit-ID: 054d4dc1d6a99a2e6f8eebc48207b534057c154d
-commit 073f45c236550f158c9a94003e4611c07dea5279
+commit c74aa0eb73bd1edf79947d92d9c618fc3424c4a6
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jul 16 09:00:23 2021 +0000
+Date: Thu Nov 18 03:50:41 2021 +0000
- upstream: Explicitly check for and start time-based rekeying in the
+ upstream: ssh-keygen -Y find-principals was verifying key validity
- client and server mainloops.
+ when using ca certs but not with simple key lifetimes within the allowed
+ signers file.
- Previously the rekey timeout could expire but rekeying would not start
- until a packet was sent or received. This could cause us to spin in
- select() on the rekey timeout if the connection was quiet.
+ Since it returns the first keys principal it finds this could
+ result in a principal with an expired key even though a valid
+ one is just below.
- ok markus@
+ patch from Fabian Stelzer; feedback/ok djm markus
- OpenBSD-Commit-ID: 4356cf50d7900f3df0a8f2117d9e07c91b9ff987
+ OpenBSD-Commit-ID: b108ed0a76b813226baf683ab468dc1cc79e0905
-commit ef7c4e52d5d840607f9ca3a302a4cbb81053eccf
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Wed Jul 14 06:46:38 2021 +0000
+commit d902d728dfd81622454260e23bc09d5e5a9a795e
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Nov 18 23:44:07 2021 +1100
- upstream: reorder SessionType; ok djm
-
- OpenBSD-Commit-ID: c7dd0b39e942b1caf4976a0b1cf0fed33d05418c
+ Correct calculation of tv_nsec in poll().
-commit 8aa2f9aeb56506dca996d68ab90ab9c0bebd7ec3
+commit 21dd5a9a3fb35e8299a1fbcf8d506f1f6b752b85
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Jul 14 11:26:50 2021 +1000
+Date: Thu Nov 18 23:11:37 2021 +1100
- Make whitespace consistent.
+ Add compat implementation of ppoll using pselect.
-commit 4f4297ee9b8a39f4dfd243a74c5f51f9e7a05723
+commit b544ce1ad4afb7ee2b09f714aa63efffc73fa93a
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Jul 14 11:26:12 2021 +1000
+Date: Thu Nov 18 23:05:34 2021 +1100
- Add ARM64 Linux self-hosted runner.
+ Put poll.h inside ifdef HAVE_POLL_H.
-commit eda8909d1b0a85b9c3804a04d03ec6738fd9dc7f
+commit 875408270c5a7dd69ed5449e5d85bd7120c88f70
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jul 13 23:48:36 2021 +0000
+Date: Thu Nov 18 03:31:44 2021 +0000
- upstream: add a SessionType directive to ssh_config, allowing the
-
- configuration file to offer equivalent control to the -N (no session) and -s
- (subsystem) command-line flags.
-
- Part of GHPR#231 by Volker Diels-Grabsch with some minor tweaks;
- feedback and ok dtucker@
+ upstream: check for POLLHUP wherever we check for POLLIN
- OpenBSD-Commit-ID: 726ee931dd4c5cc7f1d7a187b26f41257f9a2d12
+ OpenBSD-Commit-ID: 6aa6f3ec6b17c3bd9bfec672a917f003a76d93e5
-commit 7ae69f2628e338ba6e0eae7ee8a63bcf8fea7538
+commit 36b5e37030d35bbaa18ba56825b1af55971d18a0
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Jul 12 02:12:22 2021 +0000
-
- upstream: fix some broken tests; clean up output
-
- OpenBSD-Regress-ID: 1d5038edb511dc4ce1622344c1e724626a253566
-
-commit f5fc6a4c3404bbf65c21ca6361853b33d78aa87e
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Jul 12 18:00:05 2021 +1000
-
- Add configure-time detection for SSH_TIME_T_MAX.
-
- Should fix printing cert times exceeding INT_MAX (bz#3329) on platforms
- were time_t is a long long. The limit used is for the signed type, so if
- some system has a 32bit unsigned time_t then the lower limit will still
- be imposed and we would need to add some way to detect this. Anyone using
- an unsigned 64bit can let us know when it starts being a problem.
-
-commit fd2d06ae4442820429d634c0a8bae11c8e40c174
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jul 12 06:22:57 2021 +0000
+Date: Thu Nov 18 03:07:59 2021 +0000
- upstream: Make limit for time_t test unconditional in the
+ upstream: fd leak in sshd listen loop error path; from Gleb
- format_absolute_time fix for bz#3329 that allows printing of timestamps past
- INT_MAX. This was incorrectly included with the previous commit. Based on
- discussion with djm@.
+ Smirnoff
- OpenBSD-Commit-ID: 835936f6837c86504b07cabb596b613600cf0f6e
+ OpenBSD-Commit-ID: a7a2be27a690a74bf2381bc16cea38e265657412
-commit 6c29b387cd64a57b0ec8ae7d2c8d02789d88fcc3
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jul 12 06:08:57 2021 +0000
+commit b99498d0c93f1edd04857b318308a66b28316bd8
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Nov 18 03:07:20 2021 +0000
- upstream: Use existing format_absolute_time() function when
+ upstream: check for POLLHUP as well as POLLIN in sshd listen loop;
- printing cert validity instead of doing it inline. Part of bz#3329.
+ ok deraadt millert
- OpenBSD-Commit-ID: a13d4e3c4f59644c23745eb02a09b2a4e717c00c
+ OpenBSD-Commit-ID: a4f1244c5a9c2b08dac4f3b1dc22e9d1dc60c587
-commit 99981d5f8bfa383791afea03f6bce8454e96e323
+commit 1f3055d788e8cf80851eb1728b535d57eb0dba6a
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jul 9 09:55:56 2021 +0000
+Date: Thu Nov 18 03:06:03 2021 +0000
- upstream: silence redundant error message; reported by Fabian Stelzer
+ upstream: check for POLLHUP as well as POLLIN, handle transient IO
- OpenBSD-Commit-ID: 9349a703016579a60557dafd03af2fe1d44e6aa2
+ errors as well as half-close on the output side; ok deraadt millert
+
+ OpenBSD-Commit-ID: de5c5b9939a37476d256328cbb96305bdecf511e
-commit e86097813419b49d5bff5c4b51d1c3a5d4d2d804
-Author: John Ericson <John.Ericson@Obsidian.Systems>
-Date: Sat Dec 26 11:40:49 2020 -0500
+commit 9778a15fa6dbdac6a95bf15865c2688b4bd6944e
+Author: Damien Miller <djm@mindrot.org>
+Date: Thu Nov 18 10:16:55 2021 +1100
- Re-indent krb5 section after pkg-config addition.
+ adjust seccomp filter for select->poll conversion
+
+ Needed to add ppoll syscall but also to relax the fallback rlimit
+ sandbox. Linux poll() fails with EINVAL if npfds > RLIMIT_NOFILE,
+ so we have to allow a single fd in the rlimit.
-commit 32dd2daa56c294e40ff7efea482c9eac536d8cbb
-Author: John Ericson <John.Ericson@Obsidian.Systems>
-Date: Sat Dec 26 11:40:49 2020 -0500
+commit fcd8d895bbb849c64f0aed934e3303d37f696f5d
+Author: Damien Miller <djm@mindrot.org>
+Date: Thu Nov 18 10:16:44 2021 +1100
- Support finding Kerberos via pkg-config
-
- This makes cross compilation easier.
+ update depends
-commit def7a72234d7e4f684d72d33a0f7229f9eee0aa4
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jul 9 14:34:06 2021 +1000
+commit 76292787a1e93e668f10e36b4bf59ce0ae28e156
+Author: Damien Miller <djm@mindrot.org>
+Date: Thu Nov 18 09:26:20 2021 +1100
- Update comments about EGD to include prngd.
+ compat for timespecsub() and friends
-commit b5d23150b4e3368f4983fd169d432c07afeee45a
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jul 5 01:21:07 2021 +0000
+commit fd7e7de4ddb4399c7e929b44f2bbfc118eddfcf8
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Nov 17 21:06:39 2021 +0000
- upstream: Fix a couple of whitespace things. Portable already has
+ upstream: set num_listen_socks to 0 on close-all instead of -1,
- these so this removes two diffs between the two.
+ which interferes with the new poll()-based listen loop; spotted and debugged
+ by anton@+deraadt@
- OpenBSD-Commit-ID: 769f017ebafd8e741e337b3e9e89eb5ac73c9c56
+ OpenBSD-Commit-ID: f7ab8ab124f615a2e0c45fee14c38d2f2abbabbd
-commit 8f57be9f279b8e905f9883066aa633c7e67b31cf
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jul 5 01:16:46 2021 +0000
+commit fd9343579afac30a971f06643a669733d9acb407
+Author: deraadt@openbsd.org <deraadt@openbsd.org>
+Date: Sun Nov 14 18:47:43 2021 +0000
- upstream: Order includes as per style(9). Portable already has
-
- these so this removes a handful of diffs between the two.
+ upstream: use ppoll() instead of pselect() with djm
- OpenBSD-Commit-ID: 8bd7452d809b199c19bfc49511a798f414eb4a77
+ OpenBSD-Commit-ID: 980f87c9564d5d2ad55722b7a6f44f21284cd215
-commit b75624f8733b3ed9e240f86cac5d4a39dae11848
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jul 5 00:50:25 2021 +0000
+commit 092d29b232ef1a19609a5316ed7e4d896bb2e696
+Author: deraadt@openbsd.org <deraadt@openbsd.org>
+Date: Sun Nov 14 06:15:36 2021 +0000
- upstream: Remove comment referencing now-removed
-
- RhostsRSAAuthentication. ok djm@
+ upstream: match .events with .fd better
- OpenBSD-Commit-ID: 3d864bfbd99a1d4429a58e301688f3be464827a9
+ OpenBSD-Commit-ID: 77eef212ca0add905949532af390164489c5984b
-commit b67eb12f013c5441bb4f0893a97533582ad4eb13
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Jul 5 00:25:42 2021 +0000
+commit 8d642c9a90fa4ed5a3effd785fb3591e14de00cd
+Author: deraadt@openbsd.org <deraadt@openbsd.org>
+Date: Sun Nov 14 03:25:10 2021 +0000
- upstream: allow spaces to appear in usernames for local to remote,
-
- and scp -3 remote to remote copies. with & ok dtucker bz#1164
+ upstream: convert select() to poll() ok djm
- OpenBSD-Commit-ID: e9b550f3a85ffbb079b6720833da31317901d6dd
+ OpenBSD-Commit-ID: b53e4940ff10dd24f8d16e8db8ef1970015d7ead
-commit 8c4ef0943e574f614fc7c6c7e427fd81ee64ab87
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jul 2 07:20:44 2021 +0000
+commit 6582a31c388968f4073af2bd8621880735c3d42b
+Author: deraadt@openbsd.org <deraadt@openbsd.org>
+Date: Sat Nov 13 21:14:13 2021 +0000
- upstream: Remove obsolete comments about SSHv1 auth methods. ok
+ upstream: replace select() with ppoll(), including converting
- djm@
+ timeval's to timespec's to make things easier. back and forth and ok; djm
- OpenBSD-Commit-ID: 6060f70966f362d8eb4bec3da2f6c4712fbfb98f
+ OpenBSD-Commit-ID: 89d3b23c60875da919e7820f9de6213286ffbec9
-commit 88908c9b61bcb99f16e8d398fc41e2b3b4be2003
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Jul 3 23:00:19 2021 +1000
+commit 7c025c005550c86a40200a2bcdd355d09413d61a
+Author: deraadt@openbsd.org <deraadt@openbsd.org>
+Date: Sat Nov 13 17:26:13 2021 +0000
- Remove reference to ChallengeResponse.
+ upstream: It really looks like pledge "stdio dns" is possible
- challenge_response_authentication was removed from the struct, keeping
- kbd_interactive_authentication.
-
-commit 321874416d610ad2158ce6112f094a4862c2e37f
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Jul 3 20:38:09 2021 +1000
-
- Move signal.h up include order to match upstream.
+ earlier. Discussed with mestre
+
+ OpenBSD-Commit-ID: 610873de63a593e0ac7bbbcb7a0f2894d36f4c01
-commit 4fa83e2d0e32c2dd758653e0359984bbf1334f32
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Jul 3 20:36:06 2021 +1000
+commit 06acb04c20ee483fe4757bd12aec870cc4bb1076
+Author: deraadt@openbsd.org <deraadt@openbsd.org>
+Date: Fri Nov 12 05:23:49 2021 +0000
- Remove old OpenBSD version marker.
+ upstream: aggressively pre-fill the pollfd array with fd=-1
- Looks like an accidental leftover from a sync.
+ OpenBSD-Commit-ID: c2a525de8f83c1a04405bd79122c424140552a5b
-commit 9d5e31f55d5f3899b72645bac41a932d298ad73b
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Jul 3 20:34:19 2021 +1000
+commit 7eec76793dec06e8f06b6cf71f9473141c69d109
+Author: deraadt@openbsd.org <deraadt@openbsd.org>
+Date: Thu Nov 11 15:32:32 2021 +0000
- Remove duplicate error on error path.
+ upstream: Convert from select() to ppoll(). Along the way, I
- There's an extra error() call on the listen error path, it looks like
- its removal was missed during an upstream sync.
+ observed that the select() code was using exceptfds incorrectly.. ok millert
+
+ OpenBSD-Commit-ID: 548e05bfc31b2af02319eb3d051286d4128dec96
-commit 888c459925c7478ce22ff206c9ac1fb812a40caf
+commit e665ed2d0c24fe11d5470ce72fa1e187377d3fc4
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Jul 3 20:32:46 2021 +1000
+Date: Fri Nov 12 22:55:27 2021 +1100
- Remove some whitespace not in upstream.
+ Switch from LibreSSL 3.4.0 to 3.4.1.
- Reduces diff vs OpenBSD by a small amount.
+ The LibreSSL 3.4.0 release has an OPENBSD_BRANCH that points to
+ "master" and that branch no longer has the files LibreSSL expects
+ and thus it will no longer build, breaking the test.
-commit 4d2d4d47a18d93f3e0a91a241a6fdb545bbf7dc2
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Jul 3 19:27:43 2021 +1000
+commit 21b6b5a06c8c53c548d25e6074c5240e88e2ef34
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Nov 10 06:29:25 2021 +0000
- Replace remaining references to ChallengeResponse.
+ upstream: add the sntrup761x25519-sha512@openssh.com hybrid
- Portable had a few additional references to ChallengeResponse related to
- UsePAM, replaces these with equivalent keyboard-interactive ones.
+ ECDH/x25519 + Streamlined NTRU Prime post-quantum KEX to the default
+ KEXAlgorithms list (after the ECDH methods but before the prime-group DH
+ ones).
+
+ ok markus@
+
+ OpenBSD-Commit-ID: 22b77e27a04e497a10e22f138107579652854210
-commit 53237ac789183946dac6dcb8838bc3b6b9b43be1
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Jul 3 19:23:28 2021 +1000
+commit 239da797cbf07a640d7b1ea02d3f99ace3ef792d
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Nov 10 06:25:08 2021 +0000
- Sync remaining ChallengeResponse removal.
+ upstream: fix ssh-keysign for KEX algorithms that use SHA384/512
- These were omitted from commit 88868fd131.
+ exchange hashes; feedback/ok markus@
+
+ OpenBSD-Commit-ID: 09a8fda1c081f5de1e3128df64f28b7bdadee239
-commit 2c9e4b319f7e98744b188b0f58859d431def343b
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Jul 3 19:17:31 2021 +1000
+commit 6997a592ecb1013df0c6d7f8df3e6517827aef11
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Nov 8 21:32:49 2021 +0000
- Disable rocky84 to figure out why agent test fails
+ upstream: improve error message when trying to expand a ~user path
+
+ for a user that doesn't exist; better matches what the shell does
+
+ ok deraadt@
+
+ OpenBSD-Commit-ID: 1ddefa3c3a78b69ce13d1b8f67bc9f2cefd23ad6
-commit bfe19197a92b7916f64a121fbd3c179abf15e218
+commit 10b899a15c88eb40eb5f73cd0fa84ef0966f79c9
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jul 2 15:43:28 2021 +1000
+Date: Wed Nov 10 12:34:25 2021 +1100
- Remove now-unused SSHv1 enums.
+ Don't trust closefrom() on Linux.
- sRhostsRSAAuthentication and sRSAAuthentication are protocol 1 options
- and are no longer used.
+ glibc's closefrom implementation does not work in a chroot when the kernel
+ does not have close_range. It tries to read from /proc/self/fd and when
+ that fails dies with an assertion of sorts. Instead, call close_range
+ ourselves from our compat code and fall back if that fails. bz#3349,
+ with william.wilson at canonical.com and fweimer at redhat.com.
-commit c73b02d92d72458a5312bd098f32ce88868fd131
+commit eb1f63195a9a38b519536a5b398d9939261ec081
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jul 2 05:11:20 2021 +0000
+Date: Sat Nov 6 10:13:39 2021 +0000
- upstream: Remove references to ChallengeResponseAuthentication in
+ upstream: Plug a couple of minor mem leaks. From beldmit at
- favour of KbdInteractiveAuthentication. The former is what was in SSHv1, the
- latter is what is in SSHv2 (RFC4256) and they were treated as somewhat but
- not entirely equivalent. We retain the old name as deprecated alias so
- config files continue to work and a reference in the man page for people
- looking for it.
+ gmail.com via github PR#283, ok markus@
- Prompted by bz#3303 which pointed out the discrepancy between the two
- when used with Match. Man page help & ok jmc@, with & ok djm@
+ OpenBSD-Commit-ID: ec1fa7d305d46226861c3ca6fb9c9beb2ada2892
+
+commit e4f501bf1d3b53f1cc23d9521fd7c5163307b760
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Nov 5 03:10:58 2021 +0000
+
+ upstream: move cert_filter_principals() to earlier in the file for
- OpenBSD-Commit-ID: 2c1bff8e5c9852cfcdab1f3ea94dfef5a22f3b7e
+ reuse; no code change
+
+ OpenBSD-Commit-ID: 598fa9528b656b2f38bcc3cf5b6f3869a8c115cf
-commit f841fc9c8c7568a3b5d84a4cc0cefacb7dbc16b9
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jul 2 15:20:32 2021 +1000
+commit 59c60f96fee321c7f38f00372826d37f289534af
+Author: deraadt@openbsd.org <deraadt@openbsd.org>
+Date: Wed Nov 3 22:00:56 2021 +0000
- Fix ifdefs around get_random_bytes_prngd.
+ upstream: Many downstreams expect ssh to compile as non-C99...
- get_random_bytes_prngd() is used if either of PRNGD_PORT or PRNGD_SOCKET
- are defined, so adjust ifdef accordingly.
+ OpenBSD-Commit-ID: e6aa3e08bda68e5fb838fc8a49b1d2dfc38ee783
-commit 0767627cf66574484b9c0834500b42ea04fe528a
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Jul 2 14:30:23 2021 +1000
+commit 7a78fe63b0b28ef7231913dfefe9d08f9bc41c61
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Nov 6 21:07:03 2021 +1100
- wrap get_random_bytes_prngd() in ifdef
+ Skip getline() on HP-UX 10.x.
- avoid unused static function warning
+ HP-UX 10.x has a getline() implementation in libc that does not behave
+ as we expect so don't use it. With correction from Thorsten Glaser and
+ typo fix from Larkin Nickle.
-commit f93fdc4de158386efe1116bd44c5b3f4a7a82c25
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Jun 28 13:06:37 2021 +1000
+commit 343ae252ebb35c6ecae26b447bf1551a7666720e
+Author: Damien Miller <djm@mindrot.org>
+Date: Wed Nov 3 12:08:21 2021 +1100
- Add rocky84 test target.
+ basic SECURITY.md (refers people to the website)
-commit d443006c0ddfa7f6a5bd9c0ae92036f3d5f2fa3b
+commit ed45a0168638319e0a710633f6085b96b9cec656
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jun 25 06:30:22 2021 +0000
+Date: Tue Nov 2 22:57:27 2021 +0000
- upstream: fix decoding of X.509 subject name; from Leif Thuresson
+ upstream: crank SSH_SK_VERSION_MAJOR to match recent change in
- via bz3327 ok markus@
+ usr/bin/ssh
- OpenBSD-Commit-ID: 0ea2e28f39750dd388b7e317bc43dd997a217ae8
+ OpenBSD-Regress-ID: 113d181c7e3305e138db9b688cdb8b0a0019e552
-commit 2a5704ec142202d387fda2d6872fd4715ab81347
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jun 25 06:20:39 2021 +0000
+commit f3c34df860c4c1ebddacb973954e58167d9dbade
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Nov 2 22:56:40 2021 +0000
- upstream: Use better language to refer to the user. From l1ving
+ upstream: Better handle FIDO keys on tokens that provide user
- via github PR#250, ok jmc@
+ verification (UV) on the device itself, including biometric keys.
- OpenBSD-Commit-ID: 07ca3526626996613e128aeddf7748c93c4d6bbf
+ Query the token during key creation to determine whether it supports
+ on-token UV and, if so, clear the SSH_SK_USER_VERIFICATION_REQD flag
+ in the key so that ssh(1) doesn't automatically prompty for PIN later.
+
+ When making signatures with the key, query the token's capabilities
+ again and check whether the token is able (right now) to perform user-
+ verification without a PIN. If it is then the PIN prompt is bypassed
+ and user verification delegated to the token. If not (e.g. the token
+ is biometric capable, but no biometric are enrolled), then fall back
+ to user verification via the usual PIN prompt.
+
+ Work by Pedro Martelletto; ok myself and markus@
+
+ NB. cranks SSH_SK_VERSION_MAJOR
+
+ OpenBSD-Commit-ID: e318a8c258d9833a0b7eb0236cdb68b5143b2f27
-commit 4bdf7a04797a0ea1c431a9d54588417c29177d19
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jun 25 03:38:17 2021 +0000
+commit 0328a081f38c09d2d4d650e94461a47fb5eef536
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Oct 29 03:03:06 2021 +0000
- upstream: Replace SIGCHLD/notify_pipe kludge with pselect.
+ upstream: sshsig: add tests for signing key validity and
- Previously sshd's SIGCHLD handler would wake up select() by writing a
- byte to notify_pipe. We can remove this by blocking SIGCHLD, checking
- for child terminations then passing the original signal mask through
- to pselect. This ensures that the pselect will immediately wake up if
- a child terminates between wait()ing on them and the pselect.
+ find-principals
- In -portable, for platforms that do not have pselect the kludge is still
- there but is hidden behind a pselect interface.
+ - adds generic find-principals tests (this command had none before)
+ - tests certs with a timeboxed validity both with and without a
+ restriced lifetime for the CA
+ - test for a revoked CA cert
- Based on other changes for bz#2158, ok djm@
+ by Fabian Stelzer
- OpenBSD-Commit-ID: 202c85de0b3bdf1744fe53529a05404c5480d813
+ OpenBSD-Regress-ID: 9704b2c6df5b8ccfbdf2c06c5431f5f8cad280c9
-commit c9f7bba2e6f70b7ac1f5ea190d890cb5162ce127
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jun 25 15:08:18 2021 +1000
+commit ccd358e1e25e25c13f0825996283cbf7a1647a3b
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Oct 29 02:48:19 2021 +0000
- Move closefrom() to before first malloc.
+ upstream: avoid signedness warning; spotted in -portable
- When built against tcmalloc, tcmalloc allocates a descriptor for its
- internal use, so calling closefrom() afterward causes the descriptor
- number to be reused resulting in a corrupted connection. Moving the
- closefrom a little earlier should resolve this. From kircherlike at
- outlook.com via bz#3321, ok djm@
+ OpenBSD-Regress-ID: 4cacc126086487c0ea7f3d86b42dec458cf0d0c6
-commit 7ebfe4e439853b88997c9cfc2ff703408a1cca92
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jun 18 20:41:45 2021 +1000
+commit 2741f52beb11490d7033a25e56ed0496f0c78006
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Oct 29 03:20:46 2021 +0000
- Put second -lssh in link line for sftp-server.
+ upstream: ssh-keygen: make verify-time argument parsing optional
- When building --without-openssl the recent port-prngd.c change adds
- a dependency on atomicio, but since nothing else in sftp-server uses
- it, the linker may not find it. Add a second -lssh similar to other
- binaries.
+ From Fabian Stelzer
+
+ OpenBSD-Commit-ID: 1ff35e4c366a45a073663df90381be6a8ef4d370
-commit e409d7966785cfd9f5970e66a820685c42169717
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jun 18 18:34:08 2021 +1000
+commit a1217d363b88b32cfe54c4f02c6c1cf4bdefdd23
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Oct 29 13:48:34 2021 +1100
- Try EGD/PRNGD if random device fails.
-
- When built --without-openssl, try EGD/PRGGD (if configured) as a last
- resort before failing.
+ unbreak fuzz harness for recent changes
-commit e43a898043faa3a965dbaa1193cc60e0b479033d
+commit 68e522ed8183587c9367fa3842c5b75f64f3d12b
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jun 18 18:32:51 2021 +1000
+Date: Fri Oct 29 13:32:24 2021 +1100
- Split EGD/PRNGD interface into its own file.
-
- This will allow us to use it when building --without-openssl.
+ Use -Wbitwise-instead-of-logical if supported.
-commit acb2887a769a1b1912cfd7067f3ce04fad240260
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Jun 17 21:03:19 2021 +1000
+commit be28b23012aa3fa323be7ec84863cf238927c078
+Author: Damien Miller <djm@mindrot.org>
+Date: Thu Oct 28 16:24:53 2021 +1100
- Handle GIDs > 2^31 in getgrouplist.
+ use -Wmisleading-indentation cflag if available
- When compiled in 32bit mode, the getgrouplist implementation may fail
- for GIDs greater than LONG_MAX. Analysis and change from ralf.winkel
- at tui.com.
+ ok dtucker@
-commit 31fac20c941126281b527605b73bff30a8f02edd
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Thu Jun 10 09:46:28 2021 +0000
+commit 2e6f5f24dd2f9217f4ab8b737ed428d5d5278f91
+Author: Damien Miller <djm@mindrot.org>
+Date: Thu Oct 28 16:24:44 2021 +1100
- upstream: Use $SUDO when reading sshd's pidfile here too.
-
- OpenBSD-Regress-ID: 6bfb0d455d493f24839034a629c5306f84dbd409
+ depend
-commit a3a58acffc8cc527f8fc6729486d34e4c3d27643
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Thu Jun 10 09:43:51 2021 +0000
+commit a5ab4882348d26addc9830a44e053238dfa2cb58
+Author: Damien Miller <djm@mindrot.org>
+Date: Thu May 6 10:08:30 2021 +1000
- upstream: Use $SUDO when reading sshd's pidfile in case it was
+ remove built-in support for md5crypt()
- created with a very restrictive umask. This resyncs with -portable.
+ Users of MD5-hashed password should arrange for ./configure to link
+ against libxcrypt or similar. Though it would be better to avoid use
+ of MD5 password hashing entirely, it's arguably worse than DEScrypt.
- OpenBSD-Regress-ID: 07fd2af06df759d4f64b82c59094accca1076a5d
+ feedback and ok dtucker@
-commit 249ad4ae51cd3bc235e75a4846eccdf8b1416611
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Thu Jun 10 09:37:59 2021 +0000
+commit c5de1fffa6328b8246b87da28fa9df05813f76a3
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Oct 28 02:55:30 2021 +0000
- upstream: Set umask when creating hostkeys to prevent excessive
-
- permissions warning.
+ upstream: increment SSH_SK_VERSION_MAJOR to match last change
- OpenBSD-Regress-ID: 382841db0ee28dfef7f7bffbd511803e1b8ab0ef
+ OpenBSD-Regress-ID: 17873814d1cbda97f49c8528d7b5ac9cadf6ddc0
-commit 9d0892153c005cc65897e9372b01fa66fcbe2842
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Thu Jun 10 03:45:31 2021 +0000
+commit 0001d04e55802d5bd9d6dece1081a99aa4ba2828
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Oct 28 02:54:18 2021 +0000
- upstream: Add regress test for SIGHUP restart
+ upstream: When downloading resident keys from a FIDO token, pass
- while handling active and unauthenticated clients. Should catch anything
- similar to the pselect bug just fixed in sshd.c.
+ back the user ID that was used when the key was created and append it to the
+ filename the key is written to (if it is not the default).
- OpenBSD-Regress-ID: 3b3c19b5e75e43af1ebcb9586875b3ae3a4cac73
-
-commit 73f6f191f44440ca3049b9d3c8e5401d10b55097
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Thu Jun 10 03:14:14 2021 +0000
-
- upstream: Continue accept loop when pselect
+ Avoids keys being clobbered if the user created multiple
+ resident keys with the same application string but different
+ user IDs.
- returns -1, eg if it was interrupted by a signal. This should prevent
- the hang discovered by sthen@ wherein sshd receives a SIGHUP while it has
- an unauthenticated child and goes on to a blocking read on a notify_pipe.
- feedback deraadt@, ok djm@
+ feedback Pedro Martelletto; ok markus
- OpenBSD-Commit-ID: 0243c1c5544fca0974dae92cd4079543a3fceaa0
+ NB. increments SSH_SK_VERSION_MAJOR
+
+ OpenBSD-Commit-ID: dbd658b5950f583106d945641a634bc6562dd3a3
-commit c785c0ae134a8e8b5c82b2193f64c632a98159e4
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jun 8 22:30:27 2021 +0000
+commit d4bed5445646e605c383a4374fa962e23bf9e3a3
+Author: deraadt@openbsd.org <deraadt@openbsd.org>
+Date: Sun Oct 24 21:24:17 2021 +0000
- upstream: test that UserKnownHostsFile correctly accepts multiple
+ upstream: For open/openat, if the flags parameter does not contain
- arguments; would have caught readconf.c r1.356 regression
+ O_CREAT, the 3rd (variadic) mode_t parameter is irrelevant. Many developers
+ in the past have passed mode_t (0, 044, 0644, or such), which might lead
+ future people to copy this broken idiom, and perhaps even believe this
+ parameter has some meaning or implication or application. Delete them all.
+ This comes out of a conversation where tb@ noticed that a strange (but
+ intentional) pledge behaviour is to always knock-out high-bits from mode_t on
+ a number of system calls as a safety factor, and his bewilderment that this
+ appeared to be happening against valid modes (at least visually), but no
+ sorry, they are all irrelevant junk. They could all be 0xdeafbeef. ok
+ millert
- OpenBSD-Regress-ID: 71ca54e66c2a0211b04999263e56390b1f323a6a
+ OpenBSD-Commit-ID: 503d11633497115688c0c6952686524f01f53121
-commit 1a6f6b08e62c78906a3032e8d9a83e721c84574e
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jun 8 22:06:12 2021 +0000
+commit d575cf44895104e0fcb0629920fb645207218129
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Oct 22 23:27:41 2021 +1100
- upstream: fix regression in r1.356: for ssh_config options that
-
- accepted multiple string arguments, ssh was only recording the first.
- Reported by Lucas via bugs@
+ kitchensink test target now needs krb5.
+
+commit 4ae39cada214e955bcfd3448ff28f0ed18886706
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Oct 22 22:54:33 2021 +1100
+
+ Test both MIT KRB5 and Heimdal.
+
+commit 22b2681d88619e5247dc53c9f112058a7e248d48
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Oct 22 10:51:57 2021 +0000
+
+ upstream: Plug mem addrinfo mem leaks.
- OpenBSD-Commit-ID: 7cbf182f7449bf1cb7c5b4452667dc2b41170d6d
+ Prevent mem leaks in the (unlikely) event that getaddrinfo returns
+ no addresses. ALso, remove an unneeded NULL check in addr_ntop. From
+ khaleesicodes via github PR#281, ok deraadt@
+
+ OpenBSD-Commit-ID: e8a5afc686376637c355c5f7e122dc4b080b9c1a
-commit 78e30af3e2b2dd540a341cc827c6b98dd8b0a6de
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jun 8 07:40:12 2021 +0000
+commit 27c8c343b610263f83ac2328735feeb881c6c92f
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Oct 22 09:22:04 2021 +0000
- upstream: test argv_split() optional termination on comments
+ upstream: Remove unnecessary semicolons
- OpenBSD-Regress-ID: 9fd1c4a27a409897437c010cfd79c54b639a059c
+ ... in case statements. From khaleesicodes via github PR#280.
+
+ OpenBSD-Commit-ID: e1e89360b65775cff83e77ce040b342015caf4ed
-commit a023138957ea2becf1c7f93fcc42b0aaac6f2b03
+commit e7eb73b8d1fe1008d92433ea949491ce654bfaba
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Jun 8 07:05:27 2021 +0000
+Date: Fri Oct 22 09:19:34 2021 +0000
- upstream: Add testcases from bz#3319 for IPQoS and TunnelDevice
+ upstream: Fix typos in comments.
- being overridden on the command line.
+ From khaleesicodes via github PR#280.
- OpenBSD-Regress-ID: 801674d5d2d02abd58274a78cab2711f11de14a8
+ OpenBSD-Commit-ID: 26fdd83652c40f098bf7c685e8ebb9eb72cc45fc
-commit 660cea10b2cdc11f13ba99c89b1bbb368a4d9ff2
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jun 8 06:52:43 2021 +0000
+commit 052a9d8494175e24312daa6c132665e58c17fe6e
+Author: deraadt@openbsd.org <deraadt@openbsd.org>
+Date: Fri Oct 15 14:46:46 2021 +0000
- upstream: sprinkle some "# comment" at end of configuration lines
+ upstream: switch scp(1) back to sftp protocol.
- to test comment handling
+ openbsd 7.0 release shipped with the (hopefully last) scp that uses RCP
+ protocol for copying. Let's get back to testing the SFTP protocol.
- OpenBSD-Regress-ID: cb82fbf40bda5c257a9f742c63b1798e5a8fdda7
+ OpenBSD-Commit-ID: 9eaa35d95fd547b78b0a043b3f518e135f151f30
-commit acc9c32dcb6def6c7d3688bceb4c0e59bd26b411
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jun 8 06:51:47 2021 +0000
+commit a07664646bf6d293f5bbd45a5de54f3c36bb85da
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Oct 22 14:00:05 2021 +1100
- upstream: more descriptive failure message
-
- OpenBSD-Regress-ID: 5300f6faf1d9e99c0cd10827b51756c5510e3509
+ Source configs script so setup_ci can use settings
-commit ce04dd4eae23d1c9cf7c424a702f48ee78573bc1
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Jun 7 01:16:34 2021 +0000
+commit 34df52c201c6b47e5a46b50c215e4d98a8bf6587
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Oct 22 09:42:14 2021 +1100
- upstream: test AuthenticationMethods inside a Match block as well
-
- as in the main config section
-
- OpenBSD-Regress-ID: ebe0a686621b7cb8bb003ac520975279c28747f7
+ Install libedit and pam based on config flags.
-commit 9018bd821fca17e26e92f7a7e51d9b24cd62f2db
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Jun 7 00:00:50 2021 +0000
+commit 8c626cc563e8d21d844d06f9971a9ee01de6aa2a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Oct 21 16:53:39 2021 +1100
- upstream: prepare for stricter sshd_config parsing that will refuse
-
- a config that has {Allow,Deny}{Users,Groups} on a line with no subsequent
- arguments. Such lines are permitted but are nonsensical noops ATM
-
- OpenBSD-Regress-ID: ef65463fcbc0bd044e27f3fe400ea56eb4b8f650
+ Don't use 'here string", it's not POSIX.
-commit a10f929d1ce80640129fc5b6bc1acd9bf689169e
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jun 8 07:09:42 2021 +0000
+commit 086a4b5977472aefa3de918b88efad0faf83b2b1
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Oct 21 15:33:27 2021 +1100
- upstream: switch sshd_config parsing to argv_split()
-
- similar to the previous commit, this switches sshd_config parsing to
- the newer tokeniser. Config parsing will be a little stricter wrt
- quote correctness and directives appearing without arguments.
-
- feedback and ok markus@
-
- tested in snaps for the last five or so days - thanks Theo and those who
- caught bugs
-
- OpenBSD-Commit-ID: 9c4305631d20c2d194661504ce11e1f68b20d93e
+ Remove -Werror from compiler package to install.
-commit ea9e45c89a4822d74a9d97fef8480707d584da4d
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jun 8 07:07:15 2021 +0000
+commit 5a7a4687507d057f9b5e7497f3d3f82e64753c02
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Oct 21 15:00:53 2021 +1100
- upstream: Switch ssh_config parsing to use argv_split()
-
- This fixes a couple of problems with the previous tokeniser,
- strdelim()
-
- 1. strdelim() is permissive wrt accepting '=' characters. This is
- intended to allow it to tokenise "Option=value" but because it
- cannot keep state, it will incorrectly split "Opt=val=val2".
- 2. strdelim() has rudimentry handling of quoted strings, but it
- is incomplete and inconsistent. E.g. it doesn't handle escaped
- quotes inside a quoted string.
- 3. It has no support for stopping on a (unquoted) comment. Because
- of this readconf.c r1.343 added chopping of lines at '#', but
- this caused a regression because these characters may legitimately
- appear inside quoted strings.
-
- The new tokeniser is stricter is a number of cases, including #1 above
- but previously it was also possible for some directives to appear
- without arguments. AFAIK these were nonsensical in all cases, and the
- new tokeniser refuses to accept them.
-
- The new code handles quotes much better, permitting quoted space as
- well as escaped closing quotes. Finally, comment handling should be
- fixed - the tokeniser will terminate only on unquoted # characters.
-
- feedback & ok markus@
-
- tested in snaps for the last five or so days - thanks Theo and those who
- caught bugs
-
- OpenBSD-Commit-ID: dc72fd12af9d5398f4d9e159d671f9269c5b14d5
+ Build with -Werror on most recent gcc and clang.
-commit d786424986c04d1d375f231fda177c8408e05c3e
+commit 4d2cbdb525d673acf941d48a7044fcf03125611a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Oct 15 12:59:06 2021 +1100
+
+ Include string.h and stdio.h for strerror.
+
+commit fff13aaa262b7b3ec83ed21e29674cbf331780a7
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Oct 15 12:43:36 2021 +1100
+
+ Include error reason if trace disabling fails.
+
+commit d4b38144c02f3faa5271e5fb35df93507e06f1b4
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Oct 12 22:55:51 2021 +1100
+
+ Add tcmalloc test target.
+
+commit 002d65b0a30063c6e49bf8a53e709d8d5a0d45c1
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Jun 8 07:02:46 2021 +0000
+Date: Sat Oct 9 10:52:42 2021 +0000
- upstream: Check if IPQoS or TunnelDevice are already set before
+ upstream: Document that CASignatureAlgorithms, ExposeAuthInfo and
- overriding. Prevents values in config files from overriding values supplied
- on the command line. bz#3319, ok markus.
+ PubkeyAuthOptions can be used in a Match block. Patch from eehakkin via
+ github PR#277.
- OpenBSD-Commit-ID: f3b08b898c324debb9195e6865d8999406938f74
+ OpenBSD-Commit-ID: c0a63f5f52e918645967ac022b28392da4b866aa
-commit aae4b4d3585b9f944d7dbd3c9e5ba0006c55e457
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jun 8 06:54:40 2021 +0000
+commit 40bd3709dddaae3a1b6113748bec3faa6a607531
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Oct 7 15:55:49 2021 +1100
- upstream: Allow argv_split() to optionally terminate tokenisation
-
- when it encounters an unquoted comment.
-
- Add some additional utility function for working with argument
- vectors, since we'll be switching to using them to parse
- ssh/sshd_config shortly.
-
- ok markus@ as part of a larger diff; tested in snaps
-
- OpenBSD-Commit-ID: fd9c108cef2f713f24e3bc5848861d221bb3a1ac
+ Skip SK unit tests when built without security-key
-commit da9f9acaac5bab95dca642b48e0c8182b246ab69
+commit 482f73be10f10b93f818df19fcc8a912c0c371fc
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Jun 7 19:19:23 2021 +1000
+Date: Thu Oct 7 15:55:04 2021 +1100
- Save logs on failure for upstream test
+ Include relevant env vars on command line.
+
+ Makes it easier to reproduce a build by cut/pasting the configure line.
-commit 76883c60161e5f3808787085a27a8c37f8cc4e08
+commit ef5916b8acd9b1d2f39fad4951dae03b00dbe390
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Jun 7 14:36:32 2021 +1000
+Date: Thu Oct 7 14:28:02 2021 +1100
- Add obsdsnap-i386 upstream test target.
+ Only enable sk-* key types if ENABLE_SK is defined
-commit d45b9c63f947ec5ec314696e70281f6afddc0ac3
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Jun 7 03:38:38 2021 +0000
+commit 52d4232b493a9858fe616e28a8bbcc89afa2ad4d
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Oct 6 18:14:37 2021 +1100
- upstream: fix debug message when finding a private key to match a
-
- certificate being attempted for user authentication. Previously it would
- print the certificate's path, whereas it was supposed to be showing the
- private key's path. Patch from Alex Sherwin via GHPR247
+ Disable security key on minix3.
- OpenBSD-Commit-ID: d5af3be66d0f22c371dc1fe6195e774a18b2327b
+ The test doesn't work so disable.
-commit 530739d42f6102668aecd699be0ce59815c1eceb
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Jun 6 11:34:16 2021 +0000
+commit 7cd062c3a29669b8d7dc2a97e6575f4dcb7d35a2
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Oct 6 17:45:28 2021 +1100
- upstream: Match host certificates against host public keys, not private
-
- keys. Allows use of certificates with private keys held in a ssh-agent.
- Reported by Miles Zhou in bz3524; ok dtucker@
-
- OpenBSD-Commit-ID: 25f5bf70003126d19162862d9eb380bf34bac22a
+ Add USE_LIBC_SHA2 for (at least) NetBSD 9.
-commit 4265215d7300901fd7097061c7517688ade82f8e
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Jun 6 03:40:39 2021 +0000
+commit 639c440f6c3c2a8216a5eb9455ef13bf4204089c
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Oct 6 17:09:31 2021 +1100
- upstream: Client-side workaround for a bug in OpenSSH 7.4: this release
-
- allows RSA/SHA2 signatures for public key authentication but fails to
- advertise this correctly via SSH2_MSG_EXT_INFO. This causes clients of these
- server to incorrectly match PubkeyAcceptedAlgorithms and potentially refuse
- to offer valid keys.
+ Define OPENSSL_NO_SHA including OpenSSL from test.
- Reported by and based on patch from Gordon Messmer via bz3213, thanks
- also for additional analysis by Jakub Jelen. ok dtucker
+ We don't use SHA256 from OpenSSL in the sk-dummy module and the
+ definitions can conflict with system sha2.h (eg on NetBSD) so define
+ OPENSSL_NO_SHA so we don't attempt to redefine them.
+
+commit 8f4be526a338d06624f146fa26007bb9dd3a4f7b
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Oct 6 15:40:58 2021 +1100
+
+ Disable security key on NetBSD4 test.
- OpenBSD-Commit-ID: d6d0b7351d5d44c45f3daaa26efac65847a564f7
+ sk-dummy used for the security key test includes both sha2.h and OpenSSL
+ causing the definitions conflict so disable security key support on this
+ platform.
+
+commit 3b353ae58aa07a1cbbeb1da3ace21fc0dcccd66a
+Author: Damien Miller <djm@mindrot.org>
+Date: Wed Oct 6 15:07:01 2021 +1100
+
+ clean regress/misc/sk-dummy in cleandir target
-commit bda270d7fb8522d43c21a79a4b02a052d7c64de8
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Jun 6 03:17:02 2021 +0000
+commit 57680a2ab43518c5ccbd8242c40482106cde6ac1
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sat Oct 2 03:17:01 2021 +0000
- upstream: degrade gracefully if a sftp-server offers the
+ upstream: Dynamically allocate encoded HashKnownHosts and free as
- limits@openssh.com extension but fails when the client tries to invoke it.
- Reported by Hector Martin via bz3318
+ appropriate. Saves 1k of static storage and prevents snprintf "possible
+ truncation" warnings from newer compilers (although in this case it's false
+ positive since the actual sizes are limited by the output size of the SHA1).
+ ok djm@
- OpenBSD-Commit-ID: bd9d1839c41811616ede4da467e25746fcd9b967
+ OpenBSD-Commit-ID: e254ae723f7e3dce352c7d5abc4b6d87faf61bf4
-commit d345d5811afdc2d6923019b653cdd93c4cc95f76
+commit e3e62deb549fde215b777d95276c304f84bf00c6
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Jun 6 03:15:39 2021 +0000
+Date: Wed Oct 6 03:35:13 2021 +0000
- upstream: the limits@openssh.com extension was incorrectly marked
+ upstream: use libc SHA256 functions; make this work when compiled
- as an operation that writes to the filesystem, which made it unavailable in
- sftp-server read-only mode. Spotted by Hector Martin via bz3318
+ !WITH_OPENSSL
- OpenBSD-Commit-ID: f054465230787e37516c4b57098fc7975e00f067
+ OpenBSD-Regress-ID: fda0764c1097cd42f979ace29b07eb3481259890
-commit 2b71010d9b43d7b8c9ec1bf010beb00d98fa765a
-Author: naddy@openbsd.org <naddy@openbsd.org>
-Date: Sat Jun 5 13:47:00 2021 +0000
+commit 12937d867019469ebce83c2ff614cdc6688fc2d8
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Oct 1 05:20:20 2021 +0000
- upstream: PROTOCOL.certkeys: update reference from IETF draft to
-
- RFC
-
- Also fix some typos.
- ok djm@
+ upstream: Add test for ssh hashed known_hosts handling.
- OpenBSD-Commit-ID: 5e855b6c5a22b5b13f8ffa3897a868e40d349b44
+ OpenBSD-Regress-ID: bcef3b3cd5a1ad9899327b4b2183de2541aaf9cf
-commit aa99b2d9a3e45b943196914e8d8bf086646fdb54
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jun 4 23:41:29 2021 +1000
+commit 5a37cc118f464416d08cd0291a9b1611d8de9943
+Author: Damien Miller <djm@mindrot.org>
+Date: Wed Oct 6 13:16:21 2021 +1100
- Clear notify_pipe from readset if present.
+ fix broken OPENSSL_HAS_ECC test
- Prevents leaking an implementation detail to the caller.
+ spotted by dtucker
-commit 6de8dadf6b4d0627d35bca0667ca44b1d61c2c6b
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jun 4 23:24:25 2021 +1000
+commit 16a25414f303cd6790eb967aeb962040e32c9c7a
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Oct 1 22:40:06 2021 +1000
- space->tabs.
+ make sk-dummy.so work without libcrypto installed
-commit c8677065070ee34c05c7582a9c2f58d8642e552d
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jun 4 18:39:48 2021 +1000
+commit dee22129bbc61e25b1003adfa2bc584c5406ef2d
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Oct 1 16:35:49 2021 +1000
- Add pselect implementation for platforms without.
-
- This is basically the existing notify_pipe kludge from serverloop.c
- moved behind a pselect interface. It works by installing a signal
- handler that writes to a pipe that the select is watching, then calls
- the original handler.
+ make OPENSSL_HAS_ECC checks more thorough
- The select call in serverloop will become pselect soon, at which point the
- kludge will be removed from thereand will only exist in the compat layer.
- Original code by markus, help from djm.
+ ok dtucker
-commit 7cd7f302d3a072748299f362f9e241d81fcecd26
-Author: Vincent Brillault <vincent.brillault@cern.ch>
-Date: Sun May 24 09:15:06 2020 +0200
+commit 872595572b6c9a584ed754165e8b7c4c9e7e1d61
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Oct 1 16:35:05 2021 +1000
- auth_log: dont log partial successes as failures
+ fix FIDO key support for !OPENSSL_HAS_ECC case
- By design, 'partial' logins are successful logins, so initially with
- authenticated set to 1, for which another authentication is required. As
- a result, authenticated is always reset to 0 when partial is set to 1.
- However, even if authenticated is 0, those are not failed login
- attempts, similarly to attempts with authctxt->postponed set to 1.
+ ok dtucker
-commit e7606919180661edc7f698e6a1b4ef2cfb363ebf
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jun 4 06:19:07 2021 +0000
+commit 489741dc68366940d369ac670b210b4834a6c272
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Oct 1 14:51:37 2021 +1000
- upstream: The RB_GENERATE_STATIC(3) macro expands to a series of
-
- function definitions and not a statement, so there should be no semicolon
- following them. Patch from Michael Forney
-
- OpenBSD-Commit-ID: c975dd180580f0bdc0a4d5b7d41ab1f5e9b7bedd
+ enable security key support for --without-openssl
-commit c298c4da574ab92df2f051561aeb3e106b0ec954
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jun 4 05:59:18 2021 +0000
+commit c978565c8589acfe4ea37ab5099d39c84158c713
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Oct 1 13:27:50 2021 +1000
- upstream: rework authorized_keys example section, removing irrelevant
-
- stuff, de-wrapping the example lines and better aligning the examples with
- common usage and FAQs; ok jmc
-
- OpenBSD-Commit-ID: d59f1c9281f828148e2a2e49eb9629266803b75c
+ need stdlib.h for free(3)
-commit d9cb35bbec5f623589d7c58fc094817b33030f35
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jun 4 05:10:03 2021 +0000
+commit 76a398edfb51951b2d65d522d7b02c72304db300
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Thu Sep 30 05:26:26 2021 +0000
- upstream: adjust SetEnv description to clarify $TERM handling
+ upstream: Fix up whitespace left by previous
- OpenBSD-Commit-ID: 8b8cc0124856bc1094949d55615e5c44390bcb22
+ change removing privsep. No other changes.
+
+ OpenBSD-Regress-ID: 87adec225d8afaee4d6a91b2b71203f52bf14b15
-commit 771f57a8626709f2ad207058efd68fbf30d31553
+commit ddcb53b7a7b29be65d57562302b2d5f41733e8dd
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jun 4 05:09:08 2021 +0000
+Date: Thu Sep 30 05:20:08 2021 +0000
- upstream: Switch the listening select loop from select() to
-
- pselect() and mask signals while checking signal flags, umasking for pselect
- and restoring afterwards. Also restore signals before sighup_restart so they
- don't remain blocked after restart.
+ upstream: Remove references to privsep.
- This prevents a race where a SIGTERM or SIGHUP can arrive between
- checking the flag and calling select (eg if sshd is processing a
- new connection) resulting in sshd not shutting down until the next
- time it receives a new connection. bz#2158, with & ok djm@
+ This removes several do..while loops but does not change the
+ indentation of the now-shallower loops, which will be done in a separate
+ whitespace-only commit to keep changes of style and substance separate.
- OpenBSD-Commit-ID: bf85bf880fd78e00d7478657644fcda97b9a936f
+ OpenBSD-Regress-ID: 4bed1a0249df7b4a87c965066ce689e79472a8f7
-commit f64f8c00d158acc1359b8a096835849b23aa2e86
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jun 4 05:02:40 2021 +0000
+commit ece2fbe486164860de8df3f8b943cccca3085eff
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Thu Sep 30 04:22:50 2021 +0000
- upstream: allow ssh_config SetEnv to override $TERM, which is otherwise
+ upstream: Use "skip" instead of "fatal"
- handled specially by the protocol. Useful in ~/.ssh/config to set TERM to
- something generic (e.g. "xterm" instead of "xterm-256color") for destinations
- that lack terminfo entries. feedback and ok dtucker@
+ if SUDO isn't set for the *-command tests. This means running "make tests"
+ without SUDO set will perform all of the tests that it can instead of
+ failing on the ones it cannot run.
- OpenBSD-Commit-ID: 38b1ef4d5bc159c7d9d589d05e3017433e2d5758
+ OpenBSD-Regress-ID: bd4dbbb02f34b2e8c890558ad4a696248def763a
-commit 60107677dc0ce1e93c61f23c433ad54687fcd9f5
+commit bb754b470c360e787a99fb4e88e2668198e97b41
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jun 4 04:02:21 2021 +0000
+Date: Fri Oct 1 04:50:36 2021 +0000
- upstream: correct extension name "no-presence-required" =>
-
- "no-touch-required"
+ upstream: unbreak FIDO sk-ed25519 key enrollment for OPENSSL=no builds;
- document "verify-required" option
+ ok dtucker@
- OpenBSD-Commit-ID: 1879ff4062cf61d79b515e433aff0bf49a6c55c5
+ OpenBSD-Commit-ID: 6323a5241728626cbb2bf0452cf6a5bcbd7ff709
-commit ecc186e46e3e30f27539b4311366dfda502f0a08
+commit 207648d7a6415dc915260ca75850404dbf9f0a0b
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Jun 2 13:54:11 2021 +1000
+Date: Wed Sep 29 20:03:58 2021 +1000
- Retire fbsd7 test target.
-
- It's the slowest of the selfhosted targets (since it's 32bit but has
- most of the crypto algos). We still have coverage for 32bit i386.
+ Include stdlib.h for arc4random_uniform prototype.
-commit 5de0867b822ec48b5eec9abde0f5f95d1d646546
+commit 696aadc854582c164d5fc04933d2f3e212dc0e06
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Jun 2 11:21:40 2021 +1000
+Date: Wed Sep 29 20:00:30 2021 +1000
- Check for $OPENSSL in md5 fallback too.
+ Look for clang after cc and gcc.
-commit 1db69d1b6542f8419c04cee7fd523a4a11004be2
+commit a3c6375555026d85dbf811fab566b9f76f196144
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Jun 2 11:17:54 2021 +1000
+Date: Wed Sep 29 19:30:59 2021 +1000
- Add dfly60 target.
+ Use backticks instead of $(..) for portability.
+
+ Older shells (eg /bin/sh on Solaris 10) don't support $() syntax.
-commit a3f2dd955f1c19cad387a139f0e719af346ca6ef
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Jun 2 00:17:45 2021 +0000
+commit 958aaa0387133d51f84fe9c8f30bca03025f2867
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Sep 29 18:53:32 2021 +1000
- upstream: Merge back shell portability changes
-
- bringing it back in sync with -portable.
+ Skip file-based tests by default on Mac OS.
- OpenBSD-Regress-ID: c07905ba931e66ad7d849b87b7d19648007175d1
+ The file-based tests need OpenSSL so skip them.
-commit 9d482295c9f073e84d75af46b720a1c0f7ec2867
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Jun 1 23:56:20 2021 +0000
+commit 55c8bdf6e9afb0f9fa8e4f10c25c7f0081b48fd0
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Sep 29 18:42:47 2021 +1000
- upstream: Use a default value for $OPENSSL,
-
- allowing it to be overridden. Do the same in the PuTTY tests since it's
- needed there and not exported by test-exec.sh.
+ Build without OpenSSL on Mac OS.
- OpenBSD-Regress-ID: c49dcd6aa7602a8606b7afa192196ca1fa65de16
+ Modern versions don't ship enough libcrypto to build against.
-commit 07660b3c99f8ea74ddf4a440e55c16c9f7fb3dd1
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon May 24 10:25:18 2021 +0000
+commit c9172193ea975415facf0afb356d87df21535f88
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Sep 29 18:33:38 2021 +1000
- upstream: Find openssl binary via environment variable. This
-
- allows overriding if necessary (eg in -portable where we're testing against a
- specific version of OpenSSL).
+ Remove TEST_SSH_ECC.
- OpenBSD-Regress-ID: 491f39cae9e762c71aa4bf045803d077139815c5
+ Convert the only remaining user of it to runtime detection using ssh -Q.
-commit 1a4d1da9188d7c88f646b61f0d6a3b34f47c5439
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 21 04:03:47 2021 +0000
+commit 5e6d28b7874b0deae95d2c68947c45212d32e599
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Sep 29 17:48:09 2021 +1000
- upstream: fix memleak in test
-
- OpenBSD-Regress-ID: 5e529d0982aa04666604936df43242e97a7a6f81
+ Split c89 test openssl setting out.
+
+commit c4ac7f98e230e83c015678dc958b1ffe828564ad
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Sep 29 17:40:50 2021 +1000
+
+ Expand TEST_SHELL consistently with other vars.
+
+commit cfe5f7b0eb7621bfb0a756222de0431315c2ab8b
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Sep 29 17:26:50 2021 +1000
-commit 60455a5d98065a73ec9a1f303345856bbd49aecc
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 21 03:59:01 2021 +0000
+ Replace `pwd` with make variable in regress cmd.
- upstream: also check contents of remaining string
+commit 899be59da5fbc3372444bd0fbe74af48313bed33
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Sep 29 17:14:33 2021 +1000
+
+ Get BUILDDIR from autoconf.
- OpenBSD-Regress-ID: d526fa07253f4eebbc7d6205a0ab3d491ec71a28
+ Use this to replace `pwd`s in regress test command line.
-commit 39f6cd207851d7b67ca46903bfce4a9f615b5b1c
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 21 03:48:07 2021 +0000
+commit c8d92d3d4f7d560146f2f936156ec4dac3fc5811
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Sep 29 13:28:56 2021 +1000
- upstream: unit test for misc.c:strdelim() that mostly servces to
-
- highlight its inconsistencies
-
- OpenBSD-Regress-ID: 8d2bf970fcc01ccc6e36a5065f89b9c7fa934195
+ Add make clean step to tests.
-commit 7a3a1dd2c7d4461962acbcc0ebee9445ba892be0
+commit 360fb41ef8359619ab90b0d131c914494e55d3dd
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu May 27 21:23:15 2021 +1000
+Date: Wed Sep 29 11:36:13 2021 +1000
- Put minix3 config in the host-specific block.
+ Test all available clang and gcc versions.
-commit 59a194825f12fff8a7f75d91bf751ea17645711b
+commit 4fb49899d7da22952d35a4bc4c9bdb2311087893
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon May 31 06:48:42 2021 +0000
+Date: Wed Sep 29 01:32:21 2021 +0000
- upstream: Hash challenge supplied by client during FIDO key enrollment
-
- prior to passing it to libfido2, which does expect a hash.
+ upstream: Test certificate hostkeys held in ssh-agent too. Would have
- There is no effect for users who are simply generating FIDO keys using
- ssh-keygen - by default we generate a random 256 bit challenge, but
- people building attestation workflows around our tools should now have
- a more consistent experience (esp. fewer failures when they fail to
- guess the magic 32-byte challenge length requirement).
+ caught regression fixed in sshd r1.575
ok markus@
- OpenBSD-Commit-ID: b8d5363a6a7ca3b23dc28f3ca69470472959f2b5
-
-commit eb68e669bc8ab968d4cca5bf1357baca7136a826
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu May 27 21:14:15 2021 +1000
-
- Include login_cap.h for login_getpwclass override.
-
- On minix3, login_getpwclass is __RENAME'ed to __login_getpwclass50 so
- without this the include overriding login_getpwclass causes a compile
- error.
-
-commit 2063af71422501b65c7a92a5e14c0e6a3799ed89
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu May 27 21:13:38 2021 +1000
-
- Add minix3 test target.
+ OpenBSD-Regress-ID: 1f164d7bd89f83762db823eec4ddf2d2556145ed
-commit 2e1efcfd9f94352ca5f4b6958af8a454f8cf48cd
+commit ce4854e12e749a05646e5775e9deb8cfaf49a755
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed May 26 01:47:24 2021 +0000
+Date: Wed Sep 29 01:33:32 2021 +0000
- upstream: fix SEGV in UpdateHostkeys debug() message, triggered
+ upstream: add some debug output showing how many key file/command lines
- when the update removed more host keys than remain present. Fix tested by
- reporter James Cook, via bugs@
+ were processed. Useful to see whether a file or command actually has keys
+ present
- OpenBSD-Commit-ID: 44f641f6ee02bb957f0c1d150495b60cf7b869d3
+ OpenBSD-Commit-ID: 0bd9ff94e84e03a22df8e6c12f6074a95d27f23c
-commit 9acd76e6e4d2b519773e7119c33cf77f09534909
-Author: naddy@openbsd.org <naddy@openbsd.org>
-Date: Sun May 23 18:22:57 2021 +0000
+commit 15abdd523501c349b703d9a27e2bb4252ad921ef
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Sep 28 11:14:50 2021 +0000
- upstream: ssh: The client configuration keyword is
-
- "hostbasedacceptedalgorithms"
+ upstream: Make prototype for rijndaelEncrypt match function
- This fixes a mistake that slipped in when "HostbasedKeyTypes" was
- renamed to "HostbasedAcceptedAlgorithms".
+ including the bounds. Fixes error in portable where GCC>=11 takes notice of
+ the bounds. ok deraadt@
- Bug report by zack@philomathiclife.com
+ OpenBSD-Commit-ID: cdd2f05fd1549e1786a70871e513cf9e9cf099a6
+
+commit d1d29ea1d1ef1a1a54b209f062ec1dcc8399cf03
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Sep 28 11:10:05 2021 +0000
+
+ upstream: Import regenerated moduli.
- OpenBSD-Commit-ID: d745a7e8e50b2589fc56877f322ea204bc784f38
+ OpenBSD-Commit-ID: 4bec5db13b736b64b06a0fca704cbecc2874c8e1
-commit 078a0e60c92700da4c536c93c007257828ccd05b
+commit 39f2111b1d5f00206446257377dcce58cc72369f
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue May 25 11:40:47 2021 +1000
+Date: Wed Sep 29 10:53:55 2021 +1000
- Rename README.md to ci-status.md.
+ Add new compiler hardening flags.
- The original intent was to provide a status page for the CIs configured
- in that directory, but it had the side effect of replacing the top-level
- README.md.
+ Add -fzero-call-used-regs and -ftrivial-auto-var-init to the list of
+ compiler hardening flags that configure checks for. These are supported
+ by clang and gcc, and make ROP gadgets less useful and mitigate
+ stack-based infoleaks respectively. ok djm@
-commit 7be4ac813662f68e89f23c50de058a49aa32f7e4
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed May 19 01:24:05 2021 +0000
+commit bf944e3794eff5413f2df1ef37cddf96918c6bde
+Author: Damien Miller <djm@mindrot.org>
+Date: Mon Sep 27 00:03:19 2021 +1000
- upstream: restore blocking status on stdio fds before close
-
- ssh(1) needs to set file descriptors to non-blocking mode to operate
- but it was not restoring the original state on exit. This could cause
- problems with fds shared with other programs via the shell, e.g.
-
- > $ cat > test.sh << _EOF
- > #!/bin/sh
- > {
- > ssh -Fnone -oLogLevel=verbose ::1 hostname
- > cat /usr/share/dict/words
- > } | sleep 10
- > _EOF
- > $ ./test.sh
- > Authenticated to ::1 ([::1]:22).
- > Transferred: sent 2352, received 2928 bytes, in 0.1 seconds
- > Bytes per second: sent 44338.9, received 55197.4
- > cat: stdout: Resource temporarily unavailable
-
- This restores the blocking status for fds 0,1,2 (stdio) before ssh(1)
- abandons/closes them.
-
- This was reported as bz3280 and GHPR246; ok dtucker@
-
- OpenBSD-Commit-ID: 8cc67346f05aa85a598bddf2383fcfcc3aae61ce
+ initgroups needs grp.h
-commit c4902e1a653c67fea850ec99c7537f358904c0af
+commit 8c5b5655149bd76ea21026d7fe73ab387dbc3bc7
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon May 17 11:43:16 2021 +0000
+Date: Sun Sep 26 14:01:11 2021 +0000
- upstream: fix breakage of -W forwaring introduced in 1.554; reported by
-
- naddy@ and sthen@, ok sthen@
+ upstream: openssh-8.8
- OpenBSD-Commit-ID: f72558e643a26dc4150cff6e5097b5502f6c85fd
+ OpenBSD-Commit-ID: 12357794602ac979eb7312a1fb190c453f492ec4
-commit afea01381ad1fcea1543b133040f75f7542257e6
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon May 17 07:22:45 2021 +0000
+commit f3cbe43e28fe71427d41cfe3a17125b972710455
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Sep 26 14:01:03 2021 +0000
- upstream: Regenerate moduli.
+ upstream: need initgroups() before setresgid(); reported by anton@,
- OpenBSD-Commit-ID: 83c93a2a07c584c347ac6114d6329b18ce515557
+ ok deraadt@
+
+ OpenBSD-Commit-ID: 6aa003ee658b316960d94078f2a16edbc25087ce
-commit be2866d6207b090615ff083c9ef212b603816a56
+commit 8acaff41f7518be40774c626334157b1b1c5583c
Author: Damien Miller <djm@mindrot.org>
-Date: Mon May 17 09:40:23 2021 +1000
+Date: Sun Sep 26 22:16:36 2021 +1000
- Handle Android libc returning NULL pw->pw_passwd
-
- Reported by Luke Dashjr
+ update version numbers for release
-commit 5953c143008259d87342fb5155bd0b8835ba88e5
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 14 05:20:32 2021 +0000
+commit d39039ddc0010baa91c70a0fa0753a2699bbf435
+Author: kn@openbsd.org <kn@openbsd.org>
+Date: Sat Sep 25 09:40:33 2021 +0000
- upstream: fix previous: test saved no_shell_flag, not the one that just
+ upstream: RSA/SHA-1 is not used by default anymore
- got clobbered
+ OK dtucker deraadt djm
- OpenBSD-Commit-ID: b8deace085d9d941b2d02f810243b9c302e5355d
+ OpenBSD-Commit-ID: 055c51a221c3f099dd75c95362f902da1b8678c6
-commit 1e9fa55f4dc4b334651d569d3448aaa3841f736f
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 14 03:09:48 2021 +0000
+commit 9b2ee74e3aa8c461eb5552a6ebf260449bb06f7e
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Sep 24 11:08:03 2021 +1000
- upstream: Fix ssh started with ControlPersist incorrectly executing a
-
- shell when the -N (no shell) option was specified. bz3290 reported by Richard
- Schwab; patch from markus@ ok me
+ Move the fgrep replacement to hostkey-rotate.sh.
- OpenBSD-Commit-ID: ea1ea4af16a95687302f7690bdbe36a6aabf87e1
+ The fgrep replacement for buggy greps doesn't work in the sftp-glob test
+ so move it to just where we know it's needed.
-commit d1320c492f655d8f5baef8c93899d79dded217a5
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed May 12 11:34:30 2021 +0000
+commit f7039541570d4b66d76e6f574544db176d8d5c02
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Sep 24 08:04:14 2021 +1000
- upstream: Clarify language about moduli. While both ends of the
-
- connection do need to use the same parameters (ie groups), the DH-GEX
- protocol takes care of that and both ends do not need the same contents in
- the moduli file, which is what the previous text suggested. ok djm@ jmc@
+ Replacement function for buggy fgrep.
- OpenBSD-Commit-ID: f0c18cc8e79c2fbf537a432a9070ed94e96a622a
+ GNU (f)grep <=2.18, as shipped by FreeBSD<=12 and NetBSD<=9 will
+ occasionally fail to find ssh host keys in the hostkey-rotate test.
+ If we have those versions, use awk instead.
-commit d3cc4d650ce3e59f3e370b101778b0e8f1c02c4d
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 7 04:11:51 2021 +0000
+commit f6a660e5bf28a01962af87568e118a2d2e79eaa0
+Author: David Manouchehri <david.manouchehri@riseup.net>
+Date: Thu Sep 23 17:03:18 2021 -0400
- upstream: include pid in LogVerbose spam
-
- OpenBSD-Commit-ID: aacb86f96ee90c7cb84ec27452374285f89a7f00
+ Don't prompt for yes/no questions.
-commit e3c032333be5fdbbaf2751f6f478e044922b4ec4
+commit 7ed1a3117c09f8c3f1add35aad77d3ebe1b85b4d
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 7 03:09:38 2021 +0000
+Date: Mon Sep 20 06:53:56 2021 +0000
- upstream: don't sigdie() in signal handler in privsep child process;
+ upstream: fix missing -s in SYNOPSYS and usage() as well as a
- this can end up causing sandbox violations per bz3286; ok dtucker@
+ capitalisation mistake; spotted by jmc@
- OpenBSD-Commit-ID: a7f40b2141dca4287920da68ede812bff7ccfdda
+ OpenBSD-Commit-ID: 0ed8ee085c7503c60578941d8b45f3a61d4c9710
-commit a4039724a3f2abac810735fc95cf9114a3856049
+commit 8c07170135dde82a26886b600a8bf6fb290b633d
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri May 7 09:23:40 2021 +0000
+Date: Mon Sep 20 04:02:13 2021 +0000
- upstream: Increase ConnectionAttempts from 4 to 10 as the tests
+ upstream: Fix "Allocated port" debug message
- occasionally time out on heavily loaded hosts.
+ for unix domain sockets. From peder.stray at gmail.com via github PR#272,
+ ok deraadt@
- OpenBSD-Regress-ID: 29a8cdef354fc9da471a301f7f65184770434f3a
+ OpenBSD-Commit-ID: 8d5ef3fbdcdd29ebb0792b5022a4942db03f017e
-commit c0d7e36e979fa3cdb60f5dcb6ac9ad3fd018543b
+commit 277d3c6adfb128b4129db08e3d65195d94b55fe7
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 7 02:26:55 2021 +0000
+Date: Mon Sep 20 01:55:42 2021 +0000
- upstream: dump out a usable private key string too; inspired by Tyson
+ upstream: Switch scp back to use the old protocol by default, ahead of
- Whitehead
+ release. We'll wait a little longer for people to pick up sftp-server(8) that
+ supports the extension that scp needs for ~user paths to continue working in
+ SFTP protocol mode. Discussed with deraadt@
- OpenBSD-Regress-ID: 65572d5333801cb2f650ebc778cbdc955e372058
+ OpenBSD-Commit-ID: f281f603a705fba317ff076e7b11bcf2df941871
-commit 24fee8973abdf1c521cd2c0047d89e86d9c3fc38
+commit ace19b34cc15bea3482be90450c1ed0cd0dd0669
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 7 02:29:40 2021 +0000
+Date: Sat Sep 18 02:03:25 2021 +0000
- upstream: correct mistake in spec - the private key blobs are encoded
+ upstream: better error message for ~user failures when the
- verbatim and not as strings (i.e. no 4-byte length header)
+ sftp-server lacks the expand-path extension; ok deraadt@
- OpenBSD-Commit-ID: 3606b5d443d72118c5b76c4af6dd87a5d5a4f837
+ OpenBSD-Commit-ID: 9c1d965d389411f7e86f0a445158bf09b8f9e4bc
-commit f43859159cc62396ad5d080f0b1f2635a67dac02
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue May 4 22:53:52 2021 +0000
+commit 6b1238ba971ee722a310d95037b498ede5539c03
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Sep 16 15:22:22 2021 +0000
- upstream: Don't pass NULL as a string in debugging as it does not work
+ upstream: make some more scp-in-SFTP mode better match Unix idioms
- on some platforms in -portable. ok djm@
+ suggested by deraadt@
- OpenBSD-Commit-ID: 937c892c99aa3c9c272a8ed78fa7c2aba3a44fc9
+ OpenBSD-Commit-ID: 0f2439404ed4cf0b0be8bf49a1ee734836e1ac87
-commit ac31aa3c6341905935e75f0539cf4a61bbe99779
+commit e694f8ac4409931e67d08ac44ed251b20b10a957
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon May 3 00:16:45 2021 +0000
+Date: Thu Sep 16 15:11:19 2021 +0000
- upstream: more debugging for UpdateHostKeys signature failures
+ upstream: allow log_stderr==2 to prefix log messages with argv[0]
- OpenBSD-Commit-ID: 1ee95f03875e1725df15d5e4bea3e73493d57d36
+ use this to make scp's SFTP mode error messages more scp-like
+
+ prompted by and ok deraadt@
+
+ OpenBSD-Commit-ID: 0e821dbde423fc2280e47414bdc22aaa5b4e0733
-commit 8e32e97e788e0676ce83018a742203614df6a2b3
+commit 8a7a06ee505cb833e613f74a07392e9296286c30
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat May 1 20:07:47 2021 +1000
+Date: Fri Sep 17 13:03:31 2021 +1000
- Add obsd69 test target.
+ Test against LibreSSL 3.2.6, 3.3.4, 3.4.0.
-commit f06893063597c5bb9d9e93f851c4070e77d2fba9
+commit c25c84074a47f700dd6534995b4af4b456927150
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Apr 30 04:29:53 2021 +0000
+Date: Thu Sep 16 05:36:03 2021 +0000
- upstream: a little debugging in the main mux process for status
+ upstream: missing space character in ssh -G output broke the
- confirmation failures in multiplexed sessions
+ t-sshcfgparse regression test; spotted by anton@
- OpenBSD-Commit-ID: 6e27b87c95176107597035424e1439c3232bcb49
+ OpenBSD-Commit-ID: bcc36fae2f233caac4baa8e58482da4aa350eed0
-commit e65cf00da6bc31e5f54603b7feb7252dc018c033
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Apr 30 04:02:52 2021 +0000
+commit a4bee1934bf5e5575fea486628f4123d6a29dff8
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Sep 15 06:56:01 2021 +0000
- upstream: Remove now-unused skey function prototypes leftover from
+ upstream: allow CanonicalizePermittedCNAMEs=none in ssh_config; ok
- skey removal.
+ markus@
- OpenBSD-Commit-ID: 2fc36d519fd37c6f10ce74854c628561555a94c3
+ OpenBSD-Commit-ID: 668a82ba8e56d731b26ffc5703213bfe071df623
-commit ae5f9b0d5c8126214244ee6b35aae29c21028133
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Apr 29 13:01:50 2021 +1000
+commit d0fffc88c8fe90c1815c6f4097bc8cbcabc0f3dd
+Author: mbuhl@openbsd.org <mbuhl@openbsd.org>
+Date: Tue Sep 14 11:04:21 2021 +0000
- Wrap sntrup761x25519 inside ifdef.
+ upstream: put back the mux_ctx memleak fix for SSH_CHANNEL_MUX_CLIENT
- From balu.gajjala at gmail.com via bz#3306.
-
-commit 70a8dc138a6480f85065cdb239915ad4b7f928cf
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Apr 28 14:44:07 2021 +1000
-
- Add status badges for Actions-based tests.
-
-commit 40b59024cc3365815381474cdf4fe423102e391b
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Apr 28 12:22:11 2021 +1000
-
- Add obsdsnap (OpenBSD snapshot) test target.
-
-commit e627067ec8ef9ae8e7a638f4dbac91d52dee3e6d
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Apr 28 11:35:28 2021 +1000
-
- Add test building upstream OpenBSD source.
-
-commit 1b8108ebd12fc4ed0fb39ef94c5ba122558ac373
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Apr 27 14:22:20 2021 +1000
-
- Test against OpenSSL 1.1.0h instead of 1.1.0g.
+ OK mfriedl@
- 1.1.0g requires a perl glob module that's not installed by default.
-
-commit 9bc20efd39ce8525be33df3ee009f5a4564224f1
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Apr 27 12:37:59 2021 +1000
-
- Use the default VM type for libcrypto ver tests.
+ OpenBSD-Commit-ID: 1aba1da828956cacaadb81a637338734697d9798
-commit 9f79e80dc40965c2e73164531250b83b176c1eea
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Apr 27 12:24:10 2021 +1000
+commit 19b3d846f06697c85957ab79a63454f57f8e22d6
+Author: schwarze@openbsd.org <schwarze@openbsd.org>
+Date: Sat Sep 11 09:05:50 2021 +0000
- Always build OpenSSL shared.
+ upstream: Do not ignore SIGINT while waiting for input if editline(3)
- This is the default for current versions but we need it to test against
- earlier versions.
+ is not used. Instead, in non-interactive mode, exit sftp(1), like for other
+ serious errors. As pointed out by dtucker@, when compiled without editline(3)
+ support in portable OpenSSH, the el == NULL branch is also used for
+ interactive mode. In that case, discard the input line and provide a fresh
+ prompt to the user just like in the case where editline(3) is used. OK djm@
+
+ OpenBSD-Commit-ID: 7d06f4d3ebba62115527fafacf38370d09dfb393
-commit b3cc9fbdff2782eca79e33e02ac22450dc63bce9
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Apr 27 09:18:02 2021 +1000
+commit ba61123eef9c6356d438c90c1199a57a0d7bcb0a
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Sep 11 00:40:24 2021 +0000
- Fix custom OpenSSL tests.
+ upstream: when using SFTP protocol, continue transferring files after a
- Check out specified OpenSSL version. Install custom libcrypto where
- configure expects to find it. Remove unneeded OpenSSL config time
- options. Older OpenSSL versions were not make -j safe so remove it.
+ transfer error occurs. This matches original scp/rcp behaviour. ok dtucker@
+
+ OpenBSD-Commit-ID: dfe4558d71dd09707e9b5d6e7d2e53b793da69fa
-commit 77532609874a99a19e3e2eb2d1b7fa93aef963bb
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Apr 26 17:18:25 2021 +1000
+commit b0ec59a708b493c6f3940336b1a537bcb64dd2a7
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Sep 10 11:38:38 2021 +0000
- Export CC and CFLAGS for c89 test.
+ upstream: Document that non-interactive commands are run via the user's
+
+ shell using the -c flag. ok jmc@
+
+ OpenBSD-Commit-ID: 4f0d912077732eead10423afd1acf4fc0ceec477
-commit 33f62dfbe865f4de77980ab88774bf1eb5e4e040
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Apr 26 17:13:44 2021 +1000
+commit 66a658b5d9e009ea11f8a0ca6e69c7feb2d851ea
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Sep 10 10:26:02 2021 +0000
- Add c89 here too.
+ upstream: Document behaviour of arguments following non-interactive
+
+ commands. Prompted by github PR#139 from EvanTheB, feedback & ok djm@ jmc@
+
+ OpenBSD-Commit-ID: fc758d1fe0471dfab4304fcad6cd4ecc3d79162a
-commit da9d59f526fce58e11cba49cd8eb011dc0bf5677
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Apr 26 15:34:23 2021 +1000
+commit 1d47e28e407d1f95fdf8f799be23f48dcfa5206b
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Sep 10 07:11:11 2021 +0000
- Add test against OpenSSL w/out ECC.
+ upstream: Clarify which file's attributes -p preserves, and that
+
+ it's specifically the file mode bits. bz#3340 from calestyo at scientia.net,
+ ok djm@ jmc@
+
+ OpenBSD-Commit-ID: f09e6098ed1c4be00c730873049825f8ee7cb884
-commit 29e194a752359ebf85bf7fce100f23a0477fc4de
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Apr 26 14:49:59 2021 +1000
+commit b344db7a413478e4c21e4cadba4a970ad3e6128a
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Sep 10 05:46:09 2021 +0000
- Ensure we can still build with C89.
+ upstream: openssh-7.4 was incorrectly listed twice; spotted by
+
+ Dmitry Belyavskiy, ok dtucker@
+
+ OpenBSD-Commit-ID: 4b823ae448f6e899927ce7b04225ac9e489f58ef
-commit a38016d369d21df5d35f761f2b67e175e132ba22
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Apr 26 14:29:03 2021 +1000
+commit 9136d6239ad7a4a293e0418a49b69e70c76d58b8
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Thu Sep 9 06:17:39 2021 +0000
- Interop test agains PuTTY.
+ upstream: - move CAVEATS to its correct order - use the term
+
+ "legacy" protocol rather than "original", as the latter made the text
+ misleading - uppercase SCP
+
+ ok djm
+
+ OpenBSD-Commit-ID: 8479255746d5fa76a358ee59e7340fecf4245ff0
-commit 095b0307a77be8803768857cc6c0963fa52ed85b
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Apr 26 14:02:03 2021 +1000
+commit 2d678c5e3bdc2f5c99f7af5122e9d054925d560d
+Author: David Carlier <devnexen@gmail.com>
+Date: Wed Sep 8 19:49:54 2021 +0100
- Support testing against arbitary libcrytpo vers.
+ Disable tracing on FreeBSD using procctl.
- Add tests against various LibreSSL and OpenSSL versions.
+ Placed at the start of platform_disable_tracing() to prevent declaration
+ after code errors from strict C89 compilers (in the unlikely event that
+ more than one method is enabled).
-commit b16082aa110fa7128ece2a9037ff420c4a285317
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Apr 26 13:35:44 2021 +1000
+commit 73050fa38fb36ae3326d768b574806352b97002d
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Sep 8 23:31:39 2021 +0000
- Add fbsd10 test target.
+ upstream: Use the SFTP protocol by default. The original scp/rcp
+
+ protocol remains available via the -O flag.
+
+ Note that ~user/ prefixed paths in SFTP mode require a protocol extension
+ that was first shipped in OpenSSH 8.7.
+
+ ok deraadt, after baking in snaps for a while without incident
+
+ OpenBSD-Commit-ID: 23588976e28c281ff5988da0848cb821fec9213c
-commit 2c805f16b24ea37cc051c6018fcb05defab6e57a
+commit c4565e69ffa2485cff715aa842ea7a350296bfb6
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sun Apr 25 14:15:02 2021 +1000
+Date: Wed Sep 8 21:09:49 2021 +1000
- Disable compiler hardening on nbsd4.
-
- The system compiler supports -fstack-protector-all, but using it will
- result in an internal compiler error on some files.
+ Really fix test on OpenSSL 1.1.1 stable.
-commit 6a5d39305649da5dff1934ee54292ee0cebd579d
+commit 79f1bb5f56cef3ae9276207316345b8309248478
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sun Apr 25 13:01:34 2021 +1000
+Date: Wed Sep 8 18:51:39 2021 +1000
- Add nbsd3, nbsd4 and nbsd9 test targets.
+ Correct OpenSSL 1.1.1 stable identifier.
-commit d1aed05bd2e4ae70f359a394dc60a2d96b88f78c
+commit b6255593ed5ccbe5e7d3d4b26b2ad31ad4afc232
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Apr 24 22:03:46 2021 +1000
+Date: Wed Sep 8 18:39:44 2021 +1000
- Comment out nbsd2 test target for now.
+ Increment nfds when coming from startup_pipe.
+
+ If we have to increase nfds because startup_pipe[0] is above any of the
+ descriptors passed in the fd_sets, we also need to add 1 to nfds since
+ select takes highest FD number plus one. bz#3345 from yaroslav.kuzmin
+ at vmssoftware.com.
-commit a6b4ec94e5bd5a8a18cd2c9942d829d2e5698837
+commit a3e92a6794817df6012ac8546aea19652cc91b61
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Apr 24 17:52:24 2021 +1000
+Date: Wed Sep 8 13:45:10 2021 +1000
- Add OPENBSD ORIGINAL marker.
+ Tests for OpenSSL 3.0.0 release & 1.1.1 branch.
-commit 3737c9f66ee590255546c4b637b6d2be669a11eb
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 23 19:49:46 2021 +1000
+commit 4afe431da98ec1cf6a2933fe5658f4fd68dee9e2
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Sep 8 03:23:44 2021 +0000
- Replace "==" (a bashism) with "=".
+ upstream: correct my mistake in previous fix; spotted by halex
+
+ OpenBSD-Commit-ID: 3cc62d92e3f70006bf02468fc146bfc36fffa183
-commit a116b6f5be17a1dd345b7d54bf8aa3779a28a0df
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 23 16:34:48 2021 +1000
+commit ca0e455b9331213ff9505a21b94c38e34faa2bba
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Sep 7 06:03:51 2021 +0000
- Add nbsd2 test target.
+ upstream: avoid NULL deref in -Y find-principals. Report and fix
+
+ from Carlo Marcelo Arenas Belón
+ MIME-Version: 1.0
+ Content-Type: text/plain; charset=UTF-8
+ Content-Transfer-Encoding: 8bit
+
+ OpenBSD-Commit-ID: 6238486f8ecc888d6ccafcd9ad99e621bb41f1e0
-commit 196bf2a9bb771f45d9b0429cee7d325962233c44
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 23 14:54:10 2021 +1000
+commit 37616807f150fb46610bbd5031c31af4857ad1e9
+Author: millert@openbsd.org <millert@openbsd.org>
+Date: Mon Sep 6 00:36:01 2021 +0000
- Add obsd68 test target.
+ upstream: revision 1.381 neglected to remove
+
+ sChallengeResponseAuthentication from the enum. Noticed by
+ christos@zoulas.com. OK dtucker@
+
+ OpenBSD-Commit-ID: b533283a4dd6d04a867da411a4c7a8fbc90e34ff
-commit e3ba6574ed69e8b7af725cf5e8a9edaac04ff077
+commit 7acb3578cdfec0b3d34501408071f7a96c1684ea
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 23 14:53:32 2021 +1000
+Date: Sun Sep 5 20:45:42 2021 +1000
- Remove dependency on bash.
+ Correct version_num for OpenSSL dev branch.
-commit db1f9ab8feb838aee9f5b99c6fd3f211355dfdcf
+commit 65bb01111320dfd0d25e21e1fd4d3f2b77532669
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 23 14:41:13 2021 +1000
+Date: Sun Sep 5 19:37:39 2021 +1000
- Add obsd67 test target.
+ Test against OpenSSL 3 branch as well as dev.
+
+ Now that OpenSSL development has moved to 3.1, test against the most
+ recent version of the openssl-3.0 branch too.
-commit c039a6bf79192fe1daa9ddcc7c87dd98e258ae7c
+commit 864ed0d5e04a503b97202c776b7cf3f163f3eeaa
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 23 11:08:23 2021 +1000
+Date: Sun Sep 5 19:33:22 2021 +1000
- Re-add macos-11.0 test target.
+ OpenSSL development is now 3.1.*
-commit a6db3a47b56adb76870d59225ffb90a65bc4daf2
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 23 10:28:28 2021 +1000
+commit a60209a586a928f92ab323bf23bd07f57093342e
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Sep 3 07:43:23 2021 +0000
- Add openindiana test target.
+ upstream: Use .Cm instead of .Dq in StrictHostKeyChecking list for
+
+ consistency. Patch from scop via github PR#257, ok jmc@
+
+ OpenBSD-Commit-ID: 3652a91564570779431802c31224fb4a9cf39872
-commit 3fe7e73b025c07eda46d78049f1da8ed7dfc0c69
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 23 10:26:35 2021 +1000
+commit 8d1d9eb6de37331e872700e9e399a3190cca1242
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Sep 3 07:27:03 2021 +0000
- Test krb5 on Solaris 11 too.
+ upstream: Mention using ssh -i for specifying the public key file
+
+ in the case where the private key is loaded into ssh-agent but is not present
+ locally. Based on patch from rafork via github PR#215, ok jmc@
+
+ OpenBSD-Commit-ID: 2282e83b0ff78d2efbe705883b67240745fa5bb2
-commit f57fbfe5eb02df1a91f1a237c4d27165afd87c13
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Apr 22 22:27:26 2021 +1000
+commit eb4362e5e3aa7ac26138b11e44d8c191910aff64
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Sep 3 05:25:50 2021 +0000
- Don't always set SUDO.
+ upstream: Refer to KEX "algorithms" instead of "methods" to match
- Rely on sourcing configs to set as appropriate.
+ other references and improve consistency. Patch from scop via github PR#241,
+ ok djm@
+
+ OpenBSD-Commit-ID: 840bc94ff6861b28d8603c8e8c16499bfb65e32c
-commit e428f29402fb6ac140b52f8f12e06ece7bb104a0
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Apr 22 22:26:08 2021 +1000
+commit b3318946ce5725da43c4bf7eeea1b73129c47d2a
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Sep 3 05:12:25 2021 +0000
- Remove now-unused 2nd arg to configs.
+ upstream: Remove redundant attrib_clear in upload_dir_internal.
+
+ The subsequent call to stat_to_attrib clears the struct as its first step
+ anyway. From pmeinhardt via github PR#220, ok djm@
+
+ OpenBSD-Commit-ID: f5234fc6d7425b607e179acb3383f21716f3029e
-commit cb4ff640d79b3c736879582139778f016bbb2cd7
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Apr 21 01:08:04 2021 +1000
+commit 7cc3fe28896e653956a6a2eed0a25d551b83a029
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Sep 3 04:11:13 2021 +0000
- Add win10 test target.
+ upstream: Add test for client termination status on signal.
+
+ Based on patch from Alexxz via github PR#235 with some tweaks, to
+ match patch in bz#3281.
+
+ OpenBSD-Regress-ID: d87c7446fb8b5f8b45894fbbd6875df326e729e2
-commit 4457837238072836b2fa3107d603aac809624983
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Apr 20 23:31:29 2021 +1000
+commit 5428b0d239f6b516c81d1dd15aa9fe9e60af75d4
+Author: deraadt@openbsd.org <deraadt@openbsd.org>
+Date: Thu Sep 2 21:03:54 2021 +0000
- Add nbsd8 test target.
+ upstream: sys/param.h is not needed for any visible reason
+
+ OpenBSD-Commit-ID: 8bdea2d0c75692e4c5777670ac039d4b01c1f368
-commit bd4fba22e14da2fa196009010aabec5a8ba9dd42
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Apr 17 09:55:47 2021 +1000
+commit 1ff38f34b4c4545eb28106629cafa1e0496bc726
+Author: Shchelkunov Artem <a.shchelkunov@ideco.ru>
+Date: Wed Aug 11 18:07:58 2021 +0500
- Add obsd51 target.
+ Fix memory leak in error path.
+
+ *info is allocated via xstrdup but was leaked in the PAM_AUTH_ERR path.
+ From github PR#266.
-commit 9403d0e805c77a5741ea8c3281bbe92558c2f125
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 16 18:14:25 2021 +1000
+commit cb37e2f0c0ca4fef844ed7edc5d0e3b7d0e83f6a
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Wed Sep 1 03:16:06 2021 +0000
- Add fbsd13 target.
+ upstream: Fix ssh-rsa fallback for old PuTTY interop tests.
+
+ OpenBSD-Regress-ID: a19ac929da604843a5b5f0f48d2c0eb6e0773d37
-commit e86968280e358e62649d268d41f698d64d0dc9fa
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Apr 16 13:55:25 2021 +1000
+commit 8b02ef0f28dc24cda8cbcd8b7eb02bda8f8bbe59
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Wed Sep 1 00:50:27 2021 +0000
- depend
+ upstream: Add a function to skip remaining tests.
+
+ Many tests skip tests for various reasons but not in a consistent way and
+ don't always clean up, so add that and switch the tests that do that over.
+
+ OpenBSD-Regress-ID: 72d2ec90a3ee8849486956a808811734281af735
-commit 2fb25ca11e8b281363a2a2a4dec4c497a1475d9a
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Apr 16 13:53:02 2021 +1000
+commit d486845c07324c04240f1674ac513985bd356f66
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Aug 31 07:13:59 2021 +0000
- crank version in README and RPM spec files
+ upstream: Specify path to PuTTY keys.
+
+ Portable needs this and it makes no difference on OpenBSD, so resync
+ them. (Id sync only, Portable already had this.)
+
+ OpenBSD-Regress-ID: 33f6f66744455886d148527af8368811e4264162
-commit b2b60ebab0cb77b5bc02d364d72e13db882f33ae
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Apr 16 03:42:00 2021 +0000
+commit d22b299115e27606e846b23490746f69fdd4fb38
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Aug 31 06:13:23 2021 +0000
- upstream: openssh-8.6
+ upstream: Better compat tests with old PuTTY.
- OpenBSD-Commit-ID: b5f3e133c846127ec114812248bc17eff07c3e19
+ When running PuTTY interop tests and using a PuTTY version older than
+ 0.76, re-enable the ssh-rsa host key algorithm (the 256 and 512 variants
+ of RSA were added some time between 0.73 and 0.76).
+
+ OpenBSD-Regress-ID: e6138d6987aa705fa1e4f216db0bb386e1ff38e1
-commit faf2b86a46c9281d237bcdec18c99e94a4eb820a
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Thu Apr 15 16:24:31 2021 +0000
+commit 87ad70d605c3e39c9b8aa275db27120d7cc09b77
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Aug 31 17:04:50 2021 +1000
- upstream: do not pass file/func to monitor; noted by Ilja van Sprundel;
-
- ok djm@
+ Resync PuTTY interop tests.
- OpenBSD-Commit-ID: 85ae5c063845c410283cbdce685515dcd19479fa
+ Resync behaviour when REGRESS_INTEROP_PUTTY is not set with OpenBSD.
-commit 2dc328023f60212cd29504fc05d849133ae47355
-Author: Damien Miller <djm@mindrot.org>
-Date: Wed Apr 14 11:42:55 2021 +1000
+commit e47b82a7bf51021afac218bf59a3be121827653d
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Aug 31 01:25:27 2021 +0000
- sshd don't exit on transient read errors
+ upstream: Specify hostkeyalgorithms in SSHFP test.
- 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
+ Specify host key algorithms in sshd's default set for the SSHFP test,
+ from djm@. Make the reason for when the test is skipped a bit clearer.
+
+ OpenBSD-Regress-ID: 4f923dfc761480d5411de17ea6f0b30de3e32cea
-commit d5d6b7d76d171a2e6861609dcd92e714ee62ad88
-Author: Damien Miller <djm@mindrot.org>
-Date: Sat Apr 10 18:45:00 2021 +1000
+commit 7db3e0a9e8477c018757b59ee955f7372c0b55fb
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Aug 30 01:15:45 2021 +0000
- perform report_failed_grab() inline
+ upstream: adapt to RSA/SHA1 deprectation
+
+ OpenBSD-Regress-ID: 952397c39a22722880e4de9d1c50bb1a14f907bb
-commit ea996ce2d023aa3c6d31125e2c3ebda1cb42db8c
-Author: Damien Miller <djm@mindrot.org>
-Date: Sat Apr 10 18:22:57 2021 +1000
+commit 2344750250247111a6c3c6a4fe84ed583a61cc11
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Aug 29 23:53:10 2021 +0000
- dedicated gnome-ssk-askpass3 source
+ upstream: After years of forewarning, disable the RSA/SHA-1
- 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.
+ signature algorithm by default. It is feasible to create colliding SHA1
+ hashes, so we need to deprecate its use.
+
+ RSA/SHA-256/512 remains available and will be transparently selected
+ instead of RSA/SHA1 for most SSH servers released in the last five+
+ years. There is no need to regenerate RSA keys.
+
+ The use of RSA/SHA1 can be re-enabled by adding "ssh-rsa" to the
+ PubkeyAcceptedAlgorithms directives on the client and server.
- 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.
+ ok dtucker deraadt
- 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
+ OpenBSD-Commit-ID: 189bcc4789c7254e09e23734bdd5def8354ff1d5
-commit bfa5405da05d906ffd58216eb77c4375b62d64c2
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Apr 8 15:18:15 2021 +1000
+commit 56c4455d3b54b7d481c77c82115c830b9c8ce328
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Aug 29 23:44:07 2021 +0000
- Ensure valgrind-out exists.
+ upstream: wrap at 80 columns
- Normally the regress tests would create it, but running the unit tests
- on their own would fail because the directory did not exist.
+ OpenBSD-Commit-ID: 47ca2286d6b52a9747f34da16d742879e1a37bf0
-commit 1f189181f3ea09a9b08aa866f78843fec800874f
+commit 95401eea8503943449f712e5f3de52fc0bc612c5
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Apr 8 15:17:19 2021 +1000
+Date: Fri Aug 20 18:14:13 2021 +1000
- Pass OBJ to unit test make invocation.
+ Replace shell function with ssh-keygen -A.
- At least the Valgrind unit tests uses $OBJ.
+ Prevents the init script in the SysV package from trying (and failing)
+ to generate unsupported key types. Remove now-unused COMMENT_OUT_ECC.
+ ok tim@
-commit f42b550c281d28bd19e9dd6ce65069164f3482b0
+commit d83ec9ed995a76ed1d5c65cf10b447222ec86131
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Apr 8 14:20:12 2021 +1000
+Date: Fri Aug 20 15:39:05 2021 +1000
- Add pattern for valgrind-unit.
+ Remove obsolete Redhat PAM config and init script.
-commit 19e534462710e98737478fd9c44768b50c27c4c6
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Apr 8 13:31:08 2021 +1000
+commit e1a596186c81e65a34ce13076449712d3bf97eb4
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Aug 20 14:03:49 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.
+ depend
-commit 80032102d05e866dc2a48a5caf760cf42c2e090e
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Apr 8 13:25:57 2021 +1000
+commit 5450606c8f7f7a0d70211cea78bc2dab74ab35d1
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Aug 20 13:59:43 2021 +1000
- ifdef out MIN and MAX.
+ update version numbers
+
+commit feee2384ab8d694c770b7750cfa76a512bdf8246
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Aug 20 03:22:55 2021 +0000
+
+ upstream: openssh-8.7
- 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.
+ OpenBSD-Commit-ID: 8769dff0fd76ae3193d77bf83b439adee0f300cd
-commit d1bd184046bc310c405f45da3614a1dc5b3e521a
+commit 9a2ed62173cc551b2b5f479460bb015b19499de8
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Apr 7 10:23:51 2021 +1000
+Date: Fri Aug 20 10:48:13 2021 +1000
- Remove only use of warn().
+ Also check pid in pselect_notify_setup.
- 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.
+ Spotted by djm@.
-commit fea8f4b1aa85026ad5aee5ad8e1599a8d5141fe0
+commit deaadcb93ca15d4f38aa38fb340156077792ce87
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Apr 7 10:18:32 2021 +1000
+Date: Fri Aug 20 08:39:33 2021 +1000
- Move make_tmpdir() into portable-specific area.
-
- Reduces diff vs OpenBSD and makes it more likely diffs will apply
- cleanly.
+ Prefix pselect functions to clarify debug messages
-commit 13e5fa2acffd26e754c6ee1d070d0afd035d4cb7
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Apr 6 23:57:56 2021 +0000
+commit 10e45654cff221ca60fd35ee069df67208fcf415
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Aug 20 08:30:42 2021 +1000
- upstream: Add TEST_SSH_ELAPSED_TIMES environment variable to print the
+ Fix race in pselect replacement code.
- elapsed time in seconds of each test. This depends on "date +%s" which is
- not specified by POSIX but is commonly implemented.
+ On the second and subsequent calls to pselect the notify_pipe was not
+ added to the select readset, opening up a race that om G. Christensen
+ discovered on multiprocessor Solaris <=9 systems.
- OpenBSD-Regress-ID: ec3c8c19ff49b2192116a0a646ee7c9b944e8a9c
+ Also reinitialize notify_pipe if the pid changes. This will prevent a
+ parent and child from using the same FD, although this is not an issue
+ in the current structure it might be in future.
-commit ef4f46ab4387bb863b471bad124d46e8d911a79a
+commit 464ba22f1e38d25402e5ec79a9b8d34a32df5a3f
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Apr 7 09:59:15 2021 +1000
+Date: Wed Aug 18 12:51:30 2021 +1000
- Move the TEST_SSH_PORT section down a bit.
+ Check compiler for c99 declarations after code.
- This groups the portable-specific changes together and makes it a
- little more likely that patches will apply cleanly.
+ The sntrup761 reference code contains c99-style declarations after code
+ so don't try to build that if the compiler doesn't support it.
-commit 3674e33fa70dfa1fe69b345bf576113af7b7be11
+commit 7d878679a4b155a359d32104ff473f789501748d
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Apr 7 10:05:10 2021 +1000
+Date: Tue Aug 17 15:12:04 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.
+ Remove trailing backslash on regress-unit-binaries
-commit 961af266b861e30fce1e26170ee0dbb5bf591f29
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Apr 6 23:24:30 2021 +0000
+commit b71b2508f17c68c5d9dbbe537686d81cedb9a781
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Aug 17 07:59:27 2021 +1000
- upstream: include "ssherr.h" not <ssherr.h>; from Balu Gajjala via
+ Put stdint.h inside HAVE_STDINT_H.
- bz#3292
+ From Tom G. Christensen.
+
+commit 6a24567a29bd7b4ab64e1afad859ea845cbc6b8c
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Aug 16 14:13:02 2021 +1000
+
+ Improve github test driver script.
- OpenBSD-Commit-ID: e9535cd9966eb2e69e73d1ede1f44905c30310bd
+ - use a trap to always output any failed regress logs (since the script
+ sets -e, the existing log output is never invoked).
+ - pass LTESTS and SKIP_LTESTS when re-running with sshd options (eg.
+ UsePAM).
-commit e7d0a285dbdd65d8df16123ad90f15e91862f959
-Author: Damien Miller <djm@mindrot.org>
-Date: Wed Apr 7 08:50:38 2021 +1000
+commit b467cf13705f59ed348b620722ac098fe31879b7
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Aug 16 11:32:23 2021 +1000
- wrap struct rlimit in HAVE_GETRLIMIT too
+ Remove deprecated ubuntu-16.04 test targets.
+
+ Github has deprecated ubuntu-16.04 and it will be removed on 20
+ September.
-commit f283a6c2e0a9bd9369e18462acd00be56fbe5b0d
-Author: Damien Miller <djm@mindrot.org>
-Date: Wed Apr 7 08:20:35 2021 +1000
+commit 20e6eefcdf78394f05e453d456c1212ffaa6b6a4
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sun Aug 15 23:25:26 2021 +1000
- wrap getrlimit call in HAVE_GETRLIMIT; bz3291
+ Skip agent ptrace test on hurd.
-commit 679bdc4a5c9244f427a7aee9c14b0a0ed086da1f
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Apr 6 09:07:33 2021 +0000
+commit 7c9115bbbf958fbf85259a061c1122e2d046aabf
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sun Aug 15 19:37:22 2021 +1000
- 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
+ Add hurd test target.
-commit 320af2f3de6333aa123f1b088eca146a245e968a
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Sun Apr 4 11:36:56 2021 +0000
+commit 7909a566f6c6a78fcd30708dc49f4e4f9bb80ce3
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sun Aug 15 12:45:10 2021 +1000
- upstream: remove stray inserts; from matthias schmidt
-
- OpenBSD-Commit-ID: 2c36ebdc54e14bbf1daad70c6a05479a073d5c63
+ Skip scp3 tests on all dfly58 and 60 configs.
-commit 801f710953b24dd2f21939171c622eac77c7484d
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Sun Apr 4 06:11:24 2021 +0000
+commit e65198e52cb03534e8c846d1bca74c310b1526de
+Author: Tim Rice <tim@multitalents.net>
+Date: Sat Aug 14 13:08:07 2021 -0700
- upstream: missing comma; from kawashima james
-
- OpenBSD-Commit-ID: 31cec6bf26c6db4ffefc8a070715ebef274e68ea
+ openbsd-compat/openbsd-compat.h: put bsd-signal.h before bsd-misc.h
+ to get sigset_t from signal.h needed for the pselect replacement.
-commit b3ca08cb174266884d44ec710a84cd64c12414ea
+commit e50635640f79920d9375e0155cb3f4adb870eee5
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Apr 5 23:46:42 2021 +1000
+Date: Fri Aug 13 13:21:00 2021 +1000
- Install libcbor with libfido2.
+ Test OpenSSH from OpenBSD head on 6.8 and 6.9.
-commit f3ca8af87a4c32ada660da12ae95cf03d190c083
-Author: Damien Miller <djm@mindrot.org>
-Date: Sat Apr 3 18:21:08 2021 +1100
+commit e0ba38861c490c680117b7fe0a1d61a181cd00e7
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Aug 13 13:00:14 2021 +1000
- enable authopt and misc unit tests
+ Skip scp3 test on dragonfly 58 and 60.
- Neither were wired into the build, both required some build
- adaptations for -portable
+ The tests hang, so skip until we figure them out.
-commit dc1b45841fb97e3d7f655ddbcfef3839735cae5f
+commit dcce2a2bcf007bf817a2fb0dce3db83fa9201e92
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Apr 3 06:58:30 2021 +0000
+Date: Thu Aug 12 23:59:25 2021 +0000
- upstream: typos in comments; GHPR#180 from Vill
+ upstream: mention that CASignatureAlgorithms accepts +/- similarly to
- =?UTF-8?q?e=20Skytt=C3=A4?=
- MIME-Version: 1.0
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
+ the other algorithm list directives; ok jmc bz#3335
- OpenBSD-Commit-ID: 93c732381ae0e2b680c79e67c40c1814b7ceed2c
+ OpenBSD-Commit-ID: 0d46b53995817052c78e2dce9dbd133963b073d9
-commit 53ea05e09b04fd7b6dea66b42b34d65fe61b9636
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Apr 3 06:55:52 2021 +0000
+commit 090a82486e5d7a8f7f16613d67e66a673a40367f
+Author: schwarze@openbsd.org <schwarze@openbsd.org>
+Date: Thu Aug 12 09:59:00 2021 +0000
- upstream: sync CASignatureAlgorithms lists with reality. GHPR#174 from
+ upstream: In the editline(3) branch of the sftp(1) event loop,
- Matt Hazinski
+ handle SIGINT rather than ignoring it, such that the user can use Ctrl-C to
+ discard the currently edited command line and get a fresh prompt, just like
+ in ftp(1), bc(1), and in shells.
- 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
+ It is critical to not use ssl_signal() for this particular case
+ because that function unconditionally sets SA_RESTART, but here we
+ need the signal to interrupt the read(2) in the el_gets(3) event loop.
- and bad indentation on continuation lines. Prompted by GHPR#185
+ OK dtucker@ deraadt@
- OpenBSD-Commit-ID: e5c81f0cbdcc6144df1ce468ec1bac366d8ad6e9
+ OpenBSD-Commit-ID: 8025115a773f52e9bb562eaab37ea2e021cc7299
-commit 34afde5c73b5570d6f8cce9b49993b23b77bfb86
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Apr 3 05:54:14 2021 +0000
+commit e1371e4f58404d6411d9f95eb774b444cea06a26
+Author: naddy@openbsd.org <naddy@openbsd.org>
+Date: Wed Aug 11 14:07:54 2021 +0000
- upstream: whitespace (tab after space)
+ upstream: scp: tweak man page and error message for -3 by default
- 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
+ Now that the -3 option is enabled by default, flip the documentation
+ and error message logic from "requires -3" to "blocked by -R".
- =?UTF-8?q?t=C3=A4=20via=20GHPR#181?=
- MIME-Version: 1.0
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
+ ok djm@
- OpenBSD-Commit-ID: 92f31754c6296d8f403d7c293e09dc27292d22c9
+ OpenBSD-Commit-ID: a872592118444fb3acda5267b2a8c3d4c4252020
-commit 082804c14e548cada75c81003a3c68ee098138ee
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Apr 3 05:40:39 2021 +0000
+commit 49f46f6d77328a3d10a758522b670a3e8c2235e7
+Author: naddy@openbsd.org <naddy@openbsd.org>
+Date: Wed Aug 11 14:05:19 2021 +0000
- upstream: ensure that pkcs11_del_provider() is called before exit -
+ upstream: scp: do not spawn ssh with two -s flags for
- some PKCS#11 providers get upset if C_Initialize is not matched with
- C_Finalize.
+ remote-to-remote copies
- From Adithya Baglody via GHPR#234; ok markus
+ Do not add another "-s" to the argument vector every time an SFTP
+ connection is initiated. Instead, introduce a subsystem flag to
+ do_cmd() and add "-s" when the flag is set.
- OpenBSD-Commit-ID: f8e770e03b416ee9a58f9762e162add900f832b6
+ ok djm@
+
+ OpenBSD-Commit-ID: 25df69759f323661d31b2e1e790faa22e27966c1
-commit 464ebc82aa926dd132ec75a0b064574ef375675e
+commit 2a2cd00783e1da45ee730b7f453408af1358ef5b
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Apr 3 05:28:43 2021 +0000
+Date: Wed Aug 11 08:55:04 2021 +0000
- upstream: unused variable
+ upstream: test -Oprint-pubkey
- OpenBSD-Commit-ID: 85f6a394c8e0f60d15ecddda75176f112007b205
+ OpenBSD-Regress-ID: 3d51afb6d1f287975fb6fddd7a2c00a3bc5094e0
-commit dc3c0be8208c488e64a8bcb7d9efad98514e0ffb
+commit b9f4635ea5bc33ed5ebbacf332d79bae463b0f54
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Apr 3 05:21:46 2021 +0000
+Date: Wed Aug 11 08:54:17 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
+ upstream: when verifying sshsig signatures, support an option
- prompted by and based on GHPR#223 by Eero Häkkinen; ok markus@
+ (-Oprint-pubkey) to dump the full public key to stdout; based on patch from
+ Fabian Stelzer; ok markus@
- OpenBSD-Commit-ID: d7ef27abb4eeeaf6e167e9312e4abe9e89faf1e4
+ OpenBSD-Commit-ID: 0598000e5b9adfb45d42afa76ff80daaa12fc3e2
-commit f75bcbba58a08c670727ece5e3f8812125969799
-Author: Damien Miller <djm@mindrot.org>
-Date: Sat Apr 3 16:22:48 2021 +1100
+commit 750c1a45ba4e8ad63793d49418a0780e77947b9b
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Aug 11 05:21:32 2021 +0000
- missing bits from 259d648e
+ upstream: oops, missed one more %p
+
+ OpenBSD-Commit-ID: e7e62818d1564cc5cd9086eaf7a51cbd1a9701eb
-commit 4cbc4a722873d9b68cb5496304dc050d7168df78
+commit b5aa27b69ab2e1c13ac2b5ad3f8f7d389bad7489
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Mar 31 21:59:26 2021 +0000
+Date: Wed Aug 11 05:20:17 2021 +0000
- upstream: cannot effectively test posix-rename extension after
+ upstream: remove a bunch of %p in format strings; leftovers of
- changes in feature advertisment.
+ debuggings past. prompted by Michael Forney, ok dtucker@
- OpenBSD-Regress-ID: 5e390bf88d379162aaa81b60ed86b34cb0c54d29
+ OpenBSD-Commit-ID: 4853a0d6c9cecaba9ecfcc19066e52d3a8dcb2ac
-commit 259d648e63e82ade4fe2c2c73c8b67fe57d9d049
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Mar 19 04:23:50 2021 +0000
+commit 419aa01123db5ff5dbc68b2376ef23b222862338
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Aug 11 09:21:09 2021 +1000
- upstream: add a test for misc.c:argv_split(), currently fails
+ Add includes.h to compat tests.
- OpenBSD-Regress-ID: ad6b96d6ebeb9643b698b3575bdd6f78bb144200
+ On platforms where closefrom returns void (eg glibc>=2.34) the prototype
+ for closefrom in its compat tests would cause compile errors. Remove
+ this and have the tests pull in the compat headers in the same way as
+ the main code. bz#3336.
-commit 473ddfc2d6b602cb2d1d897e0e5c204de145cd9a
+commit 931f592f26239154eea3eb35a086585897b1a185
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Mar 19 03:25:01 2021 +0000
+Date: Tue Aug 10 03:35:45 2021 +0000
- upstream: split
+ upstream: adapt to scp -M flag change; make scp3.sh test SFTP mode too
- OpenBSD-Regress-ID: f6c03c0e4c58b3b9e04b161757b8c10dc8378c34
+ OpenBSD-Regress-ID: 43fea26704a0f0b962b53c1fabcb68179638f9c0
-commit 1339800fef8d0dfbfeabff71b34670105bcfddd2
+commit 391ca67fb978252c48d20c910553f803f988bd37
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Mar 31 22:16:34 2021 +0000
+Date: Tue Aug 10 03:33: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.
+ upstream: Prepare for a future where scp(1) uses the SFTP protocol by
- In practice (and assuming upgraded sftp/sftp-server at each end), this
- increases the download buffer 32->64KiB and the upload buffer
- 32->255KiB.
+ default. Replace recently added -M option to select the protocol with -O
+ (olde) and -s (SFTP) flags, and label the -s flag with a clear warning that
+ it will be removed in the near future (so no, don't use it in scripts!).
- Patches from Mike Frysinger; ok dtucker@
+ prompted by/feedback from deraadt@
- OpenBSD-Commit-ID: ebd61c80d85b951b794164acc4b2f2fd8e88606c
+ OpenBSD-Commit-ID: 92ad72cc6f0023c9be9e316d8b30eb6d8d749cfc
-commit 6653c61202d104e59c8e741329fcc567f7bc36b8
+commit bfdd4b722f124a4fa9173d20dd64dd0fc69856be
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Mar 31 21:58:07 2021 +0000
+Date: Mon Aug 9 23:56:36 2021 +0000
- upstream: do not advertise protocol extensions that have been
+ upstream: make scp -3 the default for remote-to-remote copies. It
- disallowed by the command-line options (e.g. -p/-P/-R); ok dtucker@
+ provides a much better and more intuitive user experience and doesn't require
+ exposing credentials to the source host.
- 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
+ thanks naddy@ for catching the missing argument in usage()
+
+ "Yes please!" - markus@
+ "makes a lot of sense" - deraadt@
+ "the right thing to do" - dtucker@
+
+ OpenBSD-Commit-ID: d0d2af5f0965c5192ba5b2fa461c9f9b130e5dd9
-commit 8a9520836e71830f4fccca066dba73fea3d16bda
+commit 2f7a3b51cef689ad9e93d0c6c17db5a194eb5555
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Mar 19 02:22:34 2021 +0000
+Date: Mon Aug 9 23:49:31 2021 +0000
- upstream: return non-zero exit status when killed by signal; bz#3281 ok
+ upstream: make scp in SFTP mode try to use relative paths as much
- dtucker@
+ as possible. Previosuly, it would try to make relative and ~/-rooted paths
+ absolute before requesting transfers.
- OpenBSD-Commit-ID: 117b31cf3c807993077b596bd730c24da9e9b816
+ prompted by and much discussion deraadt@
+ ok markus@
+
+ OpenBSD-Commit-ID: 46639d382ea99546a4914b545fa7b00fa1be5566
-commit 1269b8a686bf1254b03cd38af78167a04aa6ec88
+commit 2ab864010e0a93c5dd95116fb5ceaf430e2fc23c
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Mar 19 02:18:28 2021 +0000
+Date: Mon Aug 9 23:47:44 2021 +0000
- upstream: increase maximum SSH2_FXP_READ to match the maximum
+ upstream: SFTP protocol extension to allow the server to expand
- 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@
+ ~-prefixed paths, in particular ~user ones. Allows scp in sftp mode to accept
+ these paths, like scp in rcp mode does.
- OpenBSD-Commit-ID: 4e67d60d81bde7b84a742b4ee5a34001bdf80d9c
+ prompted by and much discussion deraadt@
+ ok markus@
+
+ OpenBSD-Commit-ID: 7d794def9e4de348e1e777f6030fc9bafdfff392
-commit 860b67604416640e8db14f365adc3f840aebcb1f
+commit 41b019ac067f1d1f7d99914d0ffee4d2a547c3d8
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Mar 16 06:15:43 2021 +0000
+Date: Mon Aug 9 23:44:32 2021 +0000
- upstream: don't let logging clobber errno before use
+ upstream: when scp is in SFTP mode, try to deal better with ~
- OpenBSD-Commit-ID: ce6cca370005c270c277c51c111bb6911e1680ec
+ prefixed paths. ~user paths aren't supported, but ~/ paths will be accepted
+ and prefixed with the SFTP server starting directory (more to come)
+
+ prompted by and discussed with deraadt@
+ ok markus@
+
+ OpenBSD-Commit-ID: 263a071f14555c045fd03132a8fb6cbd983df00d
-commit 5ca8a9216559349c56e09039c4335636fd85c241
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Mar 13 14:40:43 2021 +1100
+commit b4b3f3da6cdceb3fd168b5fab69d11fba73bd0ae
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Aug 9 07:21:01 2021 +0000
- Only call dh_set_moduli_file if using OpenSSL.
+ upstream: on fatal errors, make scp wait for ssh connection before
- Fixes link failure when configuring --without-openssl since dh.c is not
- linked in.
+ exiting avoids LogLevel=verbose (or greater) messages from ssh appearing
+ after scp has returned exited and control has returned to the shell; ok
+ markus@
+
+ (this was originally committed as r1.223 along with unrelated stuff that
+ I rolled back in r1.224)
+
+ OpenBSD-Commit-ID: 1261fd667ad918484889ed3d7aec074f3956a74b
-commit 867a7dcf003c51d5a83f83565771a35f0d9530ac
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Mar 13 13:52:53 2021 +1100
+commit 2ae7771749e0b4cecb107f9d4860bec16c3f4245
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Aug 9 07:19:12 2021 +0000
- Don't install moduli during tests.
+ upstream: rever r1.223 - I accidentally committed unrelated changes
- 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.
+ OpenBSD-Commit-ID: fb73f3865b2647a27dd94db73d6589506a9625f9
-commit 0c054538fccf92b4a028008321d3711107bee6d5
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Mar 13 13:51:26 2021 +1100
+commit 986abe94d481a1e82a01747360bd767b96b41eda
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Aug 9 07:16:09 2021 +0000
- Point TEST_SSH_MODULI_FILE at our own moduli.
+ upstream: show only the final path component in the progress meter;
- This will allow the test to run without requiring a moduli file
- installed at the configured default path.
+ more useful with long paths (that may truncate) and better matches
+ traditional scp behaviour; spotted by naddy@ ok deraadt@
+
+ OpenBSD-Commit-ID: 26b544d0074f03ebb8a3ebce42317d8d7ee291a3
-commit 4d48219c72ab0c71238806f057f0e9630b7dd25c
-Author: jsg@openbsd.org <jsg@openbsd.org>
-Date: Fri Mar 12 05:18:01 2021 +0000
+commit 2b67932bb3176dee4fd447af4368789e04a82b93
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Aug 9 07:13:54 2021 +0000
- upstream: spelling
+ upstream: on fatal errors, make scp wait for ssh connection before
- OpenBSD-Commit-ID: 478bc3db04f62f1048ed6e1765400f3ab325e60f
+ exiting avoids LogLevel=verbose (or greater) messages from ssh appearing
+ after scp has returned exited and control has returned to the shell; ok
+ markus@
+
+ OpenBSD-Commit-ID: ef9dab5ef5ae54a6a4c3b15d380568e94263456c
-commit 88057eb6df912abf2678ea5c846d9d9cbc92752c
+commit 724eb900ace30661d45db2ba01d0f924d95ecccb
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Mar 12 04:08:19 2021 +0000
+Date: Sun Aug 8 08:49:09 2021 +0000
- upstream: Add ModuliFile keyword to sshd_config to specify the
+ upstream: xstrdup environment variable used by ForwardAgent. bz#3328
- 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@
+ from goetze at dovetail.com, ok djm@ deraadt@
- OpenBSD-Commit-ID: 8df99d60b14ecaaa28f3469d01fc7f56bff49f66
+ OpenBSD-Commit-ID: 760320dac1c3b26904284ba417a7d63fccc5e742
-commit f07519a2af96109325b5a48b1af18b57601074ca
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Mar 12 03:43:40 2021 +0000
+commit 86b4cb3a884846b358305aad17a6ef53045fa41f
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sun Aug 8 08:27:28 2021 +0000
- upstream: pwcopy() struct passwd that we're going to reuse across a
+ upstream: Although it's POSIX, not all shells used in Portable support
- bunch of library calls; bz3273 ok dtucker@
+ the implicit 'in "$@"' after 'for i'.
- OpenBSD-Commit-ID: b6eafa977b2e44607b1b121f5de855107809b762
+ OpenBSD-Regress-ID: 3c9aec6bca4868f85d2742b6ba5223fce110bdbc
-commit 69d6d4b0c8a88d3d1288415605f36e2df61a2f12
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Mar 10 06:32:27 2021 +0000
+commit f2ccf6c9f395923695f22345e626dfd691227aaf
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sun Aug 8 17:39:56 2021 +1000
- upstream: Import regenerated moduli file.
+ Move portable specific settings down.
- OpenBSD-Commit-ID: 7ac6c252d2a5be8fbad4c66d9d35db507c9dac5b
+ This brings the top hunk of the file back in sync with OpenBSD
+ so patches to the CVS Id should apply instead of always being
+ rejected.
-commit e5895e8ecfac65086ea6b34d0d168409a66a15e1
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Mar 10 04:58:45 2021 +0000
+commit 71b0eb997e220b0fc9331635af409ad84979f2af
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sun Aug 8 07:27:52 2021 +0000
- upstream: no need to reset buffer after send_msg() as that is done
+ upstream: Move setting of USER further down the startup In portable
- for us; patch from Mike Frysinger
+ we have to change this and having it in the same hunk as the CVS Id string
+ means applying changes fails every. single. time.
- OpenBSD-Commit-ID: 565516495ff8362a38231e0f1a087b8ae66da59c
+ OpenBSD-Regress-ID: 87cd603eb6db58c9b430bf90adacb7f90864429b
-commit 721948e67488767df0fa0db71ff2578ee2bb9210
+commit f0aca2706c710a0da1a4be705f825a807cd15400
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Mar 13 01:52:16 2021 +0000
+Date: Sun Aug 8 06:38:33 2021 +0000
- upstream: Add TEST_SSH_MODULI_FILE variable to allow overriding of the
+ upstream: Drop -q in ssh-log-wrapper.sh to preserve logs.
- moduli file used during the test run.
+ scp and sftp like to add -q to the command line passed to ssh which
+ overrides the LogLevel we set in the config files and suppresses output
+ to the debug logs so drop any "-q" from the invoked ssh. In the one
+ case where we actually want to use -q in the banner test, call the ssh
+ binary directly bypassing the logging wrapper.
- OpenBSD-Regress-ID: be10f785263120edb64fc87db0e0d6570a10220a
+ OpenBSD-Regress-ID: e2c97d3c964bda33a751374c56f65cdb29755b75
-commit 82fef71e20ffef425b932bec26f5bc46aa1ed41c
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Mar 12 15:58:57 2021 +1100
+commit cf27810a649c5cfae60f8ce66eeb25caa53b13bc
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sat Aug 7 01:57:08 2021 +0000
- Allow (but return EACCES) fstatat64 in sandbox.
+ upstream: Fix prototype mismatch for do_cmd. ok djm@
- This is apparently used in some configurations of OpenSSL when glibc
- has getrandom(). bz#3276, patch from Kris Karas, ok djm@
+ OpenBSD-Commit-ID: 1c1598bb5237a7ae0be99152f185e0071163714d
-commit 1cd67ee15ce3d192ab51be22bc4872a6a7a4b6d9
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Mar 12 13:16:10 2021 +1100
+commit 85de69f64665245786e28c81ab01fe18b0e2a149
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Aug 7 01:55:01 2021 +0000
- Move generic includes outside of ifdef.
+ upstream: sftp-client.c needs poll.h
- 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.
+ remove unused variable
+
+ OpenBSD-Commit-ID: 233ac6c012cd23af62f237167a661db391055a16
-commit 2421a567a8862fe5102a4e7d60003ebffd1313dd
+commit 397c4d72e50023af5fe3aee5cc2ad407a6eb1073
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Mar 10 17:41:21 2021 +1100
+Date: Sat Aug 7 11:30:57 2021 +1000
- Import regenerated moduli file.
+ Include poll.h and friends for struct pollfd.
-commit e99080c05d9d48dbbdb022538533d53ae1bd567d
-Author: millert@openbsd.org <millert@openbsd.org>
-Date: Sat Mar 6 20:36:31 2021 +0000
+commit a9e2c533195f28627f205682482d9da384c4c52e
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Aug 7 00:14:17 2021 +0000
- upstream: Fix PRINT macro, the suffix param to sshlog() was missing.
+ upstream: do_upload() used a near-identical structure for
- Also remove redundant __func__ prefix from PRINT calls as the macro already
- adds __FILE__, __func__ and __LINE__. From Christos Zoulas. OK dtucker@
+ tracking expected status replies from the server to what do_download() was
+ using.
- OpenBSD-Commit-ID: 01fdfa9c5541151b5461d9d7d6ca186a3413d949
+ Refactor it to use the same structure and factor out some common
+ code into helper functions.
+
+ OpenBSD-Commit-ID: 0c167df8ab6df4a5292c32421922b0cf379e9054
-commit 160db17fc678ceb5e3fd4a7e006cc73866f484aa
+commit 7b1cbcb7599d9f6a3bbad79d412604aa1203b5ee
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Mar 3 22:41:49 2021 +0000
+Date: Sat Aug 7 00:12:09 2021 +0000
- upstream: don't sshbuf_get_u32() into an enum; reported by goetze
+ upstream: make scp(1) in SFTP mode follow symlinks like
- AT dovetail.com via bz3269
+ traditional scp(1) ok markus@
- OpenBSD-Commit-ID: 99a30a8f1df9bd72be54e21eee5c56a0f050921a
+ OpenBSD-Commit-ID: 97255e55be37e8e26605e4ba1e69f9781765d231
-commit cffd033817a5aa388764b6661855dcdaabab0588
-Author: sthen@openbsd.org <sthen@openbsd.org>
-Date: Wed Mar 3 21:40:16 2021 +0000
+commit 133b44e500422df68c9c25c3b6de35c0263132f1
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Aug 7 00:10:49 2021 +0000
- upstream: typo in other_hostkeys_message() display output, ok djm
+ upstream: fix incorrect directory permissions on scp -3
- OpenBSD-Commit-ID: 276f58afc97b6f5826e0be58380b737603dbf5f5
+ transfers; ok markus@
+
+ OpenBSD-Commit-ID: 64b2abaa5635a2be65ee2e77688ad9bcebf576c2
-commit 7fe141b96b13bd7dc67ca985e14d55b9bd8a03fd
+commit 98b59244ca10e62ff67a420856770cb700164f59
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Mar 3 08:42:52 2021 +0000
+Date: Sat Aug 7 00:09:57 2021 +0000
- upstream: needs FILE*; from Mike Frysinger
+ upstream: a bit more debugging of file attributes being
- OpenBSD-Commit-ID: dddb3aa9cb5792eeeaa37a1af67b5a3f25ded41d
+ sent/received over the wire
+
+ OpenBSD-Commit-ID: f68c4e207b08ef95200a8b2de499d422808e089b
-commit d2afd717e62d76bb41ab5f3ab4ce6f885c8edc98
-Author: Damien Miller <djm@mindrot.org>
-Date: Tue Mar 2 21:31:47 2021 +1100
+commit c677e65365d6f460c084e41e0c4807bb8a9cf601
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Aug 7 00:08:52 2021 +0000
- update depend
+ upstream: make scp(1) in SFTP mode output better match original
+
+ scp(1) by suppressing "Retrieving [path]" lines that were emitted to support
+ the interactive sftp(1) client. ok markus@
+
+ OpenBSD-Commit-ID: 06be293df5f156a18f366079be2f33fa68001acc
-commit f0c4eddf7cf224ebcac1f07ac8afdb30c6e9fe0a
-Author: Damien Miller <djm@mindrot.org>
-Date: Tue Mar 2 21:30:14 2021 +1100
+commit 48cd39b7a4e5e7c25101c6d1179f98fe544835cd
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Aug 7 00:07:18 2021 +0000
- update relnotes URL
+ upstream: factor out a structure duplicated between downloading
+
+ and crossloading; ok markus@
+
+ OpenBSD-Commit-ID: 96eede24d520569232086a129febe342e4765d39
-commit 67a8bb7fe62a381634db4c261720092e7d514a3d
-Author: Damien Miller <djm@mindrot.org>
-Date: Tue Mar 2 21:29:54 2021 +1100
+commit 318c06bb04ee21a0cfa6b6022a201eacaa53f388
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Aug 7 00:06:30 2021 +0000
- update RPM spec version numbers
+ upstream: use sftp_client crossloading to implement scp -3
+
+ feedback/ok markus@
+
+ OpenBSD-Commit-ID: 7db4c0086cfc12afc9cfb71d4c2fd3c7e9416ee9
-commit 0a4b23b11b9a4e6eec332dd5c6ab2ac6f62aa164
+commit de7115b373ba0be3861c65de9b606a3e0e9d29a3
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Mar 2 01:48:18 2021 +0000
+Date: Sat Aug 7 00:02:41 2021 +0000
- upstream: openssh-8.5
+ upstream: support for "cross"-loading files/directories, i.e.
- OpenBSD-Commit-ID: 185e85d60fe042b8f8fa1ef29d4ef637bdf397d6
+ downloading from one SFTP server while simultaneously uploading to another.
+
+ feedback & ok markus@
+
+ OpenBSD-Commit-ID: 3982878e29d8df0fa4ddc502f5ff6126ac714235
-commit de3866383b6720ad4cad83be76fe4c8aa111a249
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Mar 1 21:13:24 2021 +1100
+commit a50bd0367ff2063bbc70a387740a2aa6914de094
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Aug 7 00:01:29 2021 +0000
- Only upload config logs if configure fails.
+ upstream: factor our SSH2_FXP_OPEN calls into their own function;
+
+ "looks fine" markus@
+
+ OpenBSD-Commit-ID: d3dea2153f08855c6d9dacc01973248944adeffb
-commit 85ff2a564ce838f8690050081176c1de1fb33116
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sun Feb 28 22:56:30 2021 +0000
+commit e3c0ba05873cf3d3f7d19d595667a251026b2d84
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Aug 7 00:00:33 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
+ upstream: prepare for scp -3 implemented via sftp
- OpenBSD-Commit-ID: 9c87f39a048cee2a7d1c8bab951b2f716256865e
+ OpenBSD-Commit-ID: 194aac0dd87cb175334b71c2a30623a5ad55bb44
-commit e774bac35933e71f924f4301786e7fb5bbe1422f
+commit 395d8fbdb094497211e1461cf0e2f80af5617e0a
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sun Feb 28 01:50:47 2021 +0000
+Date: Fri Aug 6 09:00:18 2021 +0000
- upstream: Do not try to reset signal handler for signal 0 in
+ upstream: Make diff invocation more portable.
- subprocess. Prevents spurious debug message. ok djm@
+ POSIX does not require diff to have -N, so compare in both directions
+ with just -r, which should catch missing files in either directory.
- OpenBSD-Commit-ID: 7f9785e292dcf304457566ad4637effd27ad1d46
+ OpenBSD-Regress-ID: 0e2ec8594556a6f369ed5a0a90c6806419b845f7
-commit 351c5dbbd74ce300c4f058112f9731c867c6e225
+commit d247a73ce27b460138599648d9c637c6f2b77605
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Feb 27 23:42:37 2021 +0000
+Date: Wed Aug 4 21:28:00 2021 +0000
- upstream: fix alphabetic ordering of options; spotted by Iain Morgan
+ upstream: regression test for scp -3
- 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.
+ OpenBSD-Regress-ID: b44375d125c827754a1f722ec6b6b75b634de05d
-commit b7c6ee7b437d9adfd19ef49d6c0f19f13f26f9b3
-Author: Jeffrey H. Johnson <61629094+johnsonjh@users.noreply.github.com>
-Date: Sat Feb 27 01:04:58 2021 +0000
+commit 35c8e41a6f6d8ad76f8d1cd81ac2ea23d0d993b2
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Aug 6 05:04:42 2021 +0000
- Fix punctuatio and typo in README.md.
+ upstream: Document "ProxyJump none". bz#3334.
- Some very minor fixes, missing 's' and punctuation.
+ OpenBSD-Commit-ID: f78cc6f55731f2cd35c3a41d5352ac1ee419eba7
-commit 6248b86074804983e8f7a2058856a516dbfe2924
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Feb 26 16:45:50 2021 +1100
+commit 911ec6411821bda535d09778df7503b92f0eafab
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Wed Aug 4 01:34:55 2021 +0000
- Revert "ssh: optional bind interface if bind address specified."
+ upstream: Allow for different (but POSIX compliant) behaviour of
- This reverts commit 5a878a71a3528c2626aa1d331934fd964782d41c.
+ basename(3) and prevent a use-after-free in that case in the new sftp-compat
+ code.
- Apologies - I accidentally pushed this.
+ POSIX allows basename(3) to either return a pointer to static storage
+ or modify the passed string and return a pointer to that. OpenBSD does
+ the former and works as is, but on other platforms "filename" points
+ into "tmp" which was just freed. This makes the freeing of tmp
+ consistent with the other variable in the loop.
+
+ Pinpointed by the -portable Valgrind regress test. ok djm@ deraadt@
+
+ OpenBSD-Commit-ID: 750f3c19bd4440e4210e30dd5d7367386e833374
-commit 493339a940b13be6071629c3c2dd5a3b6fc17023
+commit 6df1fecb5d3e51f3a8027a74885c3a44f6cbfcbd
Author: Damien Miller <djm@mindrot.org>
-Date: Fri Feb 26 15:45:38 2021 +1100
+Date: Wed Aug 4 11:05:11 2021 +1000
- 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@
+ use openbsd-compat glob.h is required
-commit 5a878a71a3528c2626aa1d331934fd964782d41c
-Author: Dmitrii Turlupov <dturlupov@factor-ts.ru>
-Date: Thu Feb 4 16:27:31 2021 +0300
+commit 9ebd1828881dfc9014a344587934a5ce7db6fa1b
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Aug 3 21:03:23 2021 +1000
- ssh: optional bind interface if bind address specified.
+ Missing space between macro arg and punctuation.
- Allows the -b and -B options to be used together.
- For example, when the interface is in the VRF.
+ From jmc@
-commit 1fe4d70df94d3bcc2b35fd57cad6b5fc4b2d7b16
+commit 0fd3f62eddc7cf54dcc9053be6f58998f3eb926a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Aug 3 21:02:33 2021 +1000
+
+ Avoid lines >80 chars. From jmc@
+
+commit af5d8094d8b755e1daaf2e20ff1dc252800b4c9b
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Feb 26 04:18:42 2021 +0000
+Date: Tue Aug 3 01:05:24 2021 +0000
- upstream: remove this KEX fuzzer; it's awkward to use and doesn't play
+ upstream: regression tests for scp SFTP protocol support; mostly by
- nice with popular fuzzing drivers like libfuzzer. AFAIK nobody has used it
- but me.
+ Jakub Jelen in GHPR#194 ok markus
- OpenBSD-Regress-ID: cad919522b3ce90c147c95abaf81b0492ac296c9
+ OpenBSD-Regress-ID: 36f1458525bcb111741ec8547eaf58b13cddc715
-commit 24a3a67bd7421740d08803b84bd784e764107928
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 26 11:49:19 2021 +1100
+commit e4673b7f67ae7740131a4ecea29a846593049a91
+Author: anton@openbsd.org <anton@openbsd.org>
+Date: Thu Jul 29 15:34:09 2021 +0000
- Remove macos-11.00 PAM test target too.
+ upstream: Treat doas with arguments as a valid SUDO variable.
- These are failing apparently due to some kind of infrastructure problem,
- making it look like every commit is busted.
+ Allows one to specify SUDO="doas -n" which I do while running make regress.
+
+ ok dtucker@
+
+ OpenBSD-Regress-ID: 4fe5814b5010dbf0885500d703bea06048d11005
-commit 473201783f732ca8b0ec528b56aa55fa0d8cf717
+commit 197e29f1cca190d767c4b2b63a662f9a9e5da0b3
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Feb 26 00:16:58 2021 +0000
+Date: Mon Aug 2 23:38:27 2021 +0000
- upstream: a bit more debugging behind #ifdef DEBUG_SK
+ upstream: support for using the SFTP protocol for file transfers in
- 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.
+ scp, via a new "-M sftp" option. Marked as experimental for now.
- 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
+ Some corner-cases exist, in particular there is no attempt to
+ provide bug-compatibility with scp's weird "double shell" quoting
+ rules.
- SSH-Copy-ID-Upstream: 78178aa5017222773e4c23d9001391eeaeca8983
+ Mostly by Jakub Jelen in GHPR#194 with some tweaks by me. ok markus@
+ Thanks jmc@ for improving the scp.1 bits.
+
+ OpenBSD-Commit-ID: 6ce4c9157ff17b650ace571c9f7793d92874051c
-commit 983e05ef3b81329d76d6a802b39ad0d1f637c06c
-Author: Jakub Jelen <jjelen@redhat.com>
-Date: Tue Sep 29 10:02:45 2020 +0000
+commit dd533c7ab79d61a7796b77b64bd81b098e0d7f9f
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Fri Jul 30 14:28:13 2021 +0000
- if unable to add a missing newline, fail
+ upstream: fix a formatting error and add some Xr; from debian at
- SSH-Copy-ID-Upstream: 76b25e18f55499ea9edb4c4d6dc4a80bebc36d95
+ helgefjell de
+
+ removed references to rlogin etc. as no longer relevant;
+ suggested by djm
+
+ ok djm dtucker
+
+ OpenBSD-Commit-ID: 3c431c303068d3aec5bb18573a0bd5e0cd77c5ae
-commit 3594b3b015f6014591da88ba71bf6ff010be7411
-Author: Philip Hands <phil@hands.com>
-Date: Tue Oct 13 14:12:58 2020 +0200
+commit c7cd347a8823819411222c1e10a0d26747d0fd5c
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Fri Jul 30 14:25:01 2021 +0000
- use $AUTH_KEY_DIR, now that we have it
+ upstream: fix a formatting error and mark up known_hosts
- since that was a change made since jjelen's commit was written
+ consistently; issues reported by debian at helgefjell de
- also, quote the variables
+ ok djm dtucker
- SSH-Copy-ID-Upstream: 588cd8e5cbf95f3443d92b9ab27c5d73ceaf6616
+ OpenBSD-Commit-ID: a1fd8d21dc77f507685443832df0c9700481b0ce
-commit 333e25f7bc43cee6e36f766e39dad6f9918b318c
-Author: Jakub Jelen <jjelen@redhat.com>
-Date: Tue Sep 29 10:00:01 2020 +0000
+commit 4455aec2e4fc90f64ae4fc47e78ebc9c18721738
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Wed Jul 28 05:57:42 2021 +0000
- restorecon the correct directory
+ upstream: no need to talk about version 2 with the -Q option, so
- if using different path for authorized_keys file
+ rewrite the text to read better;
- SSH-Copy-ID-Upstream: 791a3df47b48412c726bff6f7b1d190721e65d51
+ issue reported by debian at helgefjell de
+ ok djm dtucker
+
+ OpenBSD-Commit-ID: 59fe2e8219c37906740ad062e0fdaea487dbe9cf
-commit 9beeab8a37a49a9e3ffb1972fff6621ee5bd7a71
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Feb 25 03:27:34 2021 +0000
+commit bec429338e9b30d2c7668060e82608286a8a4777
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Tue Jul 27 14:28:46 2021 +0000
- upstream: s/PubkeyAcceptedKeyTypes/PubkeyAcceptedAlgorithms/
+ upstream: word fix; reported by debian at helgefjell de
- OpenBSD-Regress-ID: 3dbc005fa29f69dc23d97e433b6dffed6fe7cb69
+ OpenBSD-Commit-ID: 0c6fd22142422a25343c5bd1a618f31618f41ece
-commit 2dd9870c16ddbd83740adeead5030d6840288c8f
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Feb 24 23:12:35 2021 +0000
+commit efad4deb5a1f1cf79ebefd63c6625059060bfbe1
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Tue Jul 27 14:14:25 2021 +0000
- upstream: Rename pubkeyacceptedkeytypes to pubkeyacceptedalgorithms in
+ upstream: standardise the grammar in the options list; issue
- test to match change to config-dump output.
+ reported by debian at helgefjell de
- OpenBSD-Regress-ID: 74c9a4ad50306be873d032819d5e55c24eb74d5d
+ ok dtucker djm
+
+ OpenBSD-Commit-ID: 7ac15575045d82f4b205a42cc7d5207fe4c3f8e6
-commit b9225c3a1c3f5827e31d5d64a71b8e0504a25619
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Feb 24 01:18:08 2021 +0000
+commit 1e11fb24066f3fc259ee30db3dbb2a3127e05956
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Aug 2 18:56:29 2021 +1000
- 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
+ Check for RLIMIT_NOFILE before trying to use it.
-commit 8b8b60542d6652b2c91e0ef9e9cc81bcb65e6b42
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Feb 23 21:55:08 2021 +0000
+commit 0f494236b49fb48c1ef33669f14822ca4f3ce2f4
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Jul 27 17:45:34 2021 +1000
- upstream: lots more s/key types/signature algorithms/ mostly in
-
- HostbasedAcceptedAlgorithms and HostKeyAlgorithms; prompted by Jakub Jelen
+ lastenv is only used in setenv.
- OpenBSD-Commit-ID: 3f719de4385b1a89e4323b2549c66aae050129cb
+ Prevents an unused variable warning on platforms that have setenv but
+ not unsetenv.
-commit 0aeb508aaabc4818970c90831e3d21843c3c6d09
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Feb 23 21:50:18 2021 +0000
+commit a1f78e08bdb3eaa88603ba3c6e01de7c8671e28a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Jul 26 12:45:30 2021 +1000
- upstream: Correct reference to signature algorithms as keys; from
-
- Jakub Jelen
+ Move SUDO to "make test" command line.
- OpenBSD-Commit-ID: 36f7ecee86fc811aa0f8e21e7a872eee044b4be5
+ Environment variables don't get passed by vmrun, so move to command
+ line.
-commit f186a020f2ba5f9c462a23293750e29ba0a746b1
+commit 02e624273b9c78a49a01239159b8c09b8409b1a0
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Feb 23 16:05:22 2021 +1100
+Date: Sun Jul 25 23:26:36 2021 +1000
- Add a couple more test VMs.
+ Set SUDO for tests and cleanup.
-commit ffcdd3d90e74176b3bb22937ad1f65a6c1cd3f9d
+commit 460ae5d93051bab70239ad823dd784822d58baad
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Feb 22 08:09:27 2021 +1100
+Date: Sun Jul 25 22:37:55 2021 +1000
- Valgrind test: split and move up list.
+ Pass OPENSSL=no to make tests too.
+
+commit b398f499c68d74ebe3298b73757cf3f36e14e0cb
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sun Jul 25 12:27:37 2021 +0000
+
+ upstream: Skip unit and makefile-based key conversion tests when
- 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.
+ we're building with OPENSSL=no.
+
+ OpenBSD-Regress-ID: 20455ed9a977c93f846059d1fcb48e29e2c8d732
-commit c3b1636770785cc2830dedd0f22ef7d3d3491d6d
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Feb 23 00:05:31 2021 +0000
+commit 727ce36c8c5941bde99216d27109405907caae4f
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sun Jul 25 12:13:03 2021 +0000
- upstream: warn when the user specifies a ForwardAgent path that does
+ upstream: Replace OPENSSL as the variable that points to the
- not exist and exit if ExitOnForwardFailure is set; bz3264
+ openssl binary with OPENSSL_BIN. This will allow us to use the OPENSSL
+ variable from mk.conf or the make(1) command line indicating if we're
+ building with our without OpenSSL, and ultimately get the regress tests
+ working in the OPENSSL=no configuration.
- OpenBSD-Commit-ID: 72f7875865e723e464c71bf8692e83110699bf26
+ OpenBSD-Regress-ID: 2d788fade3264d7803e5b54cae8875963f688c4e
-commit 5fcb0514949d61aadaf4a89cf16eb78fb47491ec
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Feb 20 13:34:02 2021 +1100
+commit 55e17101a9075f6a63af724261c5744809dcb95c
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sat Jul 24 02:57:28 2021 +0000
- Disable rlimit sandbox, doesn't work with valgrind
+ upstream: Skip RFC4716 format import and export tests when built
- Only run regress tests, runing unit tests as well makes it run longer
- than allowed y github.
+ without OpenSSL.
+
+ OpenBSD-Regress-ID: d2c2d5d38c1acc2b88cc99cfe00a2eb8bb39dfa4
-commit bb0b9bf45396c19486080d3eb0a159f94de7e6ba
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Feb 20 13:06:25 2021 +1100
+commit f5ccb5895d39cd627ad9e7b2c671d2587616100d
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sat Jul 24 02:51:14 2021 +0000
- Upload valgrind logs on failure.
+ upstream: Don't omit ssh-keygen -y from usage when built without
+
+ OpenSSL. It is actually available, albeit only for ed25519 keys.
+
+ OpenBSD-Commit-ID: 7a254c33d0e6a55c30c6b016a8d298d3cb7a7674
-commit ebb3b75e974cb241c6b9b9f5881b09c7bd32b651
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 19 22:18:50 2021 +1100
+commit 819d57ac23469f1f03baa8feb38ddefbada90fdc
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sat Jul 24 02:08:13 2021 +0000
- Rename "vm" to "os" in selfhosted to match c-cpp.
+ upstream: Exclude key conversion options from usage when built
- Should make it easier to share code or maybe merge at some point.
+ without OpenSSL since those are not available, similar to what we currently
+ do with the moduli screening options. We can also use this to skip the
+ conversion regression tests in this case.
+
+ OpenBSD-Commit-ID: 3c82caa398cf99cd4518c23bba5a2fc66b16bafe
-commit 76c0be0fe0465cb2b975dbd409f8d38b55e55bcb
+commit b6673b1d2ee90b4690ee84f634efe40225423c38
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 19 22:15:22 2021 +1100
+Date: Sat Jul 24 13:02:51 2021 +1000
- Upload regress failure logs in c-cpp too.
+ Test OpenBSD upstream with and without OpenSSL.
-commit 8751b6c3136f5225c40f41bbf29aa29e15795f6e
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 19 22:13:36 2021 +1100
+commit 9d38074b5453c1abbdf888e80828c278d3b886ac
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Jul 24 01:54:23 2021 +0000
- Comment out Solaris 64bit PAM build...
+ upstream: test for first-match-wins in authorized_keys environment=
- until I can figure out why it's failing.
+ options
+
+ OpenBSD-Regress-ID: 1517c90276fe84b5dc5821c59f88877fcc34c0e8
-commit e9f6d563c06886b277c6b9abafa99fa80726dc48
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 19 10:20:17 2021 +1100
+commit 2b76f1dd19787e784711ea297ad8fc938b4484fd
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jul 23 05:53:02 2021 +0000
- Actually run Valgrind tests.
+ upstream: Simplify keygen-convert by using $SSH_KEYTYPES directly.
+
+ OpenBSD-Regress-ID: cdbe408ec3671ea9ee9b55651ee551370d2a4108
-commit 41d232e226624f1a81c17091c36b44c9010aae62
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Feb 19 10:16:56 2021 +1100
+commit 7d64a9fb587ba9592f027f7a2264226c713d6579
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Jul 24 01:55:19 2021 +0000
- Add test against Valgrind.
+ upstream: don't leak environment= variable when it is not the first
+
+ match
+
+ OpenBSD-Commit-ID: 7fbdc3dfe0032deaf003fd937eeb4d434ee4efe0
-commit e6528d91f12fba05f0ea64224091c9d0f38bdf1d
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Feb 18 16:30:01 2021 +1100
+commit db2130e2340bf923e41c791aa9cd27b9e926042c
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Fri Jul 23 06:01:17 2021 +0000
- Add fbsd12 test target.
+ upstream: punctuation;
+
+ OpenBSD-Commit-ID: 64be152e378c45975073ab1c07e0db7eddd15806
-commit 6506cb2798d98ff03a7cc06567c392a81f540680
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Feb 18 15:21:13 2021 +1100
+commit 03190d10980c6fc9124e988cb2df13101f266507
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jul 23 05:56:47 2021 +0000
- Remove unused arg.
+ upstream: mention in comment that read_passphrase(..., RP_ALLOW_STDIN)
+
+ will try to use askpass first. bz3314
+
+ convert a couple of debug() -> debug_f() while here
+
+ OpenBSD-Commit-ID: c7e812aebc28fcc5db06d4710e0f73613dee545c
-commit 93c31a623973b0fad508214593aab6ca94b11dcb
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Feb 18 14:54:07 2021 +1100
+commit 1653ece6832b2b304d46866b262d5f69880a9ec7
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jul 23 05:07:16 2021 +0000
- Add DEBUG_SK to kitchensink builds.
+ upstream: Test conversion of ed25519 and ecdsa keys too.
+
+ OpenBSD-Regress-ID: 3676d2d00e58e0d6d37f2878f108cc2b83bbe4bb
-commit 65085740d3574eeb3289d592f042df62c2689bb0
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Feb 18 14:53:14 2021 +1100
+commit 8b7af02dcf9d2b738787efd27da7ffda9859bed2
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jul 23 04:56:21 2021 +0000
- Add bbone test target (arm32).
+ upstream: Add test for exporting pubkey from a passphrase-protected
+
+ private key.
+
+ OpenBSD-Regress-ID: da99d93e7b235fbd5b5aaa01efc411225e6ba8ac
-commit 63238f5aed66148b8d6ca7bd5fb347d624200155
+commit 441095d4a3e5048fe3c87a6c5db5bc3383d767fb
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Feb 18 02:49:35 2021 +0000
+Date: Fri Jul 23 03:54:55 2021 +0000
- upstream: Fix the hostkeys rotation extension documentation
+ upstream: regression test for time-limited signature keys
- The documentation was lacking the needed want-reply field in the initial
- global request.
+ OpenBSD-Regress-ID: 2a6f3bd900dbee0a3c96f1ff23e032c93ab392bc
+
+commit 9e1882ef6489a7dd16b6d7794af96629cae61a53
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jul 23 05:24:02 2021 +0000
+
+ upstream: note successful authentication method in final "Authenticated
- https://github.com/openssh/openssh-portable/pull/218 by dbussink
+ to ..." message and partial auth success messages (all at LogLevel=verbose)
+ ok dtucker@
- OpenBSD-Commit-ID: 051824fd78edf6d647a0b9ac011bf88e28775054
+ OpenBSD-Commit-ID: 06834b89ceb89f8f16c5321d368a66c08f441984
-commit 34c5ef6e2d06d9f0e20cb04a9aebf67a6f96609a
+commit a917e973a1b90b40ff1e950df083364b48fc6c78
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Feb 18 02:15:07 2021 +0000
+Date: Fri Jul 23 04:04:52 2021 +0000
- upstream: make names in function prototypes match those in
+ upstream: Add a ForkAfterAuthentication ssh_config(5) counterpart
- definition from https://github.com/openssh/openssh-portable/pull/225 by
- ZenithalHourlyRate
+ to the ssh(1) -f flag. Last part of GHPR231 from Volker Diels-Grabsch. ok
+ dtucker
- OpenBSD-Commit-ID: 7c736307bf3f2c7cb24d6f82f244eee959485acd
+ OpenBSD-Commit-ID: b18aeda12efdebe2093d55263c90fe4ea0bce0d3
-commit 88e3d4de31ab4f14cac658e9e0c512043b15b146
+commit e0c5088f1c96a145eb6ea1dee438010da78f9ef5
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Feb 18 02:13:58 2021 +0000
+Date: Fri Jul 23 04:00:59 2021 +0000
- upstream: unbreak SK_DEBUG builds
+ upstream: Add a StdinNull directive to ssh_config(5) that allows
- from https://github.com/openssh/openssh-portable/pull/225 by
- ZenithalHourlyRate
+ the config file to do the same thing as -n does on the ssh(1) commandline.
+ Patch from Volker Diels-Grabsch via GHPR231; ok dtucker
- OpenBSD-Commit-ID: 28d7259ce1b04d025411464decfa2f1a097b43eb
+ OpenBSD-Commit-ID: 66ddf3f15c76796d4dcd22ff464aed1edd62468e
-commit 788cbc5b74a53956ba9fff11e1ca506271a3597f
+commit e3957e21ffdc119d6d04c0b1686f8e2fe052f5ea
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Feb 18 00:30:17 2021 +0000
+Date: Fri Jul 23 03:57:20 2021 +0000
- upstream: sftp-server: implement limits@openssh.com extension
+ upstream: make authorized_keys environment="..." directives
- 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.
+ first-match-wins and more strictly limit their maximum number; prompted by
+ OOM reported by OSS-fuzz (35470).
- Patch from Mike Frysinger; ok dtucker@
+ feedback and ok dtucker@
- OpenBSD-Commit-ID: f96293221e5aa24102d9bf30e4f4ef04d5f4fb51
+ OpenBSD-Commit-ID: 01f63fc10dcd995e7aed9c378ad879161af83121
-commit 324449a68d510720d0e4dfcc8e9e5a702fe6a48f
-Author: Damien Miller <djm@mindrot.org>
-Date: Thu Feb 18 12:06:25 2021 +1100
+commit d0bb1ce731762c55acb95817df4d5fab526c7ecd
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jul 23 03:37:52 2021 +0000
- 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.
+ upstream: Let allowed signers files used by ssh-keygen(1)
- https://github.com/openssl/openssl/issues/13411
+ signatures support key lifetimes, and allow the verification mode to specify
+ a signature time to check at. This is intended for use by git to support
+ signing objects using ssh keys. ok dtucker@
- bz#3238 ok dtucker@
+ OpenBSD-Commit-ID: 3e2c67b7dcd94f0610194d1e8e4907829a40cf31
-commit 845fe9811c047063d935eca89188ed55c993626b
-Author: Damien Miller <djm@mindrot.org>
-Date: Thu Feb 18 11:25:38 2021 +1100
+commit 44142068dc7ef783d135e91ff954e754d2ed432e
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Jul 19 08:48:33 2021 +0000
- 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.
+ upstream: Use SUDO when setting up hostkey.
- Based on FreeBSD PR 37416 via Ed Maste; ok dtucker@
+ OpenBSD-Regress-ID: 990cf4481cab8dad62e90818a9b4b36c533851a7
-commit d0763c8d566119cce84d9806e419badf20444b02
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Feb 18 10:45:27 2021 +1100
+commit 6b67f3f1d1d187597e54a139cc7785c0acebd9a2
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Jul 19 05:08:54 2021 +0000
- Fixing quoting for installing moduli on target guest.
+ upstream: Increase time margin for rekey tests. Should help
+
+ reliability on very heavily loaded hosts.
+
+ OpenBSD-Regress-ID: 4c28a0fce3ea89ebde441d7091464176e9730533
-commit b3afc243bc820f323a09e3218e9ec8a30a3c1933
+commit 7953e1bfce9e76bec41c1331a29bc6cff9d416b8
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Feb 18 10:27:16 2021 +1100
+Date: Mon Jul 19 13:47:51 2021 +1000
- Install moduli on target not host.
+ Add sshfp-connect.sh file missed in previous.
-commit f060c2bc85d59d111fa18a12eb3872ee4b9f7e97
-Author: Damien Miller <djm@mindrot.org>
-Date: Thu Feb 18 10:33:58 2021 +1100
+commit b75a80fa8369864916d4c93a50576155cad4df03
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Jul 19 03:13:28 2021 +0000
- don't free string returned by login_getcapstr(3)
+ upstream: Ensure that all returned SSHFP records for the specified host
- OpenBSD and NetBSD require the caller to free strings returned
- bu the login_* functions, but FreeBSD requires that callers don't.
+ name and hostkey type match instead of only one. While there, simplify the
+ code somewhat and add some debugging. Based on discussion in bz#3322, ok
+ djm@.
+
+ OpenBSD-Commit-ID: 0a6a0a476eb7f9dfe8fe2c05a1a395e3e9b22ee4
+
+commit 1cc1fd095393663cd72ddac927d82c6384c622ba
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Jul 19 02:21:50 2021 +0000
+
+ upstream: Id sync only, -portable already has this.
- Fortunately in this case, we can harmlessly leak as the process is
- about to exec the shell/command.
+ Put dh_set_moduli_file call inside ifdef WITH_OPENSSL. Fixes
+ build with OPENSSL=no.
- From https://reviews.freebsd.org/D28617 via Ed Maste; ok dtucker@
+ OpenBSD-Commit-ID: af54abbebfb12bcde6219a44d544e18204defb15
-commit bc9b0c25703215501da28aa7a6539f96c0fa656f
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Feb 18 10:10:00 2021 +1100
+commit 33abbe2f4153f5ca5c874582f6a7cc91ae167485
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Jul 19 02:46:34 2021 +0000
- Skip unit tests on sol11 to speed things up.
+ upstream: Add test for host key verification via SSHFP records. This
+
+ requires some external setup to operate so is disabled by default (see
+ comments in sshfp-connect.sh).
+
+ OpenBSD-Regress-ID: c52c461bd1df3a803d17498917d156ef64512fd9
-commit 161873035c12cc22211fc73d07170ade47746bc5
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Feb 18 10:09:27 2021 +1100
+commit f0cd000d8e3afeb0416dce1c711c3d7c28d89bdd
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Jul 19 02:29:28 2021 +0000
- Remove SKIP_UNIT as it needs to be a make arg.
+ upstream: Add ed25519 key and test SSHFP export of it. Only test
+
+ RSA SSHFP export if we have RSA functionality compiled in.
+
+ OpenBSD-Regress-ID: b4ff5181b8c9a5862e7f0ecdd96108622333a9af
-commit 1c293868e4b4e8e74e3ea15b8dff90f6b089967a
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Feb 18 10:05:03 2021 +1100
+commit 0075511e27e5394faa28edca02bfbf13b9a6693e
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Jul 19 00:16:26 2021 +0000
- Always intall moduli.
+ upstream: Group keygen tests together.
- Allows us to run tests without falling back to a fixed modulus. Ensure that
- the directory exists.
+ OpenBSD-Regress-ID: 07e2d25c527bb44f03b7c329d893a1f2d6c5c40c
-commit 5c8f41ad100601ec2fdcbccdfe92890c31f81bbe
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Feb 18 09:59:09 2021 +1100
+commit 034828820c7e62652e7c48f9ee6b67fb7ba6fa26
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sun Jul 18 23:10:10 2021 +0000
- Quote SSHD_CONFOPTS in case it contains spaces.
+ upstream: Add test for ssh-keygen printing of SSHFP records.
+
+ OpenBSD-Regress-ID: fde9566b56eeb980e149bbe157a884838507c46b
-commit 4653116c1f5384ea7006e6396d9b53c33d218975
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Feb 18 09:51:18 2021 +1100
+commit 52c3b6985ef1d5dadb4c4fe212f8b3a78ca96812
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Jul 17 00:38:11 2021 +0000
- Fix labels on targets (dots vs underscores).
+ upstream: wrap some long lines
+
+ OpenBSD-Commit-ID: 4f5186b1466656762dae37d3e569438d900c350d
-commit 4512047f57ca3c6e8cd68f0cc69be59e98b25287
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Feb 17 21:47:48 2021 +1100
+commit 43ec991a782791d0b3f42898cd789f99a07bfaa4
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Jul 17 00:36:53 2021 +0000
- More compact representation of config matrix.
+ upstream: fix sftp on ControlPersist connections, broken by recent
+
+ SessionType change; spotted by sthen@
+
+ OpenBSD-Commit-ID: 4c5ddc5698790ae6ff50d2a4f8f832f0eeeaa234
-commit 0406cd09f05c2e419b113dd4c0eac8bc34ec915b
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Feb 17 21:19:18 2021 +1100
+commit 073f45c236550f158c9a94003e4611c07dea5279
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jul 16 09:00:23 2021 +0000
- Skip unit tests on hosted VMs to speed things up.
+ upstream: Explicitly check for and start time-based rekeying in the
+
+ client and server mainloops.
+
+ Previously the rekey timeout could expire but rekeying would not start
+ until a packet was sent or received. This could cause us to spin in
+ select() on the rekey timeout if the connection was quiet.
+
+ ok markus@
+
+ OpenBSD-Commit-ID: 4356cf50d7900f3df0a8f2117d9e07c91b9ff987
-commit 4582612e6147d766c336198c498740242fb8f1ec
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Feb 17 20:21:29 2021 +1100
+commit ef7c4e52d5d840607f9ca3a302a4cbb81053eccf
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Wed Jul 14 06:46:38 2021 +0000
- Merge macos and ubuntu tests.
+ upstream: reorder SessionType; ok djm
+
+ OpenBSD-Commit-ID: c7dd0b39e942b1caf4976a0b1cf0fed33d05418c
-commit 09f4b84654b71099559492e9aed5e1a38bf24815
+commit 8aa2f9aeb56506dca996d68ab90ab9c0bebd7ec3
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Feb 17 18:41:30 2021 +1100
+Date: Wed Jul 14 11:26:50 2021 +1000
- Convert most github hosted tests to new config structure.
+ Make whitespace consistent.
-commit 65380ff7e054be1454e5ab4fd7bb9c66f8fcbaa9
+commit 4f4297ee9b8a39f4dfd243a74c5f51f9e7a05723
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Feb 17 18:27:36 2021 +1100
+Date: Wed Jul 14 11:26:12 2021 +1000
- Only run selfhosted tests from selfhosted repo.
+ Add ARM64 Linux self-hosted runner.
-commit f031366535650b88248ed7dbf23033afdf466240
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jan 15 14:11:43 2021 +1100
+commit eda8909d1b0a85b9c3804a04d03ec6738fd9dc7f
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Jul 13 23:48:36 2021 +0000
- 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.
+ upstream: add a SessionType directive to ssh_config, allowing the
- 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.
+ configuration file to offer equivalent control to the -N (no session) and -s
+ (subsystem) command-line flags.
- 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.
+ Part of GHPR#231 by Volker Diels-Grabsch with some minor tweaks;
+ feedback and ok dtucker@
- [0] https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners#self-hosted-runner-security-with-public-repositories
+ OpenBSD-Commit-ID: 726ee931dd4c5cc7f1d7a187b26f41257f9a2d12
-commit 64bbd7444d658ef7ee14a7ea5ccc7f5810279ee7
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Feb 17 03:59:00 2021 +0000
+commit 7ae69f2628e338ba6e0eae7ee8a63bcf8fea7538
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Jul 12 02:12:22 2021 +0000
- upstream: Make sure puttygen is new enough to successfully run the
-
- PuTTY interop tests, otherwise skip them.
+ upstream: fix some broken tests; clean up output
- OpenBSD-Regress-ID: 34565bb50b8aec58331ed02a5e9e0a9a929bef51
+ OpenBSD-Regress-ID: 1d5038edb511dc4ce1622344c1e724626a253566
-commit da0a9afcc446a30ca49dd216612c41ac3cb1f2d4
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Mon Feb 15 20:43:15 2021 +0000
+commit f5fc6a4c3404bbf65c21ca6361853b33d78aa87e
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Jul 12 18:00:05 2021 +1000
- upstream: ssh: add PermitRemoteOpen for remote dynamic forwarding
-
- with SOCKS ok djm@, dtucker@
+ Add configure-time detection for SSH_TIME_T_MAX.
- OpenBSD-Commit-ID: 64fe7b6360acc4ea56aa61b66498b5ecc0a96a7c
+ Should fix printing cert times exceeding INT_MAX (bz#3329) on platforms
+ were time_t is a long long. The limit used is for the signed type, so if
+ some system has a 32bit unsigned time_t then the lower limit will still
+ be imposed and we would need to add some way to detect this. Anyone using
+ an unsigned 64bit can let us know when it starts being a problem.
-commit b696858a7f9db72a83d02cb6edaca4b30a91b386
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Mon Feb 15 20:36:35 2021 +0000
+commit fd2d06ae4442820429d634c0a8bae11c8e40c174
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Jul 12 06:22:57 2021 +0000
- upstream: factor out opt_array_append; ok djm@
+ upstream: Make limit for time_t test unconditional in the
- OpenBSD-Commit-ID: 571bc5dd35f99c5cf9de6aaeac428b168218e74a
+ format_absolute_time fix for bz#3329 that allows printing of timestamps past
+ INT_MAX. This was incorrectly included with the previous commit. Based on
+ discussion with djm@.
+
+ OpenBSD-Commit-ID: 835936f6837c86504b07cabb596b613600cf0f6e
-commit ad74fc127cc45567e170e8c6dfa2cfd9767324ec
-Author: dlg@openbsd.org <dlg@openbsd.org>
-Date: Mon Feb 15 11:09:22 2021 +0000
+commit 6c29b387cd64a57b0ec8ae7d2c8d02789d88fcc3
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Jul 12 06:08:57 2021 +0000
- upstream: ProxyJump takes "none" to disable processing like
-
- ProxyCommand does
+ upstream: Use existing format_absolute_time() function when
- ok djm@ jmc@
+ printing cert validity instead of doing it inline. Part of bz#3329.
- OpenBSD-Commit-ID: 941a2399da2193356bdc30b879d6e1692f18b6d3
+ OpenBSD-Commit-ID: a13d4e3c4f59644c23745eb02a09b2a4e717c00c
-commit 16eacdb016ccf38dd9959c78edd3a6282513aa53
+commit 99981d5f8bfa383791afea03f6bce8454e96e323
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Feb 12 03:49:09 2021 +0000
+Date: Fri Jul 9 09:55:56 2021 +0000
- upstream: sftp: add missing lsetstat@openssh.com documentation
-
- patch from Mike Frysinger
+ upstream: silence redundant error message; reported by Fabian Stelzer
- OpenBSD-Commit-ID: 9c114db88d505864075bfe7888b7c8745549715b
+ OpenBSD-Commit-ID: 9349a703016579a60557dafd03af2fe1d44e6aa2
-commit e04fd6dde16de1cdc5a4d9946397ff60d96568db
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Feb 12 03:14:18 2021 +0000
+commit e86097813419b49d5bff5c4b51d1c3a5d4d2d804
+Author: John Ericson <John.Ericson@Obsidian.Systems>
+Date: Sat Dec 26 11:40:49 2020 -0500
- upstream: factor SSH_AGENT_CONSTRAIN_EXTENSION parsing into its own
-
- function and remove an unused variable; ok dtucker@
-
- OpenBSD-Commit-ID: e1a938657fbf7ef0ba5e73b30365734a0cc96559
+ Re-indent krb5 section after pkg-config addition.
-commit 1bb130ed34721d46452529d094d9bbf045607d79
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Feb 11 10:18:05 2021 +1100
+commit 32dd2daa56c294e40ff7efea482c9eac536d8cbb
+Author: John Ericson <John.Ericson@Obsidian.Systems>
+Date: Sat Dec 26 11:40:49 2020 -0500
- Add __NR_futex_time64 to seccomp sandbox.
+ Support finding Kerberos via pkg-config
- 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.
+ This makes cross compilation easier.
-commit f88a7a431212a16e572ecabd559e632f369c363e
+commit def7a72234d7e4f684d72d33a0f7229f9eee0aa4
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Feb 6 09:37:01 2021 +1100
+Date: Fri Jul 9 14:34:06 2021 +1000
- Add a hostname function for systems that don't have it.
+ Update comments about EGD to include prngd.
+
+commit b5d23150b4e3368f4983fd169d432c07afeee45a
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Jul 5 01:21:07 2021 +0000
+
+ upstream: Fix a couple of whitespace things. Portable already has
- 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.
+ these so this removes two diffs between the two.
+
+ OpenBSD-Commit-ID: 769f017ebafd8e741e337b3e9e89eb5ac73c9c56
-commit 5e385a71ef2317856f37c91a98658eb12eb5a89c
+commit 8f57be9f279b8e905f9883066aa633c7e67b31cf
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Feb 5 22:03:40 2021 +0000
+Date: Mon Jul 5 01:16:46 2021 +0000
- upstream: Roll back the hostname->uname change in rev 1.10. It turns
+ upstream: Order includes as per style(9). Portable already has
- 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.
+ these so this removes a handful of diffs between the two.
- OpenBSD-Regress-ID: 827a707d6201d5a8e196a8c28aec1d2c76c52341
+ OpenBSD-Commit-ID: 8bd7452d809b199c19bfc49511a798f414eb4a77
-commit b446c214279de50ed8388e54897eb1be5281c894
+commit b75624f8733b3ed9e240f86cac5d4a39dae11848
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Feb 5 06:01:58 2021 +0000
+Date: Mon Jul 5 00:50:25 2021 +0000
- upstream: hostname is not specified by POSIX but uname -n is, so use
+ upstream: Remove comment referencing now-removed
- the latter for portability. Patch from Geert Hendrickx via github PR#208.
+ RhostsRSAAuthentication. ok djm@
- OpenBSD-Regress-ID: d6a79c7c4d141a0d05ade4a042eb57dddbce89f3
+ OpenBSD-Commit-ID: 3d864bfbd99a1d4429a58e301688f3be464827a9
-commit 1cb6ce98d658e5fbdae025a3bd65793980e3b5d9
-Author: David Carlier <devnexen@gmail.com>
-Date: Sat Nov 21 12:22:23 2020 +0000
+commit b67eb12f013c5441bb4f0893a97533582ad4eb13
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Jul 5 00:25:42 2021 +0000
- Using explicit_memset for the explicit_bzero compatibility layer.
+ upstream: allow spaces to appear in usernames for local to remote,
- 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.
+ and scp -3 remote to remote copies. with & ok dtucker bz#1164
+
+ OpenBSD-Commit-ID: e9b550f3a85ffbb079b6720833da31317901d6dd
-commit a35d3e911e193a652bd09eed40907e3e165b0a7b
+commit 8c4ef0943e574f614fc7c6c7e427fd81ee64ab87
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Feb 5 02:20:23 2021 +0000
+Date: Fri Jul 2 07:20:44 2021 +0000
- upstream: Remove debug message from sigchld handler. While this
+ upstream: Remove obsolete comments about SSHv1 auth methods. ok
- works on OpenBSD it can cause problems on other platforms. From kircherlike
- at outlook.com via bz#3259, ok djm@
+ djm@
- OpenBSD-Commit-ID: 3e241d7ac1ee77e3de3651780b5dc47b283a7668
+ OpenBSD-Commit-ID: 6060f70966f362d8eb4bec3da2f6c4712fbfb98f
-commit 69338ab46afe9e3dfb7762ad65351d854077c998
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Feb 2 22:36:59 2021 +0000
+commit 88908c9b61bcb99f16e8d398fc41e2b3b4be2003
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Jul 3 23:00:19 2021 +1000
- upstream: whitespace
+ Remove reference to ChallengeResponse.
- OpenBSD-Commit-ID: 544bb092e03fcbecb420196cd0f70af13ea868ad
+ challenge_response_authentication was removed from the struct, keeping
+ kbd_interactive_authentication.
-commit f71219a01d8f71c4b3ed7e456337a84ddba1653e
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Feb 2 22:36:46 2021 +0000
+commit 321874416d610ad2158ce6112f094a4862c2e37f
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Jul 3 20:38:09 2021 +1000
- 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
+ Move signal.h up include order to match upstream.
-commit 3287790e78bf5b53c4a3cafb67bb5aa03e3910f0
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Feb 2 22:35:14 2021 +0000
+commit 4fa83e2d0e32c2dd758653e0359984bbf1334f32
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Jul 3 20:36:06 2021 +1000
- upstream: memleak on error path; ok markus@
+ Remove old OpenBSD version marker.
- OpenBSD-Commit-ID: 2091a36d6ca3980c81891a6c4bdc544e63cb13a8
+ Looks like an accidental leftover from a sync.
-commit 3dd0c64e08f1bba21d71996d635c7256c8c139d1
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Jan 31 22:55:29 2021 +0000
+commit 9d5e31f55d5f3899b72645bac41a932d298ad73b
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Jul 3 20:34:19 2021 +1000
- 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).
+ Remove duplicate error on error path.
- ok markus@
+ There's an extra error() call on the listen error path, it looks like
+ its removal was missed during an upstream sync.
+
+commit 888c459925c7478ce22ff206c9ac1fb812a40caf
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Jul 3 20:32:46 2021 +1000
+
+ Remove some whitespace not in upstream.
- OpenBSD-Commit-ID: 87331c715c095b587d5c88724694cdeb701c9def
+ Reduces diff vs OpenBSD by a small amount.
-commit 7a92a324a2e351fabd0ba8ef9b434d3b12d54ee3
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sun Jan 31 10:50:10 2021 +0000
+commit 4d2d4d47a18d93f3e0a91a241a6fdb545bbf7dc2
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Jul 3 19:27:43 2021 +1000
- upstream: Set linesize returned by getline to zero when freeing and
+ Replace remaining references to ChallengeResponse.
- NULLing the returned string. OpenBSD's getline handles this just fine, but
- some implementations used by -portable do not. ok djm@
+ Portable had a few additional references to ChallengeResponse related to
+ UsePAM, replaces these with equivalent keyboard-interactive ones.
+
+commit 53237ac789183946dac6dcb8838bc3b6b9b43be1
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Jul 3 19:23:28 2021 +1000
+
+ Sync remaining ChallengeResponse removal.
- OpenBSD-Commit-ID: 4d7bd5169d3397654247db9655cc69a9908d165c
+ These were omitted from commit 88868fd131.
-commit a5dfc5bae8c16e2a7caf564758d812c7672480b5
-Author: Damien Miller <djm@mindrot.org>
-Date: Sat Jan 30 16:32:29 2021 +1100
+commit 2c9e4b319f7e98744b188b0f58859d431def343b
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Jul 3 19:17:31 2021 +1000
- allow a fuzz case to contain more than one request
+ Disable rocky84 to figure out why agent test fails
+
+commit bfe19197a92b7916f64a121fbd3c179abf15e218
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Jul 2 15:43:28 2021 +1000
+
+ Remove now-unused SSHv1 enums.
- loop until input buffer empty, no message consumed or 256 messages
- processed
+ sRhostsRSAAuthentication and sRSAAuthentication are protocol 1 options
+ and are no longer used.
-commit 0ef24ad60204022f7e33b6e9d171172c50514132
-Author: Damien Miller <djm@mindrot.org>
-Date: Sat Jan 30 16:28:23 2021 +1100
+commit c73b02d92d72458a5312bd098f32ce88868fd131
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jul 2 05:11:20 2021 +0000
- expect fuzz cases to have length prefix
+ upstream: Remove references to ChallengeResponseAuthentication in
- might make life a little easier for the fuzzer, e.g. it can now
- produce valid (multi-request) messages by smashing two cases together.
+ favour of KbdInteractiveAuthentication. The former is what was in SSHv1, the
+ latter is what is in SSHv2 (RFC4256) and they were treated as somewhat but
+ not entirely equivalent. We retain the old name as deprecated alias so
+ config files continue to work and a reference in the man page for people
+ looking for it.
+
+ Prompted by bz#3303 which pointed out the discrepancy between the two
+ when used with Match. Man page help & ok jmc@, with & ok djm@
+
+ OpenBSD-Commit-ID: 2c1bff8e5c9852cfcdab1f3ea94dfef5a22f3b7e
-commit de613f2713d2dfcd3b03c00e5558a40997f52712
-Author: Damien Miller <djm@mindrot.org>
-Date: Sat Jan 30 12:03:30 2021 +1100
+commit f841fc9c8c7568a3b5d84a4cc0cefacb7dbc16b9
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Jul 2 15:20:32 2021 +1000
- ssh-agent fuzzer
+ Fix ifdefs around get_random_bytes_prngd.
+
+ get_random_bytes_prngd() is used if either of PRNGD_PORT or PRNGD_SOCKET
+ are defined, so adjust ifdef accordingly.
-commit 7e96c877bcb2fb645355a687b8cb7347987c1c58
+commit 0767627cf66574484b9c0834500b42ea04fe528a
Author: Damien Miller <djm@mindrot.org>
-Date: Sat Jan 30 12:02:46 2021 +1100
+Date: Fri Jul 2 14:30:23 2021 +1000
- move keys out of kex_fuzz.cc into separate header
+ wrap get_random_bytes_prngd() in ifdef
- add certificates and missing key types
+ avoid unused static function warning
-commit 76f46d75664fdaa1112739ca523ff85ee4eb52b4
-Author: Damien Miller <djm@mindrot.org>
-Date: Sat Jan 30 12:02:10 2021 +1100
+commit f93fdc4de158386efe1116bd44c5b3f4a7a82c25
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Jun 28 13:06:37 2021 +1000
- some fixed test data (mostly keys) for fuzzing
+ Add rocky84 test target.
-commit 7c2e3d6de1f2edb0c8b4725b4c2b56360e032b19
+commit d443006c0ddfa7f6a5bd9c0ae92036f3d5f2fa3b
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Jan 30 00:56:38 2021 +0000
+Date: Fri Jun 25 06:30:22 2021 +0000
- upstream: add a SK_DUMMY_INTEGRATE define that allows the dummy
+ upstream: fix decoding of X.509 subject name; from Leif Thuresson
- security key middleware to be directly linked; useful for writing fuzzers,
- etc.
+ via bz3327 ok markus@
- OpenBSD-Regress-ID: 0ebd00159b58ebd85e61d8270fc02f1e45df1544
+ OpenBSD-Commit-ID: 0ea2e28f39750dd388b7e317bc43dd997a217ae8
-commit 1a4b92758690faa12f49079dd3b72567f909466d
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jan 29 06:29:46 2021 +0000
+commit 2a5704ec142202d387fda2d6872fd4715ab81347
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jun 25 06:20:39 2021 +0000
- upstream: fix the values of enum sock_type
+ upstream: Use better language to refer to the user. From l1ving
- OpenBSD-Commit-ID: 18d048f4dbfbb159ff500cfc2700b8fb1407facd
+ via github PR#250, ok jmc@
+
+ OpenBSD-Commit-ID: 07ca3526626996613e128aeddf7748c93c4d6bbf
-commit 8afaa7d7918419d3da6c0477b83db2159879cb33
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jan 29 06:28:10 2021 +0000
+commit 4bdf7a04797a0ea1c431a9d54588417c29177d19
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jun 25 03:38:17 2021 +0000
- upstream: give typedef'd struct a struct name; makes the fuzzer I'm
+ upstream: Replace SIGCHLD/notify_pipe kludge with pselect.
- writing a bit easier
+ Previously sshd's SIGCHLD handler would wake up select() by writing a
+ byte to notify_pipe. We can remove this by blocking SIGCHLD, checking
+ for child terminations then passing the original signal mask through
+ to pselect. This ensures that the pselect will immediately wake up if
+ a child terminates between wait()ing on them and the pselect.
- OpenBSD-Commit-ID: 1052ab521505a4d8384d67acb3974ef81b8896cb
+ In -portable, for platforms that do not have pselect the kludge is still
+ there but is hidden behind a pselect interface.
+
+ Based on other changes for bz#2158, ok djm@
+
+ OpenBSD-Commit-ID: 202c85de0b3bdf1744fe53529a05404c5480d813
-commit 1e660115f0c7c4a750cd31e468ff889f33dd8088
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Jan 29 11:09:14 2021 +1100
+commit c9f7bba2e6f70b7ac1f5ea190d890cb5162ce127
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Jun 25 15:08:18 2021 +1000
- fuzz diffie-hellman-group-exchange-sha1 kex too
+ Move closefrom() to before first malloc.
+
+ When built against tcmalloc, tcmalloc allocates a descriptor for its
+ internal use, so calling closefrom() afterward causes the descriptor
+ number to be reused resulting in a corrupted connection. Moving the
+ closefrom a little earlier should resolve this. From kircherlike at
+ outlook.com via bz#3321, ok djm@
-commit be5f0048ea2aaeddd27be7dcca23aaad345fa16c
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Jan 29 11:03:35 2021 +1100
+commit 7ebfe4e439853b88997c9cfc2ff703408a1cca92
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Jun 18 20:41:45 2021 +1000
- support for running kex fuzzer with null cipher
+ Put second -lssh in link line for sftp-server.
+
+ When building --without-openssl the recent port-prngd.c change adds
+ a dependency on atomicio, but since nothing else in sftp-server uses
+ it, the linker may not find it. Add a second -lssh similar to other
+ binaries.
-commit 3d59e88c0e42182c3749b446ccd9027933c84be4
+commit e409d7966785cfd9f5970e66a820685c42169717
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Jan 28 20:55:16 2021 +1100
+Date: Fri Jun 18 18:34:08 2021 +1000
- make with -j2 to use available CPUs.
+ Try EGD/PRNGD if random device fails.
+
+ When built --without-openssl, try EGD/PRGGD (if configured) as a last
+ resort before failing.
-commit 66dd9ddb5d2ea8c407908c8e8468c9d6e71db05b
+commit e43a898043faa3a965dbaa1193cc60e0b479033d
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Jan 28 14:31:01 2021 +1100
+Date: Fri Jun 18 18:32:51 2021 +1000
- Add test against openssl head and libressl head.
+ Split EGD/PRNGD interface into its own file.
+
+ This will allow us to use it when building --without-openssl.
-commit 237dbb34e24b6b7ea888d54bda4d17da0a0fd0fa
+commit acb2887a769a1b1912cfd7067f3ce04fad240260
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu Jan 28 14:30:50 2021 +1100
+Date: Thu Jun 17 21:03:19 2021 +1000
- Remove whitespace.
+ Handle GIDs > 2^31 in getgrouplist.
+
+ When compiled in 32bit mode, the getgrouplist implementation may fail
+ for GIDs greater than LONG_MAX. Analysis and change from ralf.winkel
+ at tui.com.
-commit d983e1732b8135d7ee8d92290d6dce35f736ab88
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Jan 27 23:49:46 2021 +0000
+commit 31fac20c941126281b527605b73bff30a8f02edd
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Thu Jun 10 09:46:28 2021 +0000
- upstream: fix leak: was double allocating kex->session_id buffer
+ upstream: Use $SUDO when reading sshd's pidfile here too.
- OpenBSD-Commit-ID: 3765f4cc3ae1df874dba9102a3588ba7b48b8183
+ OpenBSD-Regress-ID: 6bfb0d455d493f24839034a629c5306f84dbd409
-commit 1134a48cdcef8e7363b9f6c73ebdd24405066738
-Author: Damien Miller <djm@mindrot.org>
-Date: Thu Jan 28 08:57:31 2021 +1100
+commit a3a58acffc8cc527f8fc6729486d34e4c3d27643
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Thu Jun 10 09:43:51 2021 +0000
- correct kex name in disabled code
+ upstream: Use $SUDO when reading sshd's pidfile in case it was
+
+ created with a very restrictive umask. This resyncs with -portable.
+
+ OpenBSD-Regress-ID: 07fd2af06df759d4f64b82c59094accca1076a5d
-commit 67f47f1965abafc1830a287761125c2f4790857e
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Jan 27 10:15:08 2021 +0000
+commit 249ad4ae51cd3bc235e75a4846eccdf8b1416611
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Thu Jun 10 09:37:59 2021 +0000
- upstream: this needs kex.h now
+ upstream: Set umask when creating hostkeys to prevent excessive
- OpenBSD-Commit-ID: c5a42166c5aa002197217421a971e48be7cb5d41
+ permissions warning.
+
+ OpenBSD-Regress-ID: 382841db0ee28dfef7f7bffbd511803e1b8ab0ef
-commit 39be3dc209f28f9c1ebfeba42adde8963b01e1cd
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Jan 27 10:05:28 2021 +0000
+commit 9d0892153c005cc65897e9372b01fa66fcbe2842
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Thu Jun 10 03:45:31 2021 +0000
- upstream: make ssh->kex->session_id a sshbuf instead of u_char*/size_t
+ upstream: Add regress test for SIGHUP restart
- and use that instead of global variables containing copies of it. feedback/ok
- markus@
+ while handling active and unauthenticated clients. Should catch anything
+ similar to the pselect bug just fixed in sshd.c.
- OpenBSD-Commit-ID: a4b1b1ca4afd2e37cb9f64f737b30a6a7f96af68
+ OpenBSD-Regress-ID: 3b3c19b5e75e43af1ebcb9586875b3ae3a4cac73
-commit 4ca6a1fac328477c642329676d6469dba59019a3
+commit 73f6f191f44440ca3049b9d3c8e5401d10b55097
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Thu Jun 10 03:14:14 2021 +0000
+
+ upstream: Continue accept loop when pselect
+
+ returns -1, eg if it was interrupted by a signal. This should prevent
+ the hang discovered by sthen@ wherein sshd receives a SIGHUP while it has
+ an unauthenticated child and goes on to a blocking read on a notify_pipe.
+ feedback deraadt@, ok djm@
+
+ OpenBSD-Commit-ID: 0243c1c5544fca0974dae92cd4079543a3fceaa0
+
+commit c785c0ae134a8e8b5c82b2193f64c632a98159e4
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Jan 27 09:26:53 2021 +0000
+Date: Tue Jun 8 22:30:27 2021 +0000
- upstream: remove global variable used to stash compat flags and use the
+ upstream: test that UserKnownHostsFile correctly accepts multiple
- purpose-built ssh->compat variable instead; feedback/ok markus@
+ arguments; would have caught readconf.c r1.356 regression
- OpenBSD-Commit-ID: 7c4f200e112dae6bcf99f5bae1a5629288378a06
+ OpenBSD-Regress-ID: 71ca54e66c2a0211b04999263e56390b1f323a6a
-commit bba229b6f3328171f5e3ae85de443002523c0452
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Jan 27 12:34:07 2021 +1100
+commit 1a6f6b08e62c78906a3032e8d9a83e721c84574e
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Jun 8 22:06:12 2021 +0000
- Install moduli file before tests.
+ upstream: fix regression in r1.356: for ssh_config options that
- Reduces warnings during test runs.
+ accepted multiple string arguments, ssh was only recording the first.
+ Reported by Lucas via bugs@
+
+ OpenBSD-Commit-ID: 7cbf182f7449bf1cb7c5b4452667dc2b41170d6d
-commit 1b83185593a90a73860a503d753a95ca6d726c00
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Jan 27 11:58:26 2021 +1100
+commit 78e30af3e2b2dd540a341cc827c6b98dd8b0a6de
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Jun 8 07:40:12 2021 +0000
- Run one test with -Werror to catch warnings.
+ upstream: test argv_split() optional termination on comments
+
+ OpenBSD-Regress-ID: 9fd1c4a27a409897437c010cfd79c54b639a059c
-commit d1532d90074b212054d5fd965f833231b09982f5
+commit a023138957ea2becf1c7f93fcc42b0aaac6f2b03
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Jan 27 00:37:26 2021 +0000
+Date: Tue Jun 8 07:05:27 2021 +0000
- upstream: Logical not bitwise or. ok djm@
+ upstream: Add testcases from bz#3319 for IPQoS and TunnelDevice
- OpenBSD-Commit-ID: d4dc855cf04951b93c45caa383e1ac9af0a3b0e5
+ being overridden on the command line.
+
+ OpenBSD-Regress-ID: 801674d5d2d02abd58274a78cab2711f11de14a8
-commit 507b448a2465a53ab03a88acbc71cc51b48ca6ac
-Author: naddy@openbsd.org <naddy@openbsd.org>
-Date: Tue Jan 26 15:40:17 2021 +0000
+commit 660cea10b2cdc11f13ba99c89b1bbb368a4d9ff2
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Jun 8 06:52:43 2021 +0000
- upstream: move HostbasedAcceptedAlgorithms to the right place in
+ upstream: sprinkle some "# comment" at end of configuration lines
- alphabetical order
+ to test comment handling
- OpenBSD-Commit-ID: d766820d33dd874d944c14b0638239adb522c7ec
+ OpenBSD-Regress-ID: cb82fbf40bda5c257a9f742c63b1798e5a8fdda7
-commit e26c980778b228bdd42b8353cc70101cf49b731b
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Jan 26 11:25:01 2021 +0000
+commit acc9c32dcb6def6c7d3688bceb4c0e59bd26b411
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Jun 8 06:51:47 2021 +0000
- upstream: Remove unused variables leftover from refactoring. ok
+ upstream: more descriptive failure message
- djm@
+ OpenBSD-Regress-ID: 5300f6faf1d9e99c0cd10827b51756c5510e3509
+
+commit ce04dd4eae23d1c9cf7c424a702f48ee78573bc1
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Jun 7 01:16:34 2021 +0000
+
+ upstream: test AuthenticationMethods inside a Match block as well
- OpenBSD-Commit-ID: 8b3ad58bff828fcf874e54b2fc27a4cf1d9505e8
+ as in the main config section
+
+ OpenBSD-Regress-ID: ebe0a686621b7cb8bb003ac520975279c28747f7
-commit e9f78d6b06fc323bba1890b2dc3b8423138fb35c
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Jan 26 05:32:21 2021 +0000
+commit 9018bd821fca17e26e92f7a7e51d9b24cd62f2db
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Jun 7 00:00:50 2021 +0000
- upstream: Rename HostbasedKeyTypes (ssh) and
+ upstream: prepare for stricter sshd_config parsing that will refuse
- 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@
+ a config that has {Allow,Deny}{Users,Groups} on a line with no subsequent
+ arguments. Such lines are permitted but are nonsensical noops ATM
- OpenBSD-Commit-ID: 49451c382adc6e69d3fa0e0663eeef2daa4b199e
+ OpenBSD-Regress-ID: ef65463fcbc0bd044e27f3fe400ea56eb4b8f650
-commit 48d0d7a4dd31154c4208ec39029d60646192f978
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Jan 26 14:48:07 2021 +1100
+commit a10f929d1ce80640129fc5b6bc1acd9bf689169e
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Jun 8 07:09:42 2021 +0000
- Disable sntrup761 if compiler doesn't support VLAs.
+ upstream: switch sshd_config parsing to argv_split()
- 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.
+ similar to the previous commit, this switches sshd_config parsing to
+ the newer tokeniser. Config parsing will be a little stricter wrt
+ quote correctness and directives appearing without arguments.
- This should allow OpenSSH to build with a plain C89 compiler again.
- Spotted by tim@, ok djm@.
+ feedback and ok markus@
+
+ tested in snaps for the last five or so days - thanks Theo and those who
+ caught bugs
+
+ OpenBSD-Commit-ID: 9c4305631d20c2d194661504ce11e1f68b20d93e
-commit 37c70ea8d4f3664a88141bcdf0bf7a16bd5fd1ac
+commit ea9e45c89a4822d74a9d97fef8480707d584da4d
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jan 26 00:54:49 2021 +0000
+Date: Tue Jun 8 07:07:15 2021 +0000
- upstream: refactor key constraint parsing in ssh-agent
+ upstream: Switch ssh_config parsing to use argv_split()
- 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.
+ This fixes a couple of problems with the previous tokeniser,
+ strdelim()
+
+ 1. strdelim() is permissive wrt accepting '=' characters. This is
+ intended to allow it to tokenise "Option=value" but because it
+ cannot keep state, it will incorrectly split "Opt=val=val2".
+ 2. strdelim() has rudimentry handling of quoted strings, but it
+ is incomplete and inconsistent. E.g. it doesn't handle escaped
+ quotes inside a quoted string.
+ 3. It has no support for stopping on a (unquoted) comment. Because
+ of this readconf.c r1.343 added chopping of lines at '#', but
+ this caused a regression because these characters may legitimately
+ appear inside quoted strings.
+
+ The new tokeniser is stricter is a number of cases, including #1 above
+ but previously it was also possible for some directives to appear
+ without arguments. AFAIK these were nonsensical in all cases, and the
+ new tokeniser refuses to accept them.
+
+ The new code handles quotes much better, permitting quoted space as
+ well as escaped closing quotes. Finally, comment handling should be
+ fixed - the tokeniser will terminate only on unquoted # characters.
+
+ feedback & ok markus@
+
+ tested in snaps for the last five or so days - thanks Theo and those who
+ caught bugs
+
+ OpenBSD-Commit-ID: dc72fd12af9d5398f4d9e159d671f9269c5b14d5
+
+commit d786424986c04d1d375f231fda177c8408e05c3e
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Jun 8 07:02:46 2021 +0000
+
+ upstream: Check if IPQoS or TunnelDevice are already set before
- ok markus@
+ overriding. Prevents values in config files from overriding values supplied
+ on the command line. bz#3319, ok markus.
- OpenBSD-Commit-ID: 511cb1b1c021ee1d51a4c2d649b937445de7983c
+ OpenBSD-Commit-ID: f3b08b898c324debb9195e6865d8999406938f74
-commit e0e8bee8024fa9e31974244d14f03d799e5c0775
+commit aae4b4d3585b9f944d7dbd3c9e5ba0006c55e457
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jan 26 00:53:31 2021 +0000
+Date: Tue Jun 8 06:54:40 2021 +0000
- upstream: more ssh-agent refactoring
+ upstream: Allow argv_split() to optionally terminate tokenisation
- Allow confirm_key() to accept an additional reason suffix
+ when it encounters an unquoted comment.
- 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.
+ Add some additional utility function for working with argument
+ vectors, since we'll be switching to using them to parse
+ ssh/sshd_config shortly.
- feedback/ok markus@
+ ok markus@ as part of a larger diff; tested in snaps
- OpenBSD-Commit-ID: 29006515617d1aa2d8b85cd2bf667e849146477e
+ OpenBSD-Commit-ID: fd9c108cef2f713f24e3bc5848861d221bb3a1ac
-commit dfe18a295542c169ffde8533b3d7fe42088e2de7
+commit da9f9acaac5bab95dca642b48e0c8182b246ab69
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Jun 7 19:19:23 2021 +1000
+
+ Save logs on failure for upstream test
+
+commit 76883c60161e5f3808787085a27a8c37f8cc4e08
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Jun 7 14:36:32 2021 +1000
+
+ Add obsdsnap-i386 upstream test target.
+
+commit d45b9c63f947ec5ec314696e70281f6afddc0ac3
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jan 26 00:51:30 2021 +0000
+Date: Mon Jun 7 03:38:38 2021 +0000
- upstream: make struct hostkeys public; I have no idea why I made it
-
- opaque originally.
+ upstream: fix debug message when finding a private key to match a
- ok markus@
+ certificate being attempted for user authentication. Previously it would
+ print the certificate's path, whereas it was supposed to be showing the
+ private key's path. Patch from Alex Sherwin via GHPR247
- OpenBSD-Commit-ID: e50780b34d4bbe628d69b2405b024dd749d982f3
+ OpenBSD-Commit-ID: d5af3be66d0f22c371dc1fe6195e774a18b2327b
-commit 3b44f2513cae89c920e8fe927b9bc910a1c8c65a
+commit 530739d42f6102668aecd699be0ce59815c1eceb
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jan 26 00:49:30 2021 +0000
+Date: Sun Jun 6 11:34:16 2021 +0000
- upstream: move check_host_cert() from sshconnect,c to sshkey.c and
-
- refactor it to make it more generally usable and testable.
+ upstream: Match host certificates against host public keys, not private
- ok markus@
+ keys. Allows use of certificates with private keys held in a ssh-agent.
+ Reported by Miles Zhou in bz3524; ok dtucker@
- OpenBSD-Commit-ID: 536f489f5ff38808c1fa711ba58d4579b636f9e4
+ OpenBSD-Commit-ID: 25f5bf70003126d19162862d9eb380bf34bac22a
-commit 1fe16fd61bb53944ec510882acc0491abd66ff76
+commit 4265215d7300901fd7097061c7517688ade82f8e
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jan 26 00:47:47 2021 +0000
+Date: Sun Jun 6 03:40:39 2021 +0000
- upstream: use recallocarray to allocate the agent sockets table;
-
- also clear socket entries that are being marked as unused.
+ upstream: Client-side workaround for a bug in OpenSSH 7.4: this release
- spinkle in some debug2() spam to make it easier to watch an agent
- do its thing.
+ allows RSA/SHA2 signatures for public key authentication but fails to
+ advertise this correctly via SSH2_MSG_EXT_INFO. This causes clients of these
+ server to incorrectly match PubkeyAcceptedAlgorithms and potentially refuse
+ to offer valid keys.
- ok markus
+ Reported by and based on patch from Gordon Messmer via bz3213, thanks
+ also for additional analysis by Jakub Jelen. ok dtucker
- OpenBSD-Commit-ID: 74582c8e82e96afea46f6c7b6813a429cbc75922
+ OpenBSD-Commit-ID: d6d0b7351d5d44c45f3daaa26efac65847a564f7
-commit cb7b22ea20a01332c81c0ddcb3555ad50de9cce2
+commit bda270d7fb8522d43c21a79a4b02a052d7c64de8
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jan 26 00:46:17 2021 +0000
+Date: Sun Jun 6 03:17:02 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
+ upstream: degrade gracefully if a sftp-server offers the
- ok markus@
+ limits@openssh.com extension but fails when the client tries to invoke it.
+ Reported by Hector Martin via bz3318
- OpenBSD-Commit-ID: e0c1f4d5e6cfa525d62581e2b8de93be0cb85adb
+ OpenBSD-Commit-ID: bd9d1839c41811616ede4da467e25746fcd9b967
-commit d1e578afe7cd48140ad6e92a453f9b035363fd7f
+commit d345d5811afdc2d6923019b653cdd93c4cc95f76
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Jan 25 06:00:17 2021 +0000
+Date: Sun Jun 6 03:15:39 2021 +0000
- upstream: make ssh hostbased authentication send the signature
+ upstream: the limits@openssh.com extension was incorrectly marked
- 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.
+ as an operation that writes to the filesystem, which made it unavailable in
+ sftp-server read-only mode. Spotted by Hector Martin via bz3318
- spotted with dtucker@ ok markus@
+ OpenBSD-Commit-ID: f054465230787e37516c4b57098fc7975e00f067
+
+commit 2b71010d9b43d7b8c9ec1bf010beb00d98fa765a
+Author: naddy@openbsd.org <naddy@openbsd.org>
+Date: Sat Jun 5 13:47:00 2021 +0000
+
+ upstream: PROTOCOL.certkeys: update reference from IETF draft to
- OpenBSD-Commit-ID: 25bffe19f0326972f5728170f7da81d5f45c78c6
+ RFC
+
+ Also fix some typos.
+ ok djm@
+
+ OpenBSD-Commit-ID: 5e855b6c5a22b5b13f8ffa3897a868e40d349b44
-commit 95eca1e195a3b41baa1a725c2c5af8a09d885e4b
+commit aa99b2d9a3e45b943196914e8d8bf086646fdb54
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Jan 23 18:26:05 2021 +1100
+Date: Fri Jun 4 23:41:29 2021 +1000
- ifdef new instance of sin6_scope_id
+ Clear notify_pipe from readset if present.
- Put inside HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID similar to
- existing instance. Should fix error on UnixWare 7.
+ Prevents leaking an implementation detail to the caller.
-commit 6ffdcdda128045226dda7fbb3956407978028a1e
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jan 18 11:43:34 2021 +0000
+commit 6de8dadf6b4d0627d35bca0667ca44b1d61c2c6b
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Jun 4 23:24:25 2021 +1000
- upstream: Fix long->int for convtime tests here too. Spotted by
+ space->tabs.
+
+commit c8677065070ee34c05c7582a9c2f58d8642e552d
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Jun 4 18:39:48 2021 +1000
+
+ Add pselect implementation for platforms without.
- tobhe@.
+ This is basically the existing notify_pipe kludge from serverloop.c
+ moved behind a pselect interface. It works by installing a signal
+ handler that writes to a pipe that the select is watching, then calls
+ the original handler.
- OpenBSD-Regress-ID: a87094f5863312d00938afba771d25f788c849d0
+ The select call in serverloop will become pselect soon, at which point the
+ kludge will be removed from thereand will only exist in the compat layer.
+ Original code by markus, help from djm.
-commit b55b7565f15327d82ad7acbddafa90b658c5f0af
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jan 22 02:46:40 2021 +0000
+commit 7cd7f302d3a072748299f362f9e241d81fcecd26
+Author: Vincent Brillault <vincent.brillault@cern.ch>
+Date: Sun May 24 09:15:06 2020 +0200
- upstream: PubkeyAcceptedKeyTypes->PubkeyAcceptedAlgorithms
-
- here too.
+ auth_log: dont log partial successes as failures
- OpenBSD-Commit-ID: 3b64a640f8ce8c21d9314da9df7ce2420eefde3a
+ By design, 'partial' logins are successful logins, so initially with
+ authenticated set to 1, for which another authentication is required. As
+ a result, authenticated is always reset to 0 when partial is set to 1.
+ However, even if authenticated is 0, those are not failed login
+ attempts, similarly to attempts with authctxt->postponed set to 1.
-commit ee9c0da8035b3168e8e57c1dedc2d1b0daf00eec
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jan 22 02:44:58 2021 +0000
+commit e7606919180661edc7f698e6a1b4ef2cfb363ebf
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jun 4 06:19:07 2021 +0000
- upstream: Rename PubkeyAcceptedKeyTypes keyword to
+ upstream: The RB_GENERATE_STATIC(3) macro expands to a series of
- 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@
+ function definitions and not a statement, so there should be no semicolon
+ following them. Patch from Michael Forney
- OpenBSD-Commit-ID: 0346b2f73f54c43d4e001089759d149bfe402ca5
+ OpenBSD-Commit-ID: c975dd180580f0bdc0a4d5b7d41ab1f5e9b7bedd
-commit a8e798feabe36d02de292bcfd274712cae1d8d17
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jan 15 02:58:11 2021 +0000
+commit c298c4da574ab92df2f051561aeb3e106b0ec954
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jun 4 05:59:18 2021 +0000
- upstream: Change types in convtime() unit test to int to match change
+ upstream: rework authorized_keys example section, removing irrelevant
- its new type. Add tests for boundary conditions and fix convtime to work up
- to INT_MAX. ok djm@
+ stuff, de-wrapping the example lines and better aligning the examples with
+ common usage and FAQs; ok jmc
- OpenBSD-Regress-ID: ba2b81e9a3257fff204b020affe85b604a44f97e
+ OpenBSD-Commit-ID: d59f1c9281f828148e2a2e49eb9629266803b75c
-commit 9bde1a420626da5007bf7ab499fa2159b9eddf72
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jan 15 04:31:25 2021 +0000
+commit d9cb35bbec5f623589d7c58fc094817b33030f35
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jun 4 05:10:03 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@
+ upstream: adjust SetEnv description to clarify $TERM handling
- OpenBSD-Commit-ID: 83733f1b01b82da88b9dd1769475952aff10bdd7
+ OpenBSD-Commit-ID: 8b8cc0124856bc1094949d55615e5c44390bcb22
-commit 02da325f10b214219eae2bb1bc2d3bf0c2f13f9f
+commit 771f57a8626709f2ad207058efd68fbf30d31553
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jan 15 02:58:11 2021 +0000
+Date: Fri Jun 4 05:09:08 2021 +0000
- upstream: Change types in convtime() unit test to int to match
+ upstream: Switch the listening select loop from select() to
- change its new type. Add tests for boundary conditions and fix convtime to
- work up to INT_MAX. ok djm@
+ pselect() and mask signals while checking signal flags, umasking for pselect
+ and restoring afterwards. Also restore signals before sighup_restart so they
+ don't remain blocked after restart.
- OpenBSD-Commit-ID: 01dc0475f1484ac2f47facdfcf9221f9472145de
+ This prevents a race where a SIGTERM or SIGHUP can arrive between
+ checking the flag and calling select (eg if sshd is processing a
+ new connection) resulting in sshd not shutting down until the next
+ time it receives a new connection. bz#2158, with & ok djm@
+
+ OpenBSD-Commit-ID: bf85bf880fd78e00d7478657644fcda97b9a936f
-commit 5339ab369c225b40bc64d5ec3374f5c91b3ad609
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jan 15 02:32:41 2021 +0000
+commit f64f8c00d158acc1359b8a096835849b23aa2e86
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jun 4 05:02:40 2021 +0000
- upstream: In waitfd(), when poll returns early we are subtracting
+ upstream: allow ssh_config SetEnv to override $TERM, which is otherwise
- 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@
+ handled specially by the protocol. Useful in ~/.ssh/config to set TERM to
+ something generic (e.g. "xterm" instead of "xterm-256color") for destinations
+ that lack terminfo entries. feedback and ok dtucker@
- OpenBSD-Commit-ID: 199df060978ee9aa89b8041a3dfaf1bf7ae8dd7a
+ OpenBSD-Commit-ID: 38b1ef4d5bc159c7d9d589d05e3017433e2d5758
-commit a164862dfa863b54b7897f66e1dd75437f086c11
-Author: rob@openbsd.org <rob@openbsd.org>
-Date: Thu Jan 14 19:45:06 2021 +0000
+commit 60107677dc0ce1e93c61f23c433ad54687fcd9f5
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jun 4 04:02:21 2021 +0000
- upstream: Minor grammatical correction.
+ upstream: correct extension name "no-presence-required" =>
- OK jmc@
+ "no-touch-required"
- OpenBSD-Commit-ID: de0fad0581e212b2750751e479b79c18ff8cac02
+ document "verify-required" option
+
+ OpenBSD-Commit-ID: 1879ff4062cf61d79b515e433aff0bf49a6c55c5
-commit 8635e7df7e3a3fbb4a4f6cd5a7202883b2506087
+commit ecc186e46e3e30f27539b4311366dfda502f0a08
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Jan 13 18:00:57 2021 +1100
+Date: Wed Jun 2 13:54:11 2021 +1000
- Merge Mac OS X targets into a single config.
+ Retire fbsd7 test target.
+
+ It's the slowest of the selfhosted targets (since it's 32bit but has
+ most of the crypto algos). We still have coverage for 32bit i386.
-commit ac112ade990585c511048ed4edaf2d9fc92b61f0
+commit 5de0867b822ec48b5eec9abde0f5f95d1d646546
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Jan 12 19:22:47 2021 +1100
+Date: Wed Jun 2 11:21:40 2021 +1000
- Add Mac OS X test targets.
+ Check for $OPENSSL in md5 fallback too.
-commit 1050109b4b2884bf50fd1b3aa084c7fd0a42ae90
-Author: anatasluo <luolongjuna@gmail.com>
-Date: Mon Jan 11 13:51:39 2021 +0000
+commit 1db69d1b6542f8419c04cee7fd523a4a11004be2
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Jun 2 11:17:54 2021 +1000
- Remove duplicated declaration in fatal.c .
+ Add dfly60 target.
-commit 7d0f8a3369579dfe398536eb4e3da7bc15da9599
+commit a3f2dd955f1c19cad387a139f0e719af346ca6ef
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jan 11 04:48:22 2021 +0000
+Date: Wed Jun 2 00:17:45 2021 +0000
- upstream: Correct spelling of persourcenetblocksize in config-dump
+ upstream: Merge back shell portability changes
- mode.
+ bringing it back in sync with -portable.
- OpenBSD-Commit-ID: ecdc49e2b6bde6b6b0e52163d621831f6ac7b13d
+ OpenBSD-Regress-ID: c07905ba931e66ad7d849b87b7d19648007175d1
-commit ba328bd7a6774f30daaf90b83f1933cc4afc866c
+commit 9d482295c9f073e84d75af46b720a1c0f7ec2867
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Jan 9 12:31:46 2021 +0000
+Date: Tue Jun 1 23:56:20 2021 +0000
- upstream: Adjust kexfuzz to addr.c/addrmatch.c split.
+ upstream: Use a default value for $OPENSSL,
- OpenBSD-Regress-ID: 1d8d23bb548078020be2fb52c4c643efb190f0eb
+ allowing it to be overridden. Do the same in the PuTTY tests since it's
+ needed there and not exported by test-exec.sh.
+
+ OpenBSD-Regress-ID: c49dcd6aa7602a8606b7afa192196ca1fa65de16
-commit b08ef25552443e94c0857d5e3806dd019ccc55d7
+commit 07660b3c99f8ea74ddf4a440e55c16c9f7fb3dd1
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Jan 9 12:24:30 2021 +0000
+Date: Mon May 24 10:25:18 2021 +0000
- upstream: Update unittests for addr.c/addrmatch.c split.
+ upstream: Find openssl binary via environment variable. This
- OpenBSD-Regress-ID: de2b415fb7af084a91c6ef147a90482d8f771eef
+ allows overriding if necessary (eg in -portable where we're testing against a
+ specific version of OpenSSL).
+
+ OpenBSD-Regress-ID: 491f39cae9e762c71aa4bf045803d077139815c5
-commit 6d30673fedec2d251f4962c526fd0451f70c4d97
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jan 11 02:12:57 2021 +0000
+commit 1a4d1da9188d7c88f646b61f0d6a3b34f47c5439
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri May 21 04:03:47 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@
+ upstream: fix memleak in test
- OpenBSD-Commit-ID: 8fc932683d6b4660d52f50911d62bd6639c5db31
+ OpenBSD-Regress-ID: 5e529d0982aa04666604936df43242e97a7a6f81
-commit 7a57adb8b07b2ad0aead4b2e09ee18edc04d0481
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Sat Jan 9 12:51:12 2021 +0000
+commit 60455a5d98065a73ec9a1f303345856bbd49aecc
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri May 21 03:59:01 2021 +0000
- upstream: add a comma to previous;
+ upstream: also check contents of remaining string
- OpenBSD-Commit-ID: 9139433701c0aa86a0d3a6c7afe10d1c9c2e0869
+ OpenBSD-Regress-ID: d526fa07253f4eebbc7d6205a0ab3d491ec71a28
-commit 3a923129534b007c2e24176a8655dec74eca9c46
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Jan 9 12:10:02 2021 +0000
+commit 39f6cd207851d7b67ca46903bfce4a9f615b5b1c
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri May 21 03:48:07 2021 +0000
- upstream: Add PerSourceMaxStartups and PerSourceNetBlockSize
+ upstream: unit test for misc.c:strdelim() that mostly servces to
- options which provide more fine grained MaxStartups limits. Man page help
- jmc@, feedback & ok djm@
+ highlight its inconsistencies
- OpenBSD-Commit-ID: e2f68664e3d02c0895b35aa751c48a2af622047b
+ OpenBSD-Regress-ID: 8d2bf970fcc01ccc6e36a5065f89b9c7fa934195
-commit d9a2bc71693ea27461a78110005d5a2d8b0c6a50
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Jan 9 11:58:50 2021 +0000
+commit 7a3a1dd2c7d4461962acbcc0ebee9445ba892be0
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu May 27 21:23:15 2021 +1000
- upstream: Move address handling functions out into their own file
+ Put minix3 config in the host-specific block.
+
+commit 59a194825f12fff8a7f75d91bf751ea17645711b
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon May 31 06:48:42 2021 +0000
+
+ upstream: Hash challenge supplied by client during FIDO key enrollment
- 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).
+ prior to passing it to libfido2, which does expect a hash.
- OpenBSD-Commit-ID: e3e7d9ccc6c9b82e25cfef0ec83598e8e2327cbf
+ There is no effect for users who are simply generating FIDO keys using
+ ssh-keygen - by default we generate a random 256 bit challenge, but
+ people building attestation workflows around our tools should now have
+ a more consistent experience (esp. fewer failures when they fail to
+ guess the magic 32-byte challenge length requirement).
+
+ ok markus@
+
+ OpenBSD-Commit-ID: b8d5363a6a7ca3b23dc28f3ca69470472959f2b5
-commit b744914fcb76d70761f1b667de95841b3fc80a56
+commit eb68e669bc8ab968d4cca5bf1357baca7136a826
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Jan 9 00:36:05 2021 +1100
+Date: Thu May 27 21:14:15 2021 +1000
- Add test against Graphene hardened malloc.
+ Include login_cap.h for login_getpwclass override.
+
+ On minix3, login_getpwclass is __RENAME'ed to __login_getpwclass50 so
+ without this the include overriding login_getpwclass causes a compile
+ error.
-commit 6cb52d5bf771f6769b630fce35a8e9b8e433044f
+commit 2063af71422501b65c7a92a5e14c0e6a3799ed89
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu May 27 21:13:38 2021 +1000
+
+ Add minix3 test target.
+
+commit 2e1efcfd9f94352ca5f4b6958af8a454f8cf48cd
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jan 8 04:49:13 2021 +0000
+Date: Wed May 26 01:47:24 2021 +0000
- upstream: make CheckHostIP default to 'no'. It doesn't provide any
+ upstream: fix SEGV in UpdateHostkeys debug() message, triggered
- perceptible value and makes it much harder for hosts to change host keys,
- particularly ones that use IP-based load-balancing.
+ when the update removed more host keys than remain present. Fix tested by
+ reporter James Cook, via bugs@
- ok dtucker@
+ OpenBSD-Commit-ID: 44f641f6ee02bb957f0c1d150495b60cf7b869d3
+
+commit 9acd76e6e4d2b519773e7119c33cf77f09534909
+Author: naddy@openbsd.org <naddy@openbsd.org>
+Date: Sun May 23 18:22:57 2021 +0000
+
+ upstream: ssh: The client configuration keyword is
- OpenBSD-Commit-ID: 0db98413e82074f78c7d46784b1286d08aee78f0
+ "hostbasedacceptedalgorithms"
+
+ This fixes a mistake that slipped in when "HostbasedKeyTypes" was
+ renamed to "HostbasedAcceptedAlgorithms".
+
+ Bug report by zack@philomathiclife.com
+
+ OpenBSD-Commit-ID: d745a7e8e50b2589fc56877f322ea204bc784f38
-commit 309b642e1442961b5e57701f095bcd4acd2bfb5f
+commit 078a0e60c92700da4c536c93c007257828ccd05b
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jan 8 15:50:41 2021 +1100
+Date: Tue May 25 11:40:47 2021 +1000
- Run tests with sudo for better coverage.
+ Rename README.md to ci-status.md.
+
+ The original intent was to provide a status page for the CIs configured
+ in that directory, but it had the side effect of replacing the top-level
+ README.md.
-commit c336644351fa3c715a08b7a292e309e72792e71e
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jan 8 14:26:32 2021 +1100
+commit 7be4ac813662f68e89f23c50de058a49aa32f7e4
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed May 19 01:24:05 2021 +0000
- Add Ubuntu 16.04 and 20.04 test targets.
+ upstream: restore blocking status on stdio fds before close
+
+ ssh(1) needs to set file descriptors to non-blocking mode to operate
+ but it was not restoring the original state on exit. This could cause
+ problems with fds shared with other programs via the shell, e.g.
+
+ > $ cat > test.sh << _EOF
+ > #!/bin/sh
+ > {
+ > ssh -Fnone -oLogLevel=verbose ::1 hostname
+ > cat /usr/share/dict/words
+ > } | sleep 10
+ > _EOF
+ > $ ./test.sh
+ > Authenticated to ::1 ([::1]:22).
+ > Transferred: sent 2352, received 2928 bytes, in 0.1 seconds
+ > Bytes per second: sent 44338.9, received 55197.4
+ > cat: stdout: Resource temporarily unavailable
+
+ This restores the blocking status for fds 0,1,2 (stdio) before ssh(1)
+ abandons/closes them.
+
+ This was reported as bz3280 and GHPR246; ok dtucker@
+
+ OpenBSD-Commit-ID: 8cc67346f05aa85a598bddf2383fcfcc3aae61ce
-commit 4c7af01f9dcc1606dec033e7665a042cb0d8ec52
+commit c4902e1a653c67fea850ec99c7537f358904c0af
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jan 8 02:57:24 2021 +0000
+Date: Mon May 17 11:43:16 2021 +0000
- upstream: If a signature operation on a FIDO key fails with a
+ upstream: fix breakage of -W forwaring introduced in 1.554; reported by
- "incorrect PIN" reason and no PIN was initially requested from the user, then
- request a PIN and retry the operation.
+ naddy@ and sthen@, ok sthen@
- 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.
+ OpenBSD-Commit-ID: f72558e643a26dc4150cff6e5097b5502f6c85fd
+
+commit afea01381ad1fcea1543b133040f75f7542257e6
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon May 17 07:22:45 2021 +0000
+
+ upstream: Regenerate moduli.
- ok dtucker@
+ OpenBSD-Commit-ID: 83c93a2a07c584c347ac6114d6329b18ce515557
+
+commit be2866d6207b090615ff083c9ef212b603816a56
+Author: Damien Miller <djm@mindrot.org>
+Date: Mon May 17 09:40:23 2021 +1000
+
+ Handle Android libc returning NULL pw->pw_passwd
- OpenBSD-Commit-ID: 176db8518933d6a5bbf81a2e3cf62447158dc878
+ Reported by Luke Dashjr
-commit 64ddd0fe68c4a7acf99b78624f8af45e919cd317
+commit 5953c143008259d87342fb5155bd0b8835ba88e5
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri May 14 05:20:32 2021 +0000
+
+ upstream: fix previous: test saved no_shell_flag, not the one that just
+
+ got clobbered
+
+ OpenBSD-Commit-ID: b8deace085d9d941b2d02f810243b9c302e5355d
+
+commit 1e9fa55f4dc4b334651d569d3448aaa3841f736f
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jan 8 02:44:14 2021 +0000
+Date: Fri May 14 03:09:48 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.
+ upstream: Fix ssh started with ControlPersist incorrectly executing a
- Based on patch by Masahiro Matsuya via bz3248.
+ shell when the -N (no shell) option was specified. bz3290 reported by Richard
+ Schwab; patch from markus@ ok me
- OpenBSD-Commit-ID: 65b5e9f18bb0d10573868c3516de6e5170adb163
+ OpenBSD-Commit-ID: ea1ea4af16a95687302f7690bdbe36a6aabf87e1
-commit 599df78f3008cf78af21f8977be3e1dd085f8e2e
+commit d1320c492f655d8f5baef8c93899d79dded217a5
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jan 8 02:33:13 2021 +0000
+Date: Wed May 12 11:34:30 2021 +0000
- upstream: Update the sntrup761 creation script and generated code:
+ upstream: Clarify language about moduli. While both ends of the
- - 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.
+ connection do need to use the same parameters (ie groups), the DH-GEX
+ protocol takes care of that and both ends do not need the same contents in
+ the moduli file, which is what the previous text suggested. ok djm@ jmc@
- ok djm@
+ OpenBSD-Commit-ID: f0c18cc8e79c2fbf537a432a9070ed94e96a622a
+
+commit d3cc4d650ce3e59f3e370b101778b0e8f1c02c4d
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri May 7 04:11:51 2021 +0000
+
+ upstream: include pid in LogVerbose spam
- OpenBSD-Commit-ID: 7b9d0cf3acd5a3c1091da8afe00c904d38cf5783
+ OpenBSD-Commit-ID: aacb86f96ee90c7cb84ec27452374285f89a7f00
-commit 16448ff529affda7e2a15ee7c3200793abde0759
+commit e3c032333be5fdbbaf2751f6f478e044922b4ec4
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jan 8 02:19:24 2021 +0000
+Date: Fri May 7 03:09:38 2021 +0000
- upstream: mention that DisableForwarding is valid in a sshd_config
+ upstream: don't sigdie() in signal handler in privsep child process;
- Match block reported by Fredrik Eriksson in bz3239
+ this can end up causing sandbox violations per bz3286; ok dtucker@
- OpenBSD-Commit-ID: 3a71c3d84b597f5e43e4b40d5232797daf0993f6
+ OpenBSD-Commit-ID: a7f40b2141dca4287920da68ede812bff7ccfdda
-commit 91bac5e95b1b0debf9b2b4f05c20dcfa96b368b9
+commit a4039724a3f2abac810735fc95cf9114a3856049
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jan 4 21:58:58 2021 +0000
+Date: Fri May 7 09:23:40 2021 +0000
- upstream: estructure sntrup761.sh to process all files in a single
+ upstream: Increase ConnectionAttempts from 4 to 10 as the tests
- list, which will make it easier to reorder. Re-inline int32_MINMAX. ok
- tobhe@
+ occasionally time out on heavily loaded hosts.
- OpenBSD-Commit-ID: d145c6c19b08bb93c9e14bfaa7af589d90f144c0
+ OpenBSD-Regress-ID: 29a8cdef354fc9da471a301f7f65184770434f3a
-commit 4d96a3ebab2224f17e639a15078e03be1ad3736d
-Author: tobhe@openbsd.org <tobhe@openbsd.org>
-Date: Sun Jan 3 18:05:21 2021 +0000
+commit c0d7e36e979fa3cdb60f5dcb6ac9ad3fd018543b
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri May 7 02:26:55 2021 +0000
- upstream: Prevent redefinition of `crypto_int32' error with gcc3.
-
- Fixes compilation on luna88k.
+ upstream: dump out a usable private key string too; inspired by Tyson
- Feedback millert@
- Found by and ok aoyama@
+ Whitehead
- OpenBSD-Commit-ID: f305ddfe575a26cc53431af3fde3f4aeebed9ba6
+ OpenBSD-Regress-ID: 65572d5333801cb2f650ebc778cbdc955e372058
-commit a23954eeb930ccc8a66a2710153730769dba31b6
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jan 1 22:00:49 2021 +1100
+commit 24fee8973abdf1c521cd2c0047d89e86d9c3fc38
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri May 7 02:29:40 2021 +0000
- Undef int32 after sort routines.
+ upstream: correct mistake in spec - the private key blobs are encoded
- 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
+ verbatim and not as strings (i.e. no 4-byte length header)
+
+ OpenBSD-Commit-ID: 3606b5d443d72118c5b76c4af6dd87a5d5a4f837
-commit 3d999be7b987c848feda718cfcfcdc005ddf670d
-Author: tobhe@openbsd.org <tobhe@openbsd.org>
-Date: Wed Dec 30 14:13:28 2020 +0000
+commit f43859159cc62396ad5d080f0b1f2635a67dac02
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue May 4 22:53:52 2021 +0000
- upstream: Use int64_t for intermediate values in int32_MINMAX to
-
- prevent signed 32-bit integer overflow.
+ upstream: Don't pass NULL as a string in debugging as it does not work
- Found by and ok djm@
- ok markus@
+ on some platforms in -portable. ok djm@
- 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
+ OpenBSD-Commit-ID: 937c892c99aa3c9c272a8ed78fa7c2aba3a44fc9
-commit 659864fe81dbc57eeed3769c462679d83e026640
+commit ac31aa3c6341905935e75f0539cf4a61bbe99779
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Dec 29 01:02:15 2020 +0000
+Date: Mon May 3 00:16:45 2021 +0000
- upstream: Adapt to replacement of
-
- sntrup4591761x25519-sha512@tinyssh.org with
- sntrup761x25519-sha512@openssh.com.
-
- Also test sntrup761x25519-sha512@openssh.com in unittests/kex
+ upstream: more debugging for UpdateHostKeys signature failures
- OpenBSD-Regress-ID: cfa3506b2b077a9cac1877fb521efd2641b6030c
+ OpenBSD-Commit-ID: 1ee95f03875e1725df15d5e4bea3e73493d57d36
-commit 2c71cec020219d69df84055c59eba5799a1233ec
+commit 8e32e97e788e0676ce83018a742203614df6a2b3
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat May 1 20:07:47 2021 +1000
+
+ Add obsd69 test target.
+
+commit f06893063597c5bb9d9e93f851c4070e77d2fba9
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Dec 29 00:59:15 2020 +0000
+Date: Fri Apr 30 04:29:53 2021 +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
+ upstream: a little debugging in the main mux process for status
- (note this both the updated method and the one that it replaced are
- disabled by default)
+ confirmation failures in multiplexed sessions
- OpenBSD-Commit-ID: 2bf582b772d81ee24e911bb6f4b2aecfd39338ae
+ OpenBSD-Commit-ID: 6e27b87c95176107597035424e1439c3232bcb49
-commit 09d070ccc3574ae0d7947d212ed53c7268ef7e1f
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Tue Dec 22 07:40:26 2020 +0000
+commit e65cf00da6bc31e5f54603b7feb7252dc018c033
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Apr 30 04:02:52 2021 +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;
+ upstream: Remove now-unused skey function prototypes leftover from
- ok djm
+ skey removal.
- 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
+ OpenBSD-Commit-ID: 2fc36d519fd37c6f10ce74854c628561555a94c3
-commit 33fa3ac547e5349ca34681cce6727b2f933dff0a
+commit ae5f9b0d5c8126214244ee6b35aae29c21028133
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Dec 22 19:21:26 2020 +1100
+Date: Thu Apr 29 13:01:50 2021 +1000
- Improve AIX text.
+ Wrap sntrup761x25519 inside ifdef.
+
+ From balu.gajjala at gmail.com via bz#3306.
-commit 0f2e21c9dca89598b694932b5b05848380a23ec0
+commit 70a8dc138a6480f85065cdb239915ad4b7f928cf
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Dec 22 18:56:54 2020 +1100
+Date: Wed Apr 28 14:44:07 2021 +1000
- Include stdio.h for FILE in misc.h.
-
- Fixes build on at least OpenBSD.
+ Add status badges for Actions-based tests.
-commit 3e9811e57b57ee66b0f70d99d7258da3153b0e8a
-Author: Damien Miller <djm@mindrot.org>
-Date: Tue Dec 22 18:31:50 2020 +1100
+commit 40b59024cc3365815381474cdf4fe423102e391b
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Apr 28 12:22:11 2021 +1000
- ensure $LOGNAME is set in tests
+ Add obsdsnap (OpenBSD snapshot) test target.
-commit 3eb647cbb34d87a063aa7714256c6e56103fffda
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Dec 22 06:47:24 2020 +0000
+commit e627067ec8ef9ae8e7a638f4dbac91d52dee3e6d
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Apr 28 11:35:28 2021 +1000
- upstream: more detail for failing tests
-
- OpenBSD-Regress-ID: c68c0e5a521cad7e7f68e54c54ebf86d6c10ee1d
+ Add test building upstream OpenBSD source.
-commit 2873f19570d4d8758be24dbf78332be9a779009b
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Dec 22 06:03:36 2020 +0000
+commit 1b8108ebd12fc4ed0fb39ef94c5ba122558ac373
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Apr 27 14:22:20 2021 +1000
- upstream: regress test for KnownHostsCommand
+ Test against OpenSSL 1.1.0h instead of 1.1.0g.
- OpenBSD-Regress-ID: ffc77464320b6dabdcfa0a72e0df02659233a38a
+ 1.1.0g requires a perl glob module that's not installed by default.
-commit 0121aa87bab9ad2365de2d07f2832b56d5ff9871
-Author: tb@openbsd.org <tb@openbsd.org>
-Date: Tue Dec 22 03:05:31 2020 +0000
+commit 9bc20efd39ce8525be33df3ee009f5a4564224f1
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Apr 27 12:37:59 2021 +1000
- upstream: Remove lines accidentally left behind in the ProxyJump
-
- parsing fix r1.345.
-
- ok djm
-
- OpenBSD-Commit-ID: fe767c108c8117bea33767b080ff62eef2c55f5c
+ Use the default VM type for libcrypto ver tests.
-commit da4bf0db942b5f0278f33238b86235e5813d7a5a
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Dec 22 00:15:22 2020 +0000
+commit 9f79e80dc40965c2e73164531250b83b176c1eea
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Apr 27 12:24:10 2021 +1000
- 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@
+ Always build OpenSSL shared.
- OpenBSD-Commit-ID: 2433cff4fb323918ae968da6ff38feb99b4d33d0
+ This is the default for current versions but we need it to test against
+ earlier versions.
-commit a34e14a5a0071de2036826a00197ce38c8b4ba8b
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Dec 22 00:12:22 2020 +0000
+commit b3cc9fbdff2782eca79e33e02ac22450dc63bce9
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Apr 27 09:18:02 2021 +1000
- 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@
+ Fix custom OpenSSL tests.
- OpenBSD-Commit-ID: a80ea9fdcc156f1a18e9c166122c759fae1637bf
+ Check out specified OpenSSL version. Install custom libcrypto where
+ configure expects to find it. Remove unneeded OpenSSL config time
+ options. Older OpenSSL versions were not make -j safe so remove it.
-commit 649205fe388b56acb3481a1b2461f6b5b7c6efa6
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Dec 21 22:48:41 2020 +0000
+commit 77532609874a99a19e3e2eb2d1b7fa93aef963bb
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Apr 26 17:18:25 2021 +1000
- upstream: Remove explicit rijndael-cbc@lysator.liu.se test since the
-
- cipher was removed.
-
- OpenBSD-Regress-ID: aa93cddb4ecd9bc21446a79008a1a53050e64f17
+ Export CC and CFLAGS for c89 test.
-commit 03e93c753d7c223063ad8acaf9a30aa511e5f931
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Dec 21 11:09:32 2020 +0000
+commit 33f62dfbe865f4de77980ab88774bf1eb5e4e040
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Apr 26 17:13:44 2021 +1000
- 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
+ Add c89 here too.
-commit a11ca015879eab941add8c6bdaaec7d41107c6f5
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Dec 21 09:19:53 2020 +0000
+commit da9d59f526fce58e11cba49cd8eb011dc0bf5677
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Apr 26 15:34:23 2021 +1000
- 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
+ Add test against OpenSSL w/out ECC.
-commit d97fb879724f1670bf55d9adfea7278a93c33ae2
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Dec 21 01:31:06 2020 +0000
+commit 29e194a752359ebf85bf7fce100f23a0477fc4de
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Apr 26 14:49:59 2021 +1000
- upstream: adapt to API change in hostkeys_foreach()/load_hostkeys()
-
- OpenBSD-Regress-ID: dcb468514f32da49a446372453497dc6eeafdbf3
+ Ensure we can still build with C89.
-commit bf7eb3c266b7fd4ddda108fcf72b860af2af6406
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Oct 16 14:02:24 2020 +0000
+commit a38016d369d21df5d35f761f2b67e175e132ba22
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Apr 26 14:29:03 2021 +1000
- upstream: few more things needs match.c and addrmatch.c now that
-
- log.c calls match_pattern_list()
+ Interop test agains PuTTY.
+
+commit 095b0307a77be8803768857cc6c0963fa52ed85b
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Apr 26 14:02:03 2021 +1000
+
+ Support testing against arbitary libcrytpo vers.
- OpenBSD-Regress-ID: f7c95c76b150d0aeb00a67858b9579b7d1b2db74
+ Add tests against various LibreSSL and OpenSSL versions.
-commit 2c64f24e27a5e72a7f59e515fc4f4985355237ae
+commit b16082aa110fa7128ece2a9037ff420c4a285317
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Dec 21 14:02:56 2020 +1100
+Date: Mon Apr 26 13:35:44 2021 +1000
- Pull in missing rev 1.2.
+ Add fbsd10 test target.
-commit 0f504f592d15d8047e466eb7453067a6880992a8
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 20 23:40:19 2020 +0000
+commit 2c805f16b24ea37cc051c6018fcb05defab6e57a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sun Apr 25 14:15:02 2021 +1000
- upstream: plumb ssh_conn_info through to sshconnect.c; feedback/ok
-
- markus@
+ Disable compiler hardening on nbsd4.
- OpenBSD-Commit-ID: e8d14a09cda3f1dc55df08f8a4889beff74e68b0
+ The system compiler supports -fstack-protector-all, but using it will
+ result in an internal compiler error on some files.
-commit 729b05f59ded35483acef90a6f88aa03eae33b29
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 20 23:38:00 2020 +0000
+commit 6a5d39305649da5dff1934ee54292ee0cebd579d
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sun Apr 25 13:01:34 2021 +1000
- upstream: allow UserKnownHostsFile=none; feedback and ok markus@
-
- OpenBSD-Commit-ID: c46d515eac94a35a1d50d5fd71c4b1ca53334b48
+ Add nbsd3, nbsd4 and nbsd9 test targets.
-commit b4c7cd1185c5dc0593d47eafcc1a34fda569dd1d
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Dec 20 23:36:51 2020 +0000
+commit d1aed05bd2e4ae70f359a394dc60a2d96b88f78c
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Apr 24 22:03:46 2021 +1000
- 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
+ Comment out nbsd2 test target for now.
-commit 06fbb386bed666581095cb9cbc7a900e02bfe1b7
-Author: tobhe@openbsd.org <tobhe@openbsd.org>
-Date: Sat Dec 19 22:09:21 2020 +0000
+commit a6b4ec94e5bd5a8a18cd2c9942d829d2e5698837
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Apr 24 17:52:24 2021 +1000
- upstream: Print client kem key with correct length.
-
- ok markus@
-
- OpenBSD-Commit-ID: 91689e14a4fc6c270e265a32d1c8faba63a45755
+ Add OPENBSD ORIGINAL marker.
-commit 0ebead6593e2441e4af2735bbe2cd097607cd0d3
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Dec 17 23:28:50 2020 +0000
+commit 3737c9f66ee590255546c4b637b6d2be669a11eb
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Apr 23 19:49:46 2021 +1000
- upstream: fix possible error("%s", NULL) on error paths
-
- OpenBSD-Commit-ID: 0b3833c2cb985453ecca1d76803ebb8f3b736a11
+ Replace "==" (a bashism) with "=".
-commit d060bc7f6e6244f001e658208f53e3e2ecbbd382
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Dec 17 23:26:11 2020 +0000
+commit a116b6f5be17a1dd345b7d54bf8aa3779a28a0df
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Apr 23 16:34:48 2021 +1000
- 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
+ Add nbsd2 test target.
-commit 43026da035cd266db37df1f723d5575056150744
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Dec 17 23:10:27 2020 +0000
+commit 196bf2a9bb771f45d9b0429cee7d325962233c44
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Apr 23 14:54:10 2021 +1000
- upstream: prepare readconf.c for fuzzing; remove fatal calls and
-
- fix some (one-off) memory leaks; ok markus@
-
- OpenBSD-Commit-ID: 91c6aec57b0e7aae9190de188e9fe8933aad5ec5
+ Add obsd68 test target.
-commit bef92346c4a808f33216e54d6f4948f9df2ad7c1
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Dec 14 03:13:12 2020 +0000
+commit e3ba6574ed69e8b7af725cf5e8a9edaac04ff077
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Apr 23 14:53:32 2021 +1000
- upstream: use _PATH_SSH_USER_DIR instead of hardcoded .ssh in path
-
- OpenBSD-Commit-ID: 5c1048468813107baa872f5ee33ba51623630e01
+ Remove dependency on bash.
-commit a5ab499bd2644b4026596fc2cb24a744fa310666
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Dec 4 14:01:27 2020 +1100
+commit db1f9ab8feb838aee9f5b99c6fd3f211355dfdcf
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Apr 23 14:41:13 2021 +1000
- basic KEX fuzzer; adapted from Markus' unittest
+ Add obsd67 test target.
-commit 021ff33e383c77b11badd60cec5b141a3e3fa532
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Dec 4 13:57:43 2020 +1100
+commit c039a6bf79192fe1daa9ddcc7c87dd98e258ae7c
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Apr 23 11:08:23 2021 +1000
- use options that work with recent clang
+ Re-add macos-11.0 test target.
-commit e4d1a0b40add800b6e9352b40c2223e44acc3a45
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Dec 4 02:41:10 2020 +0000
+commit a6db3a47b56adb76870d59225ffb90a65bc4daf2
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Apr 23 10:28:28 2021 +1000
- upstream: shuffle a few utility functions into sftp-client.c; from
-
- Jakub Jelen
-
- OpenBSD-Commit-ID: fdeb1aae1f6149b193f12cd2af158f948c514a2a
+ Add openindiana test target.
-commit ace12dc64f8e3a2496ca48d36b53cb3c0a090755
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Dec 4 02:29:56 2020 +0000
+commit 3fe7e73b025c07eda46d78049f1da8ed7dfc0c69
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Apr 23 10:26:35 2021 +1000
- upstream: make ssh_free(NULL) a no-op
+ Test krb5 on Solaris 11 too.
+
+commit f57fbfe5eb02df1a91f1a237c4d27165afd87c13
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Apr 22 22:27:26 2021 +1000
+
+ Don't always set SUDO.
- OpenBSD-Commit-ID: 42cb285d94789cefe6608db89c63040ab0a80fa0
+ Rely on sourcing configs to set as appropriate.
-commit 3b98b6e27f8a122dbfda9966b1afeb3e371cce91
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Dec 4 02:29:25 2020 +0000
+commit e428f29402fb6ac140b52f8f12e06ece7bb104a0
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Apr 22 22:26:08 2021 +1000
+
+ Remove now-unused 2nd arg to configs.
- upstream: memleak of DH public bignum; found with libfuzzer
-
- OpenBSD-Commit-ID: 0e913b542c3764b100b1571fdb0d0e5cc086fe97
+commit cb4ff640d79b3c736879582139778f016bbb2cd7
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Apr 21 01:08:04 2021 +1000
-commit 553b90feedd7da5b90901d73005f86705456d686
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Dec 4 02:27:57 2020 +0000
+ Add win10 test target.
- upstream: fix minor memleak of kex->hostkey_alg on rekex
-
- OpenBSD-Commit-ID: 2c3969c74966d4ccdfeff5e5f0df0791919aef50
+commit 4457837238072836b2fa3107d603aac809624983
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Apr 20 23:31:29 2021 +1000
-commit ac0364b85e66eb53da2f9618f699ba6bd195ceea
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Dec 4 02:27:08 2020 +0000
+ Add nbsd8 test target.
- upstream: typos: s/hex/kex/ in error messages
-
- OpenBSD-Commit-ID: 43a026c9571dd779ec148de1829cf5a6b6651905
+commit bd4fba22e14da2fa196009010aabec5a8ba9dd42
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Apr 17 09:55:47 2021 +1000
-commit ee22db7c5885a1d90219202c0695bc621aa0409b
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Dec 4 02:25:13 2020 +0000
+ Add obsd51 target.
- upstream: make program name be const
-
- OpenBSD-Commit-ID: ece25680ec637fdf20502721ccb0276691df5384
+commit 9403d0e805c77a5741ea8c3281bbe92558c2f125
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Apr 16 18:14:25 2021 +1000
-commit 2bcbf679de838bb77a8bd7fa18e100df471a679c
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Nov 30 05:36:39 2020 +0000
+ Add fbsd13 target.
- 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 e86968280e358e62649d268d41f698d64d0dc9fa
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Apr 16 13:55:25 2021 +1000
-commit b755264e7d3cdf1de34e18df1af4efaa76a3c015
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Nov 28 12:52:32 2020 +0000
+ depend
- upstream: Include cipher.h for declaration of cipher_by_name.
-
- OpenBSD-Commit-ID: ddfebbca03ca0e14e00bbad9d35f94b99655d032
+commit 2fb25ca11e8b281363a2a2a4dec4c497a1475d9a
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Apr 16 13:53:02 2021 +1000
-commit 022def7bd16c3426a95e25f57cb259d54468341c
+ crank version in README and RPM spec files
+
+commit b2b60ebab0cb77b5bc02d364d72e13db882f33ae
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Nov 28 03:27:59 2020 +0000
+Date: Fri Apr 16 03:42:00 2021 +0000
- upstream: check result of strchr() against NULL rather than
-
- searched-for characters; from zhongjubin@huawei.com
+ upstream: openssh-8.6
- OpenBSD-Commit-ID: e6f57de1d4a4d25f8db2d44e8d58d847e247a4fe
+ OpenBSD-Commit-ID: b5f3e133c846127ec114812248bc17eff07c3e19
-commit 57bf03f0217554afb8980f6697a7a0b88658d0a9
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Nov 27 10:12:30 2020 +0000
+commit faf2b86a46c9281d237bcdec18c99e94a4eb820a
+Author: markus@openbsd.org <markus@openbsd.org>
+Date: Thu Apr 15 16:24:31 2021 +0000
- upstream: Document ssh-keygen -Z, sanity check its argument earlier and
+ upstream: do not pass file/func to monitor; noted by Ilja van Sprundel;
- provide a better error message if it's not correct. Prompted by bz#2879, ok
- djm@ jmc@
+ ok djm@
- OpenBSD-Commit-ID: 484178a173e92230fb1803fb4f206d61f7b58005
+ OpenBSD-Commit-ID: 85ae5c063845c410283cbdce685515dcd19479fa
-commit 33313ebc1c7135085676db62189e3520341d6b73
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Nov 27 00:49:58 2020 +0000
+commit 2dc328023f60212cd29504fc05d849133ae47355
+Author: Damien Miller <djm@mindrot.org>
+Date: Wed Apr 14 11:42:55 2021 +1000
- 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@
+ sshd don't exit on transient read errors
- OpenBSD-Commit-ID: f31ab10d9233363a6d2c9996007083ba43a093f1
+ 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 b2bcec13f17ce9174238a704e91d52203e916432
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Nov 27 00:37:10 2020 +0000
+commit d5d6b7d76d171a2e6861609dcd92e714ee62ad88
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Apr 10 18:45:00 2021 +1000
- 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
+ perform report_failed_grab() inline
-commit 19af04e2231155d513e24fdc81fbec2217ae36a6
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Nov 22 22:38:26 2020 +0000
+commit ea996ce2d023aa3c6d31125e2c3ebda1cb42db8c
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Apr 10 18:22:57 2021 +1000
- upstream: when loading PKCS#11 keys, include the key fingerprints
+ dedicated gnome-ssk-askpass3 source
- and provider/slot information in debug output.
+ 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.
- OpenBSD-Commit-ID: 969a089575d0166a9a364a9901bb6a8d9b8a1431
+ 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 9b9465ea856e15b9e9890b4ecb4110d7106e7766
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Nov 22 22:37:11 2020 +0000
+commit bfa5405da05d906ffd58216eb77c4375b62d64c2
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Apr 8 15:18:15 2021 +1000
- 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@
+ Ensure valgrind-out exists.
- OpenBSD-Commit-ID: 2d5ce4a83dbcf44e340a572e361decad8aab7bad
+ Normally the regress tests would create it, but running the unit tests
+ on their own would fail because the directory did not exist.
-commit 637017a7dd3281d3f2df804993cc27c30dbfda47
+commit 1f189181f3ea09a9b08aa866f78843fec800874f
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Nov 25 17:38:46 2020 +1100
+Date: Thu Apr 8 15:17:19 2021 +1000
- Use "=" not "==" in string test.
+ Pass OBJ to unit test make invocation.
- POSIX says "=" is string comparison and some shells (eg HP-UX) will
- complain about "==".
+ At least the Valgrind unit tests uses $OBJ.
-commit 9880f3480f9768897f3b8e714d5317fb993bc5b3
+commit f42b550c281d28bd19e9dd6ce65069164f3482b0
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Nov 20 17:16:51 2020 +1100
+Date: Thu Apr 8 14:20:12 2021 +1000
- 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.
+ Add pattern for valgrind-unit.
-commit 41935882f4e82de60dbd6e033eabe79e1b963518
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Nov 20 03:16:56 2020 +0000
+commit 19e534462710e98737478fd9c44768b50c27c4c6
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Apr 8 13:31:08 2021 +1000
- 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@
+ Run unit tests under valgrind.
- OpenBSD-Commit-ID: a82606212f2796e31f0e1af94a63355a7ad5d903
+ 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 0f90440ca70abab947acbd77795e9f130967956c
+commit 80032102d05e866dc2a48a5caf760cf42c2e090e
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Nov 20 13:37:54 2020 +1100
+Date: Thu Apr 8 13:25:57 2021 +1000
- Add new pselect6_time64 syscall on ARM.
+ ifdef out MIN and MAX.
- This is apparently needed on armhfp/armv7hl. bz#3232, patch from
- jjelen at redhat.com.
+ 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 3a7c46c72b6a1f643b1fc3589cd20d8320c3d9e1
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Nov 20 02:14:16 2020 +0000
+commit d1bd184046bc310c405f45da3614a1dc5b3e521a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Apr 7 10:23:51 2021 +1000
- 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@
+ Remove only use of warn().
- OpenBSD-Commit-ID: 687126e60a27d30f02614760ef3c3ae4e8d6af28
+ 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 076cb616b87d1ea1d292973fcd0ba38c08ea6832
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Thu Nov 19 23:05:05 2020 +0000
+commit fea8f4b1aa85026ad5aee5ad8e1599a8d5141fe0
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Apr 7 10:18:32 2021 +1000
- upstream: draft-ietf-secsh-architecture is now RFC4251.
+ Move make_tmpdir() into portable-specific area.
- OpenBSD-Commit-ID: cb0bb58c2711fb5ed519507659be1dcf179ed403
+ Reduces diff vs OpenBSD and makes it more likely diffs will apply
+ cleanly.
-commit 85cceda21f1471548e04111aefe2c4943131c1c8
+commit 13e5fa2acffd26e754c6ee1d070d0afd035d4cb7
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Nov 17 11:23:58 2020 +0000
+Date: Tue Apr 6 23:57:56 2021 +0000
- upstream: Specify that the KDF function is bcrypt. Based on github
+ upstream: Add TEST_SSH_ELAPSED_TIMES environment variable to print the
- PR#214 from rafork, ok markus@, mdoc correction jmc@
+ elapsed time in seconds of each test. This depends on "date +%s" which is
+ not specified by POSIX but is commonly implemented.
- OpenBSD-Commit-ID: d8f2853e7edbcd483f31b50da77ab80ffa18b4ef
+ OpenBSD-Regress-ID: ec3c8c19ff49b2192116a0a646ee7c9b944e8a9c
-commit 5b9720f9adbd70ba5a994f407fe07a7d016d8d65
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Nov 15 22:34:58 2020 +0000
+commit ef4f46ab4387bb863b471bad124d46e8d911a79a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Apr 7 09:59:15 2021 +1000
- upstream: revert r1.341; it breaks ProxyJump; reported by sthen@
+ Move the TEST_SSH_PORT section down a bit.
- OpenBSD-Commit-ID: 6ac2f945b26cb86d936eed338f77861d6da8356a
-
-commit 04088725ec9c44880c01799b588cd4ba47b3e8bc
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Nov 13 07:30:44 2020 +0000
+ This groups the portable-specific changes together and makes it a
+ little more likely that patches will apply cleanly.
- upstream: scrub keyboard-interactive authentication prompts coming
-
- from the server through asmprintf() prior to display; suggested by and ok
- dtucker@
+commit 3674e33fa70dfa1fe69b345bf576113af7b7be11
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Apr 7 10:05:10 2021 +1000
+
+ Further split Valgrind tests.
- OpenBSD-Commit-ID: 31fe93367645c37fbfe4691596bf6cf1e3972a58
+ Even split in two, the Valgrind tests take by far the longest to run,
+ so split them four ways to further increase parallelism.
-commit 5442b491d0ee4bb82f6341ad0ee620ef3947f8c5
+commit 961af266b861e30fce1e26170ee0dbb5bf591f29
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Nov 13 04:53:12 2020 +0000
+Date: Tue Apr 6 23:24:30 2021 +0000
- upstream: prefix keyboard interactive prompts with (user@host) to
+ upstream: include "ssherr.h" not <ssherr.h>; from Balu Gajjala via
- make it easier to determine which connection they are associated with in
- cases like scp -3, ProxyJump, etc. bz#3224 ok dtucker
+ bz#3292
- OpenBSD-Commit-ID: 67e6189b04b46c867662f8a6759cf3ecb5f59170
+ OpenBSD-Commit-ID: e9535cd9966eb2e69e73d1ede1f44905c30310bd
-commit 2992e4e7014ac1047062acfdbbf6feb156fef616
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Nov 13 17:56:11 2020 +1100
+commit e7d0a285dbdd65d8df16123ad90f15e91862f959
+Author: Damien Miller <djm@mindrot.org>
+Date: Wed Apr 7 08:50:38 2021 +1000
- 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.
+ wrap struct rlimit in HAVE_GETRLIMIT too
-commit e3f27006f15abacb7e89fda3f5e9a0bd420b7e38
+commit f283a6c2e0a9bd9369e18462acd00be56fbe5b0d
Author: Damien Miller <djm@mindrot.org>
-Date: Fri Nov 13 14:20:43 2020 +1100
+Date: Wed Apr 7 08:20:35 2021 +1000
- Revert "detect Linux/X32 systems"
+ 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
- This reverts commit 5b56bd0affea7b02b540bdbc4d1d271b0e4fc885.
+ 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.
- The approach used was incorrect; discussion in bz#3085
+ OpenBSD-Regress-ID: 24f08543ee3cdebc404f2951f3e388cc82b844a1
-commit e51dc7fab61df36e43f3bc64b673f88d388cab91
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Nov 13 13:22:15 2020 +1100
+commit 320af2f3de6333aa123f1b088eca146a245e968a
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Sun Apr 4 11:36:56 2021 +0000
- SELinux has deprecated security_context_t
+ upstream: remove stray inserts; from matthias schmidt
- (it was only ever a char* anyway)
+ OpenBSD-Commit-ID: 2c36ebdc54e14bbf1daad70c6a05479a073d5c63
-commit b79add37d118276d67f3899987b9f0629c9449c3
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Nov 13 13:43:30 2020 +1100
+commit 801f710953b24dd2f21939171c622eac77c7484d
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Sun Apr 4 06:11:24 2021 +0000
- Remove obsolete AC_HEADER_TIME macro.
+ upstream: missing comma; from kawashima james
- 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.
+ OpenBSD-Commit-ID: 31cec6bf26c6db4ffefc8a070715ebef274e68ea
-commit d5d05cdb3d4efd4a618aa52caab5bec73097c163
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Nov 12 22:56:00 2020 +0000
+commit b3ca08cb174266884d44ec710a84cd64c12414ea
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Apr 5 23:46:42 2021 +1000
- 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
+ Install libcbor with libfido2.
-commit 819b44e8b9af6ce18d3ec7505b9f461bf7991a1f
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Thu Nov 12 22:38:57 2020 +0000
+commit f3ca8af87a4c32ada660da12ae95cf03d190c083
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Apr 3 18:21:08 2021 +1100
- upstream: Prevent integer overflow when ridiculously large
-
- ConnectTimeout is specified, capping the effective value (for most platforms)
- at 24 days. bz#3229, ok djm@
+ enable authopt and misc unit tests
- OpenBSD-Commit-ID: 62d4c4b7b87d111045f8e9f28b5b532d17ac5bc0
+ Neither were wired into the build, both required some build
+ adaptations for -portable
-commit add926dd1bbe3c4db06e27cab8ab0f9a3d00a0c2
+commit dc1b45841fb97e3d7f655ddbcfef3839735cae5f
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Nov 11 05:22:32 2020 +0000
+Date: Sat Apr 3 06:58:30 2021 +0000
- upstream: fix logic error that broke URI parsing in ProxyJump
+ upstream: typos in comments; GHPR#180 from Vill
- directives; ok dtucker@
+ =?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: 96d48839b1704882a0e9a77898f5e14b2d222705
+ OpenBSD-Commit-ID: 93c732381ae0e2b680c79e67c40c1814b7ceed2c
-commit 4340dd43928dfe746cb7e75fe920b63c0d909a9a
-Author: claudio@openbsd.org <claudio@openbsd.org>
-Date: Tue Nov 10 07:46:20 2020 +0000
+commit 53ea05e09b04fd7b6dea66b42b34d65fe61b9636
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Apr 3 06:55:52 2021 +0000
- upstream: Free the previously allocated msg buffer after writing it
+ upstream: sync CASignatureAlgorithms lists with reality. GHPR#174 from
- out. OK djm@
+ Matt Hazinski
- OpenBSD-Commit-ID: 18c055870fc75e4cb9f926c86c7543e2e21d7fa4
+ OpenBSD-Commit-ID: f05e4ca54d7e67b90fe58fe1bdb1d2a37e0e2696
-commit fcf429a4c69d30d8725612a55b37181594da8ddf
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Nov 11 12:30:46 2020 +1100
+commit 57ed647ee07bb883a2f2264231bcd1df6a5b9392
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Apr 3 17:47:37 2021 +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@
+ polish whitespace for portable files
-commit 10dce8ff68ef615362cfcab0c0cc33ce524e7682
+commit 31d8d231eb9377df474746a822d380c5d68d7ad6
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Nov 8 23:19:03 2020 +0000
+Date: Sat Apr 3 06:18:40 2021 +0000
- upstream: unbreak; missing NULL check
+ upstream: highly polished whitespace, mostly fixing spaces-for-tab
- OpenBSD-Commit-ID: 6613dfab488123f454d348ef496824476b8c11c0
+ and bad indentation on continuation lines. Prompted by GHPR#185
+
+ OpenBSD-Commit-ID: e5c81f0cbdcc6144df1ce468ec1bac366d8ad6e9
-commit d5a0cd4fc430c8eda213a4010a612d4778867cd9
+commit 34afde5c73b5570d6f8cce9b49993b23b77bfb86
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Nov 8 22:37:24 2020 +0000
+Date: Sat Apr 3 05:54:14 2021 +0000
- upstream: when requesting a security key touch on stderr, inform the
-
- user once the touch has been recorded; requested by claudio@ ok markus@
+ upstream: whitespace (tab after space)
- OpenBSD-Commit-ID: 3b76ee444490e546b9ea7f879e4092ee0d256233
+ OpenBSD-Commit-ID: 0e2b3f7674e985d3f7c27ff5028e690ba1c2efd4
-commit 292bcb2479deb27204e3ff796539c003975a5f7a
+commit 7cd262c1c5a08cc7f4f30e3cab108ef089d0a57b
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Nov 9 00:33:35 2020 +1100
+Date: Sat Apr 3 16:59:10 2021 +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.
+ Save config.h and config.log on failure too.
-commit 71693251b7cbb7dd89aaac18815147124732d0d3
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sun Nov 8 12:10:20 2020 +0000
+commit 460aee9298f365357e9fd26851c22e0dca51fd6a
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Apr 3 05:46:41 2021 +0000
- upstream: Add a comment documenting the source of the moduli group
+ upstream: fix incorrect plural; from Ville Skyt
- sizes.
+ =?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: aec0725ce607630caaa62682624c6763b350391c
+ OpenBSD-Commit-ID: 92f31754c6296d8f403d7c293e09dc27292d22c9
-commit 4d94b031ff88b015f0db57e140f481bff7ae1a91
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sun Nov 8 11:46:12 2020 +0000
+commit 082804c14e548cada75c81003a3c68ee098138ee
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Apr 3 05:40:39 2021 +0000
- upstream: Replace WITH_OPENSSL ifdefs in log calls with a macro.
+ upstream: ensure that pkcs11_del_provider() is called before exit -
- 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@
+ some PKCS#11 providers get upset if C_Initialize is not matched with
+ C_Finalize.
- OpenBSD-Commit-ID: cc12a9029833d222043aecd252d654965c351a69
+ From Adithya Baglody via GHPR#234; ok markus
+
+ OpenBSD-Commit-ID: f8e770e03b416ee9a58f9762e162add900f832b6
-commit 6d2564b94e51184eb0b73b97d13a36ad50b4f810
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Nov 6 17:11:16 2020 +1100
+commit 464ebc82aa926dd132ec75a0b064574ef375675e
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Apr 3 05:28:43 2021 +0000
- Fix function body for variadic macro test.
+ upstream: unused variable
- AC_LANG_PROGRAM puts its second argument inside main() so we don't need
- to do it ourselves.
+ OpenBSD-Commit-ID: 85f6a394c8e0f60d15ecddda75176f112007b205
-commit 586f9bd2f5980e12f8cf0d3c2a761fa63175da52
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Nov 6 16:53:24 2020 +1100
+commit dc3c0be8208c488e64a8bcb7d9efad98514e0ffb
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sat Apr 3 05:21:46 2021 +0000
- Remove AC_PROC_CC_C99 obsoleted in autoconf 2.70.
+ upstream: Fix two problems in string->argv conversion: 1) multiple
- Since we only use it to make sure we can handle variadic macros,
- explicitly check only for that. with & ok djm@
+ 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 a019e353df04de1b2ca78d91b39c393256044ad7
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Nov 6 13:56:41 2020 +1100
+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
- Replace AC_TRY_COMPILE obsoleted in autoconf 2.70.
+ upstream: cannot effectively test posix-rename extension after
- Replace with the equivalent AC_COMPILE_IFELSE.
+ changes in feature advertisment.
+
+ OpenBSD-Regress-ID: 5e390bf88d379162aaa81b60ed86b34cb0c54d29
-commit 771b7795c0ef6a2fb43b4c6c66b615c2085cb9cd
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Nov 6 13:55:33 2020 +1100
+commit 259d648e63e82ade4fe2c2c73c8b67fe57d9d049
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Mar 19 04:23:50 2021 +0000
- Move AC_PROG_CC_C99 to immediately afer AC_PROG_CC.
+ upstream: add a test for misc.c:argv_split(), currently fails
- This puts the related C version selection output in the same place.
+ OpenBSD-Regress-ID: ad6b96d6ebeb9643b698b3575bdd6f78bb144200
-commit e5591161f21ab493c6284a85ac3c0710ad94998f
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Nov 6 13:54:17 2020 +1100
+commit 473ddfc2d6b602cb2d1d897e0e5c204de145cd9a
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Mar 19 03:25:01 2021 +0000
- AC_CHECK_HEADER() is obsoleted in autoconf 2.70.
+ upstream: split
- Replace with the non-obsoleted AC_CHECK_HEADERS().
+ OpenBSD-Regress-ID: f6c03c0e4c58b3b9e04b161757b8c10dc8378c34
-commit 05bcd0cadf160fd4826a2284afa7cba6ec432633
+commit 1339800fef8d0dfbfeabff71b34670105bcfddd2
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Nov 3 22:53:12 2020 +0000
+Date: Wed Mar 31 22:16:34 2021 +0000
- upstream: fold consecutive '*' wildcards to mitigate combinatorial
+ upstream: Use new limits@openssh.com protocol extension to let the
- explosion of recursive searches; ok dtucker
+ client select good limits based on what the server supports. Split the
+ download and upload buffer sizes to allow them to be chosen independently.
- OpenBSD-Commit-ID: d18bcb39c40fb8a1ab61153db987e7d11dd3792b
+ 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 7d680448db5858dc76307663f78d0b8d3c2b4a3d
+commit 6653c61202d104e59c8e741329fcc567f7bc36b8
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Oct 30 01:50:07 2020 +0000
+Date: Wed Mar 31 21:58:07 2021 +0000
- upstream: print reason in fatal error message when
+ upstream: do not advertise protocol extensions that have been
- kex_assemble_namelist() fails
+ disallowed by the command-line options (e.g. -p/-P/-R); ok dtucker@
- OpenBSD-Commit-ID: a9975ee8db6c98d6f32233d88051b2077ca63dab
+ OpenBSD-Commit-ID: 3a8a76b3f5131741aca4b41bfab8d101c9926205
-commit 95d1109fec7e89ad21f2a97e92bde1305d32a353
+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: Thu Oct 29 03:13:06 2020 +0000
+Date: Fri Mar 19 02:22:34 2021 +0000
- upstream: fix sshd_config SetEnv directive inside Match blocks; part of
+ upstream: return non-zero exit status when killed by signal; bz#3281 ok
- github PR#201 from github user manuelm
+ dtucker@
- OpenBSD-Commit-ID: 9772e3748abff3ad65ae8fc43d026ed569b1d2bc
+ OpenBSD-Commit-ID: 117b31cf3c807993077b596bd730c24da9e9b816
-commit b12b835dc022ba161afe68348e05a83dfbcb1515
+commit 1269b8a686bf1254b03cd38af78167a04aa6ec88
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Oct 29 03:01:18 2020 +0000
+Date: Fri Mar 19 02:18:28 2021 +0000
- upstream: fix type of nid in type_bits_valid(); github PR#202 from
+ upstream: increase maximum SSH2_FXP_READ to match the maximum
- github user thingsconnected
+ 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: 769d2b040dec7ab32d323daf54b854dd5dcb5485
+ OpenBSD-Commit-ID: 4e67d60d81bde7b84a742b4ee5a34001bdf80d9c
-commit 1a14c13147618144d1798c36a588397ba9008fcc
+commit 860b67604416640e8db14f365adc3f840aebcb1f
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Oct 29 02:52:43 2020 +0000
+Date: Tue Mar 16 06:15:43 2021 +0000
- upstream: whitespace; no code change
+ upstream: don't let logging clobber errno before use
- OpenBSD-Commit-ID: efefc1c47e880887bdee8cd2127ca93177eaad79
+ OpenBSD-Commit-ID: ce6cca370005c270c277c51c111bb6911e1680ec
-commit 815209abfdd2991fb92ad7d2e33374916cdcbcf4
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Oct 29 02:47:23 2020 +0000
+commit 5ca8a9216559349c56e09039c4335636fd85c241
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Mar 13 14:40:43 2021 +1100
- 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@
+ Only call dh_set_moduli_file if using OpenSSL.
- OpenBSD-Commit-ID: 5113d7f550bbd48243db1705afbf16b63792d4b7
+ Fixes link failure when configuring --without-openssl since dh.c is not
+ linked in.
-commit a575cf44e59a65506c67bddb62a712208a7a279c
-Author: Duncan Eastoe <duncan.eastoe@att.com>
-Date: Wed Oct 21 10:11:10 2020 +0100
+commit 867a7dcf003c51d5a83f83565771a35f0d9530ac
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Mar 13 13:52:53 2021 +1100
- session.c: use "denylist" terminology
+ Don't install moduli during tests.
- Follow upstream (6d755706a0059eb9e2d63517f288b75cbc3b4701) language
- improvements in this portable-specific code.
+ 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 33267feaffd5d98aa56d2f0b3a99ec352effe938
-Author: Damien Miller <djm@mindrot.org>
-Date: Tue Oct 27 16:46:31 2020 +1100
+commit 0c054538fccf92b4a028008321d3711107bee6d5
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Mar 13 13:51:26 2021 +1100
- Remove checks for strict POSIX mkdtemp()
+ Point TEST_SSH_MODULI_FILE at our own moduli.
- 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@
+ This will allow the test to run without requiring a moduli file
+ installed at the configured default path.
-commit 492d70e18bad5a8c97d05f5eddac817171e88d2c
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Oct 26 00:39:04 2020 +0000
+commit 4d48219c72ab0c71238806f057f0e9630b7dd25c
+Author: jsg@openbsd.org <jsg@openbsd.org>
+Date: Fri Mar 12 05:18:01 2021 +0000
- upstream: Minor man page fixes (capitalization, commas) identified by
-
- the manpage-l10n project via bz#3223. feedback deraadt@, ok jmc@
+ upstream: spelling
- OpenBSD-Commit-ID: ab83af0daf18369244a72daaec6c4a58a9eb7e2c
+ OpenBSD-Commit-ID: 478bc3db04f62f1048ed6e1765400f3ab325e60f
-commit eab2888cfc6cc4e2ef24bd017da9835a0f365f3f
+commit 88057eb6df912abf2678ea5c846d9d9cbc92752c
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Oct 19 22:49:23 2020 +0000
+Date: Fri Mar 12 04:08:19 2021 +0000
- upstream: Adapt XMSS to new logging infrastructure. With markus@, ok
+ upstream: Add ModuliFile keyword to sshd_config to specify the
- djm@.
+ 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: 9c35ec3aa0f710e4e3325187ceff4fa3791686de
+ OpenBSD-Commit-ID: 8df99d60b14ecaaa28f3469d01fc7f56bff49f66
-commit f7bd11e4941620991f3e727cd0131b01f0311a58
+commit f07519a2af96109325b5a48b1af18b57601074ca
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Oct 19 08:07:08 2020 +0000
+Date: Fri Mar 12 03:43:40 2021 +0000
- upstream: fix SEGV on fatal() errors spotted by dtucker@
+ upstream: pwcopy() struct passwd that we're going to reuse across a
- OpenBSD-Commit-ID: 75f155a1ac61e364ed00dc379e2c42df81067ce2
+ bunch of library calls; bz3273 ok dtucker@
+
+ OpenBSD-Commit-ID: b6eafa977b2e44607b1b121f5de855107809b762
-commit 7715a3b171049afa1feffb1d5a1245dfac36ce99
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Mon Oct 19 10:54:41 2020 +1100
+commit 69d6d4b0c8a88d3d1288415605f36e2df61a2f12
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Wed Mar 10 06:32:27 2021 +0000
- Use fatal_fr not fatal_r when passing r.
+ upstream: Import regenerated moduli file.
- Caught by the PAM -Werror tinderbox build.
+ OpenBSD-Commit-ID: 7ac6c252d2a5be8fbad4c66d9d35db507c9dac5b
-commit 816036f142ecd284c12bb3685ae316a68d2ef190
+commit e5895e8ecfac65086ea6b34d0d168409a66a15e1
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Oct 18 11:32:01 2020 +0000
+Date: Wed Mar 10 04:58:45 2021 +0000
- upstream: use the new variant log macros instead of prepending
+ upstream: no need to reset buffer after send_msg() as that is done
- __func__ and appending ssh_err(r) manually; ok markus@
+ for us; patch from Mike Frysinger
- OpenBSD-Commit-ID: 1f14b80bcfa85414b2a1a6ff714fb5362687ace8
+ OpenBSD-Commit-ID: 565516495ff8362a38231e0f1a087b8ae66da59c
-commit 9e2c4f64224f68fb84c49b5182e449f94b0dc985
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Oct 18 11:21:59 2020 +0000
+commit 721948e67488767df0fa0db71ff2578ee2bb9210
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sat Mar 13 01:52:16 2021 +0000
- upstream: variants of the log methods that append a ssherr.h string
+ upstream: Add TEST_SSH_MODULI_FILE variable to allow overriding of the
- from a supplied error code; ok markus@
+ moduli file used during the test run.
- OpenBSD-Commit-ID: aed98c4435d48d036ae6740300f6a8357b7cc0bf
+ OpenBSD-Regress-ID: be10f785263120edb64fc87db0e0d6570a10220a
-commit 28cb0a4b03940d1ee576eb767a81a4113bdc917e
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Oct 18 11:14:27 2020 +0000
+commit 82fef71e20ffef425b932bec26f5bc46aa1ed41c
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Mar 12 15:58:57 2021 +1100
- upstream: remove a level of macro indirection; ok markus@
+ Allow (but return EACCES) fstatat64 in sandbox.
- OpenBSD-Commit-ID: 0c529d06e902c5d1a6b231e1bec6157f76dc67c9
+ This is apparently used in some configurations of OpenSSL when glibc
+ has getrandom(). bz#3276, patch from Kris Karas, ok djm@
-commit 9cac1db52e6c4961c447910fe02cd68a3b2f9460
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Oct 18 11:13:45 2020 +0000
+commit 1cd67ee15ce3d192ab51be22bc4872a6a7a4b6d9
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Mar 12 13:16:10 2021 +1100
- upstream: add some variant log.h calls that prepend the calling
-
- function name; ok markus@
+ Move generic includes outside of ifdef.
- OpenBSD-Commit-ID: 4be1b2e2455b271ddb7457bc195c5367644f4e48
+ 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 d55dfed34ef6ef1f028d552a90d5f3dba8dd6f7b
-Author: Damien Miller <djm@mindrot.org>
-Date: Sat Oct 17 22:55:24 2020 +1100
+commit 2421a567a8862fe5102a4e7d60003ebffd1313dd
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Mar 10 17:41:21 2021 +1100
- missing header
+ Import regenerated moduli file.
-commit 999d7cb79a3a73d92a6dfbf174c33da0d984c7a2
-Author: Damien Miller <djm@mindrot.org>
-Date: Sat Oct 17 22:47:52 2020 +1100
+commit e99080c05d9d48dbbdb022538533d53ae1bd567d
+Author: millert@openbsd.org <millert@openbsd.org>
+Date: Sat Mar 6 20:36:31 2021 +0000
- sync regress/misc/sk-dummy/fatal.c
+ 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 3554b4afa38b3483a3302f1be18eaa6f843bb260
+commit 160db17fc678ceb5e3fd4a7e006cc73866f484aa
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Oct 17 01:28:20 2020 +0000
+Date: Wed Mar 3 22:41:49 2021 +0000
- upstream: make the log functions that exit (sshlogdie(),
+ upstream: don't sshbuf_get_u32() into an enum; reported by goetze
- sshfatal(), etc) have identical signatures. Makes things a bit more
- consistent...
+ AT dovetail.com via bz3269
- OpenBSD-Commit-ID: bd0ae124733389d7c0042e135c71ee9091362eb9
+ OpenBSD-Commit-ID: 99a30a8f1df9bd72be54e21eee5c56a0f050921a
-commit 616029a85ad7529b24bb8c4631d9607c0d6e7afe
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Fri Oct 16 14:34:33 2020 +0000
+commit cffd033817a5aa388764b6661855dcdaabab0588
+Author: sthen@openbsd.org <sthen@openbsd.org>
+Date: Wed Mar 3 21:40:16 2021 +0000
- upstream: add space between macro arg and punctuation;
+ upstream: typo in other_hostkeys_message() display output, ok djm
- OpenBSD-Commit-ID: bb81e2ed5a77832fe62ab30a915ae67cda57633e
+ OpenBSD-Commit-ID: 276f58afc97b6f5826e0be58380b737603dbf5f5
-commit f812a36cee5727147bc897d34ab9af068dd4561e
-Author: Damien Miller <djm@mindrot.org>
-Date: Sat Oct 17 12:03:34 2020 +1100
+commit 7fe141b96b13bd7dc67ca985e14d55b9bd8a03fd
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Mar 3 08:42:52 2021 +0000
- check for and require a C99 capable compiler
+ upstream: needs FILE*; from Mike Frysinger
- recent logging changes use __VA_ARGS__.
+ OpenBSD-Commit-ID: dddb3aa9cb5792eeeaa37a1af67b5a3f25ded41d
-commit f9ea6515202b59a1e2d5b885cafc1b12eff33016
+commit d2afd717e62d76bb41ab5f3ab4ce6f885c8edc98
Author: Damien Miller <djm@mindrot.org>
-Date: Sat Oct 17 11:51:20 2020 +1100
+Date: Tue Mar 2 21:31:47 2021 +1100
- logging is now macros, remove function pointers
+ update depend
-commit 0f938f998626e8359324f803157cd7c9f8f403e2
+commit f0c4eddf7cf224ebcac1f07ac8afdb30c6e9fe0a
Author: Damien Miller <djm@mindrot.org>
-Date: Sat Oct 17 11:42:26 2020 +1100
+Date: Tue Mar 2 21:30:14 2021 +1100
- adapt sk-dummy's fatal implementation to changes
+ update relnotes URL
-commit afbd9ec9e2dbad04834ce7ce53e58740434f32a5
+commit 67a8bb7fe62a381634db4c261720092e7d514a3d
Author: Damien Miller <djm@mindrot.org>
-Date: Sat Oct 17 11:33:13 2020 +1100
+Date: Tue Mar 2 21:29:54 2021 +1100
- fix netcat build problem
+ update RPM spec version numbers
-commit 793b583d097381730adaf6f68bed3c343139a013
+commit 0a4b23b11b9a4e6eec332dd5c6ab2ac6f62aa164
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Oct 16 13:26:13 2020 +0000
+Date: Tue Mar 2 01:48:18 2021 +0000
- upstream: LogVerbose keyword for ssh and sshd
+ upstream: openssh-8.5
- Allows forcing maximum debug logging by file/function/line pattern-
- lists.
+ 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
- ok markus@
+ =?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: c294c25732d1b4fe7e345cb3e044df00531a6356
+ OpenBSD-Commit-ID: 9c87f39a048cee2a7d1c8bab951b2f716256865e
-commit 752250caabda3dd24635503c4cd689b32a650794
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Oct 16 13:24:45 2020 +0000
+commit e774bac35933e71f924f4301786e7fb5bbe1422f
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sun Feb 28 01:50:47 2021 +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.
+ upstream: Do not try to reset signal handler for signal 0 in
- ok markus@
+ subprocess. Prevents spurious debug message. ok djm@
- OpenBSD-Commit-ID: 51a472610cbe37834ce6ce4a3f0e0b1ccc95a349
+ OpenBSD-Commit-ID: 7f9785e292dcf304457566ad4637effd27ad1d46
-commit acadbb3402b70f72f14d9a6930ad41be97c2f9dc
+commit 351c5dbbd74ce300c4f058112f9731c867c6e225
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Oct 16 02:37:12 2020 +0000
+Date: Sat Feb 27 23:42:37 2021 +0000
- upstream: use do_log2 instead of function pointers to different log
+ upstream: fix alphabetic ordering of options; spotted by Iain Morgan
- functions
+ 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.
- OpenBSD-Commit-ID: 88077b826d348c58352a6b394755520f4e484480
+ Some very minor fixes, missing 's' and punctuation.
-commit 95b0bcfd1531d59e056ae8af27bb741391f26ab0
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Oct 14 00:55:17 2020 +0000
+commit 6248b86074804983e8f7a2058856a516dbfe2924
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Feb 26 16:45:50 2021 +1100
- upstream: make UpdateHostkeys still more conservative: refuse to
+ Revert "ssh: optional bind interface if bind address specified."
- 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
+ This reverts commit 5a878a71a3528c2626aa1d331934fd964782d41c.
- Also, do not attempt to fix known_hosts with incomplete host/ip matches
- when there are no new or deprecated hostkeys.
+ 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
- OpenBSD-Commit-ID: 95c19842f7c41f9bd9c92aa6441a278c0fd0c4a3
+ 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 a336ce8c2c55547cc00e0070a18c55f30bb53fb6
-Author: kn@openbsd.org <kn@openbsd.org>
-Date: Mon Oct 12 08:36:36 2020 +0000
+commit 5a878a71a3528c2626aa1d331934fd964782d41c
+Author: Dmitrii Turlupov <dturlupov@factor-ts.ru>
+Date: Thu Feb 4 16:27:31 2021 +0300
- upstream: Zap unused family parameter from ssh_connect_direct()
+ ssh: optional bind interface if bind address specified.
- sshconnect.c r1.241 from 2013 made it unused; found while reading code.
+ 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
- OK djm
+ nice with popular fuzzing drivers like libfuzzer. AFAIK nobody has used it
+ but me.
- OpenBSD-Commit-ID: 219ba6d7f9925d0b7992918612680399d86712b5
+ OpenBSD-Regress-ID: cad919522b3ce90c147c95abaf81b0492ac296c9
-commit e545d94b713effab8e6c7dfabbfb76c1d84d7498
-Author: Philip Hands <phil@hands.com>
-Date: Sun Oct 4 00:15:46 2020 +0200
+commit 24a3a67bd7421740d08803b84bd784e764107928
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Feb 26 11:49:19 2021 +1100
- shift contents of long $() into filter_ids()
+ Remove macos-11.00 PAM test target too.
- 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.
+ 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
- SSH-Copy-ID-Upstream: 3dab3366a584427045c8a690a93282f02c09cf24
+ OpenBSD-Commit-ID: d9fbce14945721061cb322f0084c2165d33d1993
-commit fd360174596047b52aa1cddda74d85012a03ca4b
-Author: Philip Hands <phil@hands.com>
-Date: Sat Oct 3 23:15:16 2020 +0200
+commit fd9fa76a344118fe1ef10b9a6c9e85d39599e9a8
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Feb 26 01:15:10 2021 +1100
- combine if/elif to avoid duplication of the action
+ Remove macos-11.0 from the test target list.
- SSH-Copy-ID-Upstream: 42aeb1cc53d3f7f6e78edc210fb121fda0834914
+ It has been consistently failing for the past few days with a github
+ actions internal error.
-commit f7c3a39b016dd77709ecbf18da8282f967b86cd7
+commit 476ac8e9d33dbf96ef97aab812b8d7089d0cdc24
Author: Philip Hands <phil@hands.com>
-Date: Sat Oct 3 21:45:16 2020 +0200
+Date: Wed Feb 24 23:43:16 2021 +0100
- shellcheck tidyage
+ tidy the $INSTALLKEY_SH code layout a little
- SSH-Copy-ID-Upstream: 5b08f840e78ac544288b3983010a1b0585e966fd
+ SSH-Copy-ID-Upstream: 78178aa5017222773e4c23d9001391eeaeca8983
-commit 108676c3f26be6c873db0dd8754063699908727b
-Author: Philip Hands <phil@hands.com>
-Date: Sat Oct 3 21:10:03 2020 +0200
+commit 983e05ef3b81329d76d6a802b39ad0d1f637c06c
+Author: Jakub Jelen <jjelen@redhat.com>
+Date: Tue Sep 29 10:02:45 2020 +0000
- tidy up test of $SCRATCH_DIR creation
+ if unable to add a missing newline, fail
- SSH-Copy-ID-Upstream: 2d8b22d96c105d87743ffe8874887b06f8989b93
+ SSH-Copy-ID-Upstream: 76b25e18f55499ea9edb4c4d6dc4a80bebc36d95
-commit a9c9e91a82bc1a2cf801b4e3ef27a941dbd27717
+commit 3594b3b015f6014591da88ba71bf6ff010be7411
Author: Philip Hands <phil@hands.com>
-Date: Wed Sep 16 16:13:30 2020 +0200
+Date: Tue Oct 13 14:12:58 2020 +0200
- add -s flag: to install keys via SFTP
-
- This is prompted by:
+ use $AUTH_KEY_DIR, now that we have it
- https://bugzilla.mindrot.org/show_bug.cgi?id=3201
+ since that was a change made since jjelen's commit was written
- Thanks go to Matthias Blümel for the idea, and the helpful patch, from
- which this patch grew.
+ also, quote the variables
- SSH-Copy-ID-Upstream: f7c76dc64427cd20287a6868f672423b62057614
+ SSH-Copy-ID-Upstream: 588cd8e5cbf95f3443d92b9ab27c5d73ceaf6616
-commit f92424970c02b78852ff149378c7f2616ada4ccf
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Oct 11 22:14:38 2020 +0000
+commit 333e25f7bc43cee6e36f766e39dad6f9918b318c
+Author: Jakub Jelen <jjelen@redhat.com>
+Date: Tue Sep 29 10:00:01 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.
+ restorecon the correct directory
- ok markus@
+ if using different path for authorized_keys file
- OpenBSD-Commit-ID: 6444a705ba504c3c8ccddccd8d1b94aa33bd11c1
+ SSH-Copy-ID-Upstream: 791a3df47b48412c726bff6f7b1d190721e65d51
-commit d98f14b5328922ae3085e07007d820c4f655b57a
+commit 9beeab8a37a49a9e3ffb1972fff6621ee5bd7a71
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Oct 11 22:13:37 2020 +0000
+Date: Thu Feb 25 03:27:34 2021 +0000
- upstream: UpdateHostkeys: better CheckHostIP handling
+ upstream: s/PubkeyAcceptedKeyTypes/PubkeyAcceptedAlgorithms/
- 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.
+ 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.
- Make sure this works with HashKnownHosts too, which requires maintaining
- a list of entry-types seen across the whole file for each key.
+ 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
- ok markus@
+ pubkeyacceptedalgorithms after their current names so that the config-dump
+ mode finds and uses the current names. Spotted by Phil Pennock.
- OpenBSD-Commit-ID: 374dc263103f6b343d9671f87dbf81ffd0d6abdd
+ OpenBSD-Commit-ID: 5dd10e93cccfaff3aaaa09060c917adff04a9b15
-commit af5941ae9b013aac12585e84c4cf494f3728982f
+commit 8b8b60542d6652b2c91e0ef9e9cc81bcb65e6b42
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Oct 11 22:12:44 2020 +0000
+Date: Tue Feb 23 21:55:08 2021 +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.
+ upstream: lots more s/key types/signature algorithms/ mostly in
- ok markus@
+ HostbasedAcceptedAlgorithms and HostKeyAlgorithms; prompted by Jakub Jelen
- OpenBSD-Commit-ID: e434828191fb5f3877d4887c218682825aa59820
+ OpenBSD-Commit-ID: 3f719de4385b1a89e4323b2549c66aae050129cb
-commit 6247812c76f70b2245f3c23f5074665b3d436cae
+commit 0aeb508aaabc4818970c90831e3d21843c3c6d09
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Oct 8 01:15:16 2020 +0000
+Date: Tue Feb 23 21:50:18 2021 +0000
- upstream: don't misdetect comma-separated hostkey names as wildcards;
+ upstream: Correct reference to signature algorithms as keys; from
- spotted by naddy@
+ Jakub Jelen
- OpenBSD-Commit-ID: 4b874edfec7fc324a21b130bdb42f912177739ce
+ OpenBSD-Commit-ID: 36f7ecee86fc811aa0f8e21e7a872eee044b4be5
-commit 67146c7d022a170be3cdad2f5f40259a663fb266
-Author: wangxp006 <wangxiaopeng7@huawei.com>
-Date: Thu Oct 8 17:49:59 2020 +0800
+commit f186a020f2ba5f9c462a23293750e29ba0a746b1
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Feb 23 16:05:22 2021 +1100
- fix TEST_MALLOC_OPTIONS var
+ Add a couple more test VMs.
-commit 3205eaa3f8883a34fa4559ddef6c90d1067c5cce
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Oct 8 00:31:05 2020 +0000
+commit ffcdd3d90e74176b3bb22937ad1f65a6c1cd3f9d
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Feb 22 08:09:27 2021 +1100
- upstream: clarify conditions for UpdateHostkeys
+ Valgrind test: split and move up list.
- OpenBSD-Commit-ID: 9cba714cf6aeed769f998ccbe8c483077a618e27
+ 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 e8dfca9bfeff05de87160407fb3e6a5717fa3dcb
+commit c3b1636770785cc2830dedd0f22ef7d3d3491d6d
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Oct 7 06:38:16 2020 +0000
+Date: Tue Feb 23 00:05:31 2021 +0000
- upstream: remove GlobalKnownHostsFile for this test after
+ upstream: warn when the user specifies a ForwardAgent path that does
- UpdateHostkeys change
+ not exist and exit if ExitOnForwardFailure is set; bz3264
- OpenBSD-Regress-ID: a940ad79d59343319613ba8fc46b6ef24aa3f8e1
+ OpenBSD-Commit-ID: 72f7875865e723e464c71bf8692e83110699bf26
-commit 4aa2717d7517cff4bc423a6cfba3a2defb055aea
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Oct 7 02:26:28 2020 +0000
+commit 5fcb0514949d61aadaf4a89cf16eb78fb47491ec
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Feb 20 13:34:02 2021 +1100
- 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@
+ Disable rlimit sandbox, doesn't work with valgrind
- OpenBSD-Commit-ID: 98b524f121f4252309dd21becd8c4cacb0c6042a
+ Only run regress tests, runing unit tests as well makes it run longer
+ than allowed y github.
-commit 04c06d04475f1f673e9d9743710d194453fe3888
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Oct 7 02:25:43 2020 +0000
+commit bb0b9bf45396c19486080d3eb0a159f94de7e6ba
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Feb 20 13:06:25 2021 +1100
- 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
+ Upload valgrind logs on failure.
-commit b70e33711291f3081702133175a41cccafc0212a
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Oct 7 02:24:51 2020 +0000
+commit ebb3b75e974cb241c6b9b9f5881b09c7bd32b651
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Feb 19 22:18:50 2021 +1100
- 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@
+ Rename "vm" to "os" in selfhosted to match c-cpp.
- OpenBSD-Commit-ID: eabb771a6add676c398d38a143a1aff5f04abbb9
+ Should make it easier to share code or maybe merge at some point.
-commit aa623142e426ca1ab9db77b06dcc9b1b70bd102b
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Oct 7 02:22:23 2020 +0000
+commit 76c0be0fe0465cb2b975dbd409f8d38b55e55bcb
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Feb 19 22:15:22 2021 +1100
- 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@
+ 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...
- OpenBSD-Commit-ID: fb92d25b216bff8c136da818ac2221efaadf18ed
+ until I can figure out why it's failing.
-commit f4f14e023cafee1cd9ebe4bb0db4029e6e1fafac
+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: Wed Oct 7 02:20:35 2020 +0000
+Date: Thu Feb 18 02:49:35 2021 +0000
- upstream: simply disable UpdateHostkeys when a certificate
+ upstream: Fix the hostkeys rotation extension documentation
- successfully authenticated the host; simpler than the complicated plumbing
- via kex->flags we have now.
+ The documentation was lacking the needed want-reply field in the initial
+ global request.
- ok markus@
+ https://github.com/openssh/openssh-portable/pull/218 by dbussink
- OpenBSD-Commit-ID: 80e39644eed75717d563a7f177e8117a0e14f42c
+ OpenBSD-Commit-ID: 051824fd78edf6d647a0b9ac011bf88e28775054
-commit e79957e877db42c4c68fabcf6ecff2268e53acb5
+commit 34c5ef6e2d06d9f0e20cb04a9aebf67a6f96609a
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Oct 7 02:18:45 2020 +0000
+Date: Thu Feb 18 02:15:07 2021 +0000
- upstream: disable UpdateHostkeys by default if VerifyHostKeyDNS is
+ upstream: make names in function prototypes match those in
- enabled; suggested by Mark D. Baushke
+ definition from https://github.com/openssh/openssh-portable/pull/225 by
+ ZenithalHourlyRate
- OpenBSD-Commit-ID: 85a1b88592c81bc85df7ee7787dbbe721a0542bf
+ OpenBSD-Commit-ID: 7c736307bf3f2c7cb24d6f82f244eee959485acd
-commit 3d4c2016bae1a6f14b48c1150a4c79ca4c9968bd
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Oct 6 07:12:04 2020 +0000
+commit 88e3d4de31ab4f14cac658e9e0c512043b15b146
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Feb 18 02:13:58 2021 +0000
- upstream: Agent protocol draft is now at rev 4. ok djm@
+ upstream: unbreak SK_DEBUG builds
- OpenBSD-Commit-ID: 8c01ea3aae48aab45e01b7421b0fca2dad5e7837
+ from https://github.com/openssh/openssh-portable/pull/225 by
+ ZenithalHourlyRate
+
+ OpenBSD-Commit-ID: 28d7259ce1b04d025411464decfa2f1a097b43eb
-commit af889a40ffc113af9105c03d7b32131eb4372d50
+commit 788cbc5b74a53956ba9fff11e1ca506271a3597f
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Oct 4 09:45:01 2020 +0000
+Date: Thu Feb 18 00:30:17 2021 +0000
- upstream: when ordering host key algorithms in the client, consider
+ upstream: sftp-server: implement limits@openssh.com extension
- the ECDSA key subtype; ok markus@
+ 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.
- OpenBSD-Commit-ID: 3097686f853c61ff61772ea35f8b699931392ece
+ Patch from Mike Frysinger; ok dtucker@
+
+ OpenBSD-Commit-ID: f96293221e5aa24102d9bf30e4f4ef04d5f4fb51
-commit 2d39fc9f7e039351daa3d6aead1538ac29258add
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sun Oct 4 03:04:02 2020 +0000
+commit 324449a68d510720d0e4dfcc8e9e5a702fe6a48f
+Author: Damien Miller <djm@mindrot.org>
+Date: Thu Feb 18 12:06:25 2021 +1100
- upstream: Allow full range of UIDs and GIDs for sftp chown and
+ support OpenSSL 3.x cipher IV API change
- chgrp on 32bit platforms instead of being limited by LONG_MAX. bz#3206,
- found by booking00 at sina.cn, ok markus@
+ OpenSSL renamed the "get current CIPHER_CTX" IV operation in 3.x.
+ This uses the new name if available.
- OpenBSD-Commit-ID: 373b7bbf1f15ae482d39567ce30d18b51c9229b5
+ https://github.com/openssl/openssl/issues/13411
+
+ bz#3238 ok dtucker@
-commit 396d32f3a1a16e54df2a76b2a9b237868580dcbe
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Oct 3 09:22:26 2020 +0000
+commit 845fe9811c047063d935eca89188ed55c993626b
+Author: Damien Miller <djm@mindrot.org>
+Date: Thu Feb 18 11:25:38 2021 +1100
- upstream: There are lots of place where we want to redirect stdin,
+ prefer login_getpwclass() to login_getclass()
- 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@
+ 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.
- OpenBSD-Commit-ID: 3033ba5a4c47cacfd5def020d42cabc52fad3099
+ Based on FreeBSD PR 37416 via Ed Maste; ok dtucker@
-commit 1286981d08b8429a64613215ce8bff3f6b32488a
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Oct 3 08:30:47 2020 +0000
+commit d0763c8d566119cce84d9806e419badf20444b02
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Feb 18 10:45:27 2021 +1100
- upstream: enable UpdateHostkeys by default when the configuration
-
- has not overridden UserKnownHostsFile; ok markus@ "The timing is perfect"
- deraadt@
-
- OpenBSD-Commit-ID: 62df71c9c5242da5763cb473c2a2deefbd0cef60
+ Fixing quoting for installing moduli on target guest.
-commit 332f21537293d66508f7342dc643bc7fe45f0f69
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Oct 3 08:12:59 2020 +0000
+commit b3afc243bc820f323a09e3218e9ec8a30a3c1933
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Feb 18 10:27:16 2021 +1100
- 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
+ Install moduli on target not host.
-commit 13cee44ef907824083d89cb9395adbbd552e46c1
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Oct 3 08:11:28 2020 +0000
+commit f060c2bc85d59d111fa18a12eb3872ee4b9f7e97
+Author: Damien Miller <djm@mindrot.org>
+Date: Thu Feb 18 10:33:58 2021 +1100
- upstream: record when the host key checking code downgrades a
+ don't free string returned by login_getcapstr(3)
- 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 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.
- OpenBSD-Commit-ID: 2ada81853ff9ee7824c62f440bcf4ad62030c901
+ From https://reviews.freebsd.org/D28617 via Ed Maste; ok dtucker@
-commit 12ae8f95e2e0c273e9e7ef930b01a028ef796a3f
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Oct 3 04:15:06 2020 +0000
+commit bc9b0c25703215501da28aa7a6539f96c0fa656f
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Feb 18 10:10:00 2021 +1100
- upstream: prefer ed25519 signature algorithm variants to ECDSA; ok
-
- markus@
-
- OpenBSD-Commit-ID: 82187926fca96d35a5b5afbc091afa84e0966e5b
+ Skip unit tests on sol11 to speed things up.
-commit e5ed753add7aa8eed6b167e44db6240a76404db2
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Oct 3 03:40:38 2020 +0000
+commit 161873035c12cc22211fc73d07170ade47746bc5
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Feb 18 10:09:27 2021 +1100
- upstream: want time.h here too
-
- OpenBSD-Commit-ID: fafee8f1108c64ad8b282f9a1ed5ea830d8c58a7
+ Remove SKIP_UNIT as it needs to be a make arg.
-commit 66bd9fdf8b7762eb6a85cabbb1ae4ed955679f60
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Sat Oct 3 02:18:33 2020 +0000
+commit 1c293868e4b4e8e74e3ea15b8dff90f6b089967a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Feb 18 10:05:03 2021 +1100
- 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..
+ Always intall moduli.
- OpenBSD-Commit-ID: 58e1f72d292687f63eb357183036ee242513691c
+ Allows us to run tests without falling back to a fixed modulus. Ensure that
+ the directory exists.
-commit 86cc8ce002ea10e88a4c5d622a8fdfab8a7d261f
-Author: Damien Miller <djm@mindrot.org>
-Date: Sat Oct 3 13:38:55 2020 +1000
+commit 5c8f41ad100601ec2fdcbccdfe92890c31f81bbe
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Feb 18 09:59:09 2021 +1100
- use relative rather than system include here
+ Quote SSHD_CONFOPTS in case it contains spaces.
-commit 922cfac5ed5ead9f796f7d39f012dd653dc5c173
-Author: Damien Miller <djm@mindrot.org>
-Date: Sat Oct 3 13:38:41 2020 +1000
+commit 4653116c1f5384ea7006e6396d9b53c33d218975
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Feb 18 09:51:18 2021 +1100
- add some openbsd-compat licenses we missed
+ Fix labels on targets (dots vs underscores).
-commit ce941c75ea9cd6c358508a5b206809846c8d9240
-Author: Philip Hands <phil@hands.com>
-Date: Sat Oct 3 00:20:07 2020 +0200
+commit 4512047f57ca3c6e8cd68f0cc69be59e98b25287
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Feb 17 21:47:48 2021 +1100
- un-nest $() to make ksh cheerful
+ More compact representation of config matrix.
-commit 18ea5f4b88e303677d2003b95e5cb864b439e442
-Author: Philip Hands <phil@hands.com>
-Date: Fri Oct 2 21:30:10 2020 +0200
+commit 0406cd09f05c2e419b113dd4c0eac8bc34ec915b
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Feb 17 21:19:18 2021 +1100
- 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.
+ Skip unit tests on hosted VMs to speed things up.
-commit d9e727dcc04a52caaac87543ea1d230e9e6b5604
-Author: Oleg <Fallmay@users.noreply.github.com>
-Date: Thu Oct 1 12:09:08 2020 +0300
+commit 4582612e6147d766c336198c498740242fb8f1ec
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Feb 17 20:21:29 2021 +1100
- Fix `EOF: command not found` error in ssh-copy-id
+ Merge macos and ubuntu tests.
-commit a1a856d50c89be3206f320baa4bfb32fff4e826f
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Sep 30 09:11:39 2020 +0000
+commit 09f4b84654b71099559492e9aed5e1a38bf24815
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Feb 17 18:41:30 2021 +1100
- upstream: Regen moduli.
-
- OpenBSD-Commit-ID: 04967f8c43e9854ac34b917bcd6f5ac96c53a693
+ Convert most github hosted tests to new config structure.
-commit fa1fe3ead7069d90d3c67d62137ad66acfcc9f48
-Author: HARUYAMA Seigo <haruyama@unixuser.org>
-Date: Sun Sep 27 20:06:20 2020 +0900
+commit 65380ff7e054be1454e5ab4fd7bb9c66f8fcbaa9
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Feb 17 18:27:36 2021 +1100
- Restore first section title of INSTALL
+ Only run selfhosted tests from selfhosted repo.
-commit 279261e1ea8150c7c64ab5fe7cb4a4ea17acbb29
-Author: Damien Miller <djm@mindrot.org>
-Date: Sun Sep 27 17:25:01 2020 +1000
+commit f031366535650b88248ed7dbf23033afdf466240
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Jan 15 14:11:43 2021 +1100
- update version numbers
+ 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 58ca6ab6ff035ed12b5078e3e9c7199fe72c8587
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Sep 27 07:22:05 2020 +0000
+commit 64bbd7444d658ef7ee14a7ea5ccc7f5810279ee7
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Wed Feb 17 03:59:00 2021 +0000
- upstream: openssh 8.4
+ upstream: Make sure puttygen is new enough to successfully run the
+
+ PuTTY interop tests, otherwise skip them.
- OpenBSD-Commit-ID: a29e5b372d2c00e297da8a35a3b87c9beb3b4a58
+ OpenBSD-Regress-ID: 34565bb50b8aec58331ed02a5e9e0a9a929bef51
-commit 9bb8a303ce05ff13fb421de991b495930be103c3
-Author: Damien Miller <djm@mindrot.org>
-Date: Tue Sep 22 10:07:43 2020 +1000
+commit da0a9afcc446a30ca49dd216612c41ac3cb1f2d4
+Author: markus@openbsd.org <markus@openbsd.org>
+Date: Mon Feb 15 20:43:15 2021 +0000
- sync with upstream ssh-copy-id rev f0da1a1b7
+ upstream: ssh: add PermitRemoteOpen for remote dynamic forwarding
+
+ with SOCKS ok djm@, dtucker@
+
+ OpenBSD-Commit-ID: 64fe7b6360acc4ea56aa61b66498b5ecc0a96a7c
-commit 0a4a5571ada76b1b012bec9cf6ad1203fc19ec8d
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Sep 21 07:29:09 2020 +0000
+commit b696858a7f9db72a83d02cb6edaca4b30a91b386
+Author: markus@openbsd.org <markus@openbsd.org>
+Date: Mon Feb 15 20:36:35 2021 +0000
- upstream: close stdin when forking after authentication too; ok markus
+ upstream: factor out opt_array_append; ok djm@
- OpenBSD-Commit-ID: 43db17e4abc3e6b4a7b033aa8cdab326a7cb6c24
+ OpenBSD-Commit-ID: 571bc5dd35f99c5cf9de6aaeac428b168218e74a
-commit d14fe25e6c3b89f8af17e2894046164ac3b45688
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Sep 20 23:31:46 2020 +0000
+commit ad74fc127cc45567e170e8c6dfa2cfd9767324ec
+Author: dlg@openbsd.org <dlg@openbsd.org>
+Date: Mon Feb 15 11:09:22 2021 +0000
- upstream: close stdout/stderr after "ssh -f ..." forking
+ upstream: ProxyJump takes "none" to disable processing like
- bz#3137, ok markus
+ ProxyCommand does
- OpenBSD-Commit-ID: e2d83cc4dea1665651a7aa924ad1ed6bcaaab3e2
-
-commit 53a33a0d745179c02108589e1722457ca8ae4372
-Author: Damien Miller <djm@mindrot.org>
-Date: Sun Sep 20 15:57:09 2020 +1000
-
- .depend
+ ok djm@ jmc@
+
+ OpenBSD-Commit-ID: 941a2399da2193356bdc30b879d6e1692f18b6d3
-commit 107eb3eeafcd390e1fa7cc7672a05e994d14013e
+commit 16eacdb016ccf38dd9959c78edd3a6282513aa53
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Sep 20 05:47:25 2020 +0000
+Date: Fri Feb 12 03:49:09 2021 +0000
- upstream: cap channel input buffer size at 16MB; avoids high memory use
+ upstream: sftp: add missing lsetstat@openssh.com documentation
- when peer advertises a large window but is slow to consume the data we send
- (e.g. because of a slow network)
+ patch from Mike Frysinger
- reported by Pierre-Yves David
+ 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
- fix with & ok markus@
+ function and remove an unused variable; ok dtucker@
- OpenBSD-Commit-ID: 1452771f5e5e768876d3bfe2544e3866d6ade216
+ OpenBSD-Commit-ID: e1a938657fbf7ef0ba5e73b30365734a0cc96559
-commit acfe2ac5fe033e227ad3a56624fbbe4af8b5da04
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Sep 18 22:02:53 2020 +1000
+commit 1bb130ed34721d46452529d094d9bbf045607d79
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Feb 11 10:18:05 2021 +1100
- libfido2 1.5.0 is recommended
+ 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 52a03e9fca2d74eef953ddd4709250f365ca3975
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Sep 18 08:16:38 2020 +0000
+commit f88a7a431212a16e572ecabd559e632f369c363e
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Sat Feb 6 09:37:01 2021 +1100
- upstream: handle multiple messages in a single read()
-
- PR#183 by Dennis Kaarsemaker; feedback and ok markus@
+ Add a hostname function for systems that don't have it.
- OpenBSD-Commit-ID: 8570bb4d02d00cf70b98590716ea6a7d1cce68d1
+ 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 dc098405b2939146e17567a25b08fc6122893cdf
-Author: pedro martelletto <pedro@ambientworks.net>
-Date: Fri Sep 18 08:57:29 2020 +0200
+commit 5e385a71ef2317856f37c91a98658eb12eb5a89c
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Feb 5 22:03:40 2021 +0000
- configure.ac: add missing includes
+ upstream: Roll back the hostname->uname change in rev 1.10. It turns
- when testing, make sure to include the relevant header files that
- declare the types of the functions used by the test:
+ 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.
- - stdio.h for printf();
- - stdlib.h for exit();
- - string.h for strcmp();
- - unistd.h for unlink(), _exit(), fork(), getppid(), sleep().
+ OpenBSD-Regress-ID: 827a707d6201d5a8e196a8c28aec1d2c76c52341
-commit b3855ff053f5078ec3d3c653cdaedefaa5fc362d
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Sep 18 05:23:03 2020 +0000
+commit b446c214279de50ed8388e54897eb1be5281c894
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Feb 5 06:01:58 2021 +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.
+ upstream: hostname is not specified by POSIX but uname -n is, so use
- feedback and ok markus@
+ the latter for portability. Patch from Geert Hendrickx via github PR#208.
- OpenBSD-Commit-ID: a92dd7d7520ddd95c0a16786a7519e6d0167d35f
+ OpenBSD-Regress-ID: d6a79c7c4d141a0d05ade4a042eb57dddbce89f3
-commit f93b187ab900c7d12875952cc63350fe4de8a0a8
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Sep 18 14:55:48 2020 +1000
+commit 1cb6ce98d658e5fbdae025a3bd65793980e3b5d9
+Author: David Carlier <devnexen@gmail.com>
+Date: Sat Nov 21 12:22:23 2020 +0000
- control over the colours in gnome-ssh-askpass[23]
+ Using explicit_memset for the explicit_bzero compatibility layer.
- 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.
+ Favoriting the native implementation in this case.
-commit 9d3d36bdb10b66abd1af42e8655502487b6ba1fa
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri Sep 18 14:50:38 2020 +1000
+commit 2e0beff67def2120f4b051b1016d7fbf84823e78
+Author: Luca Weiss <luca@z3ntu.xyz>
+Date: Sun Nov 8 14:19:23 2020 +0100
- 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>.
+ Deny (non-fatal) statx in preauth privsep child.
-commit d6f507f37e6c75a899db0ef8224e72797c5563b6
+commit a35d3e911e193a652bd09eed40907e3e165b0a7b
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Sep 16 03:07:31 2020 +0000
+Date: Fri Feb 5 02:20:23 2021 +0000
- upstream: Remove unused buf, last user was removed when switching
+ upstream: Remove debug message from sigchld handler. While this
- to the sshbuf API. Patch from Sebastian Andrzej Siewior.
+ works on OpenBSD it can cause problems on other platforms. From kircherlike
+ at outlook.com via bz#3259, ok djm@
- OpenBSD-Commit-ID: 250fa17f0cec01039cc4abd95917d9746e24c889
+ OpenBSD-Commit-ID: 3e241d7ac1ee77e3de3651780b5dc47b283a7668
-commit c3c786c3a0973331ee0922b2c51832a3b8d7f20f
+commit 69338ab46afe9e3dfb7762ad65351d854077c998
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Sep 9 21:57:27 2020 +0000
+Date: Tue Feb 2 22:36:59 2021 +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
+ upstream: whitespace
- OpenBSD-Commit-ID: 73097afee1b3a5929324e345ba4a4a42347409f2
+ OpenBSD-Commit-ID: 544bb092e03fcbecb420196cd0f70af13ea868ad
-commit f2950baf0bafe6aa20dfe2e8d1ca4b23528df617
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Sep 11 14:45:23 2020 +1000
+commit f71219a01d8f71c4b3ed7e456337a84ddba1653e
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Feb 2 22:36:46 2021 +0000
- New config-build-time dependency on automake.
+ 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 600c1c27abd496372bd0cf83d21a1c119dfdf9a5
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sun Sep 6 21:56:36 2020 +1000
+commit 3287790e78bf5b53c4a3cafb67bb5aa03e3910f0
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Feb 2 22:35:14 2021 +0000
- Add aclocal.m4 and config.h.in~ to .gitignore.
+ upstream: memleak on error path; ok markus@
- aclocal.m4 is now generated by autoreconf.
+ OpenBSD-Commit-ID: 2091a36d6ca3980c81891a6c4bdc544e63cb13a8
-commit 4bf7e1d00b1dcd3a6b3239f77465c019e61c6715
-Author: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
-Date: Sat Sep 5 17:50:03 2020 +0200
+commit 3dd0c64e08f1bba21d71996d635c7256c8c139d1
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Jan 31 22:55:29 2021 +0000
- Quote the definition of OSSH_CHECK_HEADER_FOR_FIELD
+ upstream: more strictly enforce KEX state-machine by banning packet
- autoreconf complains about underquoted definition of
- OSSH_CHECK_HEADER_FOR_FIELD after aclocal.m4 has been and now is beeing
- recreated.
+ 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).
- Quote OSSH_CHECK_HEADER_FOR_FIELD as suggested.
+ ok markus@
- Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
+ OpenBSD-Commit-ID: 87331c715c095b587d5c88724694cdeb701c9def
-commit a2f3ae386b5f7938ed3c565ad71f30c4f7f010f1
-Author: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
-Date: Sat Sep 5 17:50:02 2020 +0200
+commit 7a92a324a2e351fabd0ba8ef9b434d3b12d54ee3
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sun Jan 31 10:50:10 2021 +0000
- Move the local m4 macros
+ upstream: Set linesize returned by getline to zero when freeing and
- 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.
+ NULLing the returned string. OpenBSD's getline handles this just fine, but
+ some implementations used by -portable do not. ok djm@
- Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
+ OpenBSD-Commit-ID: 4d7bd5169d3397654247db9655cc69a9908d165c
-commit 8372bff3a895b84fd78a81dc39da10928b662f5a
-Author: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
-Date: Sat Sep 5 17:50:01 2020 +0200
+commit a5dfc5bae8c16e2a7caf564758d812c7672480b5
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Jan 30 16:32:29 2021 +1100
- 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.
+ allow a fuzz case to contain more than one request
- Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
+ loop until input buffer empty, no message consumed or 256 messages
+ processed
-commit bbf20ac8065905f9cb9aeb8f1df57fcab52ee2fb
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Sep 9 03:10:21 2020 +0000
+commit 0ef24ad60204022f7e33b6e9d171172c50514132
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Jan 30 16:28:23 2021 +1100
- upstream: adapt to SSH_SK_VERSION_MAJOR crank
+ expect fuzz cases to have length prefix
- OpenBSD-Regress-ID: 0f3e76bdc8f9dbd9d22707c7bdd86051d5112ab8
+ 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 9afe2a150893b20bdf9eab764978d817b9a7b783
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Aug 28 03:17:13 2020 +0000
+commit de613f2713d2dfcd3b03c00e5558a40997f52712
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Jan 30 12:03:30 2021 +1100
- upstream: Ensure that address/mask mismatches are flagged at
-
- config-check time. ok djm@
-
- OpenBSD-Regress-ID: 8f5f4c2c0bf00e6ceae7a1755a444666de0ea5c2
+ ssh-agent fuzzer
-commit c76773524179cb654ff838dd43ba1ddb155bafaa
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Sep 9 03:08:01 2020 +0000
+commit 7e96c877bcb2fb645355a687b8cb7347987c1c58
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Jan 30 12:02:46 2021 +1100
- 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@
+ move keys out of kex_fuzz.cc into separate header
- OpenBSD-Commit-ID: 8439896e63792b2db99c6065dd9a45eabbdb7e0a
+ add certificates and missing key types
-commit c1c44eeecddf093a7983bd91e70b446de789b363
-Author: pedro martelletto <pedro@ambientworks.net>
-Date: Tue Sep 1 17:01:55 2020 +0200
+commit 76f46d75664fdaa1112739ca523ff85ee4eb52b4
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Jan 30 12:02:10 2021 +1100
- 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.
+ some fixed test data (mostly keys) for fuzzing
-commit 785f0f315bf7ac5909e988bb1ac3e019fb5e1594
+commit 7c2e3d6de1f2edb0c8b4725b4c2b56360e032b19
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Aug 31 04:33:17 2020 +0000
+Date: Sat Jan 30 00:56:38 2021 +0000
- upstream: refuse to add verify-required (PINful) FIDO keys to
+ upstream: add a SK_DUMMY_INTEGRATE define that allows the dummy
- ssh-agent until the agent supports them properly
+ security key middleware to be directly linked; useful for writing fuzzers,
+ etc.
- OpenBSD-Commit-ID: 125bd55a8df32c87c3ec33c6ebe437673a3d037e
+ OpenBSD-Regress-ID: 0ebd00159b58ebd85e61d8270fc02f1e45df1544
-commit 39e88aeff9c7cb6862b37ad1a87a03ebbb38c233
+commit 1a4b92758690faa12f49079dd3b72567f909466d
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Aug 31 00:17:41 2020 +0000
+Date: Fri Jan 29 06:29:46 2021 +0000
- upstream: Add RCS IDs to the few files that are missing them; from
-
- Pedro Martelletto
+ upstream: fix the values of enum sock_type
- OpenBSD-Commit-ID: 39aa37a43d0c75ec87f1659f573d3b5867e4a3b3
+ OpenBSD-Commit-ID: 18d048f4dbfbb159ff500cfc2700b8fb1407facd
-commit 72730249b38a676da94a1366b54a6e96e6928bcb
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Aug 28 03:15:52 2020 +0000
+commit 8afaa7d7918419d3da6c0477b83db2159879cb33
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Jan 29 06:28:10 2021 +0000
- upstream: Check that the addresses supplied to Match Address and
+ upstream: give typedef'd struct a struct name; makes the fuzzer I'm
- 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@
+ writing a bit easier
- OpenBSD-Commit-ID: 2d0b10c69fad5d8fda4c703e7c6804935289378b
+ OpenBSD-Commit-ID: 1052ab521505a4d8384d67acb3974ef81b8896cb
-commit 2a3a9822311a565a9df48ed3b6a3c972f462bd7d
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Thu Aug 27 12:34:00 2020 +0000
+commit 1e660115f0c7c4a750cd31e468ff889f33dd8088
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Jan 29 11:09:14 2021 +1100
- upstream: sentence fix; from pedro martelletto
-
- OpenBSD-Commit-ID: f95b84a1e94e9913173229f3787448eea2f8a575
+ fuzz diffie-hellman-group-exchange-sha1 kex too
-commit ce178be0d954b210c958bc2b9e998cd6a7aa73a9
+commit be5f0048ea2aaeddd27be7dcca23aaad345fa16c
Author: Damien Miller <djm@mindrot.org>
-Date: Thu Aug 27 20:01:52 2020 +1000
+Date: Fri Jan 29 11:03:35 2021 +1100
- tweak back-compat for older libfido2
+ support for running kex fuzzer with null cipher
-commit d6f45cdde031acdf434bbb27235a1055621915f4
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Aug 27 09:46:04 2020 +0000
+commit 3d59e88c0e42182c3749b446ccd9027933c84be4
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Jan 28 20:55:16 2021 +1100
- upstream: debug()-print a little info about FIDO-specific key
-
- fields via "ssh-keygen -vyf /path/key"
-
- OpenBSD-Commit-ID: cf315c4fe77db43947d111b00155165cb6b577cf
+ make with -j2 to use available CPUs.
-commit b969072cc3d62d05cb41bc6d6f3c22c764ed932f
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Aug 27 09:43:28 2020 +0000
+commit 66dd9ddb5d2ea8c407908c8e8468c9d6e71db05b
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Jan 28 14:31:01 2021 +1100
- upstream: skip a bit more FIDO token selection logic when only a
-
- single token is attached.
-
- with Pedro Martelletto
-
- OpenBSD-Commit-ID: e4a324bd9814227ec1faa8cb619580e661cca9ac
+ Add test against openssl head and libressl head.
-commit 744df42a129d7d7db26947b7561be32edac89f88
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Thu Aug 27 06:15:22 2020 +0000
+commit 237dbb34e24b6b7ea888d54bda4d17da0a0fd0fa
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Thu Jan 28 14:30:50 2021 +1100
- upstream: tweak previous;
-
- OpenBSD-Commit-ID: 92714b6531e244e4da401b2defaa376374e24be7
+ Remove whitespace.
-commit e32479645ce649b444ba5c6e7151304306a09654
+commit d983e1732b8135d7ee8d92290d6dce35f736ab88
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Aug 27 03:55:22 2020 +0000
+Date: Wed Jan 27 23:49:46 2021 +0000
- upstream: adapt to API changes
+ upstream: fix leak: was double allocating kex->session_id buffer
- OpenBSD-Regress-ID: 5f147990cb67094fe554333782ab268a572bb2dd
+ OpenBSD-Commit-ID: 3765f4cc3ae1df874dba9102a3588ba7b48b8183
-commit bbcc858ded3fbc46abfa7760e40389e3ca93884c
+commit 1134a48cdcef8e7363b9f6c73ebdd24405066738
Author: Damien Miller <djm@mindrot.org>
-Date: Thu Aug 27 12:37:12 2020 +1000
+Date: Thu Jan 28 08:57:31 2021 +1100
- degrade semi-gracefully when libfido2 is too old
+ correct kex name in disabled code
-commit 9cbbdc12cb6a2ab1e9ffe9974cca91d213c185c2
+commit 67f47f1965abafc1830a287761125c2f4790857e
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Aug 27 01:15:36 2020 +0000
+Date: Wed Jan 27 10:15:08 2021 +0000
- upstream: dummy firmware needs to match API version numner crank (for
-
- verify-required resident keys) even though it doesn't implement this feature
+ upstream: this needs kex.h now
- OpenBSD-Regress-ID: 86579ea2891e18e822e204413d011b2ae0e59657
+ OpenBSD-Commit-ID: c5a42166c5aa002197217421a971e48be7cb5d41
-commit c1e76c64956b424ba260fd4eec9970e5b5859039
+commit 39be3dc209f28f9c1ebfeba42adde8963b01e1cd
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Aug 27 02:11:09 2020 +0000
+Date: Wed Jan 27 10:05:28 2021 +0000
- upstream: remove unreachable code I forgot to delete in r1.334
+ upstream: make ssh->kex->session_id a sshbuf instead of u_char*/size_t
- OpenBSD-Commit-ID: 9ed6078251a0959ee8deda443b9ae42484fd8b18
+ and use that instead of global variables containing copies of it. feedback/ok
+ markus@
+
+ OpenBSD-Commit-ID: a4b1b1ca4afd2e37cb9f64f737b30a6a7f96af68
-commit 0caff05350bd5fc635674c9e051a0322faba5ae3
+commit 4ca6a1fac328477c642329676d6469dba59019a3
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Aug 27 01:08:45 2020 +0000
+Date: Wed Jan 27 09:26:53 2021 +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.
+ upstream: remove global variable used to stash compat flags and use the
- joint work with Pedro Martelletto; ok markus@
+ purpose-built ssh->compat variable instead; feedback/ok markus@
- OpenBSD-Commit-ID: 863182d38ef075bad1f7d20ca485752a05edb727
+ OpenBSD-Commit-ID: 7c4f200e112dae6bcf99f5bae1a5629288378a06
-commit b649b3daa6d4b8ebe1bd6de69b3db5d2c03c9af0
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Aug 27 01:08:19 2020 +0000
+commit bba229b6f3328171f5e3ae85de443002523c0452
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Jan 27 12:34:07 2021 +1100
- 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
+ Install moduli file before tests.
- OpenBSD-Commit-ID: 201c46ccdd227cddba3d64e1bdbd082afa956517
+ Reduces warnings during test runs.
-commit 642e06d0df983fa2af85126cf4b23440bb2985bf
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Aug 27 01:07:51 2020 +0000
+commit 1b83185593a90a73860a503d753a95ca6d726c00
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Jan 27 11:58:26 2021 +1100
- 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
+ Run one test with -Werror to catch warnings.
-commit 801c9f095e6d8b7b91aefd98f5001c652ea13488
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Aug 27 01:07:09 2020 +0000
+commit d1532d90074b212054d5fd965f833231b09982f5
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Wed Jan 27 00:37:26 2021 +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@
+ upstream: Logical not bitwise or. ok djm@
- OpenBSD-Commit-ID: 3a2313aae153e043d57763d766bb6d55c4e276e6
+ OpenBSD-Commit-ID: d4dc855cf04951b93c45caa383e1ac9af0a3b0e5
-commit 9b8ad93824c682ce841f53f3b5762cef4e7cc4dc
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Aug 27 01:06:18 2020 +0000
+commit 507b448a2465a53ab03a88acbc71cc51b48ca6ac
+Author: naddy@openbsd.org <naddy@openbsd.org>
+Date: Tue Jan 26 15:40:17 2021 +0000
- upstream: support for user-verified FIDO keys
+ upstream: move HostbasedAcceptedAlgorithms to the right place in
- 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.
+ alphabetical order
- 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.
+ 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
- feedback markus@ and Pedro Martelletto; ok markus@
+ djm@
- OpenBSD-Commit-ID: 57fd461e4366f87c47502c5614ec08573e6d6a15
+ OpenBSD-Commit-ID: 8b3ad58bff828fcf874e54b2fc27a4cf1d9505e8
-commit 1196d7f49d4fbc90f37e550de3056561613b0960
-Author: cheloha@openbsd.org <cheloha@openbsd.org>
-Date: Wed Aug 12 01:23:45 2020 +0000
+commit e9f78d6b06fc323bba1890b2dc3b8423138fb35c
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Jan 26 05:32:21 2021 +0000
- upstream: ssh-keyscan(1): simplify conloop() with timercmp(3),
+ upstream: Rename HostbasedKeyTypes (ssh) and
- timersub(3); ok djm@
+ 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: a102acb544f840d33ad73d40088adab4a687fa27
+ OpenBSD-Commit-ID: 49451c382adc6e69d3fa0e0663eeef2daa4b199e
-commit d0a195c89e26766d3eb8f3e4e2a00ebc98b57795
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Aug 11 09:49:57 2020 +0000
+commit 48d0d7a4dd31154c4208ec39029d60646192f978
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Jan 26 14:48:07 2021 +1100
- upstream: let ssh_config(5)'s AddKeysToAgent keyword accept a time
+ Disable sntrup761 if compiler doesn't support VLAs.
- 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@
+ 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.
- OpenBSD-Commit-ID: 792e71cacbbc25faab5424cf80bee4a006119f94
+ This should allow OpenSSH to build with a plain C89 compiler again.
+ Spotted by tim@, ok djm@.
-commit e9c2002891a7b8e66f4140557a982978f372e5a3
+commit 37c70ea8d4f3664a88141bcdf0bf7a16bd5fd1ac
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Aug 11 09:45:54 2020 +0000
+Date: Tue Jan 26 00:54:49 2021 +0000
- upstream: let the "Confirm user presence for key ..." ssh-askpass
+ upstream: refactor key constraint parsing in ssh-agent
- notification respect $SSH_ASKPASS_REQUIRE; ok markus@
+ 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.
- 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.
+ ok markus@
- 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
+ OpenBSD-Commit-ID: 511cb1b1c021ee1d51a4c2d649b937445de7983c
-commit ed6bef77f5bb5b8f9ca2914478949e29f2f0a780
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Aug 7 17:12:16 2020 +1000
+commit e0e8bee8024fa9e31974244d14f03d799e5c0775
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Jan 26 00:53:31 2021 +0000
- Always send any PAM account messages.
+ upstream: more ssh-agent refactoring
- 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
+ Allow confirm_key() to accept an additional reason suffix
- * 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
+ 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.
- 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
+ feedback/ok markus@
- avoids warnings on NetBSD
+ OpenBSD-Commit-ID: 29006515617d1aa2d8b85cd2bf667e849146477e
-commit c9e3be9f4b41fda32a2a0138d54c7a6b563bc94d
-Author: Damien Miller <djm@mindrot.org>
-Date: Tue Aug 4 14:58:46 2020 +1000
+commit dfe18a295542c169ffde8533b3d7fe42088e2de7
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Jan 26 00:51:30 2021 +0000
- undef TAILQ_CONCAT and friends
+ upstream: make struct hostkeys public; I have no idea why I made it
+
+ opaque originally.
- Needed for NetBSD. etc that supply these macros
+ ok markus@
+
+ OpenBSD-Commit-ID: e50780b34d4bbe628d69b2405b024dd749d982f3
-commit 2d8a3b7e8b0408dfeb933ac5cfd3a58f5bac49af
+commit 3b44f2513cae89c920e8fe927b9bc910a1c8c65a
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Aug 3 02:53:51 2020 +0000
+Date: Tue Jan 26 00:49:30 2021 +0000
- upstream: ensure that certificate extensions are lexically sorted.
+ upstream: move check_host_cert() from sshconnect,c to sshkey.c and
+
+ refactor it to make it more generally usable and testable.
- Previously if the user specified a custom extension then the everything would
- be in order except the custom ones. bz3198 ok dtucker markus
+ ok markus@
- OpenBSD-Commit-ID: d97deb90587b06cb227c66ffebb2d9667bf886f0
+ OpenBSD-Commit-ID: 536f489f5ff38808c1fa711ba58d4579b636f9e4
-commit a8732d74cb8e72f0c6366015687f1e649f60be87
+commit 1fe16fd61bb53944ec510882acc0491abd66ff76
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Aug 3 02:43:41 2020 +0000
+Date: Tue Jan 26 00:47:47 2021 +0000
- upstream: allow -A to explicitly enable agent forwarding in scp and
+ upstream: use recallocarray to allocate the agent sockets table;
- sftp. The default remains to not forward an agent, even when ssh_config
- enables it. ok jmc dtucker markus
+ also clear socket entries that are being marked as unused.
- 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 /*
+ spinkle in some debug2() spam to make it easier to watch an agent
+ do its thing.
- FALLTHROUGH */ comments, which is the style we currently use, and gives too
- many boring warnings. ok djm
+ ok markus
- OpenBSD-Commit-ID: 07b5031e9f49f2b69ac5e85b8da4fc9e393992a0
+ OpenBSD-Commit-ID: 74582c8e82e96afea46f6c7b6813a429cbc75922
-commit ced327b9fb78c94d143879ef4b2a02cbc5d38690
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jul 31 04:19:37 2020 +0000
+commit cb7b22ea20a01332c81c0ddcb3555ad50de9cce2
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Jan 26 00:46:17 2021 +0000
- upstream: Also compare username when checking for JumpHost loops.
+ upstream: factor out common code in the agent client
- bz#3057, ok djm@
+ 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
- OpenBSD-Commit-ID: 9bbc1d138adb34c54f3c03a15a91f75dbf418782
-
-commit ae7527010c44b3376b85d036a498f136597b2099
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jul 31 15:19:04 2020 +1000
-
- Remove AC_REVISION.
+ ok markus@
- It hasn't been useful since we switched to git in 2014. ok djm@
+ OpenBSD-Commit-ID: e0c1f4d5e6cfa525d62581e2b8de93be0cb85adb
-commit 89fc3f414be0ce4e8008332a9739a7d721269e50
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Tue Jul 28 19:40:30 2020 +1000
+commit d1e578afe7cd48140ad6e92a453f9b035363fd7f
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Jan 25 06:00:17 2021 +0000
- Use argv in OSSH_CHECK_CFLAG_COMPILE test.
+ 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@
- 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@
+ OpenBSD-Commit-ID: 25bffe19f0326972f5728170f7da81d5f45c78c6
-commit 62c81ef531b0cc7ff655455dd34f5f0c94f48e82
+commit 95eca1e195a3b41baa1a725c2c5af8a09d885e4b
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
+Date: Sat Jan 23 18:26:05 2021 +1100
- Add ssh-sk-helper and manpage to RPM spec file
+ ifdef new instance of sin6_scope_id
- Based on patch from Fabio Pedretti
+ Put inside HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID similar to
+ existing instance. Should fix error on UnixWare 7.
-commit a2855c048b3f4b17d8787bd3f24232ec0cd79abe
+commit 6ffdcdda128045226dda7fbb3956407978028a1e
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jul 17 07:09:24 2020 +0000
+Date: Mon Jan 18 11:43:34 2021 +0000
- upstream: Add %k to the TOKENs for Match Exec for consistency with
-
- the other keywords that recently got %k.
+ upstream: Fix long->int for convtime tests here too. Spotted by
- 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;
+ tobhe@.
- OpenBSD-Commit-ID: 624e47ab209450ad9ad5c69f54fa69244de5ed9a
+ OpenBSD-Regress-ID: a87094f5863312d00938afba771d25f788c849d0
-commit 40649bd0822883b684183854b16d0b8461d5697b
+commit b55b7565f15327d82ad7acbddafa90b658c5f0af
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jul 17 07:10:24 2020 +0000
+Date: Fri Jan 22 02:46:40 2021 +0000
- upstream: Add test for '%k' (HostKeyAlias) TOKEN.
+ upstream: PubkeyAcceptedKeyTypes->PubkeyAcceptedAlgorithms
+
+ here too.
- OpenBSD-Regress-ID: 8ed1ba1a811790031aad3fcea860a34ad7910456
+ OpenBSD-Commit-ID: 3b64a640f8ce8c21d9314da9df7ce2420eefde3a
-commit 6736fe680704a3518cb4f3f8f6723b00433bd3dd
+commit ee9c0da8035b3168e8e57c1dedc2d1b0daf00eec
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jul 17 03:26:58 2020 +0000
+Date: Fri Jan 22 02:44:58 2021 +0000
- upstream: Add tests for expansions on UserKnownHostsFile.
+ upstream: Rename PubkeyAcceptedKeyTypes keyword to
- 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
+ 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: f733d7b3b05e3c68967dc18dfe39b9e8fad29851
+ OpenBSD-Commit-ID: 0346b2f73f54c43d4e001089759d149bfe402ca5
-commit 8df5774a42d2eaffe057bd7f293fc6a4b1aa411c
+commit a8e798feabe36d02de292bcfd274712cae1d8d17
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jul 17 03:43:42 2020 +0000
+Date: Fri Jan 15 02:58:11 2021 +0000
- upstream: Add a '%k' TOKEN that expands to the effective HostKey of
+ upstream: Change types in convtime() unit test to int to match change
- 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)
+ its new type. Add tests for boundary conditions and fix convtime to work up
+ to INT_MAX. ok djm@
- OpenBSD-Commit-ID: 7084d723c9cc987a5c47194219efd099af5beadc
+ OpenBSD-Regress-ID: ba2b81e9a3257fff204b020affe85b604a44f97e
-commit c4f239944a4351810fd317edf408bdcd5c0102d9
+commit 9bde1a420626da5007bf7ab499fa2159b9eddf72
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jul 17 03:23:10 2020 +0000
+Date: Fri Jan 15 04:31:25 2021 +0000
- upstream: Add %-TOKEN, environment variable and tilde expansion to
+ upstream: Make output buffer larger to prevent potential truncation
- UserKnownHostsFile, allowing the file to be automagically split up in the
- configuration (eg bz#1654). ok djm@, man page parts jmc@
+ warnings from compilers not smart enough to know the strftime calls won't
+ ever fully fill "to" and "from". ok djm@
- OpenBSD-Commit-ID: 7e1b406caf147638bb51558836a72d6cc0bd1b18
+ OpenBSD-Commit-ID: 83733f1b01b82da88b9dd1769475952aff10bdd7
-commit dbaaa01daedb423c38124a72c471982fb08a16fb
-Author: solene@openbsd.org <solene@openbsd.org>
-Date: Wed Jul 15 07:50:46 2020 +0000
+commit 02da325f10b214219eae2bb1bc2d3bf0c2f13f9f
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jan 15 02:58:11 2021 +0000
- upstream: - Add [-a rounds] in ssh-keygen man page and usage() -
-
- Reorder parameters list in the first usage() case - Sentence rewording
+ upstream: Change types in convtime() unit test to int to match
- ok dtucker@
- jmc@ noticed usage() missed -a flag too
+ change its new type. Add tests for boundary conditions and fix convtime to
+ work up to INT_MAX. ok djm@
- OpenBSD-Commit-ID: f06b9afe91cc96f260b929a56e9930caecbde246
+ OpenBSD-Commit-ID: 01dc0475f1484ac2f47facdfcf9221f9472145de
-commit 69924a92c3af7b99a7541aa544a2334ec0fb092c
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Wed Jul 15 05:40:05 2020 +0000
+commit 5339ab369c225b40bc64d5ec3374f5c91b3ad609
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Jan 15 02:32:41 2021 +0000
- upstream: start sentence with capital letter;
+ upstream: In waitfd(), when poll returns early we are subtracting
- 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
+ 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@
- 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
+ OpenBSD-Commit-ID: 199df060978ee9aa89b8041a3dfaf1bf7ae8dd7a
-commit 9c9ddc1391d6af8d09580a2424ab467d0a5df3c7
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Jul 15 06:43:16 2020 +0000
+commit a164862dfa863b54b7897f66e1dd75437f086c11
+Author: rob@openbsd.org <rob@openbsd.org>
+Date: Thu Jan 14 19:45:06 2021 +0000
- upstream: Fix previous by calling the correct function.
+ upstream: Minor grammatical correction.
+
+ OK jmc@
- OpenBSD-Regress-ID: 821cdd1dff9c502cceff4518b6afcb81767cad5a
+ OpenBSD-Commit-ID: de0fad0581e212b2750751e479b79c18ff8cac02
-commit f1a4798941b4372bfe5e46f1c0f8672fe692d9e4
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Jul 15 05:36:50 2020 +0000
+commit 8635e7df7e3a3fbb4a4f6cd5a7202883b2506087
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Jan 13 18:00:57 2021 +1100
- upstream: Update test to match recent change in match.c
-
- OpenBSD-Regress-ID: 965bda1f95f09a765050707340c73ad755f41167
+ Merge Mac OS X targets into a single config.
-commit d7e71be4fd57b7c7e620d733cdf2333b27bfa924
+commit ac112ade990585c511048ed4edaf2d9fc92b61f0
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Jul 15 15:30:43 2020 +1000
+Date: Tue Jan 12 19:22:47 2021 +1100
- Adjust portable code to match changes in 939d787d,
+ Add Mac OS X test targets.
-commit fec89f32a84fd0aa1afc81deec80a460cbaf451a
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Jul 15 04:27:34 2020 +0000
+commit 1050109b4b2884bf50fd1b3aa084c7fd0a42ae90
+Author: anatasluo <luolongjuna@gmail.com>
+Date: Mon Jan 11 13:51:39 2021 +0000
- upstream: Add default for number of rounds (-a). ok djm@
-
- OpenBSD-Commit-ID: cb7e9aa04ace01a98e63e4bd77f34a42ab169b15
+ Remove duplicated declaration in fatal.c .
-commit aaa8b609a7b332be836cd9a3b782422254972777
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Jul 14 23:57:01 2020 +0000
+commit 7d0f8a3369579dfe398536eb4e3da7bc15da9599
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Jan 11 04:48:22 2021 +0000
- upstream: allow some additional control over the use of ssh-askpass
+ upstream: Correct spelling of persourcenetblocksize in config-dump
- via $SSH_ASKPASS_REQUIRE, including force-enable/disable. bz#69 ok markus@
+ mode.
- OpenBSD-Commit-ID: 3a1e6cbbf6241ddc4405c4246caa2c249f149eb2
+ OpenBSD-Commit-ID: ecdc49e2b6bde6b6b0e52163d621831f6ac7b13d
-commit 6368022cd4dd508671c4999a59ec5826df098530
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Tue Jul 7 02:47:21 2020 +0000
+commit ba328bd7a6774f30daaf90b83f1933cc4afc866c
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sat Jan 9 12:31:46 2021 +0000
- upstream: correct recently broken comments
+ upstream: Adjust kexfuzz to addr.c/addrmatch.c split.
- OpenBSD-Commit-ID: 964d9a88f7de1d0eedd3f8070b43fb6e426351f1
+ OpenBSD-Regress-ID: 1d8d23bb548078020be2fb52c4c643efb190f0eb
-commit 6d755706a0059eb9e2d63517f288b75cbc3b4701
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sun Jul 5 23:59:45 2020 +0000
+commit b08ef25552443e94c0857d5e3806dd019ccc55d7
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sat Jan 9 12:24:30 2021 +0000
- upstream: some language improvements; ok markus
+ upstream: Update unittests for addr.c/addrmatch.c split.
- OpenBSD-Commit-ID: 939d787d571b4d5da50b3b721fd0b2ac236acaa8
+ OpenBSD-Regress-ID: de2b415fb7af084a91c6ef147a90482d8f771eef
-commit b0c1e8384d5e136ebdf895d1434aea7dd8661a1c
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Fri Jul 3 10:12:26 2020 +0000
+commit 6d30673fedec2d251f4962c526fd0451f70c4d97
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Jan 11 02:12:57 2021 +0000
- upstream: update setproctitle after re-exec; ok djm
+ 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: bc92d122f9184ec2a9471ade754b80edd034ce8b
+ OpenBSD-Commit-ID: 8fc932683d6b4660d52f50911d62bd6639c5db31
-commit cd119a5ec2bf0ed5df4daff3bd14f8f7566dafd3
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Fri Jul 3 10:11:33 2020 +0000
+commit 7a57adb8b07b2ad0aead4b2e09ee18edc04d0481
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Sat Jan 9 12:51:12 2021 +0000
- upstream: keep ignoring HUP after fork+exec; ok djm
+ upstream: add a comma to previous;
- OpenBSD-Commit-ID: 7679985a84ee5ceb09839905bb6f3ddd568749a2
+ OpenBSD-Commit-ID: 9139433701c0aa86a0d3a6c7afe10d1c9c2e0869
-commit 8af4a743693ccbea3e15fc9e93edbeb610fa94f4
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Fri Jul 3 10:10:17 2020 +0000
+commit 3a923129534b007c2e24176a8655dec74eca9c46
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sat Jan 9 12:10:02 2021 +0000
- upstream: don't exit the listener on send_rexec_state errors; ok
+ upstream: Add PerSourceMaxStartups and PerSourceNetBlockSize
- djm
+ options which provide more fine grained MaxStartups limits. Man page help
+ jmc@, feedback & ok djm@
- OpenBSD-Commit-ID: 57cbd757d130d3f45b7d41310b3a15eeec137d5c
+ OpenBSD-Commit-ID: e2f68664e3d02c0895b35aa751c48a2af622047b
-commit 03da4c2b70468f04ed1c08518ea0a70e67232739
+commit d9a2bc71693ea27461a78110005d5a2d8b0c6a50
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Jul 15 04:55:47 2020 +0000
+Date: Sat Jan 9 11:58:50 2021 +0000
- upstream: Use $OBJ to find key files. Fixes test when run on an obj
+ upstream: Move address handling functions out into their own file
- directory (on OpenBSD) or out of tree (in Portable).
+ 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-Regress-ID: 938fa8ac86adaa527d64a305bd2135cfbb1c0a17
+ OpenBSD-Commit-ID: e3e7d9ccc6c9b82e25cfef0ec83598e8e2327cbf
-commit 73f20f195ad18f1cf633eb7d8be95dc1b6111eea
+commit b744914fcb76d70761f1b667de95841b3fc80a56
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat Jul 4 23:11:23 2020 +1000
+Date: Sat Jan 9 00:36:05 2021 +1100
- Wrap stdint.h in ifdef HAVE_STDINT_H.
+ Add test against Graphene hardened malloc.
-commit aa6fa4bf3023fa0e5761cd8f4b2cd015d2de74dd
+commit 6cb52d5bf771f6769b630fce35a8e9b8e433044f
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jul 3 07:25:18 2020 +0000
+Date: Fri Jan 8 04:49:13 2021 +0000
- upstream: put back the mux_ctx memleak fix, but only for channels of
+ 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.
- type SSH_CHANNEL_MUX_LISTENER; Specifically SSH_CHANNEL_MUX_PROXY channels
- should not have this structure freed.
+ ok dtucker@
- OpenBSD-Commit-ID: f3b213ae60405f77439e2b06262f054760c9d325
+ OpenBSD-Commit-ID: 0db98413e82074f78c7d46784b1286d08aee78f0
-commit d8195914eb43b20b13381f4e5a74f9f8a14f0ded
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jul 3 07:17:35 2020 +0000
+commit 309b642e1442961b5e57701f095bcd4acd2bfb5f
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Jan 8 15:50:41 2021 +1100
- upstream: revert r1.399 - the lifetime of c->mux_ctx is more complex;
-
- simply freeing it here causes other problems
-
- OpenBSD-Commit-ID: c6fee8ca94e2485faa783839541962be2834c5ed
+ Run tests with sudo for better coverage.
-commit 20b5fab9f773b3d3c7f06cb15b8f69a2c081ee80
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jul 3 07:02:37 2020 +0000
+commit c336644351fa3c715a08b7a292e309e72792e71e
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Jan 8 14:26:32 2021 +1100
- 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
+ Add Ubuntu 16.04 and 20.04 test targets.
-commit c8935081db35d73ee6355999142fa0776a2af912
+commit 4c7af01f9dcc1606dec033e7665a042cb0d8ec52
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jul 3 06:46:41 2020 +0000
+Date: Fri Jan 8 02:57:24 2021 +0000
- upstream: when redirecting sshd's log output to a file, undo this
+ 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.
- redirection after the session child process is forked(); ok dtucker@
+ ok dtucker@
- OpenBSD-Commit-ID: 6df86dd653c91f5bc8ac1916e7680d9d24690865
+ OpenBSD-Commit-ID: 176db8518933d6a5bbf81a2e3cf62447158dc878
-commit 183c4aaef944af3a1a909ffa01058c65bac55748
+commit 64ddd0fe68c4a7acf99b78624f8af45e919cd317
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jul 3 06:29:57 2020 +0000
+Date: Fri Jan 8 02:44:14 2021 +0000
- upstream: start ClientAliveInterval bookkeeping before first pass
+ upstream: don't try to use timespeccmp(3) directly as a qsort(3)
- through select() loop; fixed theoretical case where busy sshd may ignore
- timeouts from client; inspired by and ok dtucker
+ comparison function - it returns 0/1 and not the -1/0/1 that qsort expectes.
- 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
+ fixes sftp "ls -ltr" under some circumstances.
+
+ Based on patch by Masahiro Matsuya via bz3248.
+
+ OpenBSD-Commit-ID: 65b5e9f18bb0d10573868c3516de6e5170adb163
-commit f11b23346309e4d5138e733a49321aedd6eeaa2f
+commit 599df78f3008cf78af21f8977be3e1dd085f8e2e
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jul 3 05:09:06 2020 +0000
+Date: Fri Jan 8 02:33:13 2021 +0000
- upstream: Only reset the serveralive check when we receive traffic from
+ upstream: Update the sntrup761 creation script and generated code:
- 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@
+ - 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.
- 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
+ ok djm@
- needed for TAILQ_CONCAT
+ OpenBSD-Commit-ID: 7b9d0cf3acd5a3c1091da8afe00c904d38cf5783
-commit 1b90ddde49e2ff377204082b6eb130a096411dc1
+commit 16448ff529affda7e2a15ee7c3200793abde0759
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jul 3 05:08:41 2020 +0000
+Date: Fri Jan 8 02:19:24 2021 +0000
- upstream: fix memory leak of mux_ctx; patch from Sergiy Lozovsky
+ upstream: mention that DisableForwarding is valid in a sshd_config
- via bz3189 ok dtucker
+ Match block reported by Fredrik Eriksson in bz3239
- OpenBSD-Commit-ID: db249bd4526fd42d0f4f43f72f7b8b7705253bde
+ OpenBSD-Commit-ID: 3a71c3d84b597f5e43e4b40d5232797daf0993f6
-commit 55ef3e9cbd5b336bd0f89205716924886fcf86de
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Wed Jul 1 16:28:31 2020 +0000
+commit 91bac5e95b1b0debf9b2b4f05c20dcfa96b368b9
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Jan 4 21:58:58 2021 +0000
- upstream: free kex in ssh_packet_close; ok djm semarie
+ 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: dbc181e90d3d32fd97b10d75e68e374270e070a2
+ OpenBSD-Commit-ID: d145c6c19b08bb93c9e14bfaa7af589d90f144c0
-commit e1c401109b61f7dbc199b5099933d579e7fc5dc9
-Author: bket@openbsd.org <bket@openbsd.org>
-Date: Sat Jun 27 13:39:09 2020 +0000
+commit 4d96a3ebab2224f17e639a15078e03be1ad3736d
+Author: tobhe@openbsd.org <tobhe@openbsd.org>
+Date: Sun Jan 3 18:05:21 2021 +0000
- upstream: Replace TAILQ concatenation loops with TAILQ_CONCAT
+ upstream: Prevent redefinition of `crypto_int32' error with gcc3.
+
+ Fixes compilation on luna88k.
- OK djm@
+ Feedback millert@
+ Found by and ok aoyama@
- OpenBSD-Commit-ID: 454b40e09a117ddb833794358970a65b14c431ef
+ OpenBSD-Commit-ID: f305ddfe575a26cc53431af3fde3f4aeebed9ba6
-commit 14beca57ac92d62830c42444c26ba861812dc837
-Author: semarie@openbsd.org <semarie@openbsd.org>
-Date: Fri Jun 26 11:26:01 2020 +0000
+commit a23954eeb930ccc8a66a2710153730769dba31b6
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Jan 1 22:00:49 2021 +1100
- 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())
+ Undef int32 after sort routines.
- OpenBSD-Commit-ID: 9c9a6721411461b0b1c28dc00930d7251a798484
+ 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 598c3a5e3885080ced0d7c40fde00f1d5cdbb32b
+commit 148b8a661c3f93e4b6d049ee902de3d521261fbc
Author: Damien Miller <djm@mindrot.org>
-Date: Fri Jun 26 16:07:12 2020 +1000
+Date: Thu Dec 31 12:47:22 2020 +1100
- document a PAM spec problem in a frustrated comment
+ fix: missing pieces of previous commit
-commit 976c4f86286d52a0cb2aadf4a095d379c0da752e
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jun 26 05:42:16 2020 +0000
+commit 3d999be7b987c848feda718cfcfcdc005ddf670d
+Author: tobhe@openbsd.org <tobhe@openbsd.org>
+Date: Wed Dec 30 14:13:28 2020 +0000
- upstream: avoid spurious error message when ssh-keygen creates files
+ upstream: Use int64_t for intermediate values in int32_MINMAX to
+
+ prevent signed 32-bit integer overflow.
- outside ~/.ssh; with dtucker@
+ Found by and ok djm@
+ ok markus@
- OpenBSD-Commit-ID: ac0c662d44607e00ec78c266ee60752beb1c7e08
+ OpenBSD-Commit-ID: 4f0704768e34cf45fdd792bac4011c6971881bb3
-commit 32b2502a9dfdfded1ccdc1fd6dc2b3fe41bfc205
+commit 5c1953bf98732da5a76c706714ac066dbfa015ac
Author: Damien Miller <djm@mindrot.org>
-Date: Fri Jun 26 15:30:06 2020 +1000
+Date: Tue Dec 29 12:40:54 2020 +1100
- missing ifdef SELINUX; spotted by dtucker
+ adapt KEX fuzzer to PQ kex change
-commit e073106f370cdd2679e41f6f55a37b491f0e82fe
+commit 659864fe81dbc57eeed3769c462679d83e026640
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
+Date: Tue Dec 29 01:02:15 2020 +0000
- upstream: add test for mux w/-Oproxy; ok djm
+ upstream: Adapt to replacement of
- 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;
+ sntrup4591761x25519-sha512@tinyssh.org with
+ sntrup761x25519-sha512@openssh.com.
- bz#3071; ok dtucker@
+ Also test sntrup761x25519-sha512@openssh.com in unittests/kex
- OpenBSD-Commit-ID: 08fa87be50070bd8b754d9b1ebb1138d7bc9d8ee
+ OpenBSD-Regress-ID: cfa3506b2b077a9cac1877fb521efd2641b6030c
-commit fe2ec0b9c19adeab0cd9f04b8152dc17f31c31e5
+commit 2c71cec020219d69df84055c59eba5799a1233ec
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jun 26 05:04:07 2020 +0000
+Date: Tue Dec 29 00:59:15 2020 +0000
- upstream: allow "ssh-add -d -" to read keys to be deleted from
+ upstream: Update/replace the experimental post-quantim hybrid key
- stdin bz#3180; ok dtucker@
+ exchange method based on Streamlined NTRU Prime (coupled with X25519).
- 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
+ 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.
- diff)
+ 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).
- 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
+ Thanks for Daniel J Bernstein for guidance on algorithm selection.
+ Patch from Tobias Heider; feedback & ok markus@ and myself
- 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@
+ (note this both the updated method and the one that it replaced are
+ disabled by default)
- OpenBSD-Commit-ID: 59c073b569be1a60f4de36f491a4339bc4ae870f
+ OpenBSD-Commit-ID: 2bf582b772d81ee24e911bb6f4b2aecfd39338ae
-commit c9e24daac6324fcbdba171392c325bf9ccc3c768
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jun 26 04:45:11 2020 +0000
+commit 09d070ccc3574ae0d7947d212ed53c7268ef7e1f
+Author: jmc@openbsd.org <jmc@openbsd.org>
+Date: Tue Dec 22 07:40:26 2020 +0000
- upstream: Expand path to ~/.ssh/rc rather than relying on it
+ 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;
- 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@
+ ok djm
- OpenBSD-Commit-ID: 36e33ff01497af3dc8226d0c4c1526fc3a1e46bf
+ OpenBSD-Commit-ID: aba31ebea03f38f8d218857f7ce16a500c3e4aff
-commit 07f5f369a25e228a7357ef6c57205f191f073d99
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Wed Jun 24 15:12:09 2020 +0000
+commit 931c93389a80e32272712459b1102d303844453d
+Author: Damien Miller <djm@mindrot.org>
+Date: Tue Dec 22 19:43:55 2020 +1100
- upstream: fix kex mem-leak in ssh_packet_close; ok djm
-
- OpenBSD-Commit-ID: e2e9533f393620383afd0b68ef435de8d5e8abe4
+ whitespace at EOL
-commit e35995088cd6691a712bfd586bae8084a3a922ba
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Wed Jun 24 15:10:38 2020 +0000
+commit 397b1c4d393f97427283a4717e9015a2bd31b8a5
+Author: Damien Miller <djm@mindrot.org>
+Date: Tue Dec 22 19:42:37 2020 +1100
- 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
+ whitespace at EOL
-commit 250246fef22b87a54a63211c60a2def9be431fbd
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Wed Jun 24 15:09:53 2020 +0000
+commit 33fa3ac547e5349ca34681cce6727b2f933dff0a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Dec 22 19:21:26 2020 +1100
- upstream: support loading big sshd_config files w/o realloc; ok
-
- djm
-
- OpenBSD-Commit-ID: ba9238e810074ac907f0cf8cee1737ac04983171
+ Improve AIX text.
-commit 89b54900ac61986760452f132bbe3fb7249cfdac
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Wed Jun 24 15:08:53 2020 +0000
+commit 0f2e21c9dca89598b694932b5b05848380a23ec0
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Tue Dec 22 18:56:54 2020 +1100
- upstream: allow sshd_config longer than 256k; ok djm
+ Include stdio.h for FILE in misc.h.
- OpenBSD-Commit-ID: 83f40dd5457a64c1d3928eb4364461b22766beb3
+ Fixes build on at least OpenBSD.
-commit e3fa6249e6d9ceb57c14b04dd4c0cfab12fa7cd5
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Wed Jun 24 15:07:33 2020 +0000
+commit 3e9811e57b57ee66b0f70d99d7258da3153b0e8a
+Author: Damien Miller <djm@mindrot.org>
+Date: Tue Dec 22 18:31:50 2020 +1100
- upstream: only call sshkey_xmss_init() once for KEY_XMSS_CERT; ok
-
- djm
-
- OpenBSD-Commit-ID: d0002ffb7f20f538b014d1d0735facd5a81ff096
+ ensure $LOGNAME is set in tests
-commit 37f2da069c0619f2947fb92785051d82882876d7
+commit 3eb647cbb34d87a063aa7714256c6e56103fffda
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Jun 22 23:44:27 2020 +0000
+Date: Tue Dec 22 06:47:24 2020 +0000
- upstream: some clarifying comments
+ upstream: more detail for failing tests
- OpenBSD-Commit-ID: 5268479000fd97bfa30ab819f3517139daa054a2
+ OpenBSD-Regress-ID: c68c0e5a521cad7e7f68e54c54ebf86d6c10ee1d
-commit b659319a5bc9e8adf3c4facc51f37b670d2a7426
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Mon Jun 22 06:37:38 2020 +0000
+commit 2873f19570d4d8758be24dbf78332be9a779009b
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Tue Dec 22 06:03:36 2020 +0000
- upstream: updated argument name for -P in first synopsis was
-
- missed in previous;
+ upstream: regress test for KnownHostsCommand
- OpenBSD-Commit-ID: 8d84dc3050469884ea91e29ee06a371713f2d0b7
+ OpenBSD-Regress-ID: ffc77464320b6dabdcfa0a72e0df02659233a38a
-commit 02a9222cbce7131d639984c2f6c71d1551fc3333
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Mon Jun 22 06:36:40 2020 +0000
+commit 0121aa87bab9ad2365de2d07f2832b56d5ff9871
+Author: tb@openbsd.org <tb@openbsd.org>
+Date: Tue Dec 22 03:05:31 2020 +0000
- upstream: supply word missing in previous;
+ upstream: Remove lines accidentally left behind in the ProxyJump
- 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,
+ parsing fix r1.345.
- and example HTML/JS to generate webauthn signatures in SSH formats (also used
- to generate the testdata/* for the test).
+ ok djm
- OpenBSD-Regress-ID: dc575be5bb1796fdf4b8aaee0ef52a6671a0f6fb
+ OpenBSD-Commit-ID: fe767c108c8117bea33767b080ff62eef2c55f5c
-commit bb52e70fa5330070ec9a23069c311d9e277bbd6f
+commit da4bf0db942b5f0278f33238b86235e5813d7a5a
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Jun 22 05:58:35 2020 +0000
+Date: Tue Dec 22 00:15:22 2020 +0000
- upstream: Add support for FIDO webauthn (verification only).
+ upstream: add a ssh_config KnownHostsCommand that allows the client
- 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@
+ to obtain known_hosts data from a command in addition to the usual files.
- 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
+ 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).
- support for FIDO webauthn signature verification support; ok markus@
+ ok markus@
- OpenBSD-Commit-ID: c9f478fd8e0c1bd17e511ce8694f010d8e32043e
+ OpenBSD-Commit-ID: 2433cff4fb323918ae968da6ff38feb99b4d33d0
-commit 12848191f8fe725af4485d3600e0842d92f8637f
+commit a34e14a5a0071de2036826a00197ce38c8b4ba8b
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Jun 22 05:54:10 2020 +0000
+Date: Tue Dec 22 00:12:22 2020 +0000
- upstream: support for RFC4648 base64url encoding; ok markus
+ upstream: move subprocess() from auth.c to misc.c
- 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@
+ make privilege dropping optional but allow it via callbacks (to avoid
+ need to link uidswap.c everywhere)
- 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@
+ 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: ffb220b435610741dcb4de0e7fc68cbbdc876d2c
+ OpenBSD-Commit-ID: a80ea9fdcc156f1a18e9c166122c759fae1637bf
-commit 00531bb42f1af17ddabea59c3d9c4b0629000d27
+commit 649205fe388b56acb3481a1b2461f6b5b7c6efa6
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jun 19 07:21:42 2020 +0000
+Date: Mon Dec 21 22:48:41 2020 +0000
- upstream: Correct synopsis and usage for the options accepted when
+ upstream: Remove explicit rijndael-cbc@lysator.liu.se test since the
- passing a command to ssh-agent. ok jmc@
+ cipher was removed.
- 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.
+ OpenBSD-Regress-ID: aa93cddb4ecd9bc21446a79008a1a53050e64f17
-commit 1babb8bb14c423011ca34c2f563bb1c51c8fbf1d
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jun 19 19:10:47 2020 +1000
+commit 03e93c753d7c223063ad8acaf9a30aa511e5f931
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Dec 21 11:09:32 2020 +0000
- Extra brackets around sizeof() in bcrypt.
+ upstream: Remove the pre-standardization cipher
- 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.
+ 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.
- 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.
+ This will reduce the amount of work the cipher/kex regression tests need
+ to do by a little bit. ok markus@ djm@
- 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.
+ OpenBSD-Commit-ID: fb460acc18290a998fd70910b19c29b4e4f199ad
-commit 5dba1fcabacaab46693338ec829b42a1293d1f52
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jun 19 05:07:09 2020 +0000
+commit a11ca015879eab941add8c6bdaaec7d41107c6f5
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Dec 21 09:19:53 2020 +0000
- upstream: Test that ssh-agent exits when running as as subprocess
+ 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@
- of a specified command (ie "ssh-agent command"). Would have caught bz#3181.
+ ok tb@
- OpenBSD-Regress-ID: 895b4765ba5153eefaea3160a7fe08ac0b6db8b3
+ OpenBSD-Commit-ID: a2991a3794bcaf1ca2b025212cce11cdb5f6b7d6
-commit 68e8294f6b04f9590ea227e63d3e129398a49e27
+commit d97fb879724f1670bf55d9adfea7278a93c33ae2
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jun 19 04:34:21 2020 +0000
+Date: Mon Dec 21 01:31:06 2020 +0000
- upstream: run sshsig unit tests
+ upstream: adapt to API change in hostkeys_foreach()/load_hostkeys()
- OpenBSD-Regress-ID: 706ef17e2b545b64873626e0e35553da7c06052a
+ OpenBSD-Regress-ID: dcb468514f32da49a446372453497dc6eeafdbf3
-commit 5edfa1690e9a75048971fd8775f7c16d153779db
+commit bf7eb3c266b7fd4ddda108fcf72b860af2af6406
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jun 19 04:32:09 2020 +0000
+Date: Fri Oct 16 14:02:24 2020 +0000
- upstream: basic unit test for sshsig.[ch], including FIDO keys
+ upstream: few more things needs match.c and addrmatch.c now that
- verification only so far
+ log.c calls match_pattern_list()
- OpenBSD-Regress-ID: fb1f946c8fc59206bc6a6666e577b5d5d7e45896
+ OpenBSD-Regress-ID: f7c95c76b150d0aeb00a67858b9579b7d1b2db74
-commit e95c0a0e964827722d29b4bc00d5c0ff4afe0ed2
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jun 19 03:48:49 2020 +0000
+commit 2c64f24e27a5e72a7f59e515fc4f4985355237ae
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Dec 21 14:02:56 2020 +1100
- upstream: basic unit test for FIDO kep parsing
-
- OpenBSD-Regress-ID: 8089b88393dd916d7c95422b442a6fd4cfe00c82
+ Pull in missing rev 1.2.
-commit 7775819c6de3e9547ac57b87c7dd2bfd28cefcc5
+commit 0f504f592d15d8047e466eb7453067a6880992a8
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Jun 18 23:34:19 2020 +0000
+Date: Sun Dec 20 23:40:19 2020 +0000
- upstream: check public host key matches private; ok markus@ (as
+ upstream: plumb ssh_conn_info through to sshconnect.c; feedback/ok
- part of previous diff)
+ markus@
- OpenBSD-Commit-ID: 65a4f66436028748b59fb88b264cb8c94ce2ba63
+ OpenBSD-Commit-ID: e8d14a09cda3f1dc55df08f8a4889beff74e68b0
-commit c514f3c0522855b4d548286eaa113e209051a6d2
+commit 729b05f59ded35483acef90a6f88aa03eae33b29
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Thu Jun 18 23:33:38 2020 +0000
+Date: Sun Dec 20 23:38:00 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@
+ upstream: allow UserKnownHostsFile=none; feedback and ok markus@
- OpenBSD-Commit-ID: 0713cbdf9aa1ff8ac7b1f78b09ac911af510f81b
+ OpenBSD-Commit-ID: c46d515eac94a35a1d50d5fd71c4b1ca53334b48
-commit 7fafaeb5da365f4a408fec355dac04a774f27193
+commit b4c7cd1185c5dc0593d47eafcc1a34fda569dd1d
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jun 12 05:26:37 2020 +0000
+Date: Sun Dec 20 23:36:51 2020 +0000
- upstream: correct RFC number; from HARUYAMA Seigo via GH PR191
+ upstream: load_hostkeys()/hostkeys_foreach() variants for FILE*
- 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
+ Add load_hostkeys_file() and hostkeys_foreach_file() that accept a
+ FILE* argument instead of opening the file directly.
- early. ok markus@
+ Original load_hostkeys() and hostkeys_foreach() are implemented using
+ these new interfaces.
- 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
+ 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 ea547eb0329c2f8da77a4ac05f6c330bd49bdaab
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jun 5 03:25:35 2020 +0000
+commit 06fbb386bed666581095cb9cbc7a900e02bfe1b7
+Author: tobhe@openbsd.org <tobhe@openbsd.org>
+Date: Sat Dec 19 22:09:21 2020 +0000
- upstream: make sshbuf_putb(b, NULL) a no-op
+ upstream: Print client kem key with correct length.
+
+ ok markus@
- OpenBSD-Commit-ID: 976fdc99b500e347023d430df372f31c1dd128f7
+ OpenBSD-Commit-ID: 91689e14a4fc6c270e265a32d1c8faba63a45755
-commit 69796297c812640415c6cea074ea61afc899cbaa
+commit 0ebead6593e2441e4af2735bbe2cd097607cd0d3
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jun 5 03:24:36 2020 +0000
+Date: Thu Dec 17 23:28:50 2020 +0000
- upstream: make sshbuf_dump() args const
+ upstream: fix possible error("%s", NULL) on error paths
- OpenBSD-Commit-ID: b4a5accae750875d665b862504169769bcf663bd
+ OpenBSD-Commit-ID: 0b3833c2cb985453ecca1d76803ebb8f3b736a11
-commit 670428895739d1f79894bdb2457891c3afa60a59
+commit d060bc7f6e6244f001e658208f53e3e2ecbbd382
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Jun 5 03:24:16 2020 +0000
+Date: Thu Dec 17 23:26:11 2020 +0000
- upstream: wrap long line
+ upstream: refactor client percent_expand() argument passing;
- OpenBSD-Commit-ID: ed405a12bd27bdc9c52e169bc5ff3529b4ebbbb2
+ 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 2f648cf222882719040906722b3593b01df4ad1a
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Jun 5 03:15:26 2020 +0000
+commit 43026da035cd266db37df1f723d5575056150744
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Dec 17 23:10:27 2020 +0000
- upstream: Correct historical comment: provos@ modified OpenSSH to
+ upstream: prepare readconf.c for fuzzing; remove fatal calls and
- work with SSLeay (very quickly replaced by OpenSSL) not SSL in general. ok
- deraadt, historical context markus@
+ fix some (one-off) memory leaks; ok markus@
- OpenBSD-Commit-ID: 7209e07a2984b50411ed8ca5a4932da5030d2b90
+ OpenBSD-Commit-ID: 91c6aec57b0e7aae9190de188e9fe8933aad5ec5
-commit 56548e4efcc3e3e8093c2eba30c75b23e561b172
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Jun 3 08:23:18 2020 +0000
+commit bef92346c4a808f33216e54d6f4948f9df2ad7c1
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Mon Dec 14 03:13:12 2020 +0000
- upstream: Import regenerated moduli file.
+ upstream: use _PATH_SSH_USER_DIR instead of hardcoded .ssh in path
- OpenBSD-Commit-ID: 52ff0e3205036147b2499889353ac082e505ea54
+ OpenBSD-Commit-ID: 5c1048468813107baa872f5ee33ba51623630e01
-commit 8da801f585dd9c534c0cbe487a3b1648036bf2fb
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Jun 5 13:20:10 2020 +1000
+commit a5ab499bd2644b4026596fc2cb24a744fa310666
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Dec 4 14:01:27 2020 +1100
- 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@
+ basic KEX fuzzer; adapted from Markus' unittest
-commit 049297de975b92adcc2db77e3fb7046c0e3c695d
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Wed Jun 3 08:23:18 2020 +0000
+commit 021ff33e383c77b11badd60cec5b141a3e3fa532
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Dec 4 13:57:43 2020 +1100
- upstream: Import regenerated moduli file.
-
- OpenBSD-Commit-ID: 52ff0e3205036147b2499889353ac082e505ea54
+ use options that work with recent clang
-commit b458423a38a3140ac022ffcffcb332609faccfe3
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Jun 1 07:11:38 2020 +0000
+commit e4d1a0b40add800b6e9352b40c2223e44acc3a45
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Dec 4 02:41:10 2020 +0000
- upstream: Remove now-unused proto_spec and associated definitions.
+ upstream: shuffle a few utility functions into sftp-client.c; from
- ok djm@
+ Jakub Jelen
- OpenBSD-Commit-ID: 2e2b18e3aa6ee22a7b69c39f2d3bd679ec35c362
+ OpenBSD-Commit-ID: fdeb1aae1f6149b193f12cd2af158f948c514a2a
-commit 5ad3c3a33ef038b55a14ebd31faeeec46073db2c
-Author: millert@openbsd.org <millert@openbsd.org>
-Date: Fri May 29 21:22:02 2020 +0000
+commit ace12dc64f8e3a2496ca48d36b53cb3c0a090755
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Dec 4 02:29:56 2020 +0000
- upstream: Fix error message on close(2) and add printf format
-
- attributes. From Christos Zoulas, OK markus@
+ upstream: make ssh_free(NULL) a no-op
- OpenBSD-Commit-ID: 41523c999a9e3561fcc7082fd38ea2e0629ee07e
+ OpenBSD-Commit-ID: 42cb285d94789cefe6608db89c63040ab0a80fa0
-commit 712ac1efb687a945a89db6aa3e998c1a17b38653
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri May 29 11:17:56 2020 +0000
+commit 3b98b6e27f8a122dbfda9966b1afeb3e371cce91
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Dec 4 02:29:25 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@.
+ upstream: memleak of DH public bignum; found with libfuzzer
- OpenBSD-Commit-ID: 181910d7ae489f40ad609b4cf4a20f3d068a7279
+ OpenBSD-Commit-ID: 0e913b542c3764b100b1571fdb0d0e5cc086fe97
-commit 837ffa9699a9cba47ae7921d2876afaccc027133
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri May 29 20:39:00 2020 +1000
+commit 553b90feedd7da5b90901d73005f86705456d686
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Dec 4 02:27:57 2020 +0000
- Omit ToS setting if we don't have IPV6_TCLASS too.
+ upstream: fix minor memleak of kex->hostkey_alg on rekex
- Fixes tests on old BSDs.
+ OpenBSD-Commit-ID: 2c3969c74966d4ccdfeff5e5f0df0791919aef50
-commit f85b118d2150847cc333895296bc230e367be6b5
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri May 29 09:02:44 2020 +0000
+commit ac0364b85e66eb53da2f9618f699ba6bd195ceea
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Dec 4 02:27:08 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.
+ upstream: typos: s/hex/kex/ in error messages
- OpenBSD-Commit-ID: 7b90afcd8e1137a1d863204060052aef415baaf7
+ OpenBSD-Commit-ID: 43a026c9571dd779ec148de1829cf5a6b6651905
-commit ec1d50b01c84ff667240ed525f669454c4ebc8e9
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Fri May 29 05:48:39 2020 +0000
+commit ee22db7c5885a1d90219202c0695bc621aa0409b
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Dec 4 02:25:13 2020 +0000
- upstream: remove a stray .El;
+ upstream: make program name be const
- OpenBSD-Commit-ID: 58ddfe6f8a15fe10209db6664ecbe7896f1d167c
+ OpenBSD-Commit-ID: ece25680ec637fdf20502721ccb0276691df5384
-commit 058674a62ffe33f01d871d46e624bc2a2c22d91f
+commit 2bcbf679de838bb77a8bd7fa18e100df471a679c
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri May 29 04:32:26 2020 +0000
+Date: Mon Nov 30 05:36:39 2020 +0000
- upstream: Add regression and unit tests for ${ENV} style
+ upstream: Ignore comments at the end of config lines in ssh_config,
- environment variable expansion in various keywords (bz#3140). ok djm@
+ similar to what we already do for sshd_config. bz#2320, with & ok djm@
- OpenBSD-Regress-ID: 4d9ceb95d89365b7b674bc26cf064c15a5bbb197
+ OpenBSD-Commit-ID: bdbf9fc5bc72b1a14266f5f61723ed57307a6db4
-commit 0b15892fc47d6840eba1291a6be9be1a70bc8972
+commit b755264e7d3cdf1de34e18df1af4efaa76a3c015
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri May 29 01:21:35 2020 +0000
+Date: Sat Nov 28 12:52:32 2020 +0000
- upstream: Unit test for convtime. ok djm@
+ upstream: Include cipher.h for declaration of cipher_by_name.
- OpenBSD-Regress-ID: cec4239efa2fc4c7062064f07a847e1cbdbcd5dd
+ OpenBSD-Commit-ID: ddfebbca03ca0e14e00bbad9d35f94b99655d032
-commit 188e332d1c8f9f24e5b6659e9680bf083f837df9
+commit 022def7bd16c3426a95e25f57cb259d54468341c
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 29 05:37:03 2020 +0000
+Date: Sat Nov 28 03:27:59 2020 +0000
- upstream: mention that wildcards are processed in lexical order;
+ upstream: check result of strchr() against NULL rather than
- bz#3165
+ searched-for characters; from zhongjubin@huawei.com
- OpenBSD-Commit-ID: 8856f3d1612bd42e9ee606d89386cae456dd165c
+ OpenBSD-Commit-ID: e6f57de1d4a4d25f8db2d44e8d58d847e247a4fe
-commit 4a1b46e6d032608b7ec00ae51c4e25b82f460b05
+commit 57bf03f0217554afb8980f6697a7a0b88658d0a9
Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri May 29 04:25:40 2020 +0000
+Date: Fri Nov 27 10:12:30 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@
+ upstream: Document ssh-keygen -Z, sanity check its argument earlier and
- 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
+ provide a better error message if it's not correct. Prompted by bz#2879, ok
+ djm@ jmc@
- synchronize synopsis and usage.
+ OpenBSD-Commit-ID: 484178a173e92230fb1803fb4f206d61f7b58005
-commit 0f04c8467f589f85a523e19fd684c4f6c4ed9482
-Author: chl <chl@openbsd.org>
-Date: Sun Jul 26 19:12:28 2015 +0000
+commit 33313ebc1c7135085676db62189e3520341d6b73
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Nov 27 00:49:58 2020 +0000
- partial sync of regress/netcat.c with upstream
-
- remove unused variable
+ upstream: Set the specified TOS/DSCP for interactive use prior to
- 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
+ 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.
- 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. :)
+ ok dtucker@
- with input by and ok djm
+ OpenBSD-Commit-ID: f31ab10d9233363a6d2c9996007083ba43a093f1
-commit bf3893dddd35e16def04bf48ed2ee1ad695b8f82
-Author: tobias <tobias@openbsd.org>
-Date: Thu Mar 26 10:36:03 2015 +0000
+commit b2bcec13f17ce9174238a704e91d52203e916432
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Nov 27 00:37:10 2020 +0000
- partial sync of regress/netcat.c with upstream
-
- Check for short writes in fdpass(). Clean up while at it.
+ upstream: clean up passing of struct passwd from monitor to preauth
- 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
+ privsep process. No longer copy entire struct w/ pointer addresses, but pass
+ remaining scalar fields explicitly,
- Support for nc -T on IPv6 addresses.
+ Prompted by Yuichiro NAITO, feedback Thorsten Glaser; ok dtucker@
- ok sthen@
+ OpenBSD-Commit-ID: 9925df75a56732c43f3663e70dd15ff413ab3e53
-commit 4c607244054a036ad3b2449a6cb4c15feb846a76
+commit 19af04e2231155d513e24fdc81fbec2217ae36a6
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 29 03:14:02 2020 +0000
+Date: Sun Nov 22 22:38:26 2020 +0000
- upstream: fix compilation on !HAVE_DLOPEN platforms; stub function
+ upstream: when loading PKCS#11 keys, include the key fingerprints
- was not updated to match API change. From Dale Rahn via beck@ ok markus@
+ and provider/slot information in debug output.
- OpenBSD-Commit-ID: 2b8d054afe34c9ac85e417dae702ef981917b836
+ OpenBSD-Commit-ID: 969a089575d0166a9a364a9901bb6a8d9b8a1431
-commit 224418cf55611869a4ace1b8b07bba0dff77a9c3
+commit 9b9465ea856e15b9e9890b4ecb4110d7106e7766
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 29 03:11:54 2020 +0000
+Date: Sun Nov 22 22:37:11 2020 +0000
- upstream: fix exit status for downloading of FIDO resident keys;
+ upstream: when mentioning that the host key has changed, don't
- from Pedro Martelletto, ok markus@
+ 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: 0da77dc24a1084798eedd83c39a002a9d231faef
+ OpenBSD-Commit-ID: 2d5ce4a83dbcf44e340a572e361decad8aab7bad
-commit 1001dd148ed7c57bccf56afb40cb77482ea343a6
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri May 29 01:20:46 2020 +0000
+commit 637017a7dd3281d3f2df804993cc27c30dbfda47
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Nov 25 17:38:46 2020 +1100
- upstream: Fix multiplier in convtime when handling seconds after
-
- other units. bz#3171, spotted by ronf at timeheart.net, ok djm@.
+ Use "=" not "==" in string test.
- OpenBSD-Commit-ID: 95b7a848e1083974a65fbb6ccb381d438e1dd5be
+ POSIX says "=" is string comparison and some shells (eg HP-UX) will
+ complain about "==".
-commit 7af1e92cd289b7eaa9a683e9a6f2fddd98f37a01
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed May 27 22:37:53 2020 +0000
+commit 9880f3480f9768897f3b8e714d5317fb993bc5b3
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Nov 20 17:16:51 2020 +1100
- upstream: fix Include before Match in sshd_config; bz#3122 patch
-
- from Jakub Jelen
+ Restore correct flags during localtime_r check.
- OpenBSD-Commit-ID: 1b0aaf135fe6732b5d326946042665dd3beba5f4
+ We were restoring the wrong thing CPPFLAGS (we used CFLAGS) for any
+ platform that doesn't have localtime_r.
-commit 0a9a611619b0a1fecd0195ec86a9885f5d681c84
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed May 27 21:59:11 2020 +0000
+commit 41935882f4e82de60dbd6e033eabe79e1b963518
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Nov 20 03:16:56 2020 +0000
- upstream: Do not call process_queued_listen_addrs() for every
+ upstream: When doing an sftp recursive upload or download of a
- included file from sshd_config; patch from Jakub Jelen
+ 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: 0ff603d6f06a7fab4881f12503b53024799d0a49
+ OpenBSD-Commit-ID: a82606212f2796e31f0e1af94a63355a7ad5d903
-commit 16ea1fdbe736648f79a827219134331f8d9844fb
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed May 27 21:25:18 2020 +0000
+commit 0f90440ca70abab947acbd77795e9f130967956c
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Nov 20 13:37:54 2020 +1100
- upstream: fix crash in recallocarray when deleting SendEnv
-
- variables; spotted by & ok sthen@
+ Add new pselect6_time64 syscall on ARM.
- OpenBSD-Commit-ID: b881e8e849edeec5082b5c0a87d8d7cff091a8fd
+ This is apparently needed on armhfp/armv7hl. bz#3232, patch from
+ jjelen at redhat.com.
-commit 47adfdc07f4f8ea0064a1495500244de08d311ed
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed May 27 22:35:19 2020 +0000
+commit 3a7c46c72b6a1f643b1fc3589cd20d8320c3d9e1
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Fri Nov 20 02:14:16 2020 +0000
- upstream: two new tests for Include in sshd_config, checking whether
+ upstream: Explicitly initialize all members of the
- 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
+ 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-Regress-ID: 8ad5a4a385a63f0a1c59c59c763ff029b45715df
+ OpenBSD-Commit-ID: 687126e60a27d30f02614760ef3c3ae4e8d6af28
-commit 47faad8f794516c33864d866aa1b55d88416f94c
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed May 27 23:26:23 2020 +1000
+commit 076cb616b87d1ea1d292973fcd0ba38c08ea6832
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Thu Nov 19 23:05:05 2020 +0000
- Document that libfido2 >= 1.4.0 is needed.
+ upstream: draft-ietf-secsh-architecture is now RFC4251.
+
+ OpenBSD-Commit-ID: cb0bb58c2711fb5ed519507659be1dcf179ed403
-commit 4be563994c0cbe9856e7dd3078909f41beae4a9c
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue May 26 01:59:46 2020 +0000
+commit 85cceda21f1471548e04111aefe2c4943131c1c8
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Nov 17 11:23:58 2020 +0000
- upstream: fix memleak of signature; from Pedro Martelletto
+ upstream: Specify that the KDF function is bcrypt. Based on github
- OpenBSD-Commit-ID: d0a6eb07e77c001427d738b220dd024ddc64b2bb
+ PR#214 from rafork, ok markus@, mdoc correction jmc@
+
+ OpenBSD-Commit-ID: d8f2853e7edbcd483f31b50da77ab80ffa18b4ef
-commit 0c111eb84efba7c2a38b2cc3278901a0123161b9
+commit 5b9720f9adbd70ba5a994f407fe07a7d016d8d65
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue May 26 01:26:58 2020 +0000
+Date: Sun Nov 15 22:34: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@
+ upstream: revert r1.341; it breaks ProxyJump; reported by sthen@
- OpenBSD-Commit-ID: 9ab6012574ed0352d2f097d307f4a988222d1b19
+ OpenBSD-Commit-ID: 6ac2f945b26cb86d936eed338f77861d6da8356a
-commit 9c5f64b6cb3a68b99915202d318b842c6c76cf14
+commit 04088725ec9c44880c01799b588cd4ba47b3e8bc
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue May 26 01:09:05 2020 +0000
+Date: Fri Nov 13 07:30:44 2020 +0000
- upstream: improve logging for MaxStartups connection throttling:
+ upstream: scrub keyboard-interactive authentication prompts coming
- have sshd log when it starts and stops throttling and periodically while in
- this state. bz#3055 ok markus@
+ from the server through asmprintf() prior to display; suggested by and ok
+ dtucker@
- OpenBSD-Commit-ID: 2e07a09a62ab45d790d3d2d714f8cc09a9ac7ab9
+ OpenBSD-Commit-ID: 31fe93367645c37fbfe4691596bf6cf1e3972a58
-commit 756c6f66aee83a5862a6f936a316f761532f3320
+commit 5442b491d0ee4bb82f6341ad0ee620ef3947f8c5
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue May 26 01:06:52 2020 +0000
+Date: Fri Nov 13 04:53:12 2020 +0000
- upstream: add fmt_timeframe() (from bgpd) to format a time
+ upstream: prefix keyboard interactive prompts with (user@host) to
- 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@
+ 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: 414a831c662df7e68893e5233e86f2cac081ccf9
+ OpenBSD-Commit-ID: 67e6189b04b46c867662f8a6759cf3ecb5f59170
-commit 2a63ce5cd6d0e782783bf721462239b03757dd49
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon May 18 04:29:35 2020 +0000
+commit 2992e4e7014ac1047062acfdbbf6feb156fef616
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Nov 13 17:56:11 2020 +1100
- upstream: avoid possible NULL deref; from Pedro Martelletto
+ Remove use of TIME_WITH_SYS_TIME.
- OpenBSD-Commit-ID: e6099c3fbb70aa67eb106e84d8b43f1fa919b721
+ 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 4b307faf2fb0e63e51a550b37652f7f972df9676
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Fri May 15 08:34:03 2020 +0000
+commit e3f27006f15abacb7e89fda3f5e9a0bd420b7e38
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Nov 13 14:20:43 2020 +1100
- upstream: sshd listener must not block if reexecd sshd exits
+ Revert "detect Linux/X32 systems"
- 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
+ This reverts commit 5b56bd0affea7b02b540bdbc4d1d271b0e4fc885.
- OpenBSD-Commit-ID: 92ccfeb939ccd55bda914dc3fe84582158c4a9ef
+ The approach used was incorrect; discussion in bz#3085
-commit af8b16fb2cce880341c0ee570ceb0d84104bdcc0
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 15 03:57:33 2020 +0000
+commit e51dc7fab61df36e43f3bc64b673f88d388cab91
+Author: Damien Miller <djm@mindrot.org>
+Date: Fri Nov 13 13:22:15 2020 +1100
- 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
+ SELinux has deprecated security_context_t
- OpenBSD-Commit-ID: 41b394ebe57037dbc43bdd0eef21ff0511191f28
+ (it was only ever a char* anyway)
-commit d7d753e2979f2d3c904b03a08d30856cd2a6e892
-Author: deraadt@openbsd.org <deraadt@openbsd.org>
-Date: Wed May 13 22:38:41 2020 +0000
+commit b79add37d118276d67f3899987b9f0629c9449c3
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Nov 13 13:43:30 2020 +1100
- upstream: we are still aiming for pre-C99 ...
+ Remove obsolete AC_HEADER_TIME macro.
- OpenBSD-Commit-ID: a240fc9cbe60bc4e6c3d24d022eb4ab01fe1cb38
+ 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 2ad7b7e46408dbebf2a4efc4efd75a9544197d57
+commit d5d05cdb3d4efd4a618aa52caab5bec73097c163
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed May 13 10:08:02 2020 +0000
+Date: Thu Nov 12 22:56:00 2020 +0000
- upstream: Enable credProtect extension when generating a resident
+ 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])?
- key.
+ feedback and ok markus@
- 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.
+ 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
- Patch by Pedro Martelletto; ok djm and markus
+ ConnectTimeout is specified, capping the effective value (for most platforms)
+ at 24 days. bz#3229, ok djm@
- OpenBSD-Commit-ID: 013bc06a577dcaa66be3913b7f183eb8cad87e73
+ OpenBSD-Commit-ID: 62d4c4b7b87d111045f8e9f28b5b532d17ac5bc0
-commit 1e70dc3285fc9b4f6454975acb81e8702c23dd89
+commit add926dd1bbe3c4db06e27cab8ab0f9a3d00a0c2
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed May 13 09:57:17 2020 +0000
+Date: Wed Nov 11 05:22:32 2020 +0000
- upstream: always call fido_init(); previous behaviour only called
+ upstream: fix logic error that broke URI parsing in ProxyJump
- fido_init() when SK_DEBUG was defined. Harmless with current libfido2, but
- this isn't guaranteed in the future.
+ directives; ok dtucker@
- OpenBSD-Commit-ID: c7ea20ff2bcd98dd12015d748d3672d4f01f0864
+ OpenBSD-Commit-ID: 96d48839b1704882a0e9a77898f5e14b2d222705
-commit f2d84f1b3fa68d77c99238d4c645d0266fae2a74
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed May 13 09:55:57 2020 +0000
+commit 4340dd43928dfe746cb7e75fe920b63c0d909a9a
+Author: claudio@openbsd.org <claudio@openbsd.org>
+Date: Tue Nov 10 07:46:20 2020 +0000
- upstream: preserve group/world read permission on known_hosts
+ upstream: Free the previously allocated msg buffer after writing it
- file across runs of "ssh-keygen -Rf /path". The old behaviour was to remove
- all rights for group/other. bz#3146 ok dtucker@
+ out. OK djm@
- OpenBSD-Commit-ID: dc369d0e0b5dd826430c63fd5f4b269953448a8a
+ OpenBSD-Commit-ID: 18c055870fc75e4cb9f926c86c7543e2e21d7fa4
-commit 05a651400da6fbe12296c34e3d3bcf09f034fbbf
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed May 13 09:52:41 2020 +0000
+commit fcf429a4c69d30d8725612a55b37181594da8ddf
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Wed Nov 11 12:30:46 2020 +1100
- upstream: when ordering the hostkey algorithms to request from a
+ Prevent excessively long username going to PAM.
- server, prefer certificate types if the known_hosts files contain a key
- marked as a @cert-authority; bz#3157 ok markus@
+ 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.
- OpenBSD-Commit-ID: 8f194573e5bb7c01b69bbfaabc68f27c9fa5e0db
+ Based on github PR#212 from Mike Scott but implemented slightly
+ differently. ok tim@ djm@
-commit 829451815ec207e14bd54ff5cf7e22046816f042
+commit 10dce8ff68ef615362cfcab0c0cc33ce524e7682
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue May 12 01:41:32 2020 +0000
+Date: Sun Nov 8 23:19:03 2020 +0000
- upstream: fix non-ASCII quote that snuck in; spotted by Gabriel
-
- Kihlman
+ upstream: unbreak; missing NULL check
- OpenBSD-Commit-ID: 04bcde311de2325d9e45730c744c8de079b49800
+ OpenBSD-Commit-ID: 6613dfab488123f454d348ef496824476b8c11c0
-commit 5a442cec92c0efd6fffb4af84bf99c70af248ef3
+commit d5a0cd4fc430c8eda213a4010a612d4778867cd9
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon May 11 02:11:29 2020 +0000
+Date: Sun Nov 8 22:37:24 2020 +0000
- upstream: clarify role of FIDO tokens in multi-factor
+ upstream: when requesting a security key touch on stderr, inform the
- authentictation; mostly from Pedro Martelletto
+ user once the touch has been recorded; requested by claudio@ ok markus@
- OpenBSD-Commit-ID: fbe05685a1f99c74b1baca7130c5a03c2df7c0ac
+ OpenBSD-Commit-ID: 3b76ee444490e546b9ea7f879e4092ee0d256233
-commit ecb2c02d994b3e21994f31a70ff911667c262f1f
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 8 05:13:14 2020 +0000
+commit 292bcb2479deb27204e3ff796539c003975a5f7a
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Mon Nov 9 00:33:35 2020 +1100
- upstream: fix compilation with DEBUG_KEXDH; bz#3160 ok dtucker@
+ Remove preprocessor directive from log macro calls.
- OpenBSD-Commit-ID: 832e771948fb45f2270e8b8895aac36d176ba17a
+ 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 3ab6fccc3935e9b778ff52f9c8d40f215d58e01d
-Author: Damien Miller <djm@mindrot.org>
-Date: Thu May 14 12:22:09 2020 +1000
+commit 71693251b7cbb7dd89aaac18815147124732d0d3
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sun Nov 8 12:10:20 2020 +0000
- prefer ln to cp for temporary copy of sshd
+ upstream: Add a comment documenting the source of the moduli group
+
+ sizes.
- 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.
+ OpenBSD-Commit-ID: aec0725ce607630caaa62682624c6763b350391c
-commit f700d316c6b15a9cfbe87230d2dca81a5d916279
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed May 13 15:24:51 2020 +1000
+commit 4d94b031ff88b015f0db57e140f481bff7ae1a91
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sun Nov 8 11:46:12 2020 +0000
- Actually skip pty tests when needed.
+ 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 08ce6b2210f46f795e7db747809f8e587429dfd2
+commit 6d2564b94e51184eb0b73b97d13a36ad50b4f810
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
+Date: Fri Nov 6 17:11:16 2020 +1100
- explicitly manage .depend and .depend.bak
+ Fix function body for variadic macro test.
- 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
+ AC_LANG_PROGRAM puts its second argument inside main() so we don't need
+ to do it ourselves.
-commit 7c0bbed967abed6301a63e0267cc64144357a99a
-Author: Damien Miller <djm@mindrot.org>
-Date: Wed May 13 12:01:10 2020 +1000
+commit 586f9bd2f5980e12f8cf0d3c2a761fa63175da52
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Nov 6 16:53:24 2020 +1100
- 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.
+ Remove AC_PROC_CC_C99 obsoleted in autoconf 2.70.
- ok dtucker
+ Since we only use it to make sure we can handle variadic macros,
+ explicitly check only for that. with & ok djm@
-commit 58ad004acdcabf3b9f40bc3aaa206b25d998db8c
-Author: Damien Miller <djm@mindrot.org>
-Date: Tue May 12 12:58:46 2020 +1000
+commit a019e353df04de1b2ca78d91b39c393256044ad7
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Nov 6 13:56:41 2020 +1100
- prepare for 8.3 release
+ Replace AC_TRY_COMPILE obsoleted in autoconf 2.70.
+
+ Replace with the equivalent AC_COMPILE_IFELSE.
-commit 4fa9e048c2af26beb7dc2ee9479ff3323e92a7b5
+commit 771b7795c0ef6a2fb43b4c6c66b615c2085cb9cd
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri May 8 21:50:43 2020 +1000
+Date: Fri Nov 6 13:55:33 2020 +1100
- Ensure SA_SIGNAL test only signals itself.
+ Move AC_PROG_CC_C99 to immediately afer AC_PROG_CC.
- 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
+ This puts the related C version selection output in the same place.
-commit dc2da29aae76e170d22f38bb36f1f5d1edd5ec2b
-Author: Damien Miller <djm@mindrot.org>
-Date: Fri May 8 13:31:53 2020 +1000
+commit e5591161f21ab493c6284a85ac3c0710ad94998f
+Author: Darren Tucker <dtucker@dtucker.net>
+Date: Fri Nov 6 13:54:17 2020 +1100
- sync config.guess/config.sub with latest versions
+ AC_CHECK_HEADER() is obsoleted in autoconf 2.70.
- ok dtucker@
+ Replace with the non-obsoleted AC_CHECK_HEADERS().
-commit a8265bd64c14881fc7f4fa592f46dfc66b911f17
+commit 05bcd0cadf160fd4826a2284afa7cba6ec432633
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed May 6 20:58:01 2020 +0000
+Date: Tue Nov 3 22:53:12 2020 +0000
- upstream: openssh-8.3; ok deraadt@
+ upstream: fold consecutive '*' wildcards to mitigate combinatorial
- OpenBSD-Commit-ID: c8831ec88b9c750f5816aed9051031fb535d22c1
+ explosion of recursive searches; ok dtucker
+
+ OpenBSD-Commit-ID: d18bcb39c40fb8a1ab61153db987e7d11dd3792b
-commit 955854cafca88e0cdcd3d09ca1ad4ada465364a1
+commit 7d680448db5858dc76307663f78d0b8d3c2b4a3d
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed May 6 20:57:38 2020 +0000
+Date: Fri Oct 30 01:50:07 2020 +0000
- upstream: another case where a utimes() failure could make scp send
+ upstream: print reason in fatal error message when
- a desynchronising error; reminded by Aymeric Vincent ok deraadt markus
+ kex_assemble_namelist() fails
- OpenBSD-Commit-ID: 2ea611d34d8ff6d703a7a8bf858aa5dbfbfa7381
+ OpenBSD-Commit-ID: a9975ee8db6c98d6f32233d88051b2077ca63dab
-commit 59d531553fd90196946743da391f3a27cf472f4e
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Thu May 7 15:34:12 2020 +1000
+commit 95d1109fec7e89ad21f2a97e92bde1305d32a353
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Thu Oct 29 03:13:06 2020 +0000
- Check if -D_REENTRANT is needed for localtime_r.
+ upstream: fix sshd_config SetEnv directive inside Match blocks; part of
- 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.
+ github PR#201 from github user manuelm
+
+ OpenBSD-Commit-ID: 9772e3748abff3ad65ae8fc43d026ed569b1d2bc
-commit 4da393f87cd52d788c84112ee3f2191c9bcaaf30
+commit b12b835dc022ba161afe68348e05a83dfbcb1515
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 1 04:03:14 2020 +0000
+Date: Thu Oct 29 03:01:18 2020 +0000
- upstream: sure enough, some of the test data that we though were in
+ upstream: fix type of nid in type_bits_valid(); github PR#202 from
- new format were actually in the old format; fix from Michael Forney
+ github user thingsconnected
- OpenBSD-Regress-ID: a41a5c43a61b0f0b1691994dbf16dfb88e8af933
+ OpenBSD-Commit-ID: 769d2b040dec7ab32d323daf54b854dd5dcb5485
-commit 15bfafc1db4c8792265ada9623a96f387990f732
+commit 1a14c13147618144d1798c36a588397ba9008fcc
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 1 04:00:29 2020 +0000
+Date: Thu Oct 29 02:52:43 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
+ upstream: whitespace; no code change
- OpenBSD-Regress-ID: 38cf354715c96852e5b71c2393fb6e7ad28b7ca7
+ OpenBSD-Commit-ID: efefc1c47e880887bdee8cd2127ca93177eaad79
-commit 7882d2eda6ad3eb82220a85294de545d20ef82db
+commit 815209abfdd2991fb92ad7d2e33374916cdcbcf4
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 1 03:58:02 2020 +0000
+Date: Thu Oct 29 02:47:23 2020 +0000
- upstream: portability fix for sed that always emil a newline even
+ upstream: UpdateHostkeys: fixed/better detection of host keys that
- if the input does not contain one; from Michael Forney
+ exist under other names and addresses; spotted by and debugged with lots of
+ help from jca@
- OpenBSD-Regress-ID: 9190c3ddf0d2562ccc02c4a95fce0e392196bfc7
+ OpenBSD-Commit-ID: 5113d7f550bbd48243db1705afbf16b63792d4b7
-commit 8074f9499e454df0acdacea33598858a1453a357
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 1 03:36:25 2020 +0000
+commit a575cf44e59a65506c67bddb62a712208a7a279c
+Author: Duncan Eastoe <duncan.eastoe@att.com>
+Date: Wed Oct 21 10:11:10 2020 +0100
- upstream: remove obsolete RSA1 test keys; spotted by Michael Forney
+ session.c: use "denylist" terminology
- OpenBSD-Regress-ID: 6384ba889594e217d166908ed8253718ab0866da
+ Follow upstream (6d755706a0059eb9e2d63517f288b75cbc3b4701) language
+ improvements in this portable-specific code.
-commit c697e46c314aa94574af0d393d80f23e0ebc9748
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat May 2 18:34:47 2020 +1000
+commit 33267feaffd5d98aa56d2f0b3a99ec352effe938
+Author: Damien Miller <djm@mindrot.org>
+Date: Tue Oct 27 16:46:31 2020 +1100
- Update .depend.
+ 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 83657eac42941f270c4b02b2c46d9a21f616ef99
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Sat May 2 18:29:40 2020 +1000
+commit 492d70e18bad5a8c97d05f5eddac817171e88d2c
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Oct 26 00:39:04 2020 +0000
- Remove use of tail for 'make depend'.
+ upstream: Minor man page fixes (capitalization, commas) identified by
+
+ the manpage-l10n project via bz#3223. feedback deraadt@, ok jmc@
- Not every tail supports +N and we can do with out it so just remove it.
- Prompted by mforney at mforney.org.
+ OpenBSD-Commit-ID: ab83af0daf18369244a72daaec6c4a58a9eb7e2c
-commit d25d630d24c5a1c64d4e646510e79dc22d6d7b88
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat May 2 07:19:43 2020 +0000
+commit eab2888cfc6cc4e2ef24bd017da9835a0f365f3f
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Mon Oct 19 22:49:23 2020 +0000
- upstream: we have a sshkey_save_public() function to save public keys;
+ upstream: Adapt XMSS to new logging infrastructure. With markus@, ok
- use it and save a bunch of redundant code.
+ djm@.
- Patch from loic AT venez.fr; ok markus@ 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: f93e030a0ebcd0fd9054ab30db501ec63454ea5f
+ OpenBSD-Commit-ID: 75f155a1ac61e364ed00dc379e2c42df81067ce2
-commit e9dc9863723e111ae05e353d69df857f0169544a
+commit 7715a3b171049afa1feffb1d5a1245dfac36ce99
Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri May 1 18:32:25 2020 +1000
+Date: Mon Oct 19 10:54:41 2020 +1100
- 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.)
+ Use fatal_fr not fatal_r when passing r.
- Fixes rekey test when compiled with the aforementioned compiler.
+ Caught by the PAM -Werror tinderbox build.
-commit aad87b88fc2536b1ea023213729aaf4eaabe1894
+commit 816036f142ecd284c12bb3685ae316a68d2ef190
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 1 06:31:42 2020 +0000
+Date: Sun Oct 18 11:32:01 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.
+ upstream: use the new variant log macros instead of prepending
- ok deraadt@ markus@
+ __func__ and appending ssh_err(r) manually; ok markus@
- OpenBSD-Commit-ID: 6c14d233c97349cb811a8f7921ded3ae7d9e0035
+ OpenBSD-Commit-ID: 1f14b80bcfa85414b2a1a6ff714fb5362687ace8
-commit 31909696c4620c431dd55f6cd15db65c4e9b98da
+commit 9e2c4f64224f68fb84c49b5182e449f94b0dc985
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 1 06:28:52 2020 +0000
+Date: Sun Oct 18 11:21:59 2020 +0000
- upstream: expose vasnmprintf(); ok (as part of other commit) markus
+ upstream: variants of the log methods that append a ssherr.h string
- deraadt
+ from a supplied error code; ok markus@
- OpenBSD-Commit-ID: 2e80cea441c599631a870fd40307d2ade5a7f9b5
+ OpenBSD-Commit-ID: aed98c4435d48d036ae6740300f6a8357b7cc0bf
-commit 99ce9cefbe532ae979744c6d956b49f4b02aff82
+commit 28cb0a4b03940d1ee576eb767a81a4113bdc917e
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri May 1 04:23:11 2020 +0000
+Date: Sun Oct 18 11:14:27 2020 +0000
- upstream: avoid NULL dereference when attempting to convert invalid
-
- ssh.com private keys using "ssh-keygen -i"; spotted by Michael Forney
+ upstream: remove a level of macro indirection; ok markus@
- OpenBSD-Commit-ID: 2e56e6d26973967d11d13f56ea67145f435bf298
+ OpenBSD-Commit-ID: 0c529d06e902c5d1a6b231e1bec6157f76dc67c9
-commit 6c6072ba8b079e6f5caa38b011a6f4570c14ed38
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri May 1 15:09:26 2020 +1000
+commit 9cac1db52e6c4961c447910fe02cd68a3b2f9460
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Sun Oct 18 11:13:45 2020 +0000
- See if SA_RESTART signals will interrupt select().
+ upstream: add some variant log.h calls that prepend the calling
- 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.
+ function name; ok markus@
- 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.
+ OpenBSD-Commit-ID: 4be1b2e2455b271ddb7457bc195c5367644f4e48
-commit 90a0b434ed41f9c505662dba8782591818599cb3
+commit d55dfed34ef6ef1f028d552a90d5f3dba8dd6f7b
Author: Damien Miller <djm@mindrot.org>
-Date: Fri May 1 13:55:03 2020 +1000
+Date: Sat Oct 17 22:55:24 2020 +1100
- fix reversed test
+ missing header
-commit c0dfd18dd1c2107c73d18f70cd164f7ebd434b08
+commit 999d7cb79a3a73d92a6dfbf174c33da0d984c7a2
Author: Damien Miller <djm@mindrot.org>
-Date: Fri May 1 13:29:16 2020 +1000
+Date: Sat Oct 17 22:47:52 2020 +1100
- wrap sha2.h inclusion in #ifdef HAVE_SHA2_H
+ sync regress/misc/sk-dummy/fatal.c
-commit a01817a9f63dbcbbc6293aacc4019993a4cdc7e3
+commit 3554b4afa38b3483a3302f1be18eaa6f843bb260
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Apr 28 04:59:29 2020 +0000
+Date: Sat Oct 17 01:28:20 2020 +0000
- upstream: adapt dummy FIDO middleware to API change; ok markus@
+ upstream: make the log functions that exit (sshlogdie(),
+
+ sshfatal(), etc) have identical signatures. Makes things a bit more
+ consistent...
- OpenBSD-Regress-ID: 8bb84ee500c2eaa5616044314dd0247709a1790f
+ OpenBSD-Commit-ID: bd0ae124733389d7c0042e135c71ee9091362eb9
-commit 261571ddf02ea38fdb5e4a97c69ee53f847ca5b7
+commit 616029a85ad7529b24bb8c4631d9607c0d6e7afe
Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Thu Apr 30 18:28:37 2020 +0000
+Date: Fri Oct 16 14:34:33 2020 +0000
- upstream: tweak previous; ok markus
+ upstream: add space between macro arg and punctuation;
- OpenBSD-Commit-ID: 41895450ce2294ec44a5713134491cc31f0c09fd
+ OpenBSD-Commit-ID: bb81e2ed5a77832fe62ab30a915ae67cda57633e
-commit 5de21c82e1d806d3e401b5338371e354b2e0a66f
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Thu Apr 30 17:12:20 2020 +0000
+commit f812a36cee5727147bc897d34ab9af068dd4561e
+Author: Damien Miller <djm@mindrot.org>
+Date: Sat Oct 17 12:03:34 2020 +1100
- upstream: bring back debug() removed in rev 1.74; noted by pradeep
-
- kumar
+ check for and require a C99 capable compiler
- OpenBSD-Commit-ID: 8d134d22ab25979078a3b48d058557d49c402e65
+ recent logging changes use __VA_ARGS__.
-commit ea14103ce9a5e13492e805f7e9277516ff5a4273
-Author: markus@openbsd.org <markus@openbsd.org>
-Date: Thu Apr 30 17:07:10 2020 +0000
+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
- upstream: run the 2nd ssh with BatchMode for scp -3
+ 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.
- OpenBSD-Commit-ID: 77994fc8c7ca02d88e6d0d06d0f0fe842a935748
+ ok markus@
+
+ OpenBSD-Commit-ID: c294c25732d1b4fe7e345cb3e044df00531a6356
-commit 59d2de956ed29aa5565ed5e5947a7abdb27ac013
+commit 752250caabda3dd24635503c4cd689b32a650794
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Tue Apr 28 04:02:29 2020 +0000
+Date: Fri Oct 16 13:24:45 2020 +0000
- upstream: when signing a challenge using a FIDO toke, perform the
+ upstream: revised log infrastructure for OpenSSH
- 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@
+ log functions receive function, filename and line number of caller.
+ We can use this to selectively enable logging via pattern-lists.
- 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.
+ ok markus@
- OpenBSD-Commit-ID: 3565f056003707a5e678e60e03f7a3efd0464a2b
+ OpenBSD-Commit-ID: 51a472610cbe37834ce6ce4a3f0e0b1ccc95a349
-commit 4d2c87b4d1bde019cdd0f00552fcf97dd8b39940
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Sat Apr 25 06:59:36 2020 +0000
+commit acadbb3402b70f72f14d9a6930ad41be97c2f9dc
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Fri Oct 16 02:37:12 2020 +0000
- upstream: We've standardized on memset over bzero, replace a couple
+ upstream: use do_log2 instead of function pointers to different log
- that had slipped in. ok deraadt markus djm.
+ functions
- OpenBSD-Commit-ID: f5be055554ee93e6cc66b0053b590bef3728dbd6
+ OpenBSD-Commit-ID: 88077b826d348c58352a6b394755520f4e484480
-commit 7f23f42123d64272a7b00754afa6b0841d676691
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri May 1 12:21:58 2020 +1000
+commit 95b0bcfd1531d59e056ae8af27bb741391f26ab0
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Oct 14 00:55:17 2020 +0000
- Include sys/byteorder.h for htons and friends.
+ upstream: make UpdateHostkeys still more conservative: refuse to
- 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.
+ 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
- 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.
+ Also, do not attempt to fix known_hosts with incomplete host/ip matches
+ when there are no new or deprecated hostkeys.
- 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@
+ OpenBSD-Commit-ID: 95c19842f7c41f9bd9c92aa6441a278c0fd0c4a3
-commit 2c1690115a585c624eed2435075a93a463a894e2
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Fri Apr 24 03:33:21 2020 +0000
+commit a336ce8c2c55547cc00e0070a18c55f30bb53fb6
+Author: kn@openbsd.org <kn@openbsd.org>
+Date: Mon Oct 12 08:36:36 2020 +0000
- upstream: Fix incorrect error message for "too many known hosts files."
-
- bz#3149, patch from jjelen at redhat.com.
+ upstream: Zap unused family parameter from ssh_connect_direct()
- 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
+ sshconnect.c r1.241 from 2013 made it unused; found while reading code.
- because nothing sets in_non_blocking_mode any more. Patch from
- michaael.meeks at collabora.com, ok djm@
+ OK djm
- OpenBSD-Commit-ID: c403cefe97a5a99eca816e19cc849cdf926bd09c
+ OpenBSD-Commit-ID: 219ba6d7f9925d0b7992918612680399d86712b5
-commit 8654e3561772f0656e7663a0bd6a1a8cb6d43300
-Author: jmc@openbsd.org <jmc@openbsd.org>
-Date: Thu Apr 23 21:28:09 2020 +0000
+commit e545d94b713effab8e6c7dfabbfb76c1d84d7498
+Author: Philip Hands <phil@hands.com>
+Date: Sun Oct 4 00:15:46 2020 +0200
- upstream: ce examples of "Ar arg Ar arg" with "Ar arg arg" and
+ shift contents of long $() into filter_ids()
- stop the spread;
+ 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.
- OpenBSD-Commit-ID: af0e952ea0f5e2019c2ce953ed1796eca47f0705
-
-commit 67697e4a8246dd8423e44b8785f3ee31fee72d07
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Fri Apr 24 11:10:18 2020 +1000
-
- Update .depend.
+ SSH-Copy-ID-Upstream: 3dab3366a584427045c8a690a93282f02c09cf24
-commit d6cc76176216fe3fac16cd20d148d75cb9c50876
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Apr 22 14:07:00 2020 +1000
+commit fd360174596047b52aa1cddda74d85012a03ca4b
+Author: Philip Hands <phil@hands.com>
+Date: Sat Oct 3 23:15:16 2020 +0200
- Mailing list is now closed to non-subscribers.
+ combine if/elif to avoid duplication of the action
- While there, add a reference to the bugzilla. ok djm@
+ SSH-Copy-ID-Upstream: 42aeb1cc53d3f7f6e78edc210fb121fda0834914
-commit cecde6a41689d0ae585ec903b190755613a6de79
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Apr 22 12:09:40 2020 +1000
+commit f7c3a39b016dd77709ecbf18da8282f967b86cd7
+Author: Philip Hands <phil@hands.com>
+Date: Sat Oct 3 21:45:16 2020 +0200
- Put the values from env vars back.
+ shellcheck tidyage
- This merges the values from the recently removed environment into make's
- command line arguments since we actually need those.
+ SSH-Copy-ID-Upstream: 5b08f840e78ac544288b3983010a1b0585e966fd
-commit 300c4322b92e98d3346efa0aec1c094c94d0f964
-Author: Darren Tucker <dtucker@dtucker.net>
-Date: Wed Apr 22 11:33:15 2020 +1000
+commit 108676c3f26be6c873db0dd8754063699908727b
+Author: Philip Hands <phil@hands.com>
+Date: Sat Oct 3 21:10:03 2020 +0200
- Pass configure's egrep through to test-exec.sh.
+ tidy up test of $SCRATCH_DIR creation
- 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.
+ SSH-Copy-ID-Upstream: 2d8b22d96c105d87743ffe8874887b06f8989b93
-commit 01d4cdcd4514e99a4b6eb9523cd832bbf008d1d7
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Tue Apr 21 23:14:58 2020 +0000
+commit a9c9e91a82bc1a2cf801b4e3ef27a941dbd27717
+Author: Philip Hands <phil@hands.com>
+Date: Wed Sep 16 16:13:30 2020 +0200
- upstream: Backslash '$' at then end of string. Prevents warning on
-
- some shells.
+ add -s flag: to install keys via SFTP
- 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.
+ This is prompted by:
- 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
+ https://bugzilla.mindrot.org/show_bug.cgi?id=3201
- key comments, mostly by loic AT venez.fr (slightly tweaked for portability)
- ok dtucker@
+ Thanks go to Matthias Blümel for the idea, and the helpful patch, from
+ which this patch grew.
- OpenBSD-Regress-ID: 8dc6c4feaf4fe58b6d634cd89afac9a13fd19004
+ SSH-Copy-ID-Upstream: f7c76dc64427cd20287a6868f672423b62057614
-commit a98d5ba31e5e7e01317352f85fa63b846a960f8c
+commit f92424970c02b78852ff149378c7f2616ada4ccf
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Mon Apr 20 04:43:57 2020 +0000
+Date: Sun Oct 11 22:14:38 2020 +0000
- upstream: fix a bug I introduced in r1.406: when printing private key
+ upstream: UpdateHostkeys: check for keys under other names
- fingerprint of old-format key, key comments were not being displayed. Spotted
- by loic AT venez.fr, ok dtucker
+ 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.
- 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
+ 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.
- comment after regression caused by my recent pubkey loading refactor.
- Reported by loic AT venez.fr, ok dtucker@
+ ok markus@
- OpenBSD-Commit-ID: f8db49acbee6a6ccb2a4259135693b3cceedb89e
+ OpenBSD-Commit-ID: 6444a705ba504c3c8ccddccd8d1b94aa33bd11c1
-commit 094dd513f4b42e6a3cebefd18d1837eb709b4d99
+commit d98f14b5328922ae3085e07007d820c4f655b57a
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Apr 17 07:15:11 2020 +0000
+Date: Sun Oct 11 22:13:37 2020 +0000
- upstream: refactor out some duplicate private key loading code;
+ upstream: UpdateHostkeys: better CheckHostIP handling
- based on patch from loic AT venez.fr, ok dtucker@
+ 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.
- 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;
+ Make sure this works with HashKnownHosts too, which requires maintaining
+ a list of entry-types seen across the whole file for each key.
- OpenBSD-Commit-ID: c93a6cbb4bf9468fc4c13e64bc1fd4efee201a44
+ ok markus@
+
+ OpenBSD-Commit-ID: 374dc263103f6b343d9671f87dbf81ffd0d6abdd
-commit 44ae009a0112081d0d541aeaa90088bedb6f21ce
+commit af5941ae9b013aac12585e84c4cf494f3728982f
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Apr 17 04:27:03 2020 +0000
+Date: Sun Oct 11 22:12:44 2020 +0000
- upstream: auth2-pubkey r1.89 changed the order of operations to
+ upstream: UpdateHostkeys: better detect manual host entries
- checking AuthorizedKeysFile first and falling back to AuthorizedKeysCommand
- if no key was found in a file. Document this order here; bz3134
+ 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.
- 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
+ ok markus@
- so change the preprocessor test used to include it to check
- __OpenBSD__, matching the code that uses the symbols it declares.
+ OpenBSD-Commit-ID: e434828191fb5f3877d4887c218682825aa59820
-commit 54688e937a69c7aebef8a3d50cbd4c6345bab2ca
+commit 6247812c76f70b2245f3c23f5074665b3d436cae
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Apr 17 03:38:47 2020 +0000
+Date: Thu Oct 8 01:15:16 2020 +0000
- upstream: fix reversed test that caused IdentitiesOnly=yes to not
+ upstream: don't misdetect comma-separated hostkey names as wildcards;
- apply to keys loaded from a PKCS11Provider; bz3141, ok dtucker@
+ spotted by naddy@
- OpenBSD-Commit-ID: e3dd6424b94685671fe84c9b9dbe352fb659f677
+ OpenBSD-Commit-ID: 4b874edfec7fc324a21b130bdb42f912177739ce
-commit 267cbc87b5b6e78973ac4d3c7a6f807ed226928c
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Apr 17 03:34:42 2020 +0000
+commit 67146c7d022a170be3cdad2f5f40259a663fb266
+Author: wangxp006 <wangxiaopeng7@huawei.com>
+Date: Thu Oct 8 17:49:59 2020 +0800
- 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
+ fix TEST_MALLOC_OPTIONS var
-commit c90f72d29e84b4a2709078bf5546a72c29a65177
+commit 3205eaa3f8883a34fa4559ddef6c90d1067c5cce
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Fri Apr 17 03:30:05 2020 +0000
+Date: Thu Oct 8 00:31: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@
+ upstream: clarify conditions for UpdateHostkeys
- OpenBSD-Commit-ID: d08d6930ed06377a80cf53923c1955e9589342e9
+ OpenBSD-Commit-ID: 9cba714cf6aeed769f998ccbe8c483077a618e27
-commit 321c7147079270f3a154f91b59e66219aac3d514
+commit e8dfca9bfeff05de87160407fb3e6a5717fa3dcb
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
+Date: Wed Oct 7 06:38:16 2020 +0000
- upstream: add space between macro arg and punctuation;
+ upstream: remove GlobalKnownHostsFile for this test after
- 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.
+ UpdateHostkeys change
- 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.
+ OpenBSD-Regress-ID: a940ad79d59343319613ba8fc46b6ef24aa3f8e1
-commit 3779b50ee952078018a5d9e1df20977f4355df17
+commit 4aa2717d7517cff4bc423a6cfba3a2defb055aea
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Sat Apr 11 10:16:11 2020 +0000
+Date: Wed Oct 7 02:26:28 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@
+ upstream: Disable UpdateHostkeys when hostkey checking fails
- 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
+ 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.
- RemoteForward.
+ reminded by Mark D. Baushke; ok markus@
- OpenBSD-Regress-ID: 90fcbc60d510eb114a2b6eaf4a06ff87ecd80a89
+ OpenBSD-Commit-ID: 98b524f121f4252309dd21becd8c4cacb0c6042a
-commit abc3e0a5179c13c0469a1b11fe17d832abc39999
-Author: dtucker@openbsd.org <dtucker@openbsd.org>
-Date: Mon Apr 6 09:43:55 2020 +0000
+commit 04c06d04475f1f673e9d9743710d194453fe3888
+Author: djm@openbsd.org <djm@openbsd.org>
+Date: Wed Oct 7 02:25:43 2020 +0000
- upstream: Add utf8.c for asmprintf used by krl.c
+ upstream: Fix UpdateHostkeys/HashKnownHosts/CheckHostIP bug
- 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 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.
- 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@
+ reported by matthieu@ ok markus@
- OpenBSD-Commit-ID: bffc9f7e7b5cf420309a057408bef55171fd0b97
+ OpenBSD-Commit-ID: a654a8290bd1c930aac509e8158cf85e42e49cb7
-commit 2b13d3934d5803703c04803ca3a93078ecb5b715
+commit b70e33711291f3081702133175a41cccafc0212a
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Apr 8 00:10:37 2020 +0000
+Date: Wed Oct 7 02:24:51 2020 +0000
- upstream: let sshkey_try_load_public() load public keys from the
+ upstream: don't UpdateHostkeys when the hostkey is verified by the
- unencrypted envelope of private key files if not sidecar public key file is
- present.
+ GlobalKnownHostsFile file, support only UserKnownHostsFile matches
- ok markus@
+ suggested by Mark D. Baushke; feedback and ok markus@
- OpenBSD-Commit-ID: 252a0a580e10b9a6311632530d63b5ac76592040
+ OpenBSD-Commit-ID: eabb771a6add676c398d38a143a1aff5f04abbb9
-commit d01f39304eaab0352793b490a25e1ab5f59a5366
+commit aa623142e426ca1ab9db77b06dcc9b1b70bd102b
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Apr 8 00:09:24 2020 +0000
+Date: Wed Oct 7 02:22:23 2020 +0000
- upstream: simplify sshkey_try_load_public()
+ 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: 05a5d46562aafcd70736c792208b1856064f40ad
+ OpenBSD-Commit-ID: fb92d25b216bff8c136da818ac2221efaadf18ed
-commit f290ab0833e44355fc006e4e67b92446c14673ef
+commit f4f14e023cafee1cd9ebe4bb0db4029e6e1fafac
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Apr 8 00:08:46 2020 +0000
+Date: Wed Oct 7 02:20:35 2020 +0000
- upstream: add sshkey_parse_pubkey_from_private_fileblob_type()
+ upstream: simply disable UpdateHostkeys when a certificate
- Extracts a public key from the unencrypted envelope of a new-style
- OpenSSH private key.
+ successfully authenticated the host; simpler than the complicated plumbing
+ via kex->flags we have now.
ok markus@
- OpenBSD-Commit-ID: 44d7ab446e5e8c686aee96d5897b26b3939939aa
+ OpenBSD-Commit-ID: 80e39644eed75717d563a7f177e8117a0e14f42c
-commit 8d514eea4ae089626a55e11c7bc1745c8d9683e4
+commit e79957e877db42c4c68fabcf6ecff2268e53acb5
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Apr 8 00:07:19 2020 +0000
+Date: Wed Oct 7 02:18:45 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.
+ upstream: disable UpdateHostkeys by default if VerifyHostKeyDNS is
- ok markus@
+ enabled; suggested by Mark D. Baushke
- OpenBSD-Commit-ID: 0173bbb3a5cface77b0679d4dca0e15eb5600b77
+ OpenBSD-Commit-ID: 85a1b88592c81bc85df7ee7787dbbe721a0542bf
-commit 421169d0e758351b105eabfcebf42378ebf17217
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Apr 8 00:05:59 2020 +0000
+commit 3d4c2016bae1a6f14b48c1150a4c79ca4c9968bd
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Tue Oct 6 07:12:04 2020 +0000
- upstream: check private key type against requested key type in
-
- new-style private decoding; ok markus@
+ upstream: Agent protocol draft is now at rev 4. ok djm@
- OpenBSD-Commit-ID: 04d44b3a34ce12ce5187fb6f6e441a88c8c51662
+ OpenBSD-Commit-ID: 8c01ea3aae48aab45e01b7421b0fca2dad5e7837
-commit 6aabfb6d22b36d07f584cba97f4cdc4363a829da
+commit af889a40ffc113af9105c03d7b32131eb4372d50
Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Apr 8 00:04:32 2020 +0000
+Date: Sun Oct 4 09:45:01 2020 +0000
- upstream: check that pubkey in private key envelope matches actual
-
- private key
-
- (this public key is currently unusued)
+ upstream: when ordering host key algorithms in the client, consider
- ok markus@
+ the ECDSA key subtype; ok markus@
- OpenBSD-Commit-ID: 634a60b5e135d75f48249ccdf042f3555112049c
+ OpenBSD-Commit-ID: 3097686f853c61ff61772ea35f8b699931392ece
-commit c0f5b2294796451001fd328c44f0d00f1114eddf
-Author: djm@openbsd.org <djm@openbsd.org>
-Date: Wed Apr 8 00:01:52 2020 +0000
+commit 2d39fc9f7e039351daa3d6aead1538ac29258add
+Author: dtucker@openbsd.org <dtucker@openbsd.org>
+Date: Sun Oct 4 03:04:02 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.
+ upstream: Allow full range of UIDs and GIDs for sftp chown and
- ok markus@
+ chgrp on 32bit platforms instead of being limited by LONG_MAX. bz#3206,
+ found by booking00 at sina.cn, ok markus@
- OpenBSD-Commit-ID: 7de31d80fb9062aa01901ddf040c286b64ff904e
+ OpenBSD-Commit-ID: 373b7bbf1f15ae482d39567ce30d18b51c9229b5
diff --git a/INSTALL b/INSTALL
index b6e53ab6c088..c605182b9959 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,284 +1,285 @@
1. Prerequisites
----------------
-A C compiler. Any C89 or better compiler should work. Where supported,
-configure will attempt to enable the compiler's run-time integrity checking
-options. Some notes about specific compilers:
+A C compiler. Any C89 or better compiler that supports variadic macros
+should work. Where supported, configure will attempt to enable the
+compiler's run-time integrity checking options. Some notes about
+specific compilers:
- clang: -ftrapv and -sanitize=integer require the compiler-rt runtime
(CC=clang LDFLAGS=--rtlib=compiler-rt ./configure)
To support Privilege Separation (which is now required) you will need
to create the user, group and directory used by sshd for privilege
separation. See README.privsep for details.
The remaining items are optional.
A working installation of zlib:
Zlib 1.1.4 or 1.2.1.2 or greater (earlier 1.2.x versions have problems):
http://www.gzip.org/zlib/
libcrypto from either of LibreSSL or OpenSSL. Building without libcrypto
is supported but severely restricts the available ciphers and algorithms.
- LibreSSL (https://www.libressl.org/)
- OpenSSL (https://www.openssl.org) with any of the following versions:
- 1.0.x >= 1.0.1 or 1.1.0 >= 1.1.0g or any 1.1.1
Note that due to a bug in EVP_CipherInit OpenSSL 1.1 versions prior to
1.1.0g can't be used.
LibreSSL/OpenSSL should be compiled as a position-independent library
(i.e. -fPIC, eg by configuring OpenSSL as "./config [options] -fPIC"
or LibreSSL as "CFLAGS=-fPIC ./configure") otherwise OpenSSH will not
be able to link with it. If you must use a non-position-independent
libcrypto, then you may need to configure OpenSSH --without-pie.
If you build either from source, running the OpenSSL self-test ("make
tests") or the LibreSSL equivalent ("make check") and ensuring that all
tests pass is strongly recommended.
NB. If you operating system supports /dev/random, you should configure
libcrypto (LibreSSL/OpenSSL) to use it. OpenSSH relies on libcrypto's
direct support of /dev/random, or failing that, either prngd or egd.
PRNGD:
If your system lacks kernel-based random collection, the use of Lutz
Jaenicke's PRNGd is recommended. It requires that libcrypto be configured
to support it.
http://prngd.sourceforge.net/
EGD:
The Entropy Gathering Daemon (EGD) supports the same interface as prngd.
It also supported only if libcrypto is configured to support it.
http://egd.sourceforge.net/
PAM:
OpenSSH can utilise Pluggable Authentication Modules (PAM) if your
system supports it. PAM is standard most Linux distributions, Solaris,
HP-UX 11, AIX >= 5.2, FreeBSD, NetBSD and Mac OS X.
Information about the various PAM implementations are available:
Solaris PAM: http://www.sun.com/software/solaris/pam/
Linux PAM: http://www.kernel.org/pub/linux/libs/pam/
OpenPAM: http://www.openpam.org/
If you wish to build the GNOME passphrase requester, you will need the GNOME
libraries and headers.
GNOME:
http://www.gnome.org/
Alternatively, Jim Knoble <jmknoble@pobox.com> has written an excellent X11
passphrase requester. This is maintained separately at:
http://www.jmknoble.net/software/x11-ssh-askpass/
LibEdit:
sftp supports command-line editing via NetBSD's libedit. If your platform
has it available natively you can use that, alternatively you might try
these multi-platform ports:
http://www.thrysoee.dk/editline/
http://sourceforge.net/projects/libedit/
LDNS:
LDNS is a DNS BSD-licensed resolver library which supports DNSSEC.
http://nlnetlabs.nl/projects/ldns/
Autoconf:
If you modify configure.ac or configure doesn't exist (eg if you checked
the code out of git yourself) then you will need autoconf-2.69 and
automake-1.16.1 to rebuild the automatically generated files by running
"autoreconf". Earlier versions may also work but this is not guaranteed.
http://www.gnu.org/software/autoconf/
http://www.gnu.org/software/automake/
Basic Security Module (BSM):
Native BSM support is known to exist in Solaris from at least 2.5.1,
FreeBSD 6.1 and OS X. Alternatively, you may use the OpenBSM
implementation (http://www.openbsm.org).
makedepend:
https://www.x.org/archive/individual/util/
If you are making significant changes to the code you may need to rebuild
the dependency (.depend) file using "make depend", which requires the
"makedepend" tool from the X11 distribution.
libfido2:
libfido2 allows the use of hardware security keys over USB. libfido2
in turn depends on libcbor. libfido2 >= 1.5.0 is strongly recommended.
Limited functionality is possible with earlier libfido2 versions.
https://github.com/Yubico/libfido2
https://github.com/pjk/libcbor
2. Building / Installation
--------------------------
To install OpenSSH with default options:
./configure
make
make install
This will install the OpenSSH binaries in /usr/local/bin, configuration files
in /usr/local/etc, the server in /usr/local/sbin, etc. To specify a different
installation prefix, use the --prefix option to configure:
./configure --prefix=/opt
make
make install
Will install OpenSSH in /opt/{bin,etc,lib,sbin}. You can also override
specific paths, for example:
./configure --prefix=/opt --sysconfdir=/etc/ssh
make
make install
This will install the binaries in /opt/{bin,lib,sbin}, but will place the
configuration files in /etc/ssh.
If you are using PAM, you may need to manually install a PAM control
file as "/etc/pam.d/sshd" (or wherever your system prefers to keep
them). Note that the service name used to start PAM is __progname,
which is the basename of the path of your sshd (e.g., the service name
for /usr/sbin/osshd will be osshd). If you have renamed your sshd
executable, your PAM configuration may need to be modified.
A generic PAM configuration is included as "contrib/sshd.pam.generic",
you may need to edit it before using it on your system. If you are
using a recent version of Red Hat Linux, the config file in
contrib/redhat/sshd.pam should be more useful. Failure to install a
valid PAM file may result in an inability to use password
authentication. On HP-UX 11 and Solaris, the standard /etc/pam.conf
configuration will work with sshd (sshd will match the other service
name).
There are a few other options to the configure script:
--with-audit=[module] enable additional auditing via the specified module.
Currently, drivers for "debug" (additional info via syslog) and "bsm"
(Sun's Basic Security Module) are supported.
--with-pam enables PAM support. If PAM support is compiled in, it must
also be enabled in sshd_config (refer to the UsePAM directive).
--with-prngd-socket=/some/file allows you to enable EGD or PRNGD
support and to specify a PRNGd socket. Use this if your Unix lacks
/dev/random.
--with-prngd-port=portnum allows you to enable EGD or PRNGD support
and to specify a EGD localhost TCP port. Use this if your Unix lacks
/dev/random.
--with-lastlog=FILE will specify the location of the lastlog file.
./configure searches a few locations for lastlog, but may not find
it if lastlog is installed in a different place.
--without-lastlog will disable lastlog support entirely.
--with-osfsia, --without-osfsia will enable or disable OSF1's Security
Integration Architecture. The default for OSF1 machines is enable.
--with-utmpx enables utmpx support. utmpx support is automatic for
some platforms.
--without-shadow disables shadow password support.
--with-ipaddr-display forces the use of a numeric IP address in the
$DISPLAY environment variable. Some broken systems need this.
--with-default-path=PATH allows you to specify a default $PATH for sessions
started by sshd. This replaces the standard path entirely.
--with-pid-dir=PATH specifies the directory in which the sshd.pid file is
created.
--with-xauth=PATH specifies the location of the xauth binary
--with-ssl-dir=DIR allows you to specify where your Libre/OpenSSL
libraries are installed.
--with-ssl-engine enables Libre/OpenSSL's (hardware) ENGINE support
--without-openssl builds without using OpenSSL. Only a subset of ciphers
and algorithms are supported in this configuration.
--without-zlib builds without zlib. This disables the Compression option.
--with-4in6 Check for IPv4 in IPv6 mapped addresses and convert them to
real (AF_INET) IPv4 addresses. Works around some quirks on Linux.
If you need to pass special options to the compiler or linker, you
can specify these as environment variables before running ./configure.
For example:
CC="/usr/foo/cc" CFLAGS="-O" LDFLAGS="-s" LIBS="-lrubbish" ./configure
3. Configuration
----------------
The runtime configuration files are installed by in ${prefix}/etc or
whatever you specified as your --sysconfdir (/usr/local/etc by default).
The default configuration should be instantly usable, though you should
review it to ensure that it matches your security requirements.
To generate a host key, run "make host-key". Alternately you can do so
manually using the following commands:
ssh-keygen -t [type] -f /etc/ssh/ssh_host_key -N ""
for each of the types you wish to generate (rsa, dsa or ecdsa) or
ssh-keygen -A
to generate keys for all supported types.
Replacing /etc/ssh with the correct path to the configuration directory.
(${prefix}/etc or whatever you specified with --sysconfdir during
configuration).
If you have configured OpenSSH with EGD/prngd support, ensure that EGD or
prngd is running and has collected some entropy first.
For more information on configuration, please refer to the manual pages
for sshd, ssh and ssh-agent.
4. (Optional) Send survey
-------------------------
$ make survey
[check the contents of the file "survey" to ensure there's no information
that you consider sensitive]
$ make send-survey
This will send configuration information for the currently configured
host to a survey address. This will help determine which configurations
are actually in use, and what valid combinations of configure options
exist. The raw data is available only to the OpenSSH developers, however
summary data may be published.
5. Problems?
------------
If you experience problems compiling, installing or running OpenSSH,
please refer to the "reporting bugs" section of the webpage at
https://www.openssh.com/
diff --git a/LICENCE b/LICENCE
index 77ef57699712..4b0db548a1b5 100644
--- a/LICENCE
+++ b/LICENCE
@@ -1,370 +1,371 @@
This file is part of the OpenSSH software.
The licences which components of this software fall under are as
follows. First, we will summarize and say that all components
are under a BSD licence, or a licence more free than that.
OpenSSH contains no GPL code.
1)
* 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".
[Tatu continues]
* However, I am not implying to give any licenses to any patents or
* copyrights held by third parties, and the software includes parts that
* are not under my direct control. As far as I know, all included
* source code is used in accordance with the relevant license agreements
* and can be used freely for any purpose (the GNU license being the most
* restrictive); see below for details.
[However, none of that term is relevant at this point in time. All of
these restrictively licenced software components which he talks about
have been removed from OpenSSH, i.e.,
- RSA is no longer included, found in the OpenSSL library
- IDEA is no longer included, its use is deprecated
- DES is now external, in the OpenSSL library
- GMP is no longer used, and instead we call BN code from OpenSSL
- Zlib is now external, in a library
- The make-ssh-known-hosts script is no longer included
- TSS has been removed
- MD5 is now external, in the OpenSSL library
- RC4 support has been replaced with ARC4 support from OpenSSL
- Blowfish is now external, in the OpenSSL library
[The licence continues]
Note that any information and cryptographic algorithms used in this
software are publicly available on the Internet and at any major
bookstore, scientific library, and patent office worldwide. More
information can be found e.g. at "http://www.cs.hut.fi/crypto".
The legal status of this program is some combination of all these
permissions and restrictions. Use only at your own responsibility.
You will be responsible for any legal consequences yourself; I am not
making any claims whether possessing or using this is legal or not in
your country, and I am not taking any responsibility on your behalf.
NO WARRANTY
BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
3)
ssh-keyscan was contributed by David Mazieres under a BSD-style
license.
* Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
*
* Modification and redistribution in source and binary forms is
* permitted provided that due credit is given to the author and the
* OpenBSD project by leaving this copyright notice intact.
4)
The Rijndael implementation by Vincent Rijmen, Antoon Bosselaers
and Paulo Barreto is in the public domain and distributed
with the following license:
* @version 3.0 (December 2000)
*
* Optimised ANSI C code for the Rijndael cipher (now AES)
*
* @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
* @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
* @author Paulo Barreto <paulo.barreto@terra.com.br>
*
* This code is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS 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.
5)
One component of the ssh source code is under a 3-clause BSD license,
held by the University of California, since we pulled these parts from
original Berkeley code.
* 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.
6)
Remaining components of the software are provided under a standard
2-term BSD licence with the following names as copyright holders:
Markus Friedl
Theo de Raadt
Niels Provos
Dug Song
Aaron Campbell
Damien Miller
Kevin Steves
Daniel Kouril
Wesley Griffin
Per Allansson
Nils Nordman
Simon Wilkinson
Portable OpenSSH additionally includes code from the following copyright
holders, also under the 2-term BSD license:
Ben Lindstrom
Tim Rice
Andre Lucas
Chris Adams
Corinna Vinschen
Cray Inc.
Denis Parker
Gert Doering
Jakob Schlyter
Jason Downs
Juha Yrjölä
Michael Stone
Networks Associates Technology, Inc.
Solar Designer
Todd C. Miller
Wayne Schroeder
William Jones
Darren Tucker
Sun Microsystems
The SCO Group
Daniel Walsh
Red Hat, Inc
Simon Vallet / Genoscope
* 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.
8) Portable OpenSSH contains the following additional licenses:
a) snprintf replacement
* 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
b) Compatibility code (openbsd-compat)
Apart from the previously mentioned licenses, various pieces of code
in the openbsd-compat/ subdirectory are licensed as follows:
Some code is licensed under a 3-term BSD license, to the following
copyright holders:
Todd C. Miller
Theo de Raadt
Damien Miller
Eric P. Allman
The Regents of the University of California
Constantin S. Svintsoff
+ Kungliga Tekniska Högskolan
* 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.
Some code is licensed under an ISC-style license, to the following
copyright holders:
Internet Software Consortium.
Todd C. Miller
Reyk Floeter
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 TODD C. MILLER DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER 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.
Some code is licensed under a MIT-style license to the following
copyright holders:
Free Software Foundation, Inc.
* 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, distribute with modifications, 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 ABOVE 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. *
* *
* Except as contained in this notice, the name(s) of the above copyright *
* holders shall not be used in advertising or otherwise to promote the *
* sale, use or other dealings in this Software without prior written *
* authorization. *
****************************************************************************/
The Blowfish cipher implementation is licensed by Niels Provos under
a 3-clause BSD license:
* Blowfish - a fast block cipher designed by Bruce Schneier
*
* Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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.
Some replacement code is licensed by the NetBSD foundation under a
2-clause BSD license:
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Todd Vierling.
*
* 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: LICENCE,v 1.20 2017/04/30 23:26:16 djm Exp $
diff --git a/Makefile.in b/Makefile.in
index 7250d3f315e1..5dde2baa079c 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,780 +1,777 @@
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@
abs_top_builddir=@abs_top_builddir@
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@
BUILDDIR=@abs_top_builddir@
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@
+CHANNELLIBS=@CHANNELLIBS@
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 \
+ 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 \
+ auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-pubkeyfile.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 \
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)
SFTP_CLIENT_OBJS=sftp-common.o sftp-client.o sftp-glob.o
SCP_OBJS= scp.o progressmeter.o $(SFTP_CLIENT_OBJS)
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 progressmeter.o $(SFTP_CLIENT_OBJS)
+SFTP_OBJS= sftp.o sftp-usergroup.o progressmeter.o $(SFTP_CLIENT_OBJS)
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)
+all: $(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)
+ $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(GSSLIBS) $(CHANNELLIBS)
sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS)
- $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS)
+ $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) $(CHANNELLIBS)
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)
+ $(LD) -o $@ $(SSHADD_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(CHANNELLIBS)
ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHAGENT_OBJS)
- $(LD) -o $@ $(SSHAGENT_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+ $(LD) -o $@ $(SSHAGENT_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(CHANNELLIBS)
ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHKEYGEN_OBJS)
- $(LD) -o $@ $(SSHKEYGEN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+ $(LD) -o $@ $(SSHKEYGEN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(CHANNELLIBS)
ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHKEYSIGN_OBJS)
- $(LD) -o $@ $(SSHKEYSIGN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+ $(LD) -o $@ $(SSHKEYSIGN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(CHANNELLIBS)
ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a $(P11HELPER_OBJS)
- $(LD) -o $@ $(P11HELPER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
+ $(LD) -o $@ $(P11HELPER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) $(CHANNELLIBS)
ssh-sk-helper$(EXEEXT): $(LIBCOMPAT) libssh.a $(SKHELPER_OBJS)
- $(LD) -o $@ $(SKHELPER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) $(LIBFIDO2)
+ $(LD) -o $@ $(SKHELPER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) $(LIBFIDO2) $(CHANNELLIBS)
ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHKEYSCAN_OBJS)
- $(LD) -o $@ $(SSHKEYSCAN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
+ $(LD) -o $@ $(SSHKEYSCAN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) $(CHANNELLIBS)
sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a $(SFTPSERVER_OBJS)
$(LD) -o $@ $(SFTPSERVER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(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/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/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
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) 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/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)
+TESTLIBS=$(LIBS) $(CHANNELLIBS)
regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c $(REGRESSLIBS)
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/modpipe.c \
- $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
+ $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
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)
+ $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
regress/netcat$(EXEEXT): $(srcdir)/regress/netcat.c $(REGRESSLIBS)
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/netcat.c \
- $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
+ $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
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)
+ $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
regress/mkdtemp$(EXEEXT): $(srcdir)/regress/mkdtemp.c $(REGRESSLIBS)
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/mkdtemp.c \
- $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
+ $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
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)
+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
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)
+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
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)
+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
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)
+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
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)
+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
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)
+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
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)
+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
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)
+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
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)
+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
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_strdelim.o \
regress/unittests/misc/test_hpdelim.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)
+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
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)
+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
# 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) $(PICFLAG) -shared -o $@ $(SK_DUMMY_OBJS) \
- -L. -Lopenbsd-compat -lopenbsd-compat $(LDFLAGS_NOPIE) $(LIBS)
+ -L. -Lopenbsd-compat -lopenbsd-compat $(LDFLAGS_NOPIE) $(TESTLIBS)
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/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
cd $(srcdir)/regress || exit $$?; \
$(MAKE) \
.CURDIR="$(abs_top_srcdir)/regress" \
.OBJDIR="$(BUILDDIR)/regress" \
OBJ="$(BUILDDIR)/regress" \
$@ && echo $@ tests passed
interop-tests t-exec file-tests: regress-prep regress-binaries $(TARGETS)
cd $(srcdir)/regress || exit $$?; \
EGREP='@EGREP@' \
$(MAKE) \
.CURDIR="$(abs_top_srcdir)/regress" \
.OBJDIR="$(BUILDDIR)/regress" \
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_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/PROTOCOL b/PROTOCOL
index 2d50b5cb0528..685f90fa8569 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -1,652 +1,715 @@
This documents OpenSSH's deviations and extensions to the published SSH
protocol.
Note that OpenSSH's sftp and sftp-server implement revision 3 of the SSH
filexfer protocol described in:
https://www.openssh.com/txt/draft-ietf-secsh-filexfer-02.txt
Newer versions of the draft will not be supported, though some features
are individually implemented as extensions described below.
The protocol used by OpenSSH's ssh-agent is described in the file
PROTOCOL.agent
1. Transport protocol changes
1.1. transport: Protocol 2 MAC algorithm "umac-64@openssh.com"
This is a new transport-layer MAC method using the UMAC algorithm
(rfc4418). This method is identical to the "umac-64" method documented
in:
https://www.openssh.com/txt/draft-miller-secsh-umac-01.txt
1.2. transport: Protocol 2 compression algorithm "zlib@openssh.com"
This transport-layer compression method uses the zlib compression
algorithm (identical to the "zlib" method in rfc4253), but delays the
start of compression until after authentication has completed. This
avoids exposing compression code to attacks from unauthenticated users.
The method is documented in:
https://www.openssh.com/txt/draft-miller-secsh-compression-delayed-00.txt
1.3. transport: New public key algorithms "ssh-rsa-cert-v01@openssh.com",
"ssh-dsa-cert-v01@openssh.com",
"ecdsa-sha2-nistp256-cert-v01@openssh.com",
"ecdsa-sha2-nistp384-cert-v01@openssh.com" and
"ecdsa-sha2-nistp521-cert-v01@openssh.com"
OpenSSH introduces new public key algorithms to support certificate
authentication for users and host keys. These methods are documented
in the file PROTOCOL.certkeys
1.4. transport: Elliptic Curve cryptography
OpenSSH supports ECC key exchange and public key authentication as
specified in RFC5656. Only the ecdsa-sha2-nistp256, ecdsa-sha2-nistp384
and ecdsa-sha2-nistp521 curves over GF(p) are supported. Elliptic
curve points encoded using point compression are NOT accepted or
generated.
1.5 transport: Protocol 2 Encrypt-then-MAC MAC algorithms
OpenSSH supports MAC algorithms, whose names contain "-etm", that
perform the calculations in a different order to that defined in RFC
4253. These variants use the so-called "encrypt then MAC" ordering,
calculating the MAC over the packet ciphertext rather than the
plaintext. This ordering closes a security flaw in the SSH transport
protocol, where decryption of unauthenticated ciphertext provided a
"decryption oracle" that could, in conjunction with cipher flaws, reveal
session plaintext.
Specifically, the "-etm" MAC algorithms modify the transport protocol
to calculate the MAC over the packet ciphertext and to send the packet
length unencrypted. This is necessary for the transport to obtain the
length of the packet and location of the MAC tag so that it may be
verified without decrypting unauthenticated data.
As such, the MAC covers:
mac = MAC(key, sequence_number || packet_length || encrypted_packet)
where "packet_length" is encoded as a uint32 and "encrypted_packet"
contains:
byte padding_length
byte[n1] payload; n1 = packet_length - padding_length - 1
byte[n2] random padding; n2 = padding_length
1.6 transport: AES-GCM
OpenSSH supports the AES-GCM algorithm as specified in RFC 5647.
Because of problems with the specification of the key exchange
the behaviour of OpenSSH differs from the RFC as follows:
AES-GCM is only negotiated as the cipher algorithms
"aes128-gcm@openssh.com" or "aes256-gcm@openssh.com" and never as
an MAC algorithm. Additionally, if AES-GCM is selected as the cipher
the exchanged MAC algorithms are ignored and there doesn't have to be
a matching MAC.
1.7 transport: chacha20-poly1305@openssh.com authenticated encryption
OpenSSH supports authenticated encryption using ChaCha20 and Poly1305
as described in PROTOCOL.chacha20poly1305.
1.8 transport: curve25519-sha256@libssh.org key exchange algorithm
OpenSSH supports the use of ECDH in Curve25519 for key exchange as
described at:
http://git.libssh.org/users/aris/libssh.git/plain/doc/curve25519-sha256@libssh.org.txt?h=curve25519
+This is identical to curve25519-sha256 as later published in RFC8731.
+
2. Connection protocol changes
2.1. connection: Channel write close extension "eow@openssh.com"
The SSH connection protocol (rfc4254) provides the SSH_MSG_CHANNEL_EOF
message to allow an endpoint to signal its peer that it will send no
more data over a channel. Unfortunately, there is no symmetric way for
an endpoint to request that its peer should cease sending data to it
while still keeping the channel open for the endpoint to send data to
the peer.
This is desirable, since it saves the transmission of data that would
otherwise need to be discarded and it allows an endpoint to signal local
processes of the condition, e.g. by closing the corresponding file
descriptor.
OpenSSH implements a channel extension message to perform this
signalling: "eow@openssh.com" (End Of Write). This message is sent by
an endpoint when the local output of a session channel is closed or
experiences a write error. The message is formatted as follows:
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "eow@openssh.com"
boolean FALSE
On receiving this message, the peer SHOULD cease sending data of
the channel and MAY signal the process from which the channel data
originates (e.g. by closing its read file descriptor).
As with the symmetric SSH_MSG_CHANNEL_EOF message, the channel does
remain open after a "eow@openssh.com" has been sent and more data may
still be sent in the other direction. This message does not consume
window space and may be sent even if no window space is available.
NB. due to certain broken SSH implementations aborting upon receipt
of this message (in contravention of RFC4254 section 5.4), this
message is only sent to OpenSSH peers (identified by banner).
Other SSH implementations may be listed to receive this message
upon request.
2.2. connection: disallow additional sessions extension
"no-more-sessions@openssh.com"
Most SSH connections will only ever request a single session, but a
attacker may abuse a running ssh client to surreptitiously open
additional sessions under their control. OpenSSH provides a global
request "no-more-sessions@openssh.com" to mitigate this attack.
When an OpenSSH client expects that it will never open another session
(i.e. it has been started with connection multiplexing disabled), it
will send the following global request:
byte SSH_MSG_GLOBAL_REQUEST
string "no-more-sessions@openssh.com"
char want-reply
On receipt of such a message, an OpenSSH server will refuse to open
future channels of type "session" and instead immediately abort the
connection.
Note that this is not a general defence against compromised clients
(that is impossible), but it thwarts a simple attack.
NB. due to certain broken SSH implementations aborting upon receipt
of this message, the no-more-sessions request is only sent to OpenSSH
servers (identified by banner). Other SSH implementations may be
listed to receive this message upon request.
2.3. connection: Tunnel forward extension "tun@openssh.com"
OpenSSH supports layer 2 and layer 3 tunnelling via the "tun@openssh.com"
channel type. This channel type supports forwarding of network packets
with datagram boundaries intact between endpoints equipped with
interfaces like the BSD tun(4) device. Tunnel forwarding channels are
requested by the client with the following packet:
byte SSH_MSG_CHANNEL_OPEN
string "tun@openssh.com"
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
uint32 tunnel mode
uint32 remote unit number
The "tunnel mode" parameter specifies whether the tunnel should forward
layer 2 frames or layer 3 packets. It may take one of the following values:
SSH_TUNMODE_POINTOPOINT 1 /* layer 3 packets */
SSH_TUNMODE_ETHERNET 2 /* layer 2 frames */
The "tunnel unit number" specifies the remote interface number, or may
be 0x7fffffff to allow the server to automatically choose an interface. A
server that is not willing to open a client-specified unit should refuse
the request with a SSH_MSG_CHANNEL_OPEN_FAILURE error. On successful
open, the server should reply with SSH_MSG_CHANNEL_OPEN_SUCCESS.
Once established the client and server may exchange packet or frames
over the tunnel channel by encapsulating them in SSH protocol strings
and sending them as channel data. This ensures that packet boundaries
are kept intact. Specifically, packets are transmitted using normal
SSH_MSG_CHANNEL_DATA packets:
byte SSH_MSG_CHANNEL_DATA
uint32 recipient channel
string data
The contents of the "data" field for layer 3 packets is:
uint32 packet length
uint32 address family
byte[packet length - 4] packet data
The "address family" field identifies the type of packet in the message.
It may be one of:
SSH_TUN_AF_INET 2 /* IPv4 */
SSH_TUN_AF_INET6 24 /* IPv6 */
The "packet data" field consists of the IPv4/IPv6 datagram itself
without any link layer header.
The contents of the "data" field for layer 2 packets is:
uint32 packet length
byte[packet length] frame
The "frame" field contains an IEEE 802.3 Ethernet frame, including
header.
2.4. connection: Unix domain socket forwarding
OpenSSH supports local and remote Unix domain socket forwarding
using the "streamlocal" extension. Forwarding is initiated as per
TCP sockets but with a single path instead of a host and port.
Similar to direct-tcpip, direct-streamlocal is sent by the client
to request that the server make a connection to a Unix domain socket.
byte SSH_MSG_CHANNEL_OPEN
string "direct-streamlocal@openssh.com"
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
string socket path
string reserved
uint32 reserved
Similar to forwarded-tcpip, forwarded-streamlocal is sent by the
server when the client has previously send the server a streamlocal-forward
GLOBAL_REQUEST.
byte SSH_MSG_CHANNEL_OPEN
string "forwarded-streamlocal@openssh.com"
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
string socket path
string reserved for future use
The reserved field is not currently defined and is ignored on the
remote end. It is intended to be used in the future to pass
information about the socket file, such as ownership and mode.
The client currently sends the empty string for this field.
Similar to tcpip-forward, streamlocal-forward is sent by the client
to request remote forwarding of a Unix domain socket.
byte SSH2_MSG_GLOBAL_REQUEST
string "streamlocal-forward@openssh.com"
boolean TRUE
string socket path
Similar to cancel-tcpip-forward, cancel-streamlocal-forward is sent
by the client cancel the forwarding of a Unix domain socket.
byte SSH2_MSG_GLOBAL_REQUEST
string "cancel-streamlocal-forward@openssh.com"
boolean FALSE
string socket path
2.5. connection: hostkey update and rotation "hostkeys-00@openssh.com"
and "hostkeys-prove-00@openssh.com"
OpenSSH supports a protocol extension allowing a server to inform
a client of all its protocol v.2 host keys after user-authentication
has completed.
byte SSH_MSG_GLOBAL_REQUEST
string "hostkeys-00@openssh.com"
char 0 /* want-reply */
string[] hostkeys
Upon receiving this message, a client should check which of the
supplied host keys are present in known_hosts.
Note that the server may send key types that the client does not
support. The client should disregard such keys if they are received.
If the client identifies any keys that are not present for the host,
it should send a "hostkeys-prove@openssh.com" message to request the
server prove ownership of the private half of the key.
byte SSH_MSG_GLOBAL_REQUEST
string "hostkeys-prove-00@openssh.com"
char 1 /* want-reply */
string[] hostkeys
When a server receives this message, it should generate a signature
using each requested key over the following:
string "hostkeys-prove-00@openssh.com"
string session identifier
string hostkey
These signatures should be included in the reply, in the order matching
the hostkeys in the request:
byte SSH_MSG_REQUEST_SUCCESS
string[] signatures
When the client receives this reply (and not a failure), it should
validate the signatures and may update its known_hosts file, adding keys
that it has not seen before and deleting keys for the server host that
are no longer offered.
These extensions let a client learn key types that it had not previously
encountered, thereby allowing it to potentially upgrade from weaker
key algorithms to better ones. It also supports graceful key rotation:
a server may offer multiple keys of the same type for a period (to
give clients an opportunity to learn them using this extension) before
removing the deprecated key from those offered.
2.6. connection: SIGINFO support for "signal" channel request
The SSH channels protocol (RFC4254 section 6.9) supports sending a
signal to a session attached to a channel. OpenSSH supports one
extension signal "INFO@openssh.com" that allows sending SIGINFO on
BSD-derived systems.
3. Authentication protocol changes
3.1. Host-bound public key authentication
This is trivial change to the traditional "publickey" authentication
method. The authentication request is identical to the original method
but for the name and one additional field:
byte SSH2_MSG_USERAUTH_REQUEST
string username
string "ssh-connection"
string "publickey-hostbound-v00@openssh.com"
bool has_signature
string pkalg
string public key
string server host key
Because the entire SSH2_MSG_USERAUTH_REQUEST message is included in
the signed data, this ensures that a binding between the destination
user, the server identity and the session identifier is visible to the
signer. OpenSSH uses this binding via signed data to implement per-key
restrictions in ssh-agent.
A server may advertise this method using the SSH2_MSG_EXT_INFO
mechanism (RFC8308), with the following message:
string "publickey-hostbound@openssh.com"
string "0" (version)
Clients should prefer host-bound authentication when advertised by
server.
4. SFTP protocol changes
4.1. sftp: Reversal of arguments to SSH_FXP_SYMLINK
When OpenSSH's sftp-server was implemented, the order of the arguments
to the SSH_FXP_SYMLINK method was inadvertently reversed. Unfortunately,
the reversal was not noticed until the server was widely deployed. Since
fixing this to follow the specification would cause incompatibility, the
current order was retained. For correct operation, clients should send
SSH_FXP_SYMLINK as follows:
uint32 id
string targetpath
string linkpath
4.2. sftp: Server extension announcement in SSH_FXP_VERSION
OpenSSH's sftp-server lists the extensions it supports using the
standard extension announcement mechanism in the SSH_FXP_VERSION server
hello packet:
uint32 3 /* protocol version */
string ext1-name
string ext1-version
string ext2-name
string ext2-version
...
string extN-name
string extN-version
Each extension reports its integer version number as an ASCII encoded
string, e.g. "1". The version will be incremented if the extension is
ever changed in an incompatible way. The server MAY advertise the same
extension with multiple versions (though this is unlikely). Clients MUST
check the version number before attempting to use the extension.
4.3. sftp: Extension request "posix-rename@openssh.com"
This operation provides a rename operation with POSIX semantics, which
are different to those provided by the standard SSH_FXP_RENAME in
draft-ietf-secsh-filexfer-02.txt. This request is implemented as a
SSH_FXP_EXTENDED request with the following format:
uint32 id
string "posix-rename@openssh.com"
string oldpath
string newpath
On receiving this request the server will perform the POSIX operation
rename(oldpath, newpath) and will respond with a SSH_FXP_STATUS message.
This extension is advertised in the SSH_FXP_VERSION hello with version
"1".
4.4. sftp: Extension requests "statvfs@openssh.com" and
"fstatvfs@openssh.com"
These requests correspond to the statvfs and fstatvfs POSIX system
interfaces. The "statvfs@openssh.com" request operates on an explicit
pathname, and is formatted as follows:
uint32 id
string "statvfs@openssh.com"
string path
The "fstatvfs@openssh.com" operates on an open file handle:
uint32 id
string "fstatvfs@openssh.com"
string handle
These requests return a SSH_FXP_STATUS reply on failure. On success they
return the following SSH_FXP_EXTENDED_REPLY reply:
uint32 id
uint64 f_bsize /* file system block size */
uint64 f_frsize /* fundamental fs block size */
uint64 f_blocks /* number of blocks (unit f_frsize) */
uint64 f_bfree /* free blocks in file system */
uint64 f_bavail /* free blocks for non-root */
uint64 f_files /* total file inodes */
uint64 f_ffree /* free file inodes */
uint64 f_favail /* free file inodes for to non-root */
uint64 f_fsid /* file system id */
uint64 f_flag /* bit mask of f_flag values */
uint64 f_namemax /* maximum filename length */
The values of the f_flag bitmask are as follows:
#define SSH_FXE_STATVFS_ST_RDONLY 0x1 /* read-only */
#define SSH_FXE_STATVFS_ST_NOSUID 0x2 /* no setuid */
Both the "statvfs@openssh.com" and "fstatvfs@openssh.com" extensions are
advertised in the SSH_FXP_VERSION hello with version "2".
4.5. sftp: Extension request "hardlink@openssh.com"
This request is for creating a hard link to a regular file. This
request is implemented as a SSH_FXP_EXTENDED request with the
following format:
uint32 id
string "hardlink@openssh.com"
string oldpath
string newpath
On receiving this request the server will perform the operation
link(oldpath, newpath) and will respond with a SSH_FXP_STATUS message.
This extension is advertised in the SSH_FXP_VERSION hello with version
"1".
4.6. sftp: Extension request "fsync@openssh.com"
This request asks the server to call fsync(2) on an open file handle.
uint32 id
string "fsync@openssh.com"
string handle
On receiving this request, a server will call fsync(handle_fd) and will
respond with a SSH_FXP_STATUS message.
This extension is advertised in the SSH_FXP_VERSION hello with version
"1".
4.7. sftp: Extension request "lsetstat@openssh.com"
This request is like the "setstat" command, but sets file attributes on
symlinks. It is implemented as a SSH_FXP_EXTENDED request with the
following format:
uint32 id
string "lsetstat@openssh.com"
string path
ATTRS attrs
See the "setstat" command for more details.
This extension is advertised in the SSH_FXP_VERSION hello with version
"1".
4.8. sftp: Extension request "limits@openssh.com"
This request is used to determine various limits the server might impose.
Clients should not attempt to exceed these limits as the server might sever
the connection immediately.
uint32 id
string "limits@openssh.com"
The server will respond with a SSH_FXP_EXTENDED_REPLY reply:
uint32 id
uint64 max-packet-length
uint64 max-read-length
uint64 max-write-length
uint64 max-open-handles
The 'max-packet-length' applies to the total number of bytes in a
single SFTP packet. Servers SHOULD set this at least to 34000.
The 'max-read-length' is the largest length in a SSH_FXP_READ packet.
Even if the client requests a larger size, servers will usually respond
with a shorter SSH_FXP_DATA packet. Servers SHOULD set this at least to
32768.
The 'max-write-length' is the largest length in a SSH_FXP_WRITE packet
the server will accept. Servers SHOULD set this at least to 32768.
The 'max-open-handles' is the maximum number of active handles that the
server allows (e.g. handles created by SSH_FXP_OPEN and SSH_FXP_OPENDIR
packets). Servers MAY count internal file handles against this limit
(e.g. system logging or stdout/stderr), so clients SHOULD NOT expect to
open this many handles in practice.
If the server doesn't enforce a specific limit, then the field may be
set to 0. This implies the server relies on the OS to enforce limits
(e.g. available memory or file handles), and such limits might be
dynamic. The client SHOULD take care to not try to exceed reasonable
limits.
This extension is advertised in the SSH_FXP_VERSION hello with version
"1".
4.9. sftp: Extension request "expand-path@openssh.com"
This request supports canonicalisation of relative paths and
those that need tilde-expansion, i.e. "~", "~/..." and "~user/..."
These paths are expanded using shell-like rules and the resultant
path is canonicalised similarly to SSH2_FXP_REALPATH.
It is implemented as a SSH_FXP_EXTENDED request with the following
format:
uint32 id
string "expand-path@openssh.com"
string path
Its reply is the same format as that of SSH2_FXP_REALPATH.
This extension is advertised in the SSH_FXP_VERSION hello with version
"1".
4.10. sftp: Extension request "copy-data"
This request asks the server to copy data from one open file handle and
write it to a different open file handle. This avoids needing to transfer
the data across the network twice (a download followed by an upload).
byte SSH_FXP_EXTENDED
uint32 id
string "copy-data"
string read-from-handle
uint64 read-from-offset
uint64 read-data-length
string write-to-handle
uint64 write-to-offset
The server will copy read-data-length bytes starting from
read-from-offset from the read-from-handle and write them to
write-to-handle starting from write-to-offset, and then respond with a
SSH_FXP_STATUS message.
It's equivalent to issuing a series of SSH_FXP_READ requests on
read-from-handle and a series of requests of SSH_FXP_WRITE on
write-to-handle.
If read-from-handle and write-to-handle are the same, the server will
fail the request and respond with a SSH_FX_INVALID_PARAMETER message.
If read-data-length is 0, then the server will read data from the
read-from-handle until EOF is reached.
This extension is advertised in the SSH_FXP_VERSION hello with version
"1".
This request is identical to the "copy-data" request documented in:
https://tools.ietf.org/html/draft-ietf-secsh-filexfer-extensions-00#section-7
+4.11. sftp: Extension request "home-directory"
+
+This request asks the server to expand the specified user's home directory.
+An empty username implies the current user. This can be used by the client
+to expand ~/ type paths locally.
+
+ byte SSH_FXP_EXTENDED
+ uint32 id
+ string "home-directory"
+ string username
+
+This extension is advertised in the SSH_FXP_VERSION hello with version
+"1".
+
+This provides similar information as the "expand-path@openssh.com" extension.
+
+This request is identical to the "home-directory" request documented in:
+
+https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-extensions-00#section-5
+
+4.12. sftp: Extension request "users-groups-by-id@openssh.com"
+
+This request asks the server to returns user and/or group names that
+correspond to one or more IDs (e.g. as returned from a SSH_FXP_STAT
+request). This may be used by the client to provide usernames in
+directory listings.
+
+ byte SSH_FXP_EXTENDED
+ uint32 id
+ string "users-groups-by-id@openssh.com"
+ string uids
+ string gids
+
+Where "uids" and "gids" consists of one or more integer user or group
+identifiers:
+
+ uint32 id-0
+ ...
+
+The server will reply with a SSH_FXP_EXTENDED_REPLY:
+
+ byte SSH_FXP_EXTENDED_REPLY
+ string usernames
+ string groupnames
+
+Where "username" and "groupnames" consists of names in identical request
+order to "uids" and "gids" respectively:
+
+ string name-0
+ ...
+
+If a name cannot be identified for a given user or group ID, an empty
+string will be returned in its place.
+
+It is acceptable for either "uids" or "gids" to be an empty set, in
+which case the respective "usernames" or "groupnames" list will also
+be empty.
+
+This extension is advertised in the SSH_FXP_VERSION hello with version
+"1".
+
5. Miscellaneous changes
5.1 Public key format
OpenSSH public keys, as generated by ssh-keygen(1) and appearing in
authorized_keys files, are formatted as a single line of text consisting
of the public key algorithm name followed by a base64-encoded key blob.
The public key blob (before base64 encoding) is the same format used for
the encoding of public keys sent on the wire: as described in RFC4253
section 6.6 for RSA and DSA keys, RFC5656 section 3.1 for ECDSA keys
and the "New public key formats" section of PROTOCOL.certkeys for the
OpenSSH certificate formats.
5.2 Private key format
OpenSSH private keys, as generated by ssh-keygen(1) use the format
described in PROTOCOL.key by default. As a legacy option, PEM format
(RFC7468) private keys are also supported for RSA, DSA and ECDSA keys
and were the default format before OpenSSH 7.8.
5.3 KRL format
OpenSSH supports a compact format for Key Revocation Lists (KRLs). This
format is described in the PROTOCOL.krl file.
5.4 Connection multiplexing
OpenSSH's connection multiplexing uses messages as described in
PROTOCOL.mux over a Unix domain socket for communications between a
master instance and later clients.
5.5. Agent protocol extensions
OpenSSH extends the usual agent protocol. These changes are documented
in the PROTOCOL.agent file.
-$OpenBSD: PROTOCOL,v 1.44 2022/03/31 03:05:49 djm Exp $
+$OpenBSD: PROTOCOL,v 1.47 2022/09/19 10:40:52 djm Exp $
diff --git a/PROTOCOL.agent b/PROTOCOL.agent
index 67302c34495e..dba76b0c014b 100644
--- a/PROTOCOL.agent
+++ b/PROTOCOL.agent
@@ -1,84 +1,84 @@
The SSH agent protocol is described in
https://tools.ietf.org/html/draft-miller-ssh-agent-04
-This file document's OpenSSH's extensions to the agent protocol.
+This file documents OpenSSH's extensions to the agent protocol.
1. session-bind@openssh.com extension
This extension allows a ssh client to bind an agent connection to a
particular SSH session identifier as derived from the initial key
exchange (as per RFC4253 section 7.2) and the host key used for that
exchange. This binding is verifiable at the agent by including the
initial KEX signature made by the host key.
The message format is:
byte SSH_AGENTC_EXTENSION (0x1b)
string session-bind@openssh.com
string hostkey
string session identifier
string signature
bool is_forwarding
Where 'hostkey' is the encoded server host public key, 'session
identifier' is the exchange hash derived from the initial key
exchange, 'signature' is the server's signature of the session
identifier using the private hostkey, as sent in the final
SSH2_MSG_KEXDH_REPLY/SSH2_MSG_KEXECDH_REPLY message of the initial key
exchange. 'is_forwarding' is a flag indicating whether this connection
should be bound for user authentication or forwarding.
When an agent received this message, it will verify the signature and
check the consistency of its contents, including refusing to accept
a duplicate session identifier, or any attempt to bind a connection
previously bound for authentication. It will then then record the
binding for the life of the connection for use later in testing per-key
destination constraints.
2. restrict-destination-v00@openssh.com key constraint extension
The key constraint extension supports destination- and forwarding path-
restricted keys. It may be attached as a constraint when keys or
smartcard keys are added to an agent.
byte SSH_AGENT_CONSTRAIN_EXTENSION (0xff)
string restrict-destination-v00@openssh.com
constraint[] constraints
Where a constraint consists of:
string from_username (must be empty)
string from_hostname
keyspec[] from_hostkeys
string to_username
string to_hostname
keyspec[] to_hostkeys
-An a keyspec consists of:
+And a keyspec consists of:
string keyblob
bool is_ca
When receiving this message, the agent will ensure that the
'from_username' field is empty, and that 'to_hostname' and 'to_hostkeys'
have been supplied (empty 'from_hostname' and 'from_hostkeys' are valid
and signify the initial hop from the host running ssh-agent). The agent
will then record the constraint against the key.
Subsequent operations on this key including add/remove/request
identities and, in particular, signature requests will check the key
constraints against the session-bind@openssh.com bindings recorded for
the agent connection over which they were received.
3. SSH_AGENT_CONSTRAIN_MAXSIGN key constraint
This key constraint allows communication to an agent of the maximum
number of signatures that may be made with an XMSS key. The format of
the constraint is:
byte SSH_AGENT_CONSTRAIN_MAXSIGN (0x03)
uint32 max_signatures
This option is only valid for XMSS keys.
-$OpenBSD: PROTOCOL.agent,v 1.16 2022/01/01 01:55:30 jsg Exp $
+$OpenBSD: PROTOCOL.agent,v 1.18 2022/09/21 22:26:50 dtucker Exp $
diff --git a/PROTOCOL.key b/PROTOCOL.key
index 38df268b6536..cbf7a70272bf 100644
--- a/PROTOCOL.key
+++ b/PROTOCOL.key
@@ -1,71 +1,71 @@
This document describes the private key format for OpenSSH.
1. Overall format
The key consists of a header, a list of public keys, and
an encrypted list of matching private keys.
#define AUTH_MAGIC "openssh-key-v1"
byte[] AUTH_MAGIC
string ciphername
string kdfname
string kdfoptions
- int number of keys N
+ uint32 number of keys N
string publickey1
string publickey2
...
string publickeyN
string encrypted, padded list of private keys
2. KDF options for kdfname "bcrypt"
The options:
string salt
uint32 rounds
are concatenated and represented as a string.
3. Unencrypted list of N private keys
The list of privatekey/comment pairs is padded with the
bytes 1, 2, 3, ... until the total length is a multiple
of the cipher block size.
uint32 checkint
uint32 checkint
byte[] privatekey1
string comment1
byte[] privatekey2
string comment2
...
string privatekeyN
string commentN
- char 1
- char 2
- char 3
+ byte 1
+ byte 2
+ byte 3
...
- char padlen % 255
+ byte padlen % 255
where each private key is encoded using the same rules as used for
SSH agent.
Before the key is encrypted, a random integer is assigned
to both checkint fields so successful decryption can be
quickly checked by verifying that both checkint fields
hold the same value.
4. Encryption
The KDF is used to derive a key, IV (and other values required by
the cipher) from the passphrase. These values are then used to
encrypt the unencrypted list of private keys.
5. No encryption
For unencrypted keys the cipher "none" and the KDF "none"
are used with empty passphrases. The options if the KDF "none"
are the empty string.
-$OpenBSD: PROTOCOL.key,v 1.2 2021/05/07 02:29:40 djm Exp $
+$OpenBSD: PROTOCOL.key,v 1.3 2022/07/01 04:45:50 djm Exp $
diff --git a/README b/README
index 70a8f814caa9..0d3416f573c5 100644
--- a/README
+++ b/README
@@ -1,52 +1,52 @@
-See https://www.openssh.com/releasenotes.html#9.0p1 for the release notes.
+See https://www.openssh.com/releasenotes.html#9.1p1 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/README.md b/README.md
index de4717737eac..04e3a5198a91 100644
--- a/README.md
+++ b/README.md
@@ -1,84 +1,86 @@
# Portable OpenSSH
[![C/C++ CI](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/openssh.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:openssh)
OpenSSH is a complete implementation of the SSH protocol (version 2) for secure remote login, command execution and file transfer. It includes a client ``ssh`` and server ``sshd``, file transfer utilities ``scp`` and ``sftp`` as well as tools for key generation (``ssh-keygen``), run-time key storage (``ssh-agent``) and a number of supporting programs.
This is a port of OpenBSD's [OpenSSH](https://openssh.com) to most Unix-like operating systems, including Linux, OS X and Cygwin. Portable OpenSSH polyfills OpenBSD APIs that are not available elsewhere, adds sshd sandboxing for more operating systems and includes support for OS-native authentication and auditing (e.g. using PAM).
## Documentation
The official documentation for OpenSSH are the man pages for each tool:
* [ssh(1)](https://man.openbsd.org/ssh.1)
* [sshd(8)](https://man.openbsd.org/sshd.8)
* [ssh-keygen(1)](https://man.openbsd.org/ssh-keygen.1)
* [ssh-agent(1)](https://man.openbsd.org/ssh-agent.1)
* [scp(1)](https://man.openbsd.org/scp.1)
* [sftp(1)](https://man.openbsd.org/sftp.1)
* [ssh-keyscan(8)](https://man.openbsd.org/ssh-keyscan.8)
* [sftp-server(8)](https://man.openbsd.org/sftp-server.8)
## Stable Releases
Stable release tarballs are available from a number of [download mirrors](https://www.openssh.com/portable.html#downloads). We recommend the use of a stable release for most users. Please read the [release notes](https://www.openssh.com/releasenotes.html) for details of recent changes and potential incompatibilities.
## Building Portable OpenSSH
### Dependencies
Portable OpenSSH is built using autoconf and make. It requires a working C compiler, standard library and headers.
-``libcrypto`` from either [LibreSSL](https://www.libressl.org/) or [OpenSSL](https://www.openssl.org) may also be used, but OpenSSH may be built without it supporting a subset of crypto algorithms.
+``libcrypto`` from either [LibreSSL](https://www.libressl.org/) or [OpenSSL](https://www.openssl.org) may also be used. OpenSSH may be built without either of these, but the resulting binaries will have only a subset of the cryptographic algorithms normally available.
[zlib](https://www.zlib.net/) is optional; without it transport compression is not supported.
-FIDO security token support needs [libfido2](https://github.com/Yubico/libfido2) and its dependencies. Also, certain platforms and build-time options may require additional dependencies; see README.platform for details.
+FIDO security token support needs [libfido2](https://github.com/Yubico/libfido2) and its dependencies.
+
+In addition, certain platforms and build-time options may require additional dependencies; see README.platform for details about your platform.
### Building a release
Releases include a pre-built copy of the ``configure`` script and may be built using:
```
tar zxvf openssh-X.YpZ.tar.gz
cd openssh
./configure # [options]
make && make tests
```
See the [Build-time Customisation](#build-time-customisation) section below for configure options. If you plan on installing OpenSSH to your system, then you will usually want to specify destination paths.
### Building from git
If building from git, you'll need [autoconf](https://www.gnu.org/software/autoconf/) installed to build the ``configure`` script. The following commands will check out and build portable OpenSSH from git:
```
git clone https://github.com/openssh/openssh-portable # or https://anongit.mindrot.org/openssh.git
cd openssh-portable
autoreconf
./configure
make && make tests
```
### Build-time Customisation
There are many build-time customisation options available. All Autoconf destination path flags (e.g. ``--prefix``) are supported (and are usually required if you want to install OpenSSH).
-For a full list of available flags, run ``configure --help`` but a few of the more frequently-used ones are described below. Some of these flags will require additional libraries and/or headers be installed.
+For a full list of available flags, run ``./configure --help`` but a few of the more frequently-used ones are described below. Some of these flags will require additional libraries and/or headers be installed.
Flag | Meaning
--- | ---
``--with-pam`` | Enable [PAM](https://en.wikipedia.org/wiki/Pluggable_authentication_module) support. [OpenPAM](https://www.openpam.org/), [Linux PAM](http://www.linux-pam.org/) and Solaris PAM are supported.
``--with-libedit`` | Enable [libedit](https://www.thrysoee.dk/editline/) support for sftp.
``--with-kerberos5`` | Enable Kerberos/GSSAPI support. Both [Heimdal](https://www.h5l.org/) and [MIT](https://web.mit.edu/kerberos/) Kerberos implementations are supported.
``--with-selinux`` | Enable [SELinux](https://en.wikipedia.org/wiki/Security-Enhanced_Linux) support.
``--with-security-key-builtin`` | Include built-in support for U2F/FIDO2 security keys. This requires [libfido2](https://github.com/Yubico/libfido2) be installed.
## Development
Portable OpenSSH development is discussed on the [openssh-unix-dev mailing list](https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev) ([archive mirror](https://marc.info/?l=openssh-unix-dev)). Bugs and feature requests are tracked on our [Bugzilla](https://bugzilla.mindrot.org/).
## Reporting bugs
_Non-security_ bugs may be reported to the developers via [Bugzilla](https://bugzilla.mindrot.org/) or via the mailing list above. Security bugs should be reported to [openssh@openssh.com](mailto:openssh.openssh.com).
diff --git a/addr.c b/addr.c
index 1ad10ae0fdf7..abf3e3d97818 100644
--- a/addr.c
+++ b/addr.c
@@ -1,435 +1,435 @@
-/* $OpenBSD: addr.c,v 1.4 2021/10/22 10:51:57 dtucker Exp $ */
+/* $OpenBSD: addr.c,v 1.5 2022/04/29 04:55:07 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 "addr.h"
#define _SA(x) ((struct sockaddr *)(x))
int
addr_unicast_masklen(int af)
{
switch (af) {
case AF_INET:
return 32;
case AF_INET6:
return 128;
default:
return -1;
}
}
static inline int
masklen_valid(int af, u_int masklen)
{
switch (af) {
case AF_INET:
return masklen <= 32 ? 0 : -1;
case AF_INET6:
return masklen <= 128 ? 0 : -1;
default:
return -1;
}
}
int
addr_xaddr_to_sa(const struct xaddr *xa, struct sockaddr *sa, socklen_t *len,
u_int16_t port)
{
struct sockaddr_in *in4 = (struct sockaddr_in *)sa;
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
if (xa == NULL || sa == NULL || len == NULL)
return -1;
switch (xa->af) {
case AF_INET:
if (*len < sizeof(*in4))
return -1;
memset(sa, '\0', sizeof(*in4));
*len = sizeof(*in4);
#ifdef SOCK_HAS_LEN
in4->sin_len = sizeof(*in4);
#endif
in4->sin_family = AF_INET;
in4->sin_port = htons(port);
memcpy(&in4->sin_addr, &xa->v4, sizeof(in4->sin_addr));
break;
case AF_INET6:
if (*len < sizeof(*in6))
return -1;
memset(sa, '\0', sizeof(*in6));
*len = sizeof(*in6);
#ifdef SOCK_HAS_LEN
in6->sin6_len = sizeof(*in6);
#endif
in6->sin6_family = AF_INET6;
in6->sin6_port = htons(port);
memcpy(&in6->sin6_addr, &xa->v6, sizeof(in6->sin6_addr));
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
in6->sin6_scope_id = xa->scope_id;
#endif
break;
default:
return -1;
}
return 0;
}
/*
* Convert struct sockaddr to struct xaddr
* Returns 0 on success, -1 on failure.
*/
int
addr_sa_to_xaddr(struct sockaddr *sa, socklen_t slen, struct xaddr *xa)
{
struct sockaddr_in *in4 = (struct sockaddr_in *)sa;
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
memset(xa, '\0', sizeof(*xa));
switch (sa->sa_family) {
case AF_INET:
if (slen < (socklen_t)sizeof(*in4))
return -1;
xa->af = AF_INET;
memcpy(&xa->v4, &in4->sin_addr, sizeof(xa->v4));
break;
case AF_INET6:
if (slen < (socklen_t)sizeof(*in6))
return -1;
xa->af = AF_INET6;
memcpy(&xa->v6, &in6->sin6_addr, sizeof(xa->v6));
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
xa->scope_id = in6->sin6_scope_id;
#endif
break;
default:
return -1;
}
return 0;
}
int
addr_invert(struct xaddr *n)
{
int i;
if (n == NULL)
return -1;
switch (n->af) {
case AF_INET:
n->v4.s_addr = ~n->v4.s_addr;
return 0;
case AF_INET6:
for (i = 0; i < 4; i++)
n->addr32[i] = ~n->addr32[i];
return 0;
default:
return -1;
}
}
/*
* Calculate a netmask of length 'l' for address family 'af' and
* store it in 'n'.
* Returns 0 on success, -1 on failure.
*/
int
addr_netmask(int af, u_int l, struct xaddr *n)
{
int i;
if (masklen_valid(af, l) != 0 || n == NULL)
return -1;
memset(n, '\0', sizeof(*n));
switch (af) {
case AF_INET:
n->af = AF_INET;
if (l == 0)
return 0;
n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff);
return 0;
case AF_INET6:
n->af = AF_INET6;
for (i = 0; i < 4 && l >= 32; i++, l -= 32)
n->addr32[i] = 0xffffffffU;
if (i < 4 && l != 0)
n->addr32[i] = htonl((0xffffffff << (32 - l)) &
0xffffffff);
return 0;
default:
return -1;
}
}
int
addr_hostmask(int af, u_int l, struct xaddr *n)
{
if (addr_netmask(af, l, n) == -1 || addr_invert(n) == -1)
return -1;
return 0;
}
/*
* Perform logical AND of addresses 'a' and 'b', storing result in 'dst'.
* Returns 0 on success, -1 on failure.
*/
int
addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b)
{
int i;
if (dst == NULL || a == NULL || b == NULL || a->af != b->af)
return -1;
memcpy(dst, a, sizeof(*dst));
switch (a->af) {
case AF_INET:
dst->v4.s_addr &= b->v4.s_addr;
return 0;
case AF_INET6:
dst->scope_id = a->scope_id;
for (i = 0; i < 4; i++)
dst->addr32[i] &= b->addr32[i];
return 0;
default:
return -1;
}
}
int
addr_cmp(const struct xaddr *a, const struct xaddr *b)
{
int i;
if (a->af != b->af)
return (a->af == AF_INET6 ? 1 : -1);
switch (a->af) {
case AF_INET:
/*
* Can't just subtract here as 255.255.255.255 - 0.0.0.0 is
* too big to fit into a signed int
*/
if (a->v4.s_addr == b->v4.s_addr)
return 0;
return (ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr) ? 1 : -1);
case AF_INET6:
/*
* Do this a byte at a time to avoid the above issue and
* any endian problems
*/
for (i = 0; i < 16; i++)
if (a->addr8[i] - b->addr8[i] != 0)
return (a->addr8[i] - b->addr8[i]);
if (a->scope_id == b->scope_id)
return (0);
return (a->scope_id > b->scope_id ? 1 : -1);
default:
return (-1);
}
}
int
addr_is_all0s(const struct xaddr *a)
{
int i;
switch (a->af) {
case AF_INET:
return (a->v4.s_addr == 0 ? 0 : -1);
case AF_INET6:
for (i = 0; i < 4; i++)
if (a->addr32[i] != 0)
return -1;
return 0;
default:
return -1;
}
}
/*
* Test whether host portion of address 'a', as determined by 'masklen'
* is all zeros.
* Returns 0 if host portion of address is all-zeros,
* -1 if not all zeros or on failure.
*/
int
addr_host_is_all0s(const struct xaddr *a, u_int masklen)
{
struct xaddr tmp_addr, tmp_mask, tmp_result;
memcpy(&tmp_addr, a, sizeof(tmp_addr));
if (addr_hostmask(a->af, masklen, &tmp_mask) == -1)
return -1;
if (addr_and(&tmp_result, &tmp_addr, &tmp_mask) == -1)
return -1;
return addr_is_all0s(&tmp_result);
}
/*
* Parse string address 'p' into 'n'.
* Returns 0 on success, -1 on failure.
*/
int
addr_pton(const char *p, struct xaddr *n)
{
struct addrinfo hints, *ai;
memset(&hints, '\0', sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0)
return -1;
if (ai == NULL)
return -1;
if (ai->ai_addr == NULL) {
freeaddrinfo(ai);
return -1;
}
if (n != NULL && addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen,
n) == -1) {
freeaddrinfo(ai);
return -1;
}
freeaddrinfo(ai);
return 0;
}
int
addr_sa_pton(const char *h, const char *s, struct sockaddr *sa, socklen_t slen)
{
struct addrinfo hints, *ai;
memset(&hints, '\0', sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
if (h == NULL || getaddrinfo(h, s, &hints, &ai) != 0)
return -1;
if (ai == NULL)
return -1;
if (ai->ai_addr == NULL) {
freeaddrinfo(ai);
return -1;
}
if (sa != NULL) {
if (slen < ai->ai_addrlen) {
freeaddrinfo(ai);
return -1;
}
memcpy(sa, &ai->ai_addr, ai->ai_addrlen);
}
freeaddrinfo(ai);
return 0;
}
int
addr_ntop(const struct xaddr *n, char *p, size_t len)
{
struct sockaddr_storage ss;
socklen_t slen = sizeof(ss);
if (addr_xaddr_to_sa(n, _SA(&ss), &slen, 0) == -1)
return -1;
if (p == NULL || len == 0)
return -1;
if (getnameinfo(_SA(&ss), slen, p, len, NULL, 0,
NI_NUMERICHOST) == -1)
return -1;
return 0;
}
/*
* Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z).
* Return -1 on parse error, -2 on inconsistency or 0 on success.
*/
int
addr_pton_cidr(const char *p, struct xaddr *n, u_int *l)
{
struct xaddr tmp;
long unsigned int masklen = 999;
char addrbuf[64], *mp, *cp;
/* Don't modify argument */
if (p == NULL || strlcpy(addrbuf, p, sizeof(addrbuf)) >= sizeof(addrbuf))
return -1;
if ((mp = strchr(addrbuf, '/')) != NULL) {
*mp = '\0';
mp++;
masklen = strtoul(mp, &cp, 10);
- if (*mp == '\0' || *cp != '\0' || masklen > 128)
+ if (*mp < '0' || *mp > '9' || *cp != '\0' || masklen > 128)
return -1;
}
if (addr_pton(addrbuf, &tmp) == -1)
return -1;
if (mp == NULL)
masklen = addr_unicast_masklen(tmp.af);
if (masklen_valid(tmp.af, masklen) == -1)
return -2;
if (addr_host_is_all0s(&tmp, masklen) != 0)
return -2;
if (n != NULL)
memcpy(n, &tmp, sizeof(*n));
if (l != NULL)
*l = masklen;
return 0;
}
int
addr_netmatch(const struct xaddr *host, const struct xaddr *net, u_int masklen)
{
struct xaddr tmp_mask, tmp_result;
if (host->af != net->af)
return -1;
if (addr_netmask(host->af, masklen, &tmp_mask) == -1)
return -1;
if (addr_and(&tmp_result, host, &tmp_mask) == -1)
return -1;
return addr_cmp(&tmp_result, net);
}
diff --git a/auth.c b/auth.c
index 58754c070010..13e8d7998a98 100644
--- a/auth.c
+++ b/auth.c
@@ -1,1007 +1,858 @@
-/* $OpenBSD: auth.c,v 1.154 2022/02/23 11:17:10 djm Exp $ */
+/* $OpenBSD: auth.c,v 1.158 2022/06/03 04:47:21 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;
u_int i;
int r;
/* Shouldn't be called if pw is NULL, but better safe than sorry... */
if (!pw || !pw->pw_name)
return 0;
if (!options.use_pam && platform_locked_account(pw)) {
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);
#if defined(CUSTOM_FAILED_LOGIN) || defined(SSH_AUDIT_EVENTS)
if (authenticated == 0 && !(authctxt->postponed || partial)) {
/* Log failed login attempt */
# ifdef CUSTOM_FAILED_LOGIN
if (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");
# endif
# ifdef SSH_AUDIT_EVENTS
audit_event(ssh, audit_classify_auth(method));
# endif
}
#endif
#if defined(CUSTOM_FAILED_LOGIN) && defined(WITH_AIXAUTHENTICATE)
if (authenticated)
sys_auth_record_login(authctxt->user,
auth_get_canonical_hostname(ssh, options.use_dns), "ssh",
loginmsg);
#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));
- 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 int done = 0;
static struct passwd fake;
const char hashchars[] = "./ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz0123456789"; /* from bcrypt.c */
char *cp;
if (done)
return (&fake);
memset(&fake, 0, sizeof(fake));
fake.pw_name = "NOUSER";
fake.pw_passwd = xstrdup("$2a$10$"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
for (cp = fake.pw_passwd + 7; *cp != '\0'; cp++)
*cp = hashchars[arc4random_uniform(sizeof(hashchars) - 1)];
#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";
done = 1;
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 based on conflation of hostnames and IP addresses.
*/
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();
+ if ((restricted = sshauthopt_new()) == NULL)
+ fatal_f("sshauthopt_new failed");
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/auth.h b/auth.h
index a65d8fd02d38..6d2d3976234e 100644
--- a/auth.h
+++ b/auth.h
@@ -1,235 +1,247 @@
-/* $OpenBSD: auth.h,v 1.102 2021/12/19 22:12:07 djm Exp $ */
+/* $OpenBSD: auth.h,v 1.106 2022/06/15 16:08:25 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.
*
*/
#ifndef AUTH_H
#define AUTH_H
#include <signal.h>
+#include <stdio.h>
#ifdef HAVE_LOGIN_CAP
#include <login_cap.h>
#endif
#ifdef BSD_AUTH
#include <bsd_auth.h>
#endif
#ifdef KRB5
#include <krb5.h>
#endif
struct passwd;
struct ssh;
struct sshbuf;
struct sshkey;
+struct sshkey_cert;
struct sshauthopt;
typedef struct Authctxt Authctxt;
typedef struct Authmethod Authmethod;
typedef struct KbdintDevice KbdintDevice;
struct Authctxt {
sig_atomic_t success;
int authenticated; /* authenticated and alarms cancelled */
int postponed; /* authentication needs another step */
int valid; /* user exists and is allowed to login */
int attempt;
int failures;
int server_caused_failure;
int force_pwchange;
char *user; /* username sent by the client */
char *service;
struct passwd *pw; /* set if 'valid' */
char *style;
/* Method lists for multiple authentication */
char **auth_methods; /* modified from server config */
u_int num_auth_methods;
/* Authentication method-specific data */
void *methoddata;
void *kbdintctxt;
#ifdef BSD_AUTH
auth_session_t *as;
#endif
#ifdef KRB5
krb5_context krb5_ctx;
krb5_ccache krb5_fwd_ccache;
krb5_principal krb5_user;
char *krb5_ticket_file;
char *krb5_ccname;
#endif
struct sshbuf *loginmsg;
/* Authentication keys already used; these will be refused henceforth */
struct sshkey **prev_keys;
u_int nprev_keys;
/* Last used key and ancillary information from active auth method */
struct sshkey *auth_method_key;
char *auth_method_info;
/* Information exposed to session */
struct sshbuf *session_info; /* Auth info for environment */
};
/*
* Every authentication method has to handle authentication requests for
* non-existing users, or for users that are not allowed to login. In this
* case 'valid' is set to 0, but 'user' points to the username requested by
* the client.
*/
struct Authmethod {
char *name;
char *synonym;
int (*userauth)(struct ssh *, const char *);
int *enabled;
};
/*
* Keyboard interactive device:
* init_ctx returns: non NULL upon success
* query returns: 0 - success, otherwise failure
* respond returns: 0 - success, 1 - need further interaction,
* otherwise - failure
*/
struct KbdintDevice
{
const char *name;
void* (*init_ctx)(Authctxt*);
int (*query)(void *ctx, char **name, char **infotxt,
u_int *numprompts, char ***prompts, u_int **echo_on);
int (*respond)(void *ctx, u_int numresp, char **responses);
void (*free_ctx)(void *ctx);
};
int
auth_rhosts2(struct passwd *, const char *, const char *, const char *);
int auth_password(struct ssh *, const char *);
int hostbased_key_allowed(struct ssh *, struct passwd *,
const char *, char *, struct sshkey *);
-int user_key_allowed(struct ssh *, struct passwd *, struct sshkey *, int,
- struct sshauthopt **);
+int user_key_allowed(struct ssh *ssh, struct passwd *, struct sshkey *,
+ int, struct sshauthopt **);
int auth2_key_already_used(Authctxt *, const struct sshkey *);
/*
* Handling auth method-specific information for logging and prevention
* of key reuse during multiple authentication.
*/
void auth2_authctxt_reset_info(Authctxt *);
void auth2_record_key(Authctxt *, int, const struct sshkey *);
void auth2_record_info(Authctxt *authctxt, const char *, ...)
__attribute__((__format__ (printf, 2, 3)))
__attribute__((__nonnull__ (2)));
void auth2_update_session_info(Authctxt *, const char *, const char *);
#ifdef KRB5
int auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *);
int auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt);
int auth_krb5_password(Authctxt *authctxt, const char *password);
void krb5_cleanup_proc(Authctxt *authctxt);
#endif /* KRB5 */
#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
#include <shadow.h>
int auth_shadow_acctexpired(struct spwd *);
int auth_shadow_pwexpired(Authctxt *);
#endif
#include "auth-pam.h"
#include "audit.h"
void remove_kbdint_device(const char *);
void do_authentication2(struct ssh *);
void auth_log(struct ssh *, int, int, const char *, const char *);
void auth_maxtries_exceeded(struct ssh *) __attribute__((noreturn));
void userauth_finish(struct ssh *, int, const char *, const char *);
int auth_root_allowed(struct ssh *, const char *);
char *auth2_read_banner(void);
int auth2_methods_valid(const char *, int);
int auth2_update_methods_lists(Authctxt *, const char *, const char *);
int auth2_setup_methods_lists(Authctxt *);
int auth2_method_allowed(Authctxt *, const char *, const char *);
void privsep_challenge_enable(void);
int auth2_challenge(struct ssh *, char *);
void auth2_challenge_stop(struct ssh *);
int bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **);
int bsdauth_respond(void *, u_int, char **);
int allowed_user(struct ssh *, struct passwd *);
struct passwd * getpwnamallow(struct ssh *, const char *user);
char *expand_authorized_keys(const char *, struct passwd *pw);
char *authorized_principals_file(struct passwd *);
-FILE *auth_openkeyfile(const char *, struct passwd *, int);
-FILE *auth_openprincipals(const char *, struct passwd *, int);
int auth_key_is_revoked(struct sshkey *);
const char *auth_get_canonical_hostname(struct ssh *, int);
HostStatus
check_key_in_hostfiles(struct passwd *, struct sshkey *, const char *,
const char *, const char *);
/* hostkey handling */
struct sshkey *get_hostkey_by_index(int);
struct sshkey *get_hostkey_public_by_index(int, struct ssh *);
struct sshkey *get_hostkey_public_by_type(int, int, struct ssh *);
struct sshkey *get_hostkey_private_by_type(int, int, struct ssh *);
int get_hostkey_index(struct sshkey *, int, struct ssh *);
int sshd_hostkey_sign(struct ssh *, struct sshkey *, struct sshkey *,
u_char **, size_t *, const u_char *, size_t, const char *);
/* Key / cert options linkage to auth layer */
const struct sshauthopt *auth_options(struct ssh *);
int auth_activate_options(struct ssh *, struct sshauthopt *);
void auth_restrict_session(struct ssh *);
-int auth_authorise_keyopts(struct ssh *, struct passwd *pw,
- struct sshauthopt *, int, const char *);
void auth_log_authopts(const char *, const struct sshauthopt *, int);
/* debug messages during authentication */
void auth_debug_add(const char *fmt,...)
__attribute__((format(printf, 1, 2)));
void auth_debug_send(struct ssh *);
void auth_debug_reset(void);
struct passwd *fakepw(void);
+/* auth2-pubkeyfile.c */
+int auth_authorise_keyopts(struct passwd *, struct sshauthopt *, int,
+ const char *, const char *, const char *);
+int auth_check_principals_line(char *, const struct sshkey_cert *,
+ const char *, struct sshauthopt **);
+int auth_process_principals(FILE *, const char *,
+ const struct sshkey_cert *, struct sshauthopt **);
+int auth_check_authkey_line(struct passwd *, struct sshkey *,
+ char *, const char *, const char *, const char *, struct sshauthopt **);
+int auth_check_authkeys_file(struct passwd *, FILE *, char *,
+ struct sshkey *, const char *, const char *, struct sshauthopt **);
+FILE *auth_openkeyfile(const char *, struct passwd *, int);
+FILE *auth_openprincipals(const char *, struct passwd *, int);
+
int sys_auth_passwd(struct ssh *, const char *);
#if defined(KRB5) && !defined(HEIMDAL)
krb5_error_code ssh_krb5_cc_gen(krb5_context, krb5_ccache *);
#endif
#endif /* AUTH_H */
diff --git a/auth2-hostbased.c b/auth2-hostbased.c
index 36b9d2f5b0e5..6b517db411df 100644
--- a/auth2-hostbased.c
+++ b/auth2-hostbased.c
@@ -1,261 +1,266 @@
-/* $OpenBSD: auth2-hostbased.c,v 1.49 2022/01/06 22:01:14 djm Exp $ */
+/* $OpenBSD: auth2-hostbased.c,v 1.50 2022/09/17 10:34:29 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 <stdlib.h>
#include <pwd.h>
#include <string.h>
#include <stdarg.h>
#include "xmalloc.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 "canohost.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
#include "monitor_wrap.h"
#include "pathnames.h"
#include "ssherr.h"
#include "match.h"
/* import */
extern ServerOptions options;
static int
userauth_hostbased(struct ssh *ssh, const char *method)
{
Authctxt *authctxt = ssh->authctxt;
struct sshbuf *b;
struct sshkey *key = NULL;
char *pkalg, *cuser, *chost;
u_char *pkblob, *sig;
size_t alen, blen, slen;
int r, pktype, authenticated = 0;
/* XXX use sshkey_froms() */
if ((r = sshpkt_get_cstring(ssh, &pkalg, &alen)) != 0 ||
(r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 ||
(r = sshpkt_get_cstring(ssh, &chost, NULL)) != 0 ||
(r = sshpkt_get_cstring(ssh, &cuser, NULL)) != 0 ||
(r = sshpkt_get_string(ssh, &sig, &slen)) != 0)
fatal_fr(r, "parse packet");
debug_f("cuser %s chost %s pkalg %s slen %zu",
cuser, chost, pkalg, slen);
#ifdef DEBUG_PK
debug("signature:");
sshbuf_dump_data(sig, slen, stderr);
#endif
pktype = sshkey_type_from_name(pkalg);
if (pktype == KEY_UNSPEC) {
/* this is perfectly legal */
logit_f("unsupported public key algorithm: %s",
pkalg);
goto done;
}
if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
error_fr(r, "key_from_blob");
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) {
error("Refusing RSA key because peer uses unsafe "
"signature format");
goto done;
}
if (match_pattern_list(pkalg, options.hostbased_accepted_algos, 0) != 1) {
logit_f("signature algorithm %s not in "
"HostbasedAcceptedAlgorithms", pkalg);
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;
}
+ if ((r = sshkey_check_rsa_length(key,
+ options.required_rsa_size)) != 0) {
+ logit_r(r, "refusing %s key", sshkey_type(key));
+ goto done;
+ }
if (!authctxt->valid || authctxt->user == NULL) {
debug2_f("disabled because of invalid user");
goto done;
}
if ((b = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
/* reconstruct packet */
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->user)) != 0 ||
(r = sshbuf_put_cstring(b, authctxt->service)) != 0 ||
(r = sshbuf_put_cstring(b, method)) != 0 ||
(r = sshbuf_put_string(b, pkalg, alen)) != 0 ||
(r = sshbuf_put_string(b, pkblob, blen)) != 0 ||
(r = sshbuf_put_cstring(b, chost)) != 0 ||
(r = sshbuf_put_cstring(b, cuser)) != 0)
fatal_fr(r, "reconstruct packet");
#ifdef DEBUG_PK
sshbuf_dump(b, stderr);
#endif
auth2_record_info(authctxt,
"client user \"%.100s\", client host \"%.100s\"", cuser, chost);
/* test for allowed key and correct signature */
authenticated = 0;
if (PRIVSEP(hostbased_key_allowed(ssh, authctxt->pw, cuser,
chost, key)) &&
PRIVSEP(sshkey_verify(key, sig, slen,
sshbuf_ptr(b), sshbuf_len(b), pkalg, ssh->compat, NULL)) == 0)
authenticated = 1;
auth2_record_key(authctxt, authenticated, key);
sshbuf_free(b);
done:
debug2_f("authenticated %d", authenticated);
sshkey_free(key);
free(pkalg);
free(pkblob);
free(cuser);
free(chost);
free(sig);
return authenticated;
}
/* return 1 if given hostkey is allowed */
int
hostbased_key_allowed(struct ssh *ssh, struct passwd *pw,
const char *cuser, char *chost, struct sshkey *key)
{
const char *resolvedname, *ipaddr, *lookup, *reason;
HostStatus host_status;
int len;
char *fp;
if (auth_key_is_revoked(key))
return 0;
resolvedname = auth_get_canonical_hostname(ssh, options.use_dns);
ipaddr = ssh_remote_ipaddr(ssh);
debug2_f("chost %s resolvedname %s ipaddr %s",
chost, resolvedname, ipaddr);
if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') {
debug2("stripping trailing dot from chost %s", chost);
chost[len - 1] = '\0';
}
if (options.hostbased_uses_name_from_packet_only) {
if (auth_rhosts2(pw, cuser, chost, chost) == 0) {
debug2_f("auth_rhosts2 refused user \"%.100s\" "
"host \"%.100s\" (from packet)", cuser, chost);
return 0;
}
lookup = chost;
} else {
if (strcasecmp(resolvedname, chost) != 0)
logit("userauth_hostbased mismatch: "
"client sends %s, but we resolve %s to %s",
chost, ipaddr, resolvedname);
if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0) {
debug2_f("auth_rhosts2 refused "
"user \"%.100s\" host \"%.100s\" addr \"%.100s\"",
cuser, resolvedname, ipaddr);
return 0;
}
lookup = resolvedname;
}
debug2_f("access allowed by auth_rhosts2");
if (sshkey_is_cert(key) &&
sshkey_cert_check_authority_now(key, 1, 0, 0, lookup, &reason)) {
error("%s", reason);
auth_debug_add("%s", reason);
return 0;
}
host_status = check_key_in_hostfiles(pw, key, lookup,
_PATH_SSH_SYSTEM_HOSTFILE,
options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
/* backward compat if no key has been found. */
if (host_status == HOST_NEW) {
host_status = check_key_in_hostfiles(pw, key, lookup,
_PATH_SSH_SYSTEM_HOSTFILE2,
options.ignore_user_known_hosts ? NULL :
_PATH_SSH_USER_HOSTFILE2);
}
if (host_status == HOST_OK) {
if (sshkey_is_cert(key)) {
if ((fp = sshkey_fingerprint(key->cert->signature_key,
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
fatal_f("sshkey_fingerprint fail");
verbose("Accepted certificate ID \"%s\" signed by "
"%s CA %s from %s@%s", key->cert->key_id,
sshkey_type(key->cert->signature_key), fp,
cuser, lookup);
} else {
if ((fp = sshkey_fingerprint(key,
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
fatal_f("sshkey_fingerprint fail");
verbose("Accepted %s public key %s from %s@%s",
sshkey_type(key), fp, cuser, lookup);
}
free(fp);
}
return (host_status == HOST_OK);
}
Authmethod method_hostbased = {
"hostbased",
NULL,
userauth_hostbased,
&options.hostbased_authentication
};
diff --git a/auth2-passwd.c b/auth2-passwd.c
index f8a6dbc19395..cc12cfbc1f1a 100644
--- a/auth2-passwd.c
+++ b/auth2-passwd.c
@@ -1,78 +1,80 @@
-/* $OpenBSD: auth2-passwd.c,v 1.20 2021/12/19 22:12:07 djm Exp $ */
+/* $OpenBSD: auth2-passwd.c,v 1.21 2022/05/27 04:29:40 dtucker 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 <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include "packet.h"
#include "ssherr.h"
#include "log.h"
#include "sshkey.h"
#include "hostfile.h"
#include "auth.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
#include "monitor_wrap.h"
#include "misc.h"
#include "servconf.h"
/* import */
extern ServerOptions options;
static int
userauth_passwd(struct ssh *ssh, const char *method)
{
- char *password;
+ char *password = NULL;
int authenticated = 0, r;
u_char change;
- size_t len;
+ size_t len = 0;
if ((r = sshpkt_get_u8(ssh, &change)) != 0 ||
(r = sshpkt_get_cstring(ssh, &password, &len)) != 0 ||
(change && (r = sshpkt_get_cstring(ssh, NULL, NULL)) != 0) ||
- (r = sshpkt_get_end(ssh)) != 0)
+ (r = sshpkt_get_end(ssh)) != 0) {
+ freezero(password, len);
fatal_fr(r, "parse packet");
+ }
if (change)
logit("password change not supported");
else if (PRIVSEP(auth_password(ssh, password)) == 1)
authenticated = 1;
freezero(password, len);
return authenticated;
}
Authmethod method_passwd = {
"password",
NULL,
userauth_passwd,
&options.password_authentication
};
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index d297a5c3d975..5d59febc3aef 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -1,1094 +1,815 @@
-/* $OpenBSD: auth2-pubkey.c,v 1.113 2022/02/27 01:33:59 naddy Exp $ */
+/* $OpenBSD: auth2-pubkey.c,v 1.117 2022/09/17 10:34:29 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
+ * Copyright (c) 2010 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/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 "kex.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, const char *method)
{
Authctxt *authctxt = ssh->authctxt;
struct passwd *pw = authctxt->pw;
struct sshbuf *b = NULL;
struct sshkey *key = NULL, *hostkey = 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 hostbound, r, pktype;
int req_presence = 0, req_verify = 0, authenticated = 0;
struct sshauthopt *authopts = NULL;
struct sshkey_sig_details *sig_details = NULL;
hostbound = strcmp(method, "publickey-hostbound-v00@openssh.com") == 0;
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 %s packet", method);
/* hostbound auth includes the hostkey offered at initial KEX */
if (hostbound) {
if ((r = sshpkt_getb_froms(ssh, &b)) != 0 ||
(r = sshkey_fromb(b, &hostkey)) != 0)
fatal_fr(r, "parse %s hostkey", method);
if (ssh->kex->initial_hostkey == NULL)
fatal_f("internal error: initial hostkey not recorded");
if (!sshkey_equal(hostkey, ssh->kex->initial_hostkey))
fatal_f("%s packet contained wrong host key", method);
sshbuf_free(b);
b = NULL;
}
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("signature algorithm %s not in "
"PubkeyAcceptedAlgorithms", pkalg);
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;
}
+ if ((r = sshkey_check_rsa_length(key,
+ options.required_rsa_size)) != 0) {
+ logit_r(r, "refusing %s key", sshkey_type(key));
+ 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("%s have %s signature for %s%s%s",
method, 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, method)) != 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 %s packet", method);
if (hostbound &&
(r = sshkey_puts(ssh->kex->initial_hostkey, b)) != 0)
fatal_fr(r, "reconstruct %s packet", method);
#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("%s test pkalg %s pkblob %s%s%s", method, 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);
sshkey_free(hostkey);
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, nonblank = 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;
-
- nonblank++;
- snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum);
- if (check_principals_line(ssh, cp, cert, loc, authoptsp) == 0)
- found_principal = 1;
- }
- debug2_f("%s: processed %lu/%lu lines", file, nonblank, linenum);
- 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,
+match_principals_file(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);
+ success = auth_process_principals(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,
+match_principals_command(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) != 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);
+ ok = auth_process_principals(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_now(key, 0, 0, 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, nonblank = 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;
-
- nonblank++;
- snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum);
- if (check_authkey_line(ssh, pw, key, cp, loc, authoptsp) == 0)
- found_key = 1;
- }
- free(line);
- debug2_f("%s: processed %lu/%lu lines", file, nonblank, linenum);
- return found_key;
-}
-
/* Authenticate a certificate key against TrustedUserCAKeys */
static int
-user_cert_trusted_ca(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
+user_cert_trusted_ca(struct passwd *pw, struct sshkey *key,
+ const char *remote_ip, const char *remote_host,
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,
+ if (match_principals_file(pw, principals_file,
key->cert, &principals_opts))
found_principal = 1;
}
/* Try querying command if specified */
- if (!found_principal && match_principals_command(ssh, pw, key,
+ if (!found_principal && match_principals_command(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;
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_now(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) {
+ if (auth_authorise_keyopts(pw, cert_opts, 0,
+ remote_ip, remote_host, "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) {
+ if (auth_authorise_keyopts(pw, principals_opts, 0,
+ remote_ip, remote_host, "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)
+user_key_allowed2(struct passwd *pw, struct sshkey *key,
+ char *file, const char *remote_ip, const char *remote_host,
+ 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);
+ found_key = auth_check_authkeys_file(pw, f, file,
+ key, remote_ip, remote_host, 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)
+user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key,
+ const char *remote_ip, const char *remote_host,
+ 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) != 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);
+ ok = auth_check_authkeys_file(user_pw, f,
+ options.authorized_keys_command, key, remote_ip,
+ remote_host, 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;
+ const char *remote_ip = ssh_remote_ipaddr(ssh);
+ const char *remote_host = auth_get_canonical_hostname(ssh,
+ options.use_dns);
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);
+ success = user_key_allowed2(pw, key, file,
+ remote_ip, remote_host, &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)
+ if ((success = user_cert_trusted_ca(pw, key, remote_ip, remote_host,
+ &opts)) != 0)
goto out;
sshauthopt_free(opts);
opts = NULL;
- if ((success = user_key_command_allowed2(ssh, pw, key, &opts)) != 0)
+ if ((success = user_key_command_allowed2(pw, key, remote_ip,
+ remote_host, &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",
"publickey-hostbound-v00@openssh.com",
userauth_pubkey,
&options.pubkey_authentication
};
diff --git a/auth2-pubkeyfile.c b/auth2-pubkeyfile.c
new file mode 100644
index 000000000000..0cfacac353c0
--- /dev/null
+++ b/auth2-pubkeyfile.c
@@ -0,0 +1,501 @@
+/* $OpenBSD: auth2-pubkeyfile.c,v 1.3 2022/07/01 03:52:57 djm Exp $ */
+/*
+ * Copyright (c) 2000 Markus Friedl. All rights reserved.
+ * Copyright (c) 2010 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/stat.h>
+
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "ssh.h"
+#include "log.h"
+#include "misc.h"
+#include "compat.h"
+#include "sshkey.h"
+#include "digest.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "auth-options.h"
+#include "authfile.h"
+#include "match.h"
+#include "ssherr.h"
+
+int
+auth_authorise_keyopts(struct passwd *pw, struct sshauthopt *opts,
+ int allow_cert_authority, const char *remote_ip, const char *remote_host,
+ const char *loc)
+{
+ 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;
+}
+
+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.
+ */
+int
+auth_check_principals_line(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;
+}
+
+int
+auth_process_principals(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, nonblank = 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;
+
+ nonblank++;
+ snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum);
+ if (auth_check_principals_line(cp, cert, loc, authoptsp) == 0)
+ found_principal = 1;
+ }
+ debug2_f("%s: processed %lu/%lu lines", file, nonblank, linenum);
+ free(line);
+ 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.
+ */
+int
+auth_check_authkey_line(struct passwd *pw, struct sshkey *key,
+ char *cp, const char *remote_ip, const char *remote_host, 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,
+ SSH_FP_HASH_DEFAULT, 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(pw, keyopts,
+ sshkey_is_cert(key), remote_ip, remote_host, 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(pw, certopts, 0,
+ remote_ip, remote_host, 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_now(key, 0, 0, 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.
+ */
+int
+auth_check_authkeys_file(struct passwd *pw, FILE *f, char *file,
+ struct sshkey *key, const char *remote_ip,
+ const char *remote_host, struct sshauthopt **authoptsp)
+{
+ char *cp, *line = NULL, loc[256];
+ size_t linesize = 0;
+ int found_key = 0;
+ u_long linenum = 0, nonblank = 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;
+
+ nonblank++;
+ snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum);
+ if (auth_check_authkey_line(pw, key, cp,
+ remote_ip, remote_host, loc, authoptsp) == 0)
+ found_key = 1;
+ }
+ free(line);
+ debug2_f("%s: processed %lu/%lu lines", file, nonblank, linenum);
+ return found_key;
+}
+
+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 (errno != ENOENT) {
+ logit("Could not open user '%s' %s '%s': %s",
+ pw->pw_name, file_type, file, strerror(errno));
+ } else if (log_missing) {
+ debug("Could not open user '%s' %s '%s': %s",
+ pw->pw_name, file_type, file, 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");
+}
+
diff --git a/authfd.c b/authfd.c
index 76e48aab779e..b633e35eaf8b 100644
--- a/authfd.c
+++ b/authfd.c
@@ -1,754 +1,755 @@
-/* $OpenBSD: authfd.c,v 1.129 2021/12/19 22:10:24 djm Exp $ */
+/* $OpenBSD: authfd.c,v 1.130 2022/04/27 11:08:55 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Functions for connecting the local authentication agent.
*
* 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 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/un.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include "xmalloc.h"
#include "ssh.h"
#include "sshbuf.h"
#include "sshkey.h"
#include "authfd.h"
#include "cipher.h"
#include "compat.h"
#include "log.h"
#include "atomicio.h"
#include "misc.h"
#include "ssherr.h"
#define MAX_AGENT_IDENTITIES 2048 /* Max keys in agent reply */
#define MAX_AGENT_REPLY_LEN (256 * 1024) /* Max bytes in agent reply */
/* macro to check for "agent failure" message */
#define agent_failed(x) \
((x == SSH_AGENT_FAILURE) || \
(x == SSH_COM_AGENT2_FAILURE) || \
(x == SSH2_AGENT_FAILURE))
/* Convert success/failure response from agent to a err.h status */
static int
decode_reply(u_char type)
{
if (agent_failed(type))
return SSH_ERR_AGENT_FAILURE;
else if (type == SSH_AGENT_SUCCESS)
return 0;
else
return SSH_ERR_INVALID_FORMAT;
}
/*
* Opens an authentication socket at the provided path and stores the file
* descriptor in fdp. Returns 0 on success and an error on failure.
*/
int
ssh_get_authentication_socket_path(const char *authsocket, int *fdp)
{
int sock, oerrno;
struct sockaddr_un sunaddr;
+ debug3_f("path '%s'", authsocket);
memset(&sunaddr, 0, sizeof(sunaddr));
sunaddr.sun_family = AF_UNIX;
strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
return SSH_ERR_SYSTEM_ERROR;
/* close on exec */
if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1 ||
connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
oerrno = errno;
close(sock);
errno = oerrno;
return SSH_ERR_SYSTEM_ERROR;
}
if (fdp != NULL)
*fdp = sock;
else
close(sock);
return 0;
}
/*
* Opens the default authentication socket and stores the file descriptor in
* fdp. Returns 0 on success and an error on failure.
*/
int
ssh_get_authentication_socket(int *fdp)
{
const char *authsocket;
if (fdp != NULL)
*fdp = -1;
authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
if (authsocket == NULL || *authsocket == '\0')
return SSH_ERR_AGENT_NOT_PRESENT;
return ssh_get_authentication_socket_path(authsocket, fdp);
}
/* Communicate with agent: send request and read reply */
static int
ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply)
{
int r;
size_t l, len;
char buf[1024];
/* Get the length of the message, and format it in the buffer. */
len = sshbuf_len(request);
POKE_U32(buf, len);
/* Send the length and then the packet to the agent. */
if (atomicio(vwrite, sock, buf, 4) != 4 ||
atomicio(vwrite, sock, sshbuf_mutable_ptr(request),
sshbuf_len(request)) != sshbuf_len(request))
return SSH_ERR_AGENT_COMMUNICATION;
/*
* Wait for response from the agent. First read the length of the
* response packet.
*/
if (atomicio(read, sock, buf, 4) != 4)
return SSH_ERR_AGENT_COMMUNICATION;
/* Extract the length, and check it for sanity. */
len = PEEK_U32(buf);
if (len > MAX_AGENT_REPLY_LEN)
return SSH_ERR_INVALID_FORMAT;
/* Read the rest of the response in to the buffer. */
sshbuf_reset(reply);
while (len > 0) {
l = len;
if (l > sizeof(buf))
l = sizeof(buf);
if (atomicio(read, sock, buf, l) != l)
return SSH_ERR_AGENT_COMMUNICATION;
if ((r = sshbuf_put(reply, buf, l)) != 0)
return r;
len -= l;
}
return 0;
}
/* Communicate with agent: sent request, read and decode status reply */
static int
ssh_request_reply_decode(int sock, struct sshbuf *request)
{
struct sshbuf *reply;
int r;
u_char type;
if ((reply = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = ssh_request_reply(sock, request, reply)) != 0 ||
(r = sshbuf_get_u8(reply, &type)) != 0 ||
(r = decode_reply(type)) != 0)
goto out;
/* success */
r = 0;
out:
sshbuf_free(reply);
return r;
}
/*
* Closes the agent socket if it should be closed (depends on how it was
* obtained). The argument must have been returned by
* ssh_get_authentication_socket().
*/
void
ssh_close_authentication_socket(int sock)
{
if (getenv(SSH_AUTHSOCKET_ENV_NAME))
close(sock);
}
/* Lock/unlock agent */
int
ssh_lock_agent(int sock, int lock, const char *password)
{
int r;
u_char type = lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK;
struct sshbuf *msg;
if ((msg = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_u8(msg, type)) != 0 ||
(r = sshbuf_put_cstring(msg, password)) != 0 ||
(r = ssh_request_reply_decode(sock, msg)) != 0)
goto out;
/* success */
r = 0;
out:
sshbuf_free(msg);
return r;
}
static int
deserialise_identity2(struct sshbuf *ids, struct sshkey **keyp, char **commentp)
{
int r;
char *comment = NULL;
const u_char *blob;
size_t blen;
if ((r = sshbuf_get_string_direct(ids, &blob, &blen)) != 0 ||
(r = sshbuf_get_cstring(ids, &comment, NULL)) != 0)
goto out;
if ((r = sshkey_from_blob(blob, blen, keyp)) != 0)
goto out;
if (commentp != NULL) {
*commentp = comment;
comment = NULL;
}
r = 0;
out:
free(comment);
return r;
}
/*
* Fetch list of identities held by the agent.
*/
int
ssh_fetch_identitylist(int sock, struct ssh_identitylist **idlp)
{
u_char type;
u_int32_t num, i;
struct sshbuf *msg;
struct ssh_identitylist *idl = NULL;
int r;
/*
* Send a message to the agent requesting for a list of the
* identities it can represent.
*/
if ((msg = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_REQUEST_IDENTITIES)) != 0)
goto out;
if ((r = ssh_request_reply(sock, msg, msg)) != 0)
goto out;
/* Get message type, and verify that we got a proper answer. */
if ((r = sshbuf_get_u8(msg, &type)) != 0)
goto out;
if (agent_failed(type)) {
r = SSH_ERR_AGENT_FAILURE;
goto out;
} else if (type != SSH2_AGENT_IDENTITIES_ANSWER) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* Get the number of entries in the response and check it for sanity. */
if ((r = sshbuf_get_u32(msg, &num)) != 0)
goto out;
if (num > MAX_AGENT_IDENTITIES) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (num == 0) {
r = SSH_ERR_AGENT_NO_IDENTITIES;
goto out;
}
/* Deserialise the response into a list of keys/comments */
if ((idl = calloc(1, sizeof(*idl))) == NULL ||
(idl->keys = calloc(num, sizeof(*idl->keys))) == NULL ||
(idl->comments = calloc(num, sizeof(*idl->comments))) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
for (i = 0; i < num;) {
if ((r = deserialise_identity2(msg, &(idl->keys[i]),
&(idl->comments[i]))) != 0) {
if (r == SSH_ERR_KEY_TYPE_UNKNOWN) {
/* Gracefully skip unknown key types */
num--;
continue;
} else
goto out;
}
i++;
}
idl->nkeys = num;
*idlp = idl;
idl = NULL;
r = 0;
out:
sshbuf_free(msg);
if (idl != NULL)
ssh_free_identitylist(idl);
return r;
}
void
ssh_free_identitylist(struct ssh_identitylist *idl)
{
size_t i;
if (idl == NULL)
return;
for (i = 0; i < idl->nkeys; i++) {
if (idl->keys != NULL)
sshkey_free(idl->keys[i]);
if (idl->comments != NULL)
free(idl->comments[i]);
}
free(idl->keys);
free(idl->comments);
free(idl);
}
/*
* Check if the ssh agent has a given key.
* Returns 0 if found, or a negative SSH_ERR_* error code on failure.
*/
int
ssh_agent_has_key(int sock, const struct sshkey *key)
{
int r, ret = SSH_ERR_KEY_NOT_FOUND;
size_t i;
struct ssh_identitylist *idlist = NULL;
if ((r = ssh_fetch_identitylist(sock, &idlist)) != 0) {
return r;
}
for (i = 0; i < idlist->nkeys; i++) {
if (sshkey_equal_public(idlist->keys[i], key)) {
ret = 0;
break;
}
}
ssh_free_identitylist(idlist);
return ret;
}
/*
* Sends a challenge (typically from a server via ssh(1)) to the agent,
* and waits for a response from the agent.
* Returns true (non-zero) if the agent gave the correct answer, zero
* otherwise.
*/
/* encode signature algorithm in flag bits, so we can keep the msg format */
static u_int
agent_encode_alg(const struct sshkey *key, const char *alg)
{
if (alg != NULL && sshkey_type_plain(key->type) == KEY_RSA) {
if (strcmp(alg, "rsa-sha2-256") == 0 ||
strcmp(alg, "rsa-sha2-256-cert-v01@openssh.com") == 0)
return SSH_AGENT_RSA_SHA2_256;
if (strcmp(alg, "rsa-sha2-512") == 0 ||
strcmp(alg, "rsa-sha2-512-cert-v01@openssh.com") == 0)
return SSH_AGENT_RSA_SHA2_512;
}
return 0;
}
/* ask agent to sign data, returns err.h code on error, 0 on success */
int
ssh_agent_sign(int sock, const struct sshkey *key,
u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, const char *alg, u_int compat)
{
struct sshbuf *msg;
u_char *sig = NULL, type = 0;
size_t len = 0;
u_int flags = 0;
int r = SSH_ERR_INTERNAL_ERROR;
*sigp = NULL;
*lenp = 0;
if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE)
return SSH_ERR_INVALID_ARGUMENT;
if ((msg = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
flags |= agent_encode_alg(key, alg);
if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
(r = sshkey_puts(key, msg)) != 0 ||
(r = sshbuf_put_string(msg, data, datalen)) != 0 ||
(r = sshbuf_put_u32(msg, flags)) != 0)
goto out;
if ((r = ssh_request_reply(sock, msg, msg)) != 0)
goto out;
if ((r = sshbuf_get_u8(msg, &type)) != 0)
goto out;
if (agent_failed(type)) {
r = SSH_ERR_AGENT_FAILURE;
goto out;
} else if (type != SSH2_AGENT_SIGN_RESPONSE) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((r = sshbuf_get_string(msg, &sig, &len)) != 0)
goto out;
/* Check what we actually got back from the agent. */
if ((r = sshkey_check_sigtype(sig, len, alg)) != 0)
goto out;
/* success */
*sigp = sig;
*lenp = len;
sig = NULL;
len = 0;
r = 0;
out:
freezero(sig, len);
sshbuf_free(msg);
return r;
}
/* Encode key for a message to the agent. */
static int
encode_dest_constraint_hop(struct sshbuf *m,
const struct dest_constraint_hop *dch)
{
struct sshbuf *b;
u_int i;
int r;
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_cstring(b, dch->user)) != 0 ||
(r = sshbuf_put_cstring(b, dch->hostname)) != 0 ||
(r = sshbuf_put_string(b, NULL, 0)) != 0) /* reserved */
goto out;
for (i = 0; i < dch->nkeys; i++) {
if ((r = sshkey_puts(dch->keys[i], b)) != 0 ||
(r = sshbuf_put_u8(b, dch->key_is_ca[i] != 0)) != 0)
goto out;
}
if ((r = sshbuf_put_stringb(m, b)) != 0)
goto out;
/* success */
r = 0;
out:
sshbuf_free(b);
return r;
}
static int
encode_dest_constraint(struct sshbuf *m, const struct dest_constraint *dc)
{
struct sshbuf *b;
int r;
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = encode_dest_constraint_hop(b, &dc->from) != 0) ||
(r = encode_dest_constraint_hop(b, &dc->to) != 0) ||
(r = sshbuf_put_string(b, NULL, 0)) != 0) /* reserved */
goto out;
if ((r = sshbuf_put_stringb(m, b)) != 0)
goto out;
/* success */
r = 0;
out:
sshbuf_free(b);
return r;
}
static int
encode_constraints(struct sshbuf *m, u_int life, u_int confirm, u_int maxsign,
const char *provider, struct dest_constraint **dest_constraints,
size_t ndest_constraints)
{
int r;
struct sshbuf *b = NULL;
size_t i;
if (life != 0) {
if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_LIFETIME)) != 0 ||
(r = sshbuf_put_u32(m, life)) != 0)
goto out;
}
if (confirm != 0) {
if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_CONFIRM)) != 0)
goto out;
}
if (maxsign != 0) {
if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_MAXSIGN)) != 0 ||
(r = sshbuf_put_u32(m, maxsign)) != 0)
goto out;
}
if (provider != NULL) {
if ((r = sshbuf_put_u8(m,
SSH_AGENT_CONSTRAIN_EXTENSION)) != 0 ||
(r = sshbuf_put_cstring(m,
"sk-provider@openssh.com")) != 0 ||
(r = sshbuf_put_cstring(m, provider)) != 0)
goto out;
}
if (dest_constraints != NULL && ndest_constraints > 0) {
if ((b = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
for (i = 0; i < ndest_constraints; i++) {
if ((r = encode_dest_constraint(b,
dest_constraints[i])) != 0)
goto out;
}
if ((r = sshbuf_put_u8(m,
SSH_AGENT_CONSTRAIN_EXTENSION)) != 0 ||
(r = sshbuf_put_cstring(m,
"restrict-destination-v00@openssh.com")) != 0 ||
(r = sshbuf_put_stringb(m, b)) != 0)
goto out;
}
r = 0;
out:
sshbuf_free(b);
return r;
}
/*
* Adds an identity to the authentication server.
* This call is intended only for use by ssh-add(1) and like applications.
*/
int
ssh_add_identity_constrained(int sock, struct sshkey *key,
const char *comment, u_int life, u_int confirm, u_int maxsign,
const char *provider, struct dest_constraint **dest_constraints,
size_t ndest_constraints)
{
struct sshbuf *msg;
int r, constrained = (life || confirm || maxsign ||
provider || dest_constraints);
u_char type;
if ((msg = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
switch (key->type) {
#ifdef WITH_OPENSSL
case KEY_RSA:
case KEY_RSA_CERT:
case KEY_DSA:
case KEY_DSA_CERT:
case KEY_ECDSA:
case KEY_ECDSA_CERT:
case KEY_ECDSA_SK:
case KEY_ECDSA_SK_CERT:
#endif
case KEY_ED25519:
case KEY_ED25519_CERT:
case KEY_ED25519_SK:
case KEY_ED25519_SK_CERT:
case KEY_XMSS:
case KEY_XMSS_CERT:
type = constrained ?
SSH2_AGENTC_ADD_ID_CONSTRAINED :
SSH2_AGENTC_ADD_IDENTITY;
if ((r = sshbuf_put_u8(msg, type)) != 0 ||
(r = sshkey_private_serialize_maxsign(key, msg, maxsign,
0)) != 0 ||
(r = sshbuf_put_cstring(msg, comment)) != 0)
goto out;
break;
default:
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if (constrained &&
(r = encode_constraints(msg, life, confirm, maxsign,
provider, dest_constraints, ndest_constraints)) != 0)
goto out;
if ((r = ssh_request_reply_decode(sock, msg)) != 0)
goto out;
/* success */
r = 0;
out:
sshbuf_free(msg);
return r;
}
/*
* Removes an identity from the authentication server.
* This call is intended only for use by ssh-add(1) and like applications.
*/
int
ssh_remove_identity(int sock, const struct sshkey *key)
{
struct sshbuf *msg;
int r;
u_char *blob = NULL;
size_t blen;
if ((msg = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if (key->type != KEY_UNSPEC) {
if ((r = sshkey_to_blob(key, &blob, &blen)) != 0)
goto out;
if ((r = sshbuf_put_u8(msg,
SSH2_AGENTC_REMOVE_IDENTITY)) != 0 ||
(r = sshbuf_put_string(msg, blob, blen)) != 0)
goto out;
} else {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((r = ssh_request_reply_decode(sock, msg)) != 0)
goto out;
/* success */
r = 0;
out:
if (blob != NULL)
freezero(blob, blen);
sshbuf_free(msg);
return r;
}
/*
* Add/remove an token-based identity from the authentication server.
* This call is intended only for use by ssh-add(1) and like applications.
*/
int
ssh_update_card(int sock, int add, const char *reader_id, const char *pin,
u_int life, u_int confirm,
struct dest_constraint **dest_constraints, size_t ndest_constraints)
{
struct sshbuf *msg;
int r, constrained = (life || confirm);
u_char type;
if (add) {
type = constrained ?
SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED :
SSH_AGENTC_ADD_SMARTCARD_KEY;
} else
type = SSH_AGENTC_REMOVE_SMARTCARD_KEY;
if ((msg = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_u8(msg, type)) != 0 ||
(r = sshbuf_put_cstring(msg, reader_id)) != 0 ||
(r = sshbuf_put_cstring(msg, pin)) != 0)
goto out;
if (constrained &&
(r = encode_constraints(msg, life, confirm, 0, NULL,
dest_constraints, ndest_constraints)) != 0)
goto out;
if ((r = ssh_request_reply_decode(sock, msg)) != 0)
goto out;
/* success */
r = 0;
out:
sshbuf_free(msg);
return r;
}
/*
* Removes all identities from the agent.
* This call is intended only for use by ssh-add(1) and like applications.
*
* This supports the SSH protocol 1 message to because, when clearing all
* keys from an agent, we generally want to clear both protocol v1 and v2
* keys.
*/
int
ssh_remove_all_identities(int sock, int version)
{
struct sshbuf *msg;
u_char type = (version == 1) ?
SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES :
SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
int r;
if ((msg = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_u8(msg, type)) != 0)
goto out;
if ((r = ssh_request_reply_decode(sock, msg)) != 0)
goto out;
/* success */
r = 0;
out:
sshbuf_free(msg);
return r;
}
/* Binds a session ID to a hostkey via the initial KEX signature. */
int
ssh_agent_bind_hostkey(int sock, const struct sshkey *key,
const struct sshbuf *session_id, const struct sshbuf *signature,
int forwarding)
{
struct sshbuf *msg;
int r;
if (key == NULL || session_id == NULL || signature == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if ((msg = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_u8(msg, SSH_AGENTC_EXTENSION)) != 0 ||
(r = sshbuf_put_cstring(msg, "session-bind@openssh.com")) != 0 ||
(r = sshkey_puts(key, msg)) != 0 ||
(r = sshbuf_put_stringb(msg, session_id)) != 0 ||
(r = sshbuf_put_stringb(msg, signature)) != 0 ||
(r = sshbuf_put_u8(msg, forwarding ? 1 : 0)) != 0)
goto out;
if ((r = ssh_request_reply_decode(sock, msg)) != 0)
goto out;
/* success */
r = 0;
out:
sshbuf_free(msg);
return r;
}
diff --git a/authfile.c b/authfile.c
index a399efc3e738..9ed4f4c3a30d 100644
--- a/authfile.c
+++ b/authfile.c
@@ -1,521 +1,526 @@
-/* $OpenBSD: authfile.c,v 1.142 2022/01/01 01:55:30 jsg Exp $ */
+/* $OpenBSD: authfile.c,v 1.143 2022/06/21 14:52:13 tobhe Exp $ */
/*
* Copyright (c) 2000, 2013 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 <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include "cipher.h"
#include "ssh.h"
#include "log.h"
#include "authfile.h"
#include "misc.h"
#include "atomicio.h"
#include "sshkey.h"
#include "sshbuf.h"
#include "ssherr.h"
#include "krl.h"
#define MAX_KEY_FILE_SIZE (1024 * 1024)
/* Save a key blob to a file */
static int
sshkey_save_private_blob(struct sshbuf *keybuf, const char *filename)
{
int r;
mode_t omask;
omask = umask(077);
r = sshbuf_write_file(filename, keybuf);
umask(omask);
return r;
}
int
sshkey_save_private(struct sshkey *key, const char *filename,
const char *passphrase, const char *comment,
int format, const char *openssh_format_cipher, int openssh_format_rounds)
{
struct sshbuf *keyblob = NULL;
int r;
if ((keyblob = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshkey_private_to_fileblob(key, keyblob, passphrase, comment,
format, openssh_format_cipher, openssh_format_rounds)) != 0)
goto out;
if ((r = sshkey_save_private_blob(keyblob, filename)) != 0)
goto out;
r = 0;
out:
sshbuf_free(keyblob);
return r;
}
/* XXX remove error() calls from here? */
int
sshkey_perm_ok(int fd, const char *filename)
{
struct stat st;
if (fstat(fd, &st) == -1)
return SSH_ERR_SYSTEM_ERROR;
/*
* if a key owned by the user is accessed, then we check the
* permissions of the file. if the key owned by a different user,
* then we don't care.
*/
#ifdef HAVE_CYGWIN
if (check_ntsec(filename))
#endif
if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("Permissions 0%3.3o for '%s' are too open.",
(u_int)st.st_mode & 0777, filename);
error("It is required that your private key files are NOT accessible by others.");
error("This private key will be ignored.");
return SSH_ERR_KEY_BAD_PERMISSIONS;
}
return 0;
}
int
sshkey_load_private_type(int type, const char *filename, const char *passphrase,
struct sshkey **keyp, char **commentp)
{
int fd, r;
if (keyp != NULL)
*keyp = NULL;
if (commentp != NULL)
*commentp = NULL;
if ((fd = open(filename, O_RDONLY)) == -1)
return SSH_ERR_SYSTEM_ERROR;
r = sshkey_perm_ok(fd, filename);
if (r != 0)
goto out;
r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp);
if (r == 0 && keyp && *keyp)
r = sshkey_set_filename(*keyp, filename);
out:
close(fd);
return r;
}
int
sshkey_load_private(const char *filename, const char *passphrase,
struct sshkey **keyp, char **commentp)
{
return sshkey_load_private_type(KEY_UNSPEC, filename, passphrase,
keyp, commentp);
}
int
sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
struct sshkey **keyp, char **commentp)
{
struct sshbuf *buffer = NULL;
int r;
if (keyp != NULL)
*keyp = NULL;
if ((r = sshbuf_load_fd(fd, &buffer)) != 0 ||
(r = sshkey_parse_private_fileblob_type(buffer, type,
passphrase, keyp, commentp)) != 0)
goto out;
/* success */
r = 0;
out:
sshbuf_free(buffer);
return r;
}
/* Load a pubkey from the unencrypted envelope of a new-format private key */
static int
sshkey_load_pubkey_from_private(const char *filename, struct sshkey **pubkeyp)
{
struct sshbuf *buffer = NULL;
struct sshkey *pubkey = NULL;
int r, fd;
if (pubkeyp != NULL)
*pubkeyp = NULL;
if ((fd = open(filename, O_RDONLY)) == -1)
return SSH_ERR_SYSTEM_ERROR;
if ((r = sshbuf_load_fd(fd, &buffer)) != 0 ||
(r = sshkey_parse_pubkey_from_private_fileblob_type(buffer,
KEY_UNSPEC, &pubkey)) != 0)
goto out;
if ((r = sshkey_set_filename(pubkey, filename)) != 0)
goto out;
/* success */
if (pubkeyp != NULL) {
*pubkeyp = pubkey;
pubkey = NULL;
}
r = 0;
out:
close(fd);
sshbuf_free(buffer);
sshkey_free(pubkey);
return r;
}
static int
sshkey_try_load_public(struct sshkey **kp, const char *filename,
char **commentp)
{
FILE *f;
char *line = NULL, *cp;
size_t linesize = 0;
int r;
struct sshkey *k = NULL;
*kp = NULL;
if (commentp != NULL)
*commentp = NULL;
if ((f = fopen(filename, "r")) == NULL)
return SSH_ERR_SYSTEM_ERROR;
if ((k = sshkey_new(KEY_UNSPEC)) == NULL) {
fclose(f);
return SSH_ERR_ALLOC_FAIL;
}
while (getline(&line, &linesize, f) != -1) {
cp = line;
switch (*cp) {
case '#':
case '\n':
case '\0':
continue;
}
/* Abort loading if this looks like a private key */
if (strncmp(cp, "-----BEGIN", 10) == 0 ||
strcmp(cp, "SSH PRIVATE KEY FILE") == 0)
break;
/* Skip leading whitespace. */
for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
;
if (*cp) {
if ((r = sshkey_read(k, &cp)) == 0) {
cp[strcspn(cp, "\r\n")] = '\0';
if (commentp) {
*commentp = strdup(*cp ?
cp : filename);
if (*commentp == NULL)
r = SSH_ERR_ALLOC_FAIL;
}
/* success */
*kp = k;
free(line);
fclose(f);
return r;
}
}
}
free(k);
free(line);
fclose(f);
return SSH_ERR_INVALID_FORMAT;
}
/* load public key from any pubkey file */
int
sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
{
char *pubfile = NULL;
int r, oerrno;
if (keyp != NULL)
*keyp = NULL;
if (commentp != NULL)
*commentp = NULL;
if ((r = sshkey_try_load_public(keyp, filename, commentp)) == 0)
goto out;
/* try .pub suffix */
if (asprintf(&pubfile, "%s.pub", filename) == -1)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshkey_try_load_public(keyp, pubfile, commentp)) == 0)
goto out;
/* finally, try to extract public key from private key file */
if ((r = sshkey_load_pubkey_from_private(filename, keyp)) == 0)
goto out;
/* Pretend we couldn't find the key */
r = SSH_ERR_SYSTEM_ERROR;
errno = ENOENT;
out:
oerrno = errno;
free(pubfile);
errno = oerrno;
return r;
}
/* Load the certificate associated with the named private key */
int
sshkey_load_cert(const char *filename, struct sshkey **keyp)
{
struct sshkey *pub = NULL;
char *file = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
if (keyp != NULL)
*keyp = NULL;
if (asprintf(&file, "%s-cert.pub", filename) == -1)
return SSH_ERR_ALLOC_FAIL;
r = sshkey_try_load_public(keyp, file, NULL);
free(file);
sshkey_free(pub);
return r;
}
/* Load private key and certificate */
int
sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
struct sshkey **keyp)
{
struct sshkey *key = NULL, *cert = NULL;
int r;
if (keyp != NULL)
*keyp = NULL;
switch (type) {
#ifdef WITH_OPENSSL
case KEY_RSA:
case KEY_DSA:
case KEY_ECDSA:
#endif /* WITH_OPENSSL */
case KEY_ED25519:
case KEY_XMSS:
case KEY_UNSPEC:
break;
default:
return SSH_ERR_KEY_TYPE_UNKNOWN;
}
if ((r = sshkey_load_private_type(type, filename,
passphrase, &key, NULL)) != 0 ||
(r = sshkey_load_cert(filename, &cert)) != 0)
goto out;
/* Make sure the private key matches the certificate */
if (sshkey_equal_public(key, cert) == 0) {
r = SSH_ERR_KEY_CERT_MISMATCH;
goto out;
}
if ((r = sshkey_to_certified(key)) != 0 ||
(r = sshkey_cert_copy(cert, key)) != 0)
goto out;
r = 0;
if (keyp != NULL) {
*keyp = key;
key = NULL;
}
out:
sshkey_free(key);
sshkey_free(cert);
return r;
}
/*
* Returns success if the specified "key" is listed in the file "filename",
* SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
* If "strict_type" is set then the key type must match exactly,
* otherwise a comparison that ignores certificate data is performed.
* If "check_ca" is set and "key" is a certificate, then its CA key is
* also checked and sshkey_in_file() will return success if either is found.
*/
int
sshkey_in_file(struct sshkey *key, const char *filename, int strict_type,
int check_ca)
{
FILE *f;
char *line = NULL, *cp;
size_t linesize = 0;
int r = 0;
struct sshkey *pub = NULL;
int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
strict_type ? sshkey_equal : sshkey_equal_public;
if ((f = fopen(filename, "r")) == NULL)
return SSH_ERR_SYSTEM_ERROR;
while (getline(&line, &linesize, f) != -1) {
sshkey_free(pub);
pub = NULL;
cp = line;
/* Skip leading whitespace. */
for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
;
/* Skip comments and empty lines */
switch (*cp) {
case '#':
case '\n':
case '\0':
continue;
}
if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
switch (r = sshkey_read(pub, &cp)) {
case 0:
break;
case SSH_ERR_KEY_LENGTH:
continue;
default:
goto out;
}
if (sshkey_compare(key, pub) ||
(check_ca && sshkey_is_cert(key) &&
sshkey_compare(key->cert->signature_key, pub))) {
r = 0;
goto out;
}
}
r = SSH_ERR_KEY_NOT_FOUND;
out:
free(line);
sshkey_free(pub);
fclose(f);
return r;
}
/*
* Checks whether the specified key is revoked, returning 0 if not,
* SSH_ERR_KEY_REVOKED if it is or another error code if something
* unexpected happened.
* This will check both the key and, if it is a certificate, its CA key too.
* "revoked_keys_file" may be a KRL or a one-per-line list of public keys.
*/
int
sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file)
{
int r;
r = ssh_krl_file_contains_key(revoked_keys_file, key);
/* If this was not a KRL to begin with then continue below */
if (r != SSH_ERR_KRL_BAD_MAGIC)
return r;
/*
* If the file is not a KRL or we can't handle KRLs then attempt to
* parse the file as a flat list of keys.
*/
switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) {
case 0:
/* Key found => revoked */
return SSH_ERR_KEY_REVOKED;
case SSH_ERR_KEY_NOT_FOUND:
/* Key not found => not revoked */
return 0;
default:
/* Some other error occurred */
return r;
}
}
/*
* Advanced *cpp past the end of key options, defined as the first unquoted
* whitespace character. Returns 0 on success or -1 on failure (e.g.
* unterminated quotes).
*/
int
sshkey_advance_past_options(char **cpp)
{
char *cp = *cpp;
int quoted = 0;
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
if (*cp == '\\' && cp[1] == '"')
cp++; /* Skip both */
else if (*cp == '"')
quoted = !quoted;
}
*cpp = cp;
/* return failure for unterminated quotes */
return (*cp == '\0' && quoted) ? -1 : 0;
}
/* Save a public key */
int
sshkey_save_public(const struct sshkey *key, const char *path,
const char *comment)
{
int fd, oerrno;
FILE *f = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
return SSH_ERR_SYSTEM_ERROR;
if ((f = fdopen(fd, "w")) == NULL) {
r = SSH_ERR_SYSTEM_ERROR;
+ close(fd);
goto fail;
}
if ((r = sshkey_write(key, f)) != 0)
goto fail;
fprintf(f, " %s\n", comment);
- if (ferror(f) || fclose(f) != 0) {
+ if (ferror(f)) {
r = SSH_ERR_SYSTEM_ERROR;
+ goto fail;
+ }
+ if (fclose(f) != 0) {
+ r = SSH_ERR_SYSTEM_ERROR;
+ f = NULL;
fail:
- oerrno = errno;
- if (f != NULL)
+ if (f != NULL) {
+ oerrno = errno;
fclose(f);
- else
- close(fd);
- errno = oerrno;
+ errno = oerrno;
+ }
return r;
}
return 0;
}
diff --git a/channels.c b/channels.c
index ee3c787922fb..e75a0cf9b509 100644
--- a/channels.c
+++ b/channels.c
@@ -1,5133 +1,5143 @@
-/* $OpenBSD: channels.c,v 1.415 2022/03/30 21:10:25 djm Exp $ */
+/* $OpenBSD: channels.c,v 1.420 2022/09/19 08:49:50 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>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#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"
/* XXX remove once we're satisfied there's no lurking bugs */
/* #define DEBUG_CHANNEL_POLL 1 */
/* -- 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 IO actions */
typedef void chan_fn(struct ssh *, Channel *c);
/*
* 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;
/*
* 'channel_pre*' are called just before IO to add any bits
* relevant to channels in the c->io_want bitmasks.
*
* 'channel_post*': perform any appropriate operations for
* channels which have c->io_ready 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)
{
+ int val;
+
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 */
c->restore_block = 0;
if (nonblock == CHANNEL_NONBLOCK_STDIO) {
/*
* Special handling for stdio file descriptors: do not set
* non-blocking mode if they are TTYs. Otherwise prepare to
* restore their blocking state on exit to avoid interfering
* with other programs that follow.
*/
- if (rfd != -1 && !isatty(rfd) && fcntl(rfd, F_GETFL) == 0) {
+ if (rfd != -1 && !isatty(rfd) &&
+ (val = fcntl(rfd, F_GETFL)) != -1 && !(val & O_NONBLOCK)) {
c->restore_block |= CHANNEL_RESTORE_RFD;
set_nonblock(rfd);
}
- if (wfd != -1 && !isatty(wfd) && fcntl(wfd, F_GETFL) == 0) {
+ if (wfd != -1 && !isatty(wfd) &&
+ (val = fcntl(wfd, F_GETFL)) != -1 && !(val & O_NONBLOCK)) {
c->restore_block |= CHANNEL_RESTORE_WFD;
set_nonblock(wfd);
}
- if (efd != -1 && !isatty(efd) && fcntl(efd, F_GETFL) == 0) {
+ if (efd != -1 && !isatty(efd) &&
+ (val = fcntl(efd, F_GETFL)) != -1 && !(val & O_NONBLOCK)) {
c->restore_block |= CHANNEL_RESTORE_EFD;
set_nonblock(efd);
}
} else 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.
+ * Allocate a new channel object and set its type and socket.
*/
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)
+ u_int window, u_int maxpack, int extusage, const char *remote_name,
+ int nonblock)
{
struct ssh_channels *sc = ssh->chanctxt;
- u_int i, found;
+ u_int i, found = 0;
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;
}
int
channel_close_fd(struct ssh *ssh, Channel *c, int *fdp)
{
int ret, fd = *fdp;
if (fd == -1)
return 0;
if ((*fdp == c->rfd && (c->restore_block & CHANNEL_RESTORE_RFD) != 0) ||
(*fdp == c->wfd && (c->restore_block & CHANNEL_RESTORE_WFD) != 0) ||
(*fdp == c->efd && (c->restore_block & CHANNEL_RESTORE_EFD) != 0))
(void)fcntl(*fdp, F_SETFL, 0); /* restore blocking */
if (*fdp == c->rfd) {
c->io_want &= ~SSH_CHAN_IO_RFD;
c->io_ready &= ~SSH_CHAN_IO_RFD;
c->rfd = -1;
c->pfds[0] = -1;
}
if (*fdp == c->wfd) {
c->io_want &= ~SSH_CHAN_IO_WFD;
c->io_ready &= ~SSH_CHAN_IO_WFD;
c->wfd = -1;
c->pfds[1] = -1;
}
if (*fdp == c->efd) {
c->io_want &= ~SSH_CHAN_IO_EFD;
c->io_ready &= ~SSH_CHAN_IO_EFD;
c->efd = -1;
c->pfds[2] = -1;
}
if (*fdp == c->sock) {
c->io_want &= ~SSH_CHAN_IO_SOCK;
c->io_ready &= ~SSH_CHAN_IO_SOCK;
c->sock = -1;
c->pfds[3] = -1;
}
ret = close(fd);
*fdp = -1; /* probably redundant */
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, &c->sock);
if (rfd != sock)
channel_close_fd(ssh, c, &c->rfd);
if (wfd != sock && wfd != rfd)
channel_close_fd(ssh, c, &c->wfd);
if (efd != sock && efd != rfd && efd != wfd)
channel_close_fd(ssh, c, &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 specified 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);
free(c->mux_ctx);
c->mux_ctx = NULL;
} 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;
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, &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 io 0x%02x/0x%02x",
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,
c->io_want, c->io_ready);
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)
{
c->io_want = SSH_CHAN_IO_SOCK_R;
}
static void
channel_pre_connecting(struct ssh *ssh, Channel *c)
{
debug3("channel %d: waiting for connection", c->self);
c->io_want = SSH_CHAN_IO_SOCK_W;
}
static void
channel_pre_open(struct ssh *ssh, Channel *c)
{
c->io_want = 0;
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)
c->io_want |= SSH_CHAN_IO_RFD;
if (c->ostate == CHAN_OUTPUT_OPEN ||
c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
if (sshbuf_len(c->output) > 0) {
c->io_want |= SSH_CHAN_IO_WFD;
} 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)
c->io_want |= SSH_CHAN_IO_EFD_W;
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)
c->io_want |= SSH_CHAN_IO_EFD_R;
}
/* 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)
{
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);
} 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)
{
c->io_want = 0;
if (c->istate == CHAN_INPUT_OPEN && !c->mux_pause &&
sshbuf_check_reserve(c->input, CHAN_RBUF) == 0)
c->io_want |= SSH_CHAN_IO_RFD;
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)
c->io_want |= SSH_CHAN_IO_WFD;
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, int nonblock)
{
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);
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)
{
const u_char *p;
u_int have;
int ret;
c->io_want = 0;
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 */
c->io_want |= SSH_CHAN_IO_RFD;
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 */
c->io_want |= SSH_CHAN_IO_RFD;
if (sshbuf_len(c->output))
c->io_want |= SSH_CHAN_IO_WFD;
} 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_io_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)
{
Channel *nc;
struct sockaddr_storage addr;
int r, newsock, oerrno, remote_port;
socklen_t addrlen;
char buf[16384], *remote_ipaddr;
if ((c->io_ready & SSH_CHAN_IO_SOCK_R) == 0)
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, &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)
{
Channel *nc;
struct sockaddr_storage addr;
int newsock, nextstate;
socklen_t addrlen;
char *rtype;
if ((c->io_ready & SSH_CHAN_IO_SOCK_R) == 0)
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)
{
Channel *nc;
int r, newsock;
struct sockaddr_storage addr;
socklen_t addrlen;
if ((c->io_ready & SSH_CHAN_IO_SOCK_R) == 0)
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)
{
int err = 0, sock, isopen, r;
socklen_t sz = sizeof(err);
if ((c->io_ready & SSH_CHAN_IO_SOCK_W) == 0)
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;
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)
{
char buf[CHAN_RBUF];
ssize_t len;
int r, force;
size_t have, avail, maxlen = CHANNEL_MAX_READ;
int pty_zeroread = 0;
#ifdef PTY_ZEROREAD
/* Bug on AIX: read(1) can return 0 for a non-closed fd */
pty_zeroread = c->isatty;
#endif
force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED;
if (!force && (c->io_ready & SSH_CHAN_IO_RFD) == 0)
return 1;
if ((avail = sshbuf_avail(c->input)) == 0)
return 1; /* Shouldn't happen */
/*
* For "simple" channels (i.e. not datagram or filtered), we can
* read directly to the channel buffer.
*/
if (!pty_zeroread && c->input_filter == NULL && !c->datagram) {
/* Only OPEN channels have valid rwin */
if (c->type == SSH_CHANNEL_OPEN) {
if ((have = sshbuf_len(c->input)) >= c->remote_window)
return 1; /* shouldn't happen */
if (maxlen > c->remote_window - have)
maxlen = c->remote_window - have;
}
if (maxlen > avail)
maxlen = avail;
if ((r = sshbuf_read(c->rfd, c->input, maxlen, NULL)) != 0) {
if (errno == EINTR || (!force &&
(errno == EAGAIN || errno == EWOULDBLOCK)))
return 1;
debug2("channel %d: read failed rfd %d maxlen %zu: %s",
c->self, c->rfd, maxlen, ssh_err(r));
goto rfail;
}
return 1;
}
errno = 0;
len = read(c->rfd, buf, sizeof(buf));
/* fixup AIX zero-length read with errno set to look more like errors */
if (pty_zeroread && len == 0 && errno != 0)
len = -1;
if (len == -1 && (errno == EINTR ||
((errno == EAGAIN || errno == EWOULDBLOCK) && !force)))
return 1;
if (len < 0 || (!pty_zeroread && len == 0)) {
debug2("channel %d: read<=0 rfd %d len %zd: %s",
c->self, c->rfd, len,
len == 0 ? "closed" : strerror(errno));
rfail:
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)
{
struct termios tio;
u_char *data = NULL, *buf; /* XXX const; need filter API change */
size_t dlen, olen = 0;
int r, len;
if ((c->io_ready & SSH_CHAN_IO_WFD) == 0)
return 1;
if (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 = MINIMUM(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)
{
int r;
ssize_t len;
if ((c->io_ready & SSH_CHAN_IO_EFD_W) == 0)
return 1;
if (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, &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)
{
char buf[CHAN_RBUF];
ssize_t len;
int r, force;
force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED;
if (!force && (c->io_ready & SSH_CHAN_IO_EFD_R) == 0)
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, &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)
{
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);
else if (c->extended_usage == CHAN_EXTENDED_READ ||
c->extended_usage == CHAN_EXTENDED_IGNORE)
return channel_handle_efd_read(ssh, c);
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)
{
channel_handle_rfd(ssh, c);
channel_handle_wfd(ssh, c);
channel_handle_efd(ssh, c);
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)
{
u_int need;
if ((c->io_ready & SSH_CHAN_IO_RFD) == 0)
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)
{
ssize_t len;
int r;
if ((c->io_ready & SSH_CHAN_IO_WFD) == 0)
return;
if (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)
{
channel_post_mux_client_read(ssh, c);
channel_post_mux_client_write(ssh, c);
}
static void
channel_post_mux_listener(struct ssh *ssh, Channel *c)
{
Channel *nc;
struct sockaddr_storage addr;
socklen_t addrlen;
int newsock;
uid_t euid;
gid_t egid;
if ((c->io_ready & SSH_CHAN_IO_SOCK_R) == 0)
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)
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, 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;
+ /* Try to keep IO going while rekeying */
+ if (ssh_packet_is_rekeying(ssh) && c->type != SSH_CHANNEL_OPEN)
+ 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);
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 preparing IO.
* This is necessary for things that need to happen after reading
* the network-input but need to be completed before IO event setup, e.g.
* because they may create new channels.
*/
static void
channel_before_prepare_io(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_io_rdynamic(ssh, c);
}
}
static void
dump_channel_poll(const char *func, const char *what, Channel *c,
u_int pollfd_offset, struct pollfd *pfd)
{
#ifdef DEBUG_CHANNEL_POLL
debug3("%s: channel %d: %s r%d w%d e%d s%d c->pfds [ %d %d %d %d ] "
"io_want 0x%02x io_ready 0x%02x pfd[%u].fd=%d "
"pfd.ev 0x%02x pfd.rev 0x%02x", func, c->self, what,
c->rfd, c->wfd, c->efd, c->sock,
c->pfds[0], c->pfds[1], c->pfds[2], c->pfds[3],
c->io_want, c->io_ready,
pollfd_offset, pfd->fd, pfd->events, pfd->revents);
#endif
}
/* Prepare pollfd entries for a single channel */
static void
channel_prepare_pollfd(Channel *c, u_int *next_pollfd,
struct pollfd *pfd, u_int npfd)
{
u_int ev, p = *next_pollfd;
if (c == NULL)
return;
if (p + 4 > npfd) {
/* Shouldn't happen */
fatal_f("channel %d: bad pfd offset %u (max %u)",
c->self, p, npfd);
}
c->pfds[0] = c->pfds[1] = c->pfds[2] = c->pfds[3] = -1;
/*
* prepare c->rfd
*
* This is a special case, since c->rfd might be the same as
* c->wfd, c->efd and/or c->sock. Handle those here if they want
* IO too.
*/
if (c->rfd != -1) {
ev = 0;
if ((c->io_want & SSH_CHAN_IO_RFD) != 0)
ev |= POLLIN;
/* rfd == wfd */
if (c->wfd == c->rfd) {
if ((c->io_want & SSH_CHAN_IO_WFD) != 0)
ev |= POLLOUT;
}
/* rfd == efd */
if (c->efd == c->rfd) {
if ((c->io_want & SSH_CHAN_IO_EFD_R) != 0)
ev |= POLLIN;
if ((c->io_want & SSH_CHAN_IO_EFD_W) != 0)
ev |= POLLOUT;
}
/* rfd == sock */
if (c->sock == c->rfd) {
if ((c->io_want & SSH_CHAN_IO_SOCK_R) != 0)
ev |= POLLIN;
if ((c->io_want & SSH_CHAN_IO_SOCK_W) != 0)
ev |= POLLOUT;
}
/* Pack a pfd entry if any event armed for this fd */
if (ev != 0) {
c->pfds[0] = p;
pfd[p].fd = c->rfd;
pfd[p].events = ev;
dump_channel_poll(__func__, "rfd", c, p, &pfd[p]);
p++;
}
}
/* prepare c->wfd if wanting IO and not already handled above */
if (c->wfd != -1 && c->rfd != c->wfd) {
ev = 0;
if ((c->io_want & SSH_CHAN_IO_WFD))
ev |= POLLOUT;
/* Pack a pfd entry if any event armed for this fd */
if (ev != 0) {
c->pfds[1] = p;
pfd[p].fd = c->wfd;
pfd[p].events = ev;
dump_channel_poll(__func__, "wfd", c, p, &pfd[p]);
p++;
}
}
/* prepare c->efd if wanting IO and not already handled above */
if (c->efd != -1 && c->rfd != c->efd) {
ev = 0;
if ((c->io_want & SSH_CHAN_IO_EFD_R) != 0)
ev |= POLLIN;
if ((c->io_want & SSH_CHAN_IO_EFD_W) != 0)
ev |= POLLOUT;
/* Pack a pfd entry if any event armed for this fd */
if (ev != 0) {
c->pfds[2] = p;
pfd[p].fd = c->efd;
pfd[p].events = ev;
dump_channel_poll(__func__, "efd", c, p, &pfd[p]);
p++;
}
}
/* prepare c->sock if wanting IO and not already handled above */
if (c->sock != -1 && c->rfd != c->sock) {
ev = 0;
if ((c->io_want & SSH_CHAN_IO_SOCK_R) != 0)
ev |= POLLIN;
if ((c->io_want & SSH_CHAN_IO_SOCK_W) != 0)
ev |= POLLOUT;
/* Pack a pfd entry if any event armed for this fd */
if (ev != 0) {
c->pfds[3] = p;
pfd[p].fd = c->sock;
pfd[p].events = 0;
dump_channel_poll(__func__, "sock", c, p, &pfd[p]);
p++;
}
}
*next_pollfd = p;
}
/* * Allocate/prepare poll structure */
void
channel_prepare_poll(struct ssh *ssh, struct pollfd **pfdp, u_int *npfd_allocp,
u_int *npfd_activep, u_int npfd_reserved, time_t *minwait_secs)
{
struct ssh_channels *sc = ssh->chanctxt;
u_int i, oalloc, p, npfd = npfd_reserved;
channel_before_prepare_io(ssh); /* might create a new channel */
-
+ /* clear out I/O flags from last poll */
+ for (i = 0; i < sc->channels_alloc; i++) {
+ if (sc->channels[i] == NULL)
+ continue;
+ sc->channels[i]->io_want = sc->channels[i]->io_ready = 0;
+ }
/* Allocate 4x pollfd for each channel (rfd, wfd, efd, sock) */
if (sc->channels_alloc >= (INT_MAX / 4) - npfd_reserved)
fatal_f("too many channels"); /* shouldn't happen */
- if (!ssh_packet_is_rekeying(ssh))
- npfd += sc->channels_alloc * 4;
+ npfd += sc->channels_alloc * 4;
if (npfd > *npfd_allocp) {
*pfdp = xrecallocarray(*pfdp, *npfd_allocp,
npfd, sizeof(**pfdp));
*npfd_allocp = npfd;
}
*npfd_activep = npfd_reserved;
- if (ssh_packet_is_rekeying(ssh))
- return;
-
oalloc = sc->channels_alloc;
channel_handler(ssh, CHAN_PRE, minwait_secs);
if (oalloc != sc->channels_alloc) {
/* shouldn't happen */
fatal_f("channels_alloc changed during CHAN_PRE "
"(was %u, now %u)", oalloc, sc->channels_alloc);
}
/* Prepare pollfd */
p = npfd_reserved;
for (i = 0; i < sc->channels_alloc; i++)
channel_prepare_pollfd(sc->channels[i], &p, *pfdp, npfd);
*npfd_activep = p;
}
static void
fd_ready(Channel *c, int p, struct pollfd *pfds, u_int npfd, int fd,
const char *what, u_int revents_mask, u_int ready)
{
struct pollfd *pfd = &pfds[p];
if (fd == -1)
return;
if (p == -1 || (u_int)p >= npfd)
fatal_f("channel %d: bad pfd %d (max %u)", c->self, p, npfd);
dump_channel_poll(__func__, what, c, p, pfd);
if (pfd->fd != fd) {
fatal("channel %d: inconsistent %s fd=%d pollfd[%u].fd %d "
"r%d w%d e%d s%d", c->self, what, fd, p, pfd->fd,
c->rfd, c->wfd, c->efd, c->sock);
}
if ((pfd->revents & POLLNVAL) != 0) {
fatal("channel %d: invalid %s pollfd[%u].fd %d r%d w%d e%d s%d",
c->self, what, p, pfd->fd, c->rfd, c->wfd, c->efd, c->sock);
}
if ((pfd->revents & (revents_mask|POLLHUP|POLLERR)) != 0)
c->io_ready |= ready & c->io_want;
}
/*
* After poll, perform any appropriate operations for channels which have
* events pending.
*/
void
channel_after_poll(struct ssh *ssh, struct pollfd *pfd, u_int npfd)
{
struct ssh_channels *sc = ssh->chanctxt;
u_int i;
int p;
Channel *c;
#ifdef DEBUG_CHANNEL_POLL
for (p = 0; p < (int)npfd; p++) {
if (pfd[p].revents == 0)
continue;
debug_f("pfd[%u].fd %d rev 0x%04x",
p, pfd[p].fd, pfd[p].revents);
}
#endif
/* Convert pollfd into c->io_ready */
for (i = 0; i < sc->channels_alloc; i++) {
c = sc->channels[i];
if (c == NULL)
continue;
/* if rfd is shared with efd/sock then wfd should be too */
if (c->rfd != -1 && c->wfd != -1 && c->rfd != c->wfd &&
(c->rfd == c->efd || c->rfd == c->sock)) {
/* Shouldn't happen */
fatal_f("channel %d: unexpected fds r%d w%d e%d s%d",
c->self, c->rfd, c->wfd, c->efd, c->sock);
}
c->io_ready = 0;
/* rfd, potentially shared with wfd, efd and sock */
if (c->rfd != -1 && (p = c->pfds[0]) != -1) {
fd_ready(c, p, pfd, npfd, c->rfd,
"rfd", POLLIN, SSH_CHAN_IO_RFD);
if (c->rfd == c->wfd) {
fd_ready(c, p, pfd, npfd, c->wfd,
"wfd/r", POLLOUT, SSH_CHAN_IO_WFD);
}
if (c->rfd == c->efd) {
fd_ready(c, p, pfd, npfd, c->efd,
"efdr/r", POLLIN, SSH_CHAN_IO_EFD_R);
fd_ready(c, p, pfd, npfd, c->efd,
"efdw/r", POLLOUT, SSH_CHAN_IO_EFD_W);
}
if (c->rfd == c->sock) {
fd_ready(c, p, pfd, npfd, c->sock,
"sockr/r", POLLIN, SSH_CHAN_IO_SOCK_R);
fd_ready(c, p, pfd, npfd, c->sock,
"sockw/r", POLLOUT, SSH_CHAN_IO_SOCK_W);
}
dump_channel_poll(__func__, "rfd", c, p, pfd);
}
/* wfd */
if (c->wfd != -1 && c->wfd != c->rfd &&
(p = c->pfds[1]) != -1) {
fd_ready(c, p, pfd, npfd, c->wfd,
"wfd", POLLOUT, SSH_CHAN_IO_WFD);
dump_channel_poll(__func__, "wfd", c, p, pfd);
}
/* efd */
if (c->efd != -1 && c->efd != c->rfd &&
(p = c->pfds[2]) != -1) {
fd_ready(c, p, pfd, npfd, c->efd,
"efdr", POLLIN, SSH_CHAN_IO_EFD_R);
fd_ready(c, p, pfd, npfd, c->efd,
"efdw", POLLOUT, SSH_CHAN_IO_EFD_W);
dump_channel_poll(__func__, "efd", c, p, pfd);
}
/* sock */
if (c->sock != -1 && c->sock != c->rfd &&
(p = c->pfds[3]) != -1) {
fd_ready(c, p, pfd, npfd, c->sock,
"sockr", POLLIN, SSH_CHAN_IO_SOCK_R);
fd_ready(c, p, pfd, npfd, c->sock,
"sockw", POLLOUT, SSH_CHAN_IO_SOCK_W);
dump_channel_poll(__func__, "sock", c, p, pfd);
}
}
channel_handler(ssh, CHAN_POST, 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);
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);
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 [%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");
+ error_f("getnameinfo failed");
continue;
}
break;
default:
continue;
}
+ debug_f("start for host %.100s ([%.100s]:%s)",
+ cctx->host, ntop, strport);
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));
+ debug_f("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);
+ debug_f("connect 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 dfb82f8ce262..828c1b61b443 100644
--- a/channels.h
+++ b/channels.h
@@ -1,383 +1,383 @@
-/* $OpenBSD: channels.h,v 1.142 2022/03/30 21:10:25 djm Exp $ */
+/* $OpenBSD: channels.h,v 1.143 2022/05/05 00:56:58 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
/* nonblocking flags for channel_new */
#define CHANNEL_NONBLOCK_LEAVE 0 /* don't modify non-blocking state */
#define CHANNEL_NONBLOCK_SET 1 /* set non-blocking state */
#define CHANNEL_NONBLOCK_STDIO 2 /* set non-blocking and restore on close */
/* c->restore_block mask flags */
#define CHANNEL_RESTORE_RFD 0x01
#define CHANNEL_RESTORE_WFD 0x02
#define CHANNEL_RESTORE_EFD 0x04
/* 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 */
u_int io_want; /* bitmask of SSH_CHAN_IO_* */
u_int io_ready; /* bitmask of SSH_CHAN_IO_* */
int pfds[4]; /* pollfd entries for rfd/wfd/efd/sock */
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-IO handlers for newly created
* channels are delayed until the first call
* to a matching pre-IO handler.
* this way post-IO handlers are not
* accidentally called if a FD gets reused */
int restore_block; /* fd mask to restore blocking status */
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;
/* 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;
};
#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
/* file descriptor events */
#define SSH_CHAN_IO_RFD 0x01
#define SSH_CHAN_IO_WFD 0x02
#define SSH_CHAN_IO_EFD_R 0x04
#define SSH_CHAN_IO_EFD_W 0x08
#define SSH_CHAN_IO_EFD (SSH_CHAN_IO_EFD_R|SSH_CHAN_IO_EFD_W)
#define SSH_CHAN_IO_SOCK_R 0x10
#define SSH_CHAN_IO_SOCK_W 0x20
#define SSH_CHAN_IO_SOCK (SSH_CHAN_IO_SOCK_R|SSH_CHAN_IO_SOCK_W)
/* Read buffer size */
#define CHAN_RBUF (16*1024)
/* Maximum size for direct reads to buffers */
#define CHANNEL_MAX_READ CHAN_SES_PACKET_DEFAULT
/* 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);
+ u_int, u_int, int, const 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 *, Channel *, 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) */
struct pollfd;
void channel_prepare_poll(struct ssh *, struct pollfd **,
u_int *, u_int *, u_int, time_t *);
void channel_after_poll(struct ssh *, struct pollfd *, u_int);
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, 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-ctr.c b/cipher-ctr.c
deleted file mode 100644
index 32771f28743b..000000000000
--- a/cipher-ctr.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/* $OpenBSD: cipher-ctr.c,v 1.11 2010/10/01 23:05:32 djm Exp $ */
-/*
- * Copyright (c) 2003 Markus Friedl <markus@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"
-
-#if defined(WITH_OPENSSL) && !defined(OPENSSL_HAVE_EVPCTR)
-#include <sys/types.h>
-
-#include <stdarg.h>
-#include <string.h>
-
-#include <openssl/evp.h>
-
-#include "xmalloc.h"
-#include "log.h"
-
-/* compatibility with old or broken OpenSSL versions */
-#include "openbsd-compat/openssl-compat.h"
-
-#ifndef USE_BUILTIN_RIJNDAEL
-#include <openssl/aes.h>
-#endif
-
-struct ssh_aes_ctr_ctx
-{
- AES_KEY aes_ctx;
- u_char aes_counter[AES_BLOCK_SIZE];
-};
-
-/*
- * increment counter 'ctr',
- * the counter is of size 'len' bytes and stored in network-byte-order.
- * (LSB at ctr[len-1], MSB at ctr[0])
- */
-static void
-ssh_ctr_inc(u_char *ctr, size_t len)
-{
- int i;
-
- for (i = len - 1; i >= 0; i--)
- if (++ctr[i]) /* continue on overflow */
- return;
-}
-
-static int
-ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
- LIBCRYPTO_EVP_INL_TYPE len)
-{
- struct ssh_aes_ctr_ctx *c;
- size_t n = 0;
- u_char buf[AES_BLOCK_SIZE];
-
- if (len == 0)
- return (1);
- if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL)
- return (0);
-
- while ((len--) > 0) {
- if (n == 0) {
- AES_encrypt(c->aes_counter, buf, &c->aes_ctx);
- ssh_ctr_inc(c->aes_counter, AES_BLOCK_SIZE);
- }
- *(dest++) = *(src++) ^ buf[n];
- n = (n + 1) % AES_BLOCK_SIZE;
- }
- return (1);
-}
-
-static int
-ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
- int enc)
-{
- struct ssh_aes_ctr_ctx *c;
-
- if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
- c = xmalloc(sizeof(*c));
- EVP_CIPHER_CTX_set_app_data(ctx, c);
- }
- if (key != NULL)
- AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
- &c->aes_ctx);
- if (iv != NULL)
- memcpy(c->aes_counter, iv, AES_BLOCK_SIZE);
- return (1);
-}
-
-static int
-ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx)
-{
- struct ssh_aes_ctr_ctx *c;
-
- if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
- memset(c, 0, sizeof(*c));
- free(c);
- EVP_CIPHER_CTX_set_app_data(ctx, NULL);
- }
- return (1);
-}
-
-void
-ssh_aes_ctr_iv(EVP_CIPHER_CTX *evp, int doset, u_char * iv, size_t len)
-{
- struct ssh_aes_ctr_ctx *c;
-
- if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
- fatal("ssh_aes_ctr_iv: no context");
- if (doset)
- memcpy(c->aes_counter, iv, len);
- else
- memcpy(iv, c->aes_counter, len);
-}
-
-const EVP_CIPHER *
-evp_aes_128_ctr(void)
-{
- static EVP_CIPHER aes_ctr;
-
- memset(&aes_ctr, 0, sizeof(EVP_CIPHER));
- aes_ctr.nid = NID_undef;
- aes_ctr.block_size = AES_BLOCK_SIZE;
- aes_ctr.iv_len = AES_BLOCK_SIZE;
- aes_ctr.key_len = 16;
- aes_ctr.init = ssh_aes_ctr_init;
- aes_ctr.cleanup = ssh_aes_ctr_cleanup;
- aes_ctr.do_cipher = ssh_aes_ctr;
-#ifndef SSH_OLD_EVP
- aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
- EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV;
-#endif
- return (&aes_ctr);
-}
-
-#endif /* defined(WITH_OPENSSL) && !defined(OPENSSL_HAVE_EVPCTR) */
diff --git a/cipher.c b/cipher.c
index 5b3a86d69219..02aea4089ff9 100644
--- a/cipher.c
+++ b/cipher.c
@@ -1,539 +1,526 @@
/* $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;
} else if (!EVP_CIPHER_CTX_get_iv(cc->evp, iv, len))
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 f8350e67224b..0050f3eb6faa 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,2625 +1,2625 @@
-/* $OpenBSD: clientloop.c,v 1.378 2022/01/22 00:49:34 djm Exp $ */
+/* $OpenBSD: clientloop.c,v 1.380 2022/06/03 04:30:46 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
#ifdef HAVE_POLL_H
#include <poll.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"
/* Permitted RSA signature algorithms for UpdateHostkeys proofs */
#define HOSTKEY_PROOF_RSA_ALGS "rsa-sha2-512,rsa-sha2-256"
/* import options */
extern Options options;
/* 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 *);
static void quit_message(const char *fmt, ...)
__attribute__((__format__ (printf, 1, 2)));
static void
quit_message(const char *fmt, ...)
{
char *msg;
va_list args;
int r;
va_start(args, fmt);
xvasprintf(&msg, fmt, args);
va_end(args);
if ((r = sshbuf_putf(stderr_buffer, "%s\r\n", msg)) != 0)
fatal_fr(r, "sshbuf_putf");
quit_pending = 1;
}
/*
* 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, struct pollfd **pfdp,
u_int *npfd_allocp, u_int *npfd_activep, int rekeying,
int *conn_in_readyp, int *conn_out_readyp)
{
int timeout_secs, pollwait;
time_t minwait_secs = 0, now = monotime();
int ret;
u_int p;
*conn_in_readyp = *conn_out_readyp = 0;
/* Prepare channel poll. First two pollfd entries are reserved */
channel_prepare_poll(ssh, pfdp, npfd_allocp, npfd_activep, 2,
&minwait_secs);
if (*npfd_activep < 2)
fatal_f("bad npfd %u", *npfd_activep); /* shouldn't happen */
/* channel_prepare_poll could have closed the last channel */
if (session_closed && !channel_still_open(ssh) &&
!ssh_packet_have_data_to_write(ssh)) {
/* clear events since we did not call poll() */
for (p = 0; p < *npfd_activep; p++)
(*pfdp)[p].revents = 0;
return;
}
/* Monitor server connection on reserved pollfd entries */
(*pfdp)[0].fd = connection_in;
(*pfdp)[0].events = POLLIN;
(*pfdp)[1].fd = connection_out;
(*pfdp)[1].events = ssh_packet_have_data_to_write(ssh) ? POLLOUT : 0;
/*
* Wait for something to happen. This will suspend the process until
* some polled 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)
pollwait = -1;
else if (timeout_secs >= INT_MAX / 1000)
pollwait = INT_MAX;
else
pollwait = timeout_secs * 1000;
ret = poll(*pfdp, *npfd_activep, pollwait);
if (ret == -1) {
/*
* We have to clear the events because we return.
* We have to return, because the mainloop checks for the flags
* set by the signal handlers.
*/
for (p = 0; p < *npfd_activep; p++)
(*pfdp)[p].revents = 0;
if (errno == EINTR)
return;
/* Note: we might still have data in the buffers. */
quit_message("poll: %s", strerror(errno));
return;
}
*conn_in_readyp = (*pfdp)[0].revents != 0;
*conn_out_readyp = (*pfdp)[1].revents != 0;
if (options.server_alive_interval > 0 && !*conn_in_readyp &&
monotime() >= server_alive_time) {
/*
* ServerAlive check is needed. We can't rely on the poll
* 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)
{
int r;
/*
* Read input from the server, and add any such data to the buffer of
* the packet subsystem.
*/
schedule_server_alive_check();
if ((r = ssh_packet_process_read(ssh, connection_in)) == 0)
return; /* success */
if (r == SSH_ERR_SYSTEM_ERROR) {
if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)
return;
if (errno == EPIPE) {
quit_message("Connection to %s closed by remote host.",
host);
return;
}
}
quit_message("Read from remote host %s: %s", host, ssh_err(r));
}
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) {
debug3_f("channel %d: mux request: %s", c->self,
cr->request_type);
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)
{
struct pollfd *pfd = NULL;
u_int npfd_alloc = 0, npfd_active = 0;
double start_time, total_time;
int r, len;
u_int64_t ibytes, obytes;
int conn_in_ready, conn_out_ready;
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");
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) ||
options.fork_after_authentication) {
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);
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).
*/
client_wait_until_can_do_something(ssh, &pfd, &npfd_alloc,
&npfd_active, ssh_packet_is_rekeying(ssh),
&conn_in_ready, &conn_out_ready);
if (quit_pending)
break;
- /* Do channel operations unless rekeying in progress. */
- if (!ssh_packet_is_rekeying(ssh))
- channel_after_poll(ssh, pfd, npfd_active);
+ /* Do channel operations. */
+ channel_after_poll(ssh, pfd, npfd_active);
/* Buffer input from the connection. */
if (conn_in_ready)
client_process_net_input(ssh);
if (quit_pending)
break;
/* A timeout may have triggered rekeying */
if ((r = ssh_packet_check_rekey(ssh)) != 0)
fatal_fr(r, "cannot start rekeying");
/*
* Send as much buffered packet data as possible to the
* sender.
*/
if (conn_out_ready) {
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(pfd);
/* 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);
/*
* 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 (options.session_type == SESSION_TYPE_NONE &&
received_signal == SIGTERM) {
received_signal = 0;
exit_status = 0;
}
if (received_signal) {
verbose("Killed by signal %d.", (int) received_signal);
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_INFO)
quit_message("Connection to %s closed.", host);
/* 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;
}
if ((r = ssh_agent_bind_hostkey(sock, ssh->kex->initial_hostkey,
ssh->kex->session_id, ssh->kex->initial_sig, 1)) == 0)
debug_f("bound agent to hostkey");
else
debug2_fr(r, "ssh_agent_bind_hostkey");
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->old_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, plaintype;
const u_char *sig;
const char *rsa_kexalg = NULL;
char *alg = NULL;
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;
}
if (sshkey_type_plain(sshkey_type_from_name(
ssh->kex->hostkey_alg)) == KEY_RSA)
rsa_kexalg = 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;
plaintype = sshkey_type_plain(ctx->keys[i]->type);
/* 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;
}
if ((r = sshkey_get_sigtype(sig, siglen, &alg)) != 0) {
error_fr(r, "server gave unintelligible signature "
"for %s key %zu", sshkey_type(ctx->keys[i]), i);
goto out;
}
/*
* Special case for RSA keys: if a RSA hostkey was negotiated,
* then use its signature type for verification of RSA hostkey
* proofs. Otherwise, accept only RSA-SHA256/512 signatures.
*/
if (plaintype == KEY_RSA && rsa_kexalg == NULL &&
match_pattern_list(alg, HOSTKEY_PROOF_RSA_ALGS, 0) != 1) {
debug_f("server used untrusted RSA signature algorithm "
"%s for key %zu, disregarding", alg, i);
free(alg);
/* zap the key from the list */
sshkey_free(ctx->keys[i]);
ctx->keys[i] = NULL;
ndone++;
continue;
}
debug3_f("verify %s key %zu using sigalg %s",
sshkey_type(ctx->keys[i]), i, alg);
free(alg);
if ((r = sshkey_verify(ctx->keys[i], sig, siglen,
sshbuf_ptr(signdata), sshbuf_len(signdata),
plaintype == KEY_RSA ? rsa_kexalg : NULL, 0, NULL)) != 0) {
error_fr(r, "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;
+ size_t i, j, len;
+ int matched, 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));
+ (int)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));
+ (int)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 || options.session_type == SESSION_TYPE_NONE) {
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/compat.c b/compat.c
index 0dbea68c625f..46dfe3a9c2e7 100644
--- a/compat.c
+++ b/compat.c
@@ -1,208 +1,215 @@
-/* $OpenBSD: compat.c,v 1.119 2021/09/10 05:46:09 djm Exp $ */
+/* $OpenBSD: compat.c,v 1.120 2022/07/01 03:35:45 dtucker Exp $ */
/*
* 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.
*/
#include "includes.h"
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "xmalloc.h"
#include "packet.h"
#include "compat.h"
#include "log.h"
#include "match.h"
#include "kex.h"
/* determine bug flags from SSH protocol banner */
void
compat_banner(struct ssh *ssh, const char *version)
{
int i;
static struct {
char *pat;
int bugs;
} check[] = {
{ "OpenSSH_2.*,"
"OpenSSH_3.0*,"
"OpenSSH_3.1*", SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR|
SSH_BUG_SIGTYPE},
{ "OpenSSH_3.*", SSH_OLD_FORWARD_ADDR|SSH_BUG_SIGTYPE },
{ "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF|
SSH_BUG_SIGTYPE},
{ "OpenSSH_2*,"
"OpenSSH_3*,"
"OpenSSH_4*", SSH_BUG_SIGTYPE },
{ "OpenSSH_5*", SSH_NEW_OPENSSH|SSH_BUG_DYNAMIC_RPORT|
SSH_BUG_SIGTYPE},
{ "OpenSSH_6.6.1*", SSH_NEW_OPENSSH|SSH_BUG_SIGTYPE},
{ "OpenSSH_6.5*,"
"OpenSSH_6.6*", SSH_NEW_OPENSSH|SSH_BUG_CURVE25519PAD|
SSH_BUG_SIGTYPE},
{ "OpenSSH_7.4*", SSH_NEW_OPENSSH|SSH_BUG_SIGTYPE|
SSH_BUG_SIGTYPE74},
{ "OpenSSH_7.0*,"
"OpenSSH_7.1*,"
"OpenSSH_7.2*,"
"OpenSSH_7.3*,"
"OpenSSH_7.5*,"
"OpenSSH_7.6*,"
"OpenSSH_7.7*", SSH_NEW_OPENSSH|SSH_BUG_SIGTYPE},
{ "OpenSSH*", SSH_NEW_OPENSSH },
{ "*MindTerm*", 0 },
{ "3.0.*", SSH_BUG_DEBUG },
{ "3.0 SecureCRT*", SSH_OLD_SESSIONID },
{ "1.7 SecureFX*", SSH_OLD_SESSIONID },
{ "1.2.18*,"
"1.2.19*,"
"1.2.20*,"
"1.2.21*,"
"1.2.22*", SSH_BUG_IGNOREMSG },
{ "1.3.2*", /* F-Secure */
SSH_BUG_IGNOREMSG },
{ "Cisco-1.*", SSH_BUG_DHGEX_LARGE|
SSH_BUG_HOSTKEYS },
{ "*SSH Compatible Server*", /* Netscreen */
SSH_BUG_PASSWORDPAD },
{ "*OSU_0*,"
"OSU_1.0*,"
"OSU_1.1*,"
"OSU_1.2*,"
"OSU_1.3*,"
"OSU_1.4*,"
"OSU_1.5alpha1*,"
"OSU_1.5alpha2*,"
"OSU_1.5alpha3*", SSH_BUG_PASSWORDPAD },
{ "*SSH_Version_Mapper*",
SSH_BUG_SCANNER },
{ "PuTTY_Local:*," /* dev versions < Sep 2014 */
"PuTTY-Release-0.5*," /* 0.50-0.57, DH-GEX in >=0.52 */
"PuTTY_Release_0.5*," /* 0.58-0.59 */
"PuTTY_Release_0.60*,"
"PuTTY_Release_0.61*,"
"PuTTY_Release_0.62*,"
"PuTTY_Release_0.63*,"
"PuTTY_Release_0.64*",
SSH_OLD_DHGEX },
{ "FuTTY*", SSH_OLD_DHGEX }, /* Putty Fork */
{ "Probe-*",
SSH_BUG_PROBE },
{ "TeraTerm SSH*,"
"TTSSH/1.5.*,"
"TTSSH/2.1*,"
"TTSSH/2.2*,"
"TTSSH/2.3*,"
"TTSSH/2.4*,"
"TTSSH/2.5*,"
"TTSSH/2.6*,"
"TTSSH/2.70*,"
"TTSSH/2.71*,"
"TTSSH/2.72*", SSH_BUG_HOSTKEYS },
{ "WinSCP_release_4*,"
"WinSCP_release_5.0*,"
"WinSCP_release_5.1,"
"WinSCP_release_5.1.*,"
"WinSCP_release_5.5,"
"WinSCP_release_5.5.*,"
"WinSCP_release_5.6,"
"WinSCP_release_5.6.*,"
"WinSCP_release_5.7,"
"WinSCP_release_5.7.1,"
"WinSCP_release_5.7.2,"
"WinSCP_release_5.7.3,"
"WinSCP_release_5.7.4",
SSH_OLD_DHGEX },
{ "ConfD-*",
SSH_BUG_UTF8TTYMODE },
{ "Twisted_*", 0 },
{ "Twisted*", SSH_BUG_DEBUG },
{ NULL, 0 }
};
/* process table, return first match */
ssh->compat = 0;
for (i = 0; check[i].pat; i++) {
if (match_pattern_list(version, check[i].pat, 0) == 1) {
debug_f("match: %s pat %s compat 0x%08x",
version, check[i].pat, check[i].bugs);
ssh->compat = check[i].bugs;
return;
}
}
debug_f("no match: %s", version);
}
+/* Always returns pointer to allocated memory, caller must free. */
char *
compat_cipher_proposal(struct ssh *ssh, char *cipher_prop)
{
if (!(ssh->compat & SSH_BUG_BIGENDIANAES))
- return cipher_prop;
+ return xstrdup(cipher_prop);
debug2_f("original cipher proposal: %s", cipher_prop);
if ((cipher_prop = match_filter_denylist(cipher_prop, "aes*")) == NULL)
fatal("match_filter_denylist failed");
debug2_f("compat cipher proposal: %s", cipher_prop);
if (*cipher_prop == '\0')
fatal("No supported ciphers found");
return cipher_prop;
}
+/* Always returns pointer to allocated memory, caller must free. */
char *
compat_pkalg_proposal(struct ssh *ssh, char *pkalg_prop)
{
if (!(ssh->compat & SSH_BUG_RSASIGMD5))
- return pkalg_prop;
+ return xstrdup(pkalg_prop);
debug2_f("original public key proposal: %s", pkalg_prop);
if ((pkalg_prop = match_filter_denylist(pkalg_prop, "ssh-rsa")) == NULL)
fatal("match_filter_denylist failed");
debug2_f("compat public key proposal: %s", pkalg_prop);
if (*pkalg_prop == '\0')
fatal("No supported PK algorithms found");
return pkalg_prop;
}
+/* Always returns pointer to allocated memory, caller must free. */
char *
compat_kex_proposal(struct ssh *ssh, char *p)
{
+ char *cp = NULL;
+
if ((ssh->compat & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0)
- return p;
+ return xstrdup(p);
debug2_f("original KEX proposal: %s", p);
if ((ssh->compat & SSH_BUG_CURVE25519PAD) != 0)
if ((p = match_filter_denylist(p,
"curve25519-sha256@libssh.org")) == NULL)
fatal("match_filter_denylist failed");
if ((ssh->compat & SSH_OLD_DHGEX) != 0) {
+ cp = p;
if ((p = match_filter_denylist(p,
"diffie-hellman-group-exchange-sha256,"
"diffie-hellman-group-exchange-sha1")) == NULL)
fatal("match_filter_denylist failed");
+ free(cp);
}
debug2_f("compat KEX proposal: %s", p);
if (*p == '\0')
fatal("No supported key exchange algorithms found");
return p;
}
diff --git a/config.h.in b/config.h.in
index 8d2a3bc65b56..d08cf41add37 100644
--- a/config.h.in
+++ b/config.h.in
@@ -1,2111 +1,2115 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define if building universal (internal helper macro) */
#undef AC_APPLE_UNIVERSAL_BUILD
/* Define if you have a getaddrinfo that fails for the all-zeros IPv6 address
*/
#undef AIX_GETNAMEINFO_HACK
/* Define if your AIX loginfailed() function takes 4 arguments (AIX >= 5.2) */
#undef AIX_LOGINFAILED_4ARG
/* System only supports IPv4 audit records */
#undef AU_IPv4
/* Define if your resolver libs need this for getrrsetbyname */
#undef BIND_8_COMPAT
/* The system has incomplete BSM API */
#undef BROKEN_BSM_API
/* broken in chroots on older kernels */
#undef BROKEN_CLOSEFROM
/* Define if cmsg_type is not passed correctly */
#undef BROKEN_CMSG_TYPE
/* getaddrinfo is broken (if present) */
#undef BROKEN_GETADDRINFO
/* getgroups(0,NULL) will return -1 */
#undef BROKEN_GETGROUPS
/* getline is not what we expect */
#undef BROKEN_GETLINE
/* FreeBSD glob does not do what we need */
#undef BROKEN_GLOB
/* Define if you system's inet_ntoa is busted (e.g. Irix gcc issue) */
#undef BROKEN_INET_NTOA
/* Define if your struct dirent expects you to allocate extra space for d_name
*/
#undef BROKEN_ONE_BYTE_DIRENT_D_NAME
/* System poll(2) implementation is broken */
#undef BROKEN_POLL
/* Can't do comparisons on readv */
#undef BROKEN_READV_COMPARISON
/* NetBSD read function is sometimes redirected, breaking atomicio comparisons
against it */
#undef BROKEN_READ_COMPARISON
/* Needed for NeXT */
#undef BROKEN_SAVED_UIDS
/* Define if your setregid() is broken */
#undef BROKEN_SETREGID
/* Define if your setresgid() is broken */
#undef BROKEN_SETRESGID
/* Define if your setresuid() is broken */
#undef BROKEN_SETRESUID
/* Define if your setreuid() is broken */
#undef BROKEN_SETREUID
/* LynxOS has broken setvbuf() implementation */
#undef BROKEN_SETVBUF
/* QNX shadow support is broken */
#undef BROKEN_SHADOW_EXPIRE
/* Define if your snprintf is busted */
#undef BROKEN_SNPRINTF
/* strndup broken, see APAR IY61211 */
#undef BROKEN_STRNDUP
/* strnlen broken, see APAR IY62551 */
#undef BROKEN_STRNLEN
/* strnvis detected broken */
#undef BROKEN_STRNVIS
/* tcgetattr with ICANON may hang */
#undef BROKEN_TCGETATTR_ICANON
/* updwtmpx is broken (if present) */
#undef BROKEN_UPDWTMPX
/* Define if you have BSD auth support */
#undef BSD_AUTH
/* Define if you want to specify the path to your lastlog file */
#undef CONF_LASTLOG_FILE
/* Define if you want to specify the path to your utmp file */
#undef CONF_UTMP_FILE
/* Define if you want to specify the path to your wtmpx file */
#undef CONF_WTMPX_FILE
/* Define if you want to specify the path to your wtmp file */
#undef CONF_WTMP_FILE
/* Need to call setpgrp as root */
#undef DISABLE_FD_PASSING
/* Define if you don't want to use lastlog */
#undef DISABLE_LASTLOG
/* Define if you don't want to use your system's login() call */
#undef DISABLE_LOGIN
/* Define if you don't want to use pututline() etc. to write [uw]tmp */
#undef DISABLE_PUTUTLINE
/* Define if you don't want to use pututxline() etc. to write [uw]tmpx */
#undef DISABLE_PUTUTXLINE
/* Define if you want to disable shadow passwords */
#undef DISABLE_SHADOW
/* Define if you don't want to use utmp */
#undef DISABLE_UTMP
/* Define if you don't want to use utmpx */
#undef DISABLE_UTMPX
/* Define if you don't want to use wtmp */
#undef DISABLE_WTMP
/* Define if you don't want to use wtmpx */
#undef DISABLE_WTMPX
/* Enable for PKCS#11 support */
#undef ENABLE_PKCS11
/* Enable for U2F/FIDO support */
#undef ENABLE_SK
/* Enable for built-in U2F/FIDO support */
#undef ENABLE_SK_INTERNAL
/* define if fflush(NULL) does not work */
#undef FFLUSH_NULL_BUG
/* File names may not contain backslash characters */
#undef FILESYSTEM_NO_BACKSLASH
/* fsid_t has member val */
#undef FSID_HAS_VAL
/* fsid_t has member __val */
#undef FSID_HAS___VAL
/* getpgrp takes one arg */
#undef GETPGRP_VOID
/* Conflicting defs for getspnam */
#undef GETSPNAM_CONFLICTING_DEFS
/* Define if your system glob() function has the GLOB_ALTDIRFUNC extension */
#undef GLOB_HAS_ALTDIRFUNC
/* Define if your system glob() function has gl_matchc options in glob_t */
#undef GLOB_HAS_GL_MATCHC
/* Define if your system glob() function has gl_statv options in glob_t */
#undef GLOB_HAS_GL_STATV
/* Define this if you want GSSAPI support in the version 2 protocol */
#undef GSSAPI
/* Define if you want to use shadow password expire field */
#undef HAS_SHADOW_EXPIRE
/* Define if your system uses access rights style file descriptor passing */
#undef HAVE_ACCRIGHTS_IN_MSGHDR
/* Define if you have ut_addr in utmp.h */
#undef HAVE_ADDR_IN_UTMP
/* Define if you have ut_addr in utmpx.h */
#undef HAVE_ADDR_IN_UTMPX
/* Define if you have ut_addr_v6 in utmp.h */
#undef HAVE_ADDR_V6_IN_UTMP
/* Define if you have ut_addr_v6 in utmpx.h */
#undef HAVE_ADDR_V6_IN_UTMPX
/* Define to 1 if you have the `arc4random' function. */
#undef HAVE_ARC4RANDOM
/* Define to 1 if you have the `arc4random_buf' function. */
#undef HAVE_ARC4RANDOM_BUF
/* Define to 1 if you have the `arc4random_stir' function. */
#undef HAVE_ARC4RANDOM_STIR
/* Define to 1 if you have the `arc4random_uniform' function. */
#undef HAVE_ARC4RANDOM_UNIFORM
/* Define to 1 if you have the `asprintf' function. */
#undef HAVE_ASPRINTF
/* OpenBSD's gcc has bounded */
#undef HAVE_ATTRIBUTE__BOUNDED__
/* Have attribute nonnull */
#undef HAVE_ATTRIBUTE__NONNULL__
/* OpenBSD's gcc has sentinel */
#undef HAVE_ATTRIBUTE__SENTINEL__
/* Define to 1 if you have the `aug_get_machine' function. */
#undef HAVE_AUG_GET_MACHINE
/* Define to 1 if you have the `b64_ntop' function. */
#undef HAVE_B64_NTOP
/* Define to 1 if you have the `b64_pton' function. */
#undef HAVE_B64_PTON
/* Define if you have the basename function. */
#undef HAVE_BASENAME
/* Define to 1 if you have the `bcopy' function. */
#undef HAVE_BCOPY
/* Define to 1 if you have the `bcrypt_pbkdf' function. */
#undef HAVE_BCRYPT_PBKDF
/* Define to 1 if you have the `bindresvport_sa' function. */
#undef HAVE_BINDRESVPORT_SA
/* Define to 1 if you have the `blf_enc' function. */
#undef HAVE_BLF_ENC
/* Define to 1 if you have the <blf.h> header file. */
#undef HAVE_BLF_H
/* Define to 1 if you have the `Blowfish_expand0state' function. */
#undef HAVE_BLOWFISH_EXPAND0STATE
/* Define to 1 if you have the `Blowfish_expandstate' function. */
#undef HAVE_BLOWFISH_EXPANDSTATE
/* Define to 1 if you have the `Blowfish_initstate' function. */
#undef HAVE_BLOWFISH_INITSTATE
/* Define to 1 if you have the `Blowfish_stream2word' function. */
#undef HAVE_BLOWFISH_STREAM2WORD
/* Define to 1 if you have the `BN_is_prime_ex' function. */
#undef HAVE_BN_IS_PRIME_EX
/* Define to 1 if you have the <bsd/libutil.h> header file. */
#undef HAVE_BSD_LIBUTIL_H
/* Define to 1 if you have the <bsm/audit.h> header file. */
#undef HAVE_BSM_AUDIT_H
/* Define to 1 if you have the <bstring.h> header file. */
#undef HAVE_BSTRING_H
/* Define to 1 if you have the `bzero' function. */
#undef HAVE_BZERO
/* calloc(0, x) returns NULL */
#undef HAVE_CALLOC
+/* Define if you have caph_cache_tzdata */
+#undef HAVE_CAPH_CACHE_TZDATA
+
+/* Define to 1 if you have the <capsicum_helpers.h> header file. */
+#undef HAVE_CAPSICUM_HELPERS_H
+
/* Define to 1 if you have the `cap_rights_limit' function. */
#undef HAVE_CAP_RIGHTS_LIMIT
/* Define to 1 if you have the `clock' function. */
#undef HAVE_CLOCK
/* Have clock_gettime */
#undef HAVE_CLOCK_GETTIME
/* define if you have clock_t data type */
#undef HAVE_CLOCK_T
/* Define to 1 if you have the `closefrom' function. */
#undef HAVE_CLOSEFROM
/* Define to 1 if you have the `close_range' function. */
#undef HAVE_CLOSE_RANGE
/* Define if gai_strerror() returns const char * */
#undef HAVE_CONST_GAI_STRERROR_PROTO
/* Define if your system uses ancillary data style file descriptor passing */
#undef HAVE_CONTROL_IN_MSGHDR
/* Define to 1 if you have the `crypt' function. */
#undef HAVE_CRYPT
/* Define to 1 if you have the <crypto/sha2.h> header file. */
#undef HAVE_CRYPTO_SHA2_H
/* Define to 1 if you have the <crypt.h> header file. */
#undef HAVE_CRYPT_H
/* Define if you are on Cygwin */
#undef HAVE_CYGWIN
/* Define if your libraries define daemon() */
#undef HAVE_DAEMON
/* Define to 1 if you have the declaration of `AI_NUMERICSERV', and to 0 if
you don't. */
#undef HAVE_DECL_AI_NUMERICSERV
/* Define to 1 if you have the declaration of `authenticate', and to 0 if you
don't. */
#undef HAVE_DECL_AUTHENTICATE
/* Define to 1 if you have the declaration of `bzero', and to 0 if you don't.
*/
#undef HAVE_DECL_BZERO
/* Define to 1 if you have the declaration of `ftruncate', and to 0 if you
don't. */
#undef HAVE_DECL_FTRUNCATE
+/* Define to 1 if you have the declaration of `getentropy', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETENTROPY
+
/* Define to 1 if you have the declaration of `getpeereid', and to 0 if you
don't. */
#undef HAVE_DECL_GETPEEREID
/* Define to 1 if you have the declaration of `GLOB_NOMATCH', and to 0 if you
don't. */
#undef HAVE_DECL_GLOB_NOMATCH
/* Define to 1 if you have the declaration of `GSS_C_NT_HOSTBASED_SERVICE',
and to 0 if you don't. */
#undef HAVE_DECL_GSS_C_NT_HOSTBASED_SERVICE
/* Define to 1 if you have the declaration of `howmany', and to 0 if you
don't. */
#undef HAVE_DECL_HOWMANY
/* Define to 1 if you have the declaration of `h_errno', and to 0 if you
don't. */
#undef HAVE_DECL_H_ERRNO
/* Define to 1 if you have the declaration of `loginfailed', and to 0 if you
don't. */
#undef HAVE_DECL_LOGINFAILED
/* Define to 1 if you have the declaration of `loginrestrictions', and to 0 if
you don't. */
#undef HAVE_DECL_LOGINRESTRICTIONS
/* Define to 1 if you have the declaration of `loginsuccess', and to 0 if you
don't. */
#undef HAVE_DECL_LOGINSUCCESS
/* Define to 1 if you have the declaration of `MAXSYMLINKS', and to 0 if you
don't. */
#undef HAVE_DECL_MAXSYMLINKS
/* Define to 1 if you have the declaration of `memmem', and to 0 if you don't.
*/
#undef HAVE_DECL_MEMMEM
/* Define to 1 if you have the declaration of `NFDBITS', and to 0 if you
don't. */
#undef HAVE_DECL_NFDBITS
/* Define to 1 if you have the declaration of `offsetof', and to 0 if you
don't. */
#undef HAVE_DECL_OFFSETOF
/* Define to 1 if you have the declaration of `O_NONBLOCK', and to 0 if you
don't. */
#undef HAVE_DECL_O_NONBLOCK
/* Define to 1 if you have the declaration of `passwdexpired', and to 0 if you
don't. */
#undef HAVE_DECL_PASSWDEXPIRED
/* Define to 1 if you have the declaration of `readv', and to 0 if you don't.
*/
#undef HAVE_DECL_READV
/* Define to 1 if you have the declaration of `setauthdb', and to 0 if you
don't. */
#undef HAVE_DECL_SETAUTHDB
/* Define to 1 if you have the declaration of `SHUT_RD', and to 0 if you
don't. */
#undef HAVE_DECL_SHUT_RD
/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you
don't. */
#undef HAVE_DECL_UINT32_MAX
/* Define to 1 if you have the declaration of `writev', and to 0 if you don't.
*/
#undef HAVE_DECL_WRITEV
/* Define to 1 if you have the declaration of `_getlong', and to 0 if you
don't. */
#undef HAVE_DECL__GETLONG
/* Define to 1 if you have the declaration of `_getshort', and to 0 if you
don't. */
#undef HAVE_DECL__GETSHORT
/* Define to 1 if you have the `DES_crypt' function. */
#undef HAVE_DES_CRYPT
/* Define if you have /dev/ptmx */
#undef HAVE_DEV_PTMX
/* Define if you have /dev/ptc */
#undef HAVE_DEV_PTS_AND_PTC
/* Define to 1 if you have the `DH_get0_key' function. */
#undef HAVE_DH_GET0_KEY
/* Define to 1 if you have the `DH_get0_pqg' function. */
#undef HAVE_DH_GET0_PQG
/* Define to 1 if you have the `DH_set0_key' function. */
#undef HAVE_DH_SET0_KEY
/* Define to 1 if you have the `DH_set0_pqg' function. */
#undef HAVE_DH_SET0_PQG
/* Define to 1 if you have the `DH_set_length' function. */
#undef HAVE_DH_SET_LENGTH
/* Define to 1 if you have the <dirent.h> header file. */
#undef HAVE_DIRENT_H
/* Define to 1 if you have the `dirfd' function. */
#undef HAVE_DIRFD
/* Define to 1 if you have the `dirname' function. */
#undef HAVE_DIRNAME
/* Define to 1 if you have the `dlopen' function. */
#undef HAVE_DLOPEN
/* Define to 1 if you have the `DSA_generate_parameters_ex' function. */
#undef HAVE_DSA_GENERATE_PARAMETERS_EX
/* Define to 1 if you have the `DSA_get0_key' function. */
#undef HAVE_DSA_GET0_KEY
/* Define to 1 if you have the `DSA_get0_pqg' function. */
#undef HAVE_DSA_GET0_PQG
/* Define to 1 if you have the `DSA_set0_key' function. */
#undef HAVE_DSA_SET0_KEY
/* Define to 1 if you have the `DSA_set0_pqg' function. */
#undef HAVE_DSA_SET0_PQG
/* Define to 1 if you have the `DSA_SIG_get0' function. */
#undef HAVE_DSA_SIG_GET0
/* Define to 1 if you have the `DSA_SIG_set0' function. */
#undef HAVE_DSA_SIG_SET0
/* Define to 1 if you have the `ECDSA_SIG_get0' function. */
#undef HAVE_ECDSA_SIG_GET0
/* Define to 1 if you have the `ECDSA_SIG_set0' function. */
#undef HAVE_ECDSA_SIG_SET0
/* Define to 1 if you have the `EC_KEY_METHOD_new' function. */
#undef HAVE_EC_KEY_METHOD_NEW
/* Define to 1 if you have the <elf.h> header file. */
#undef HAVE_ELF_H
/* Define to 1 if you have the `endgrent' function. */
#undef HAVE_ENDGRENT
/* Define to 1 if you have the <endian.h> header file. */
#undef HAVE_ENDIAN_H
/* Define to 1 if you have the `endutent' function. */
#undef HAVE_ENDUTENT
/* Define to 1 if you have the `endutxent' function. */
#undef HAVE_ENDUTXENT
/* Define to 1 if you have the `err' function. */
#undef HAVE_ERR
/* Define to 1 if you have the `errx' function. */
#undef HAVE_ERRX
/* Define to 1 if you have the <err.h> header file. */
#undef HAVE_ERR_H
/* Define if your system has /etc/default/login */
#undef HAVE_ETC_DEFAULT_LOGIN
/* Define to 1 if you have the `EVP_chacha20' function. */
#undef HAVE_EVP_CHACHA20
-/* Define to 1 if you have the `EVP_CIPHER_CTX_ctrl' function. */
-#undef HAVE_EVP_CIPHER_CTX_CTRL
-
/* Define to 1 if you have the `EVP_CIPHER_CTX_get_iv' function. */
#undef HAVE_EVP_CIPHER_CTX_GET_IV
/* Define to 1 if you have the `EVP_CIPHER_CTX_get_updated_iv' function. */
#undef HAVE_EVP_CIPHER_CTX_GET_UPDATED_IV
/* Define to 1 if you have the `EVP_CIPHER_CTX_iv' function. */
#undef HAVE_EVP_CIPHER_CTX_IV
/* Define to 1 if you have the `EVP_CIPHER_CTX_iv_noconst' function. */
#undef HAVE_EVP_CIPHER_CTX_IV_NOCONST
/* Define to 1 if you have the `EVP_CIPHER_CTX_set_iv' function. */
#undef HAVE_EVP_CIPHER_CTX_SET_IV
/* Define to 1 if you have the `EVP_DigestFinal_ex' function. */
#undef HAVE_EVP_DIGESTFINAL_EX
/* Define to 1 if you have the `EVP_DigestInit_ex' function. */
#undef HAVE_EVP_DIGESTINIT_EX
/* Define to 1 if you have the `EVP_MD_CTX_cleanup' function. */
#undef HAVE_EVP_MD_CTX_CLEANUP
/* Define to 1 if you have the `EVP_MD_CTX_copy_ex' function. */
#undef HAVE_EVP_MD_CTX_COPY_EX
/* Define to 1 if you have the `EVP_MD_CTX_free' function. */
#undef HAVE_EVP_MD_CTX_FREE
/* Define to 1 if you have the `EVP_MD_CTX_init' function. */
#undef HAVE_EVP_MD_CTX_INIT
/* Define to 1 if you have the `EVP_MD_CTX_new' function. */
#undef HAVE_EVP_MD_CTX_NEW
/* Define to 1 if you have the `EVP_PKEY_get0_RSA' function. */
#undef HAVE_EVP_PKEY_GET0_RSA
/* Define to 1 if you have the `EVP_sha256' function. */
#undef HAVE_EVP_SHA256
/* Define to 1 if you have the `EVP_sha384' function. */
#undef HAVE_EVP_SHA384
/* Define to 1 if you have the `EVP_sha512' function. */
#undef HAVE_EVP_SHA512
/* Define if you have ut_exit in utmp.h */
#undef HAVE_EXIT_IN_UTMP
/* Define to 1 if you have the `explicit_bzero' function. */
#undef HAVE_EXPLICIT_BZERO
/* Define to 1 if you have the `explicit_memset' function. */
#undef HAVE_EXPLICIT_MEMSET
/* Define to 1 if you have the `fchmod' function. */
#undef HAVE_FCHMOD
/* Define to 1 if you have the `fchmodat' function. */
#undef HAVE_FCHMODAT
/* Define to 1 if you have the `fchown' function. */
#undef HAVE_FCHOWN
/* Define to 1 if you have the `fchownat' function. */
#undef HAVE_FCHOWNAT
/* Use F_CLOSEM fcntl for closefrom */
#undef HAVE_FCNTL_CLOSEM
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if the system has the type `fd_mask'. */
#undef HAVE_FD_MASK
/* Define to 1 if you have the <features.h> header file. */
#undef HAVE_FEATURES_H
/* Define to 1 if you have the `fido_assert_set_clientdata' function. */
#undef HAVE_FIDO_ASSERT_SET_CLIENTDATA
/* Define to 1 if you have the `fido_cred_prot' function. */
#undef HAVE_FIDO_CRED_PROT
/* Define to 1 if you have the `fido_cred_set_clientdata' function. */
#undef HAVE_FIDO_CRED_SET_CLIENTDATA
/* Define to 1 if you have the `fido_cred_set_prot' function. */
#undef HAVE_FIDO_CRED_SET_PROT
/* Define to 1 if you have the `fido_dev_get_touch_begin' function. */
#undef HAVE_FIDO_DEV_GET_TOUCH_BEGIN
/* Define to 1 if you have the `fido_dev_get_touch_status' function. */
#undef HAVE_FIDO_DEV_GET_TOUCH_STATUS
+/* Define to 1 if you have the `fido_dev_is_winhello' function. */
+#undef HAVE_FIDO_DEV_IS_WINHELLO
+
/* Define to 1 if you have the `fido_dev_supports_cred_prot' function. */
#undef HAVE_FIDO_DEV_SUPPORTS_CRED_PROT
/* Define to 1 if you have the <floatingpoint.h> header file. */
#undef HAVE_FLOATINGPOINT_H
/* Define to 1 if you have the `flock' function. */
#undef HAVE_FLOCK
/* Define to 1 if you have the `fmt_scaled' function. */
#undef HAVE_FMT_SCALED
/* Define to 1 if you have the `fnmatch' function. */
#undef HAVE_FNMATCH
/* Define to 1 if you have the <fnmatch.h> header file. */
#undef HAVE_FNMATCH_H
/* Define to 1 if you have the `freeaddrinfo' function. */
#undef HAVE_FREEADDRINFO
/* Define to 1 if you have the `freezero' function. */
#undef HAVE_FREEZERO
/* Define to 1 if the system has the type `fsblkcnt_t'. */
#undef HAVE_FSBLKCNT_T
/* Define to 1 if the system has the type `fsfilcnt_t'. */
#undef HAVE_FSFILCNT_T
/* Define to 1 if you have the `fstatfs' function. */
#undef HAVE_FSTATFS
/* Define to 1 if you have the `fstatvfs' function. */
#undef HAVE_FSTATVFS
/* Define to 1 if you have the `futimes' function. */
#undef HAVE_FUTIMES
/* Define to 1 if you have the `gai_strerror' function. */
#undef HAVE_GAI_STRERROR
/* Define to 1 if you have the `getaddrinfo' function. */
#undef HAVE_GETADDRINFO
/* Define to 1 if you have the `getaudit' function. */
#undef HAVE_GETAUDIT
/* Define to 1 if you have the `getaudit_addr' function. */
#undef HAVE_GETAUDIT_ADDR
/* Define to 1 if you have the `getcwd' function. */
#undef HAVE_GETCWD
+/* Define to 1 if you have the `getentropy' function. */
+#undef HAVE_GETENTROPY
+
/* Define to 1 if you have the `getgrouplist' function. */
#undef HAVE_GETGROUPLIST
/* Define to 1 if you have the `getgrset' function. */
#undef HAVE_GETGRSET
/* Define to 1 if you have the `getlastlogxbyname' function. */
#undef HAVE_GETLASTLOGXBYNAME
/* Define to 1 if you have the `getline' function. */
#undef HAVE_GETLINE
/* Define to 1 if you have the `getluid' function. */
#undef HAVE_GETLUID
/* Define to 1 if you have the `getnameinfo' function. */
#undef HAVE_GETNAMEINFO
/* Define to 1 if you have the `getopt' function. */
#undef HAVE_GETOPT
/* Define to 1 if you have the <getopt.h> header file. */
#undef HAVE_GETOPT_H
/* Define if your getopt(3) defines and uses optreset */
#undef HAVE_GETOPT_OPTRESET
/* Define if your libraries define getpagesize() */
#undef HAVE_GETPAGESIZE
/* Define to 1 if you have the `getpeereid' function. */
#undef HAVE_GETPEEREID
/* Define to 1 if you have the `getpeerucred' function. */
#undef HAVE_GETPEERUCRED
/* Define to 1 if you have the `getpgid' function. */
#undef HAVE_GETPGID
/* Define to 1 if you have the `getpgrp' function. */
#undef HAVE_GETPGRP
/* Define to 1 if you have the `getpwanam' function. */
#undef HAVE_GETPWANAM
/* Define to 1 if you have the `getrandom' function. */
#undef HAVE_GETRANDOM
/* Define to 1 if you have the `getrlimit' function. */
#undef HAVE_GETRLIMIT
/* Define if getrrsetbyname() exists */
#undef HAVE_GETRRSETBYNAME
/* Define to 1 if you have the `getseuserbyname' function. */
#undef HAVE_GETSEUSERBYNAME
/* Define to 1 if you have the `getsid' function. */
#undef HAVE_GETSID
/* Define to 1 if you have the `gettimeofday' function. */
#undef HAVE_GETTIMEOFDAY
/* Define to 1 if you have the `getttyent' function. */
#undef HAVE_GETTTYENT
/* Define to 1 if you have the `getutent' function. */
#undef HAVE_GETUTENT
/* Define to 1 if you have the `getutid' function. */
#undef HAVE_GETUTID
/* Define to 1 if you have the `getutline' function. */
#undef HAVE_GETUTLINE
/* Define to 1 if you have the `getutxent' function. */
#undef HAVE_GETUTXENT
/* Define to 1 if you have the `getutxid' function. */
#undef HAVE_GETUTXID
/* Define to 1 if you have the `getutxline' function. */
#undef HAVE_GETUTXLINE
/* Define to 1 if you have the `getutxuser' function. */
#undef HAVE_GETUTXUSER
/* Define to 1 if you have the `get_default_context_with_level' function. */
#undef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
/* Define to 1 if you have the `glob' function. */
#undef HAVE_GLOB
/* Define to 1 if you have the <glob.h> header file. */
#undef HAVE_GLOB_H
/* Define to 1 if you have the `group_from_gid' function. */
#undef HAVE_GROUP_FROM_GID
/* Define to 1 if you have the <gssapi_generic.h> header file. */
#undef HAVE_GSSAPI_GENERIC_H
/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
#undef HAVE_GSSAPI_GSSAPI_GENERIC_H
/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
#undef HAVE_GSSAPI_GSSAPI_H
/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
#undef HAVE_GSSAPI_GSSAPI_KRB5_H
/* Define to 1 if you have the <gssapi.h> header file. */
#undef HAVE_GSSAPI_H
/* Define to 1 if you have the <gssapi_krb5.h> header file. */
#undef HAVE_GSSAPI_KRB5_H
/* Define if HEADER.ad exists in arpa/nameser.h */
#undef HAVE_HEADER_AD
/* Define to 1 if you have the `HMAC_CTX_init' function. */
#undef HAVE_HMAC_CTX_INIT
/* Define if you have ut_host in utmp.h */
#undef HAVE_HOST_IN_UTMP
/* Define if you have ut_host in utmpx.h */
#undef HAVE_HOST_IN_UTMPX
/* Define to 1 if you have the <iaf.h> header file. */
#undef HAVE_IAF_H
/* Define to 1 if you have the <ia.h> header file. */
#undef HAVE_IA_H
/* Define if you have ut_id in utmp.h */
#undef HAVE_ID_IN_UTMP
/* Define if you have ut_id in utmpx.h */
#undef HAVE_ID_IN_UTMPX
/* Define to 1 if you have the <ifaddrs.h> header file. */
#undef HAVE_IFADDRS_H
/* Define to 1 if you have the `inet_aton' function. */
#undef HAVE_INET_ATON
/* Define to 1 if you have the `inet_ntoa' function. */
#undef HAVE_INET_NTOA
/* Define to 1 if you have the `inet_ntop' function. */
#undef HAVE_INET_NTOP
/* Define to 1 if you have the `innetgr' function. */
#undef HAVE_INNETGR
/* define if you have int64_t data type */
#undef HAVE_INT64_T
/* Define to 1 if the system has the type `intmax_t'. */
#undef HAVE_INTMAX_T
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* define if you have intxx_t data type */
#undef HAVE_INTXX_T
/* Define to 1 if the system has the type `in_addr_t'. */
#undef HAVE_IN_ADDR_T
/* Define to 1 if the system has the type `in_port_t'. */
#undef HAVE_IN_PORT_T
/* Define if you have isblank(3C). */
#undef HAVE_ISBLANK
/* Define to 1 if you have the `killpg' function. */
#undef HAVE_KILLPG
/* Define to 1 if you have the `krb5_cc_new_unique' function. */
#undef HAVE_KRB5_CC_NEW_UNIQUE
/* Define to 1 if you have the `krb5_free_error_message' function. */
#undef HAVE_KRB5_FREE_ERROR_MESSAGE
/* Define to 1 if you have the `krb5_get_error_message' function. */
#undef HAVE_KRB5_GET_ERROR_MESSAGE
/* Define to 1 if you have the <langinfo.h> header file. */
#undef HAVE_LANGINFO_H
/* Define to 1 if you have the <lastlog.h> header file. */
#undef HAVE_LASTLOG_H
/* Define if you want ldns support */
#undef HAVE_LDNS
/* Define to 1 if you have the <libaudit.h> header file. */
#undef HAVE_LIBAUDIT_H
/* Define to 1 if you have the `bsm' library (-lbsm). */
#undef HAVE_LIBBSM
-/* Define to 1 if you have the `crypt' library (-lcrypt). */
-#undef HAVE_LIBCRYPT
-
/* Define to 1 if you have the `dl' library (-ldl). */
#undef HAVE_LIBDL
/* Define to 1 if you have the <libgen.h> header file. */
#undef HAVE_LIBGEN_H
/* Define if system has libiaf that supports set_id */
#undef HAVE_LIBIAF
/* Define to 1 if you have the `network' library (-lnetwork). */
#undef HAVE_LIBNETWORK
/* Define to 1 if you have the `pam' library (-lpam). */
#undef HAVE_LIBPAM
/* Define to 1 if you have the <libproc.h> header file. */
#undef HAVE_LIBPROC_H
/* Define to 1 if you have the `socket' library (-lsocket). */
#undef HAVE_LIBSOCKET
/* Define to 1 if you have the <libutil.h> header file. */
#undef HAVE_LIBUTIL_H
/* Define to 1 if you have the `xnet' library (-lxnet). */
#undef HAVE_LIBXNET
/* Define to 1 if you have the `z' library (-lz). */
#undef HAVE_LIBZ
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define to 1 if you have the <linux/audit.h> header file. */
#undef HAVE_LINUX_AUDIT_H
/* Define to 1 if you have the <linux/filter.h> header file. */
#undef HAVE_LINUX_FILTER_H
/* Define to 1 if you have the <linux/if_tun.h> header file. */
#undef HAVE_LINUX_IF_TUN_H
/* Define to 1 if you have the <linux/seccomp.h> header file. */
#undef HAVE_LINUX_SECCOMP_H
/* Define to 1 if you have the `llabs' function. */
#undef HAVE_LLABS
/* Define to 1 if you have the <locale.h> header file. */
#undef HAVE_LOCALE_H
/* Define to 1 if you have the `localtime_r' function. */
#undef HAVE_LOCALTIME_R
/* Define to 1 if you have the `login' function. */
#undef HAVE_LOGIN
/* Define to 1 if you have the <login_cap.h> header file. */
#undef HAVE_LOGIN_CAP_H
/* Define to 1 if you have the `login_getcapbool' function. */
#undef HAVE_LOGIN_GETCAPBOOL
/* Define to 1 if you have the `login_getpwclass' function. */
#undef HAVE_LOGIN_GETPWCLASS
/* Define to 1 if you have the <login.h> header file. */
#undef HAVE_LOGIN_H
/* Define to 1 if you have the `logout' function. */
#undef HAVE_LOGOUT
/* Define to 1 if you have the `logwtmp' function. */
#undef HAVE_LOGWTMP
/* Define to 1 if the system has the type `long double'. */
#undef HAVE_LONG_DOUBLE
/* Define to 1 if the system has the type `long long'. */
#undef HAVE_LONG_LONG
/* Define to 1 if you have the <maillock.h> header file. */
#undef HAVE_MAILLOCK_H
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
to 0 otherwise. */
#undef HAVE_MALLOC
/* Define to 1 if you have the `mblen' function. */
#undef HAVE_MBLEN
/* Define to 1 if you have the `mbtowc' function. */
#undef HAVE_MBTOWC
/* Define to 1 if you have the `memmem' function. */
#undef HAVE_MEMMEM
/* Define to 1 if you have the `memmove' function. */
#undef HAVE_MEMMOVE
-/* Define to 1 if you have the <memory.h> header file. */
-#undef HAVE_MEMORY_H
-
/* Define to 1 if you have the `memset_s' function. */
#undef HAVE_MEMSET_S
/* Define to 1 if you have the `mkdtemp' function. */
#undef HAVE_MKDTEMP
/* define if you have mode_t data type */
#undef HAVE_MODE_T
/* Some systems put nanosleep outside of libc */
#undef HAVE_NANOSLEEP
/* Define to 1 if you have the <ndir.h> header file. */
#undef HAVE_NDIR_H
/* Define to 1 if you have the <netdb.h> header file. */
#undef HAVE_NETDB_H
/* Define to 1 if you have the <netgroup.h> header file. */
#undef HAVE_NETGROUP_H
/* Define to 1 if you have the <net/if_tun.h> header file. */
#undef HAVE_NET_IF_TUN_H
/* Define to 1 if you have the <net/route.h> header file. */
#undef HAVE_NET_ROUTE_H
/* Define if you are on NeXT */
#undef HAVE_NEXT
/* Define to 1 if the system has the type `nfds_t'. */
#undef HAVE_NFDS_T
/* Define to 1 if you have the `ngetaddrinfo' function. */
#undef HAVE_NGETADDRINFO
/* Define to 1 if you have the `nl_langinfo' function. */
#undef HAVE_NL_LANGINFO
/* Define to 1 if you have the `nsleep' function. */
#undef HAVE_NSLEEP
/* Define to 1 if you have the `ogetaddrinfo' function. */
#undef HAVE_OGETADDRINFO
/* Define if you have an old version of PAM which takes only one argument to
pam_strerror */
#undef HAVE_OLD_PAM
/* Define to 1 if you have the `openlog_r' function. */
#undef HAVE_OPENLOG_R
/* Define to 1 if you have the `openpty' function. */
#undef HAVE_OPENPTY
/* as a macro */
#undef HAVE_OPENSSL_ADD_ALL_ALGORITHMS
/* Define to 1 if you have the `OPENSSL_init_crypto' function. */
#undef HAVE_OPENSSL_INIT_CRYPTO
/* Define to 1 if you have the `OpenSSL_version' function. */
#undef HAVE_OPENSSL_VERSION
/* Define to 1 if you have the `OpenSSL_version_num' function. */
#undef HAVE_OPENSSL_VERSION_NUM
/* Define if you have Digital Unix Security Integration Architecture */
#undef HAVE_OSF_SIA
/* Define to 1 if you have the `pam_getenvlist' function. */
#undef HAVE_PAM_GETENVLIST
/* Define to 1 if you have the <pam/pam_appl.h> header file. */
#undef HAVE_PAM_PAM_APPL_H
/* Define to 1 if you have the `pam_putenv' function. */
#undef HAVE_PAM_PUTENV
/* Define to 1 if you have the <paths.h> header file. */
#undef HAVE_PATHS_H
/* Define if you have ut_pid in utmp.h */
#undef HAVE_PID_IN_UTMP
/* define if you have pid_t data type */
#undef HAVE_PID_T
/* Define to 1 if you have the `pledge' function. */
#undef HAVE_PLEDGE
/* Define to 1 if you have the `poll' function. */
#undef HAVE_POLL
/* Define to 1 if you have the <poll.h> header file. */
#undef HAVE_POLL_H
/* Define to 1 if you have the `ppoll' function. */
#undef HAVE_PPOLL
/* Define to 1 if you have the `prctl' function. */
#undef HAVE_PRCTL
/* Define to 1 if you have the `priv_basicset' function. */
#undef HAVE_PRIV_BASICSET
/* Define to 1 if you have the <priv.h> header file. */
#undef HAVE_PRIV_H
/* Define to 1 if you have the `procctl' function. */
#undef HAVE_PROCCTL
/* Define if you have /proc/$pid/fd */
#undef HAVE_PROC_PID
/* Define to 1 if you have the `proc_pidinfo' function. */
#undef HAVE_PROC_PIDINFO
/* Define to 1 if you have the `pselect' function. */
#undef HAVE_PSELECT
/* Define to 1 if you have the `pstat' function. */
#undef HAVE_PSTAT
/* Define to 1 if you have the <pty.h> header file. */
#undef HAVE_PTY_H
/* Define to 1 if you have the `pututline' function. */
#undef HAVE_PUTUTLINE
/* Define to 1 if you have the `pututxline' function. */
#undef HAVE_PUTUTXLINE
/* Define to 1 if you have the `raise' function. */
#undef HAVE_RAISE
/* Define to 1 if you have the `readpassphrase' function. */
#undef HAVE_READPASSPHRASE
/* Define to 1 if you have the <readpassphrase.h> header file. */
#undef HAVE_READPASSPHRASE_H
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
and to 0 otherwise. */
#undef HAVE_REALLOC
/* Define to 1 if you have the `reallocarray' function. */
#undef HAVE_REALLOCARRAY
/* Define to 1 if you have the `realpath' function. */
#undef HAVE_REALPATH
/* Define to 1 if you have the `recallocarray' function. */
#undef HAVE_RECALLOCARRAY
/* Define to 1 if you have the `recvmsg' function. */
#undef HAVE_RECVMSG
/* sys/resource.h has RLIMIT_NPROC */
#undef HAVE_RLIMIT_NPROC
/* Define to 1 if you have the <rpc/types.h> header file. */
#undef HAVE_RPC_TYPES_H
/* Define to 1 if you have the `rresvport_af' function. */
#undef HAVE_RRESVPORT_AF
/* Define to 1 if you have the `RSA_generate_key_ex' function. */
#undef HAVE_RSA_GENERATE_KEY_EX
/* Define to 1 if you have the `RSA_get0_crt_params' function. */
#undef HAVE_RSA_GET0_CRT_PARAMS
/* Define to 1 if you have the `RSA_get0_factors' function. */
#undef HAVE_RSA_GET0_FACTORS
/* Define to 1 if you have the `RSA_get0_key' function. */
#undef HAVE_RSA_GET0_KEY
/* Define to 1 if you have the `RSA_get_default_method' function. */
#undef HAVE_RSA_GET_DEFAULT_METHOD
/* Define to 1 if you have the `RSA_meth_dup' function. */
#undef HAVE_RSA_METH_DUP
/* Define to 1 if you have the `RSA_meth_free' function. */
#undef HAVE_RSA_METH_FREE
/* Define to 1 if you have the `RSA_meth_get_finish' function. */
#undef HAVE_RSA_METH_GET_FINISH
/* Define to 1 if you have the `RSA_meth_set1_name' function. */
#undef HAVE_RSA_METH_SET1_NAME
/* Define to 1 if you have the `RSA_meth_set_finish' function. */
#undef HAVE_RSA_METH_SET_FINISH
/* Define to 1 if you have the `RSA_meth_set_priv_dec' function. */
#undef HAVE_RSA_METH_SET_PRIV_DEC
/* Define to 1 if you have the `RSA_meth_set_priv_enc' function. */
#undef HAVE_RSA_METH_SET_PRIV_ENC
/* Define to 1 if you have the `RSA_set0_crt_params' function. */
#undef HAVE_RSA_SET0_CRT_PARAMS
/* Define to 1 if you have the `RSA_set0_factors' function. */
#undef HAVE_RSA_SET0_FACTORS
/* Define to 1 if you have the `RSA_set0_key' function. */
#undef HAVE_RSA_SET0_KEY
/* Define to 1 if you have the <sandbox.h> header file. */
#undef HAVE_SANDBOX_H
/* Define to 1 if you have the `sandbox_init' function. */
#undef HAVE_SANDBOX_INIT
/* define if you have sa_family_t data type */
#undef HAVE_SA_FAMILY_T
/* Define to 1 if you have the `scan_scaled' function. */
#undef HAVE_SCAN_SCALED
/* Define if you have SecureWare-based protected password database */
#undef HAVE_SECUREWARE
/* Define to 1 if you have the <security/pam_appl.h> header file. */
#undef HAVE_SECURITY_PAM_APPL_H
/* Define to 1 if you have the `sendmsg' function. */
#undef HAVE_SENDMSG
/* Define to 1 if you have the `setauthdb' function. */
#undef HAVE_SETAUTHDB
/* Define to 1 if you have the `setdtablesize' function. */
#undef HAVE_SETDTABLESIZE
/* Define to 1 if you have the `setegid' function. */
#undef HAVE_SETEGID
/* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV
/* Define to 1 if you have the `seteuid' function. */
#undef HAVE_SETEUID
/* Define to 1 if you have the `setgroupent' function. */
#undef HAVE_SETGROUPENT
/* Define to 1 if you have the `setgroups' function. */
#undef HAVE_SETGROUPS
/* Define to 1 if you have the `setlinebuf' function. */
#undef HAVE_SETLINEBUF
/* Define to 1 if you have the `setlogin' function. */
#undef HAVE_SETLOGIN
/* Define to 1 if you have the `setluid' function. */
#undef HAVE_SETLUID
/* Define to 1 if you have the `setpassent' function. */
#undef HAVE_SETPASSENT
/* Define to 1 if you have the `setpcred' function. */
#undef HAVE_SETPCRED
/* Define to 1 if you have the `setpflags' function. */
#undef HAVE_SETPFLAGS
/* Define to 1 if you have the `setppriv' function. */
#undef HAVE_SETPPRIV
/* Define to 1 if you have the `setproctitle' function. */
#undef HAVE_SETPROCTITLE
/* Define to 1 if you have the `setregid' function. */
#undef HAVE_SETREGID
/* Define to 1 if you have the `setresgid' function. */
#undef HAVE_SETRESGID
/* Define to 1 if you have the `setresuid' function. */
#undef HAVE_SETRESUID
/* Define to 1 if you have the `setreuid' function. */
#undef HAVE_SETREUID
/* Define to 1 if you have the `setrlimit' function. */
#undef HAVE_SETRLIMIT
/* Define to 1 if you have the `setsid' function. */
#undef HAVE_SETSID
/* Define to 1 if you have the `setutent' function. */
#undef HAVE_SETUTENT
/* Define to 1 if you have the `setutxdb' function. */
#undef HAVE_SETUTXDB
/* Define to 1 if you have the `setutxent' function. */
#undef HAVE_SETUTXENT
/* Define to 1 if you have the `setvbuf' function. */
#undef HAVE_SETVBUF
/* Define to 1 if you have the `set_id' function. */
#undef HAVE_SET_ID
/* Define to 1 if you have the `SHA256Update' function. */
#undef HAVE_SHA256UPDATE
/* Define to 1 if you have the <sha2.h> header file. */
#undef HAVE_SHA2_H
/* Define to 1 if you have the `SHA384Update' function. */
#undef HAVE_SHA384UPDATE
/* Define to 1 if you have the `SHA512Update' function. */
#undef HAVE_SHA512UPDATE
/* Define to 1 if you have the <shadow.h> header file. */
#undef HAVE_SHADOW_H
/* Define to 1 if you have the `sigaction' function. */
#undef HAVE_SIGACTION
/* Define to 1 if the system has the type `sighandler_t'. */
#undef HAVE_SIGHANDLER_T
/* Define to 1 if you have the `sigvec' function. */
#undef HAVE_SIGVEC
/* Define to 1 if the system has the type `sig_atomic_t'. */
#undef HAVE_SIG_ATOMIC_T
/* define if you have size_t data type */
#undef HAVE_SIZE_T
/* Define to 1 if you have the `snprintf' function. */
#undef HAVE_SNPRINTF
/* Define to 1 if you have the `socketpair' function. */
#undef HAVE_SOCKETPAIR
/* Have PEERCRED socket option */
#undef HAVE_SO_PEERCRED
/* define if you have ssize_t data type */
#undef HAVE_SSIZE_T
/* Fields in struct sockaddr_storage */
#undef HAVE_SS_FAMILY_IN_SS
/* Define if you have ut_ss in utmpx.h */
#undef HAVE_SS_IN_UTMPX
/* Define to 1 if you have the `statfs' function. */
#undef HAVE_STATFS
/* Define to 1 if you have the `statvfs' function. */
#undef HAVE_STATVFS
/* Define to 1 if you have the <stddef.h> header file. */
#undef HAVE_STDDEF_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the `strcasestr' function. */
#undef HAVE_STRCASESTR
/* Define to 1 if you have the `strdup' function. */
#undef HAVE_STRDUP
/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR
/* Define to 1 if you have the `strftime' function. */
#undef HAVE_STRFTIME
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strlcat' function. */
#undef HAVE_STRLCAT
/* Define to 1 if you have the `strlcpy' function. */
#undef HAVE_STRLCPY
/* Define to 1 if you have the `strmode' function. */
#undef HAVE_STRMODE
/* Define to 1 if you have the `strndup' function. */
#undef HAVE_STRNDUP
/* Define to 1 if you have the `strnlen' function. */
#undef HAVE_STRNLEN
/* Define to 1 if you have the `strnvis' function. */
#undef HAVE_STRNVIS
/* Define to 1 if you have the `strptime' function. */
#undef HAVE_STRPTIME
/* Define to 1 if you have the `strsep' function. */
#undef HAVE_STRSEP
/* Define to 1 if you have the `strsignal' function. */
#undef HAVE_STRSIGNAL
/* Define to 1 if you have the `strtoll' function. */
#undef HAVE_STRTOLL
/* Define to 1 if you have the `strtonum' function. */
#undef HAVE_STRTONUM
/* Define to 1 if you have the `strtoul' function. */
#undef HAVE_STRTOUL
/* Define to 1 if you have the `strtoull' function. */
#undef HAVE_STRTOULL
/* define if you have struct addrinfo data type */
#undef HAVE_STRUCT_ADDRINFO
/* define if you have struct in6_addr data type */
#undef HAVE_STRUCT_IN6_ADDR
/* Define to 1 if `pw_change' is a member of `struct passwd'. */
#undef HAVE_STRUCT_PASSWD_PW_CHANGE
/* Define to 1 if `pw_class' is a member of `struct passwd'. */
#undef HAVE_STRUCT_PASSWD_PW_CLASS
/* Define to 1 if `pw_expire' is a member of `struct passwd'. */
#undef HAVE_STRUCT_PASSWD_PW_EXPIRE
/* Define to 1 if `pw_gecos' is a member of `struct passwd'. */
#undef HAVE_STRUCT_PASSWD_PW_GECOS
/* Define to 1 if `fd' is a member of `struct pollfd'. */
#undef HAVE_STRUCT_POLLFD_FD
/* define if you have struct sockaddr_in6 data type */
#undef HAVE_STRUCT_SOCKADDR_IN6
/* Define to 1 if `sin6_scope_id' is a member of `struct sockaddr_in6'. */
#undef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
/* define if you have struct sockaddr_storage data type */
#undef HAVE_STRUCT_SOCKADDR_STORAGE
/* Define to 1 if `f_files' is a member of `struct statfs'. */
#undef HAVE_STRUCT_STATFS_F_FILES
/* Define to 1 if `f_flags' is a member of `struct statfs'. */
#undef HAVE_STRUCT_STATFS_F_FLAGS
/* Define to 1 if `st_blksize' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_BLKSIZE
/* Define to 1 if `st_mtim' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_MTIM
/* Define to 1 if `st_mtime' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_MTIME
/* define if you have struct timespec */
#undef HAVE_STRUCT_TIMESPEC
/* define if you have struct timeval */
#undef HAVE_STRUCT_TIMEVAL
/* Define to 1 if you have the `swap32' function. */
#undef HAVE_SWAP32
/* Define to 1 if you have the `sysconf' function. */
#undef HAVE_SYSCONF
/* Define if you have syslen in utmpx.h */
#undef HAVE_SYSLEN_IN_UTMPX
/* Define to 1 if you have the <sys/audit.h> header file. */
#undef HAVE_SYS_AUDIT_H
/* Define to 1 if you have the <sys/bitypes.h> header file. */
#undef HAVE_SYS_BITYPES_H
/* Define to 1 if you have the <sys/bsdtty.h> header file. */
#undef HAVE_SYS_BSDTTY_H
/* Define to 1 if you have the <sys/byteorder.h> header file. */
#undef HAVE_SYS_BYTEORDER_H
/* Define to 1 if you have the <sys/capsicum.h> header file. */
#undef HAVE_SYS_CAPSICUM_H
/* Define to 1 if you have the <sys/cdefs.h> header file. */
#undef HAVE_SYS_CDEFS_H
/* Define to 1 if you have the <sys/dir.h> header file. */
#undef HAVE_SYS_DIR_H
/* Define if your system defines sys_errlist[] */
#undef HAVE_SYS_ERRLIST
/* Define to 1 if you have the <sys/file.h> header file. */
#undef HAVE_SYS_FILE_H
/* Define to 1 if you have the <sys/label.h> header file. */
#undef HAVE_SYS_LABEL_H
/* Define to 1 if you have the <sys/mman.h> header file. */
#undef HAVE_SYS_MMAN_H
/* Define to 1 if you have the <sys/mount.h> header file. */
#undef HAVE_SYS_MOUNT_H
/* Define to 1 if you have the <sys/ndir.h> header file. */
#undef HAVE_SYS_NDIR_H
/* Define if your system defines sys_nerr */
#undef HAVE_SYS_NERR
/* Define to 1 if you have the <sys/param.h> header file. */
#undef HAVE_SYS_PARAM_H
/* Define to 1 if you have the <sys/poll.h> header file. */
#undef HAVE_SYS_POLL_H
/* Define to 1 if you have the <sys/prctl.h> header file. */
#undef HAVE_SYS_PRCTL_H
/* Define to 1 if you have the <sys/procctl.h> header file. */
#undef HAVE_SYS_PROCCTL_H
/* Define to 1 if you have the <sys/pstat.h> header file. */
#undef HAVE_SYS_PSTAT_H
/* Define to 1 if you have the <sys/ptms.h> header file. */
#undef HAVE_SYS_PTMS_H
/* Define to 1 if you have the <sys/ptrace.h> header file. */
#undef HAVE_SYS_PTRACE_H
/* Define to 1 if you have the <sys/random.h> header file. */
#undef HAVE_SYS_RANDOM_H
/* Define to 1 if you have the <sys/select.h> header file. */
#undef HAVE_SYS_SELECT_H
/* Define to 1 if you have the <sys/statvfs.h> header file. */
#undef HAVE_SYS_STATVFS_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/stream.h> header file. */
#undef HAVE_SYS_STREAM_H
/* Define to 1 if you have the <sys/stropts.h> header file. */
#undef HAVE_SYS_STROPTS_H
/* Define to 1 if you have the <sys/strtio.h> header file. */
#undef HAVE_SYS_STRTIO_H
/* Define to 1 if you have the <sys/sysctl.h> header file. */
#undef HAVE_SYS_SYSCTL_H
/* Force use of sys/syslog.h on Ultrix */
#undef HAVE_SYS_SYSLOG_H
/* Define to 1 if you have the <sys/sysmacros.h> header file. */
#undef HAVE_SYS_SYSMACROS_H
/* Define to 1 if you have the <sys/timers.h> header file. */
#undef HAVE_SYS_TIMERS_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/un.h> header file. */
#undef HAVE_SYS_UN_H
/* Define to 1 if you have the <sys/vfs.h> header file. */
#undef HAVE_SYS_VFS_H
/* Define to 1 if you have the `tcgetpgrp' function. */
#undef HAVE_TCGETPGRP
/* Define to 1 if you have the `tcsendbreak' function. */
#undef HAVE_TCSENDBREAK
/* Define to 1 if you have the `time' function. */
#undef HAVE_TIME
+/* Define to 1 if you have the `timegm' function. */
+#undef HAVE_TIMEGM
+
/* Define to 1 if you have the <time.h> header file. */
#undef HAVE_TIME_H
/* Define if you have ut_time in utmp.h */
#undef HAVE_TIME_IN_UTMP
/* Define if you have ut_time in utmpx.h */
#undef HAVE_TIME_IN_UTMPX
/* Define to 1 if you have the `timingsafe_bcmp' function. */
#undef HAVE_TIMINGSAFE_BCMP
/* Define to 1 if you have the <tmpdir.h> header file. */
#undef HAVE_TMPDIR_H
/* Define to 1 if you have the `truncate' function. */
#undef HAVE_TRUNCATE
/* Define to 1 if you have the <ttyent.h> header file. */
#undef HAVE_TTYENT_H
/* Define if you have ut_tv in utmp.h */
#undef HAVE_TV_IN_UTMP
/* Define if you have ut_tv in utmpx.h */
#undef HAVE_TV_IN_UTMPX
/* Define if you have ut_type in utmp.h */
#undef HAVE_TYPE_IN_UTMP
/* Define if you have ut_type in utmpx.h */
#undef HAVE_TYPE_IN_UTMPX
/* Define to 1 if you have the <ucred.h> header file. */
#undef HAVE_UCRED_H
/* Define to 1 if the system has the type `uintmax_t'. */
#undef HAVE_UINTMAX_T
/* define if you have uintxx_t data type */
#undef HAVE_UINTXX_T
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `unsetenv' function. */
#undef HAVE_UNSETENV
/* Define to 1 if the system has the type `unsigned long long'. */
#undef HAVE_UNSIGNED_LONG_LONG
/* Define to 1 if you have the `updwtmp' function. */
#undef HAVE_UPDWTMP
/* Define to 1 if you have the `updwtmpx' function. */
#undef HAVE_UPDWTMPX
/* Define to 1 if you have the <usersec.h> header file. */
#undef HAVE_USERSEC_H
/* Define to 1 if you have the `user_from_uid' function. */
#undef HAVE_USER_FROM_UID
/* Define to 1 if you have the `usleep' function. */
#undef HAVE_USLEEP
/* Define to 1 if you have the <util.h> header file. */
#undef HAVE_UTIL_H
/* Define to 1 if you have the `utimensat' function. */
#undef HAVE_UTIMENSAT
/* Define to 1 if you have the `utimes' function. */
#undef HAVE_UTIMES
/* Define to 1 if you have the <utime.h> header file. */
#undef HAVE_UTIME_H
/* Define to 1 if you have the `utmpname' function. */
#undef HAVE_UTMPNAME
/* Define to 1 if you have the `utmpxname' function. */
#undef HAVE_UTMPXNAME
/* Define to 1 if you have the <utmpx.h> header file. */
#undef HAVE_UTMPX_H
/* Define to 1 if you have the <utmp.h> header file. */
#undef HAVE_UTMP_H
/* define if you have u_char data type */
#undef HAVE_U_CHAR
/* define if you have u_int data type */
#undef HAVE_U_INT
/* define if you have u_int64_t data type */
#undef HAVE_U_INT64_T
/* define if you have u_intxx_t data type */
#undef HAVE_U_INTXX_T
/* Define to 1 if you have the `vasprintf' function. */
#undef HAVE_VASPRINTF
/* Define if va_copy exists */
#undef HAVE_VA_COPY
/* Define to 1 if you have the <vis.h> header file. */
#undef HAVE_VIS_H
/* Define to 1 if you have the `vsnprintf' function. */
#undef HAVE_VSNPRINTF
/* Define to 1 if you have the `waitpid' function. */
#undef HAVE_WAITPID
/* Define to 1 if you have the `warn' function. */
#undef HAVE_WARN
/* Define to 1 if you have the <wchar.h> header file. */
#undef HAVE_WCHAR_H
/* Define to 1 if you have the `wcwidth' function. */
#undef HAVE_WCWIDTH
/* Define to 1 if you have the `_getlong' function. */
#undef HAVE__GETLONG
/* Define to 1 if you have the `_getpty' function. */
#undef HAVE__GETPTY
/* Define to 1 if you have the `_getshort' function. */
#undef HAVE__GETSHORT
/* Define if you have struct __res_state _res as an extern */
#undef HAVE__RES_EXTERN
/* Define to 1 if you have the `__b64_ntop' function. */
#undef HAVE___B64_NTOP
/* Define to 1 if you have the `__b64_pton' function. */
#undef HAVE___B64_PTON
/* Define if compiler implements __FUNCTION__ */
#undef HAVE___FUNCTION__
/* Define if libc defines __progname */
#undef HAVE___PROGNAME
/* Fields in struct sockaddr_storage */
#undef HAVE___SS_FAMILY_IN_SS
/* Define if __va_copy exists */
#undef HAVE___VA_COPY
/* Define if compiler implements __func__ */
#undef HAVE___func__
/* Define this if you are using the Heimdal version of Kerberos V5 */
#undef HEIMDAL
/* Define if you need to use IP address instead of hostname in $DISPLAY */
#undef IPADDR_IN_DISPLAY
/* Detect IPv4 in IPv6 mapped addresses and treat as IPv4 */
#undef IPV4_IN_IPV6
/* Define if your system choked on IP TOS setting */
#undef IP_TOS_IS_BROKEN
/* Define if you want Kerberos 5 support */
#undef KRB5
/* Define if pututxline updates lastlog too */
#undef LASTLOG_WRITE_PUTUTXLINE
/* Define to whatever link() returns for "not supported" if it doesn't return
EOPNOTSUPP. */
#undef LINK_OPNOTSUPP_ERRNO
/* Adjust Linux out-of-memory killer */
#undef LINUX_OOM_ADJUST
/* max value of long long calculated by configure */
#undef LLONG_MAX
/* min value of long long calculated by configure */
#undef LLONG_MIN
/* Account locked with pw(1) */
#undef LOCKED_PASSWD_PREFIX
/* String used in /etc/passwd to denote locked account */
#undef LOCKED_PASSWD_STRING
/* String used in /etc/passwd to denote locked account */
#undef LOCKED_PASSWD_SUBSTR
/* Some systems need a utmpx entry for /bin/login to work */
#undef LOGIN_NEEDS_UTMPX
/* Set this to your mail directory if you do not have _PATH_MAILDIR */
#undef MAIL_DIRECTORY
/* Need setpgrp to for controlling tty */
#undef NEED_SETPGRP
/* compiler does not accept __attribute__ on prototype args */
#undef NO_ATTRIBUTE_ON_PROTOTYPE_ARGS
/* compiler does not accept __attribute__ on return types */
#undef NO_ATTRIBUTE_ON_RETURN_TYPE
/* SA_RESTARTed signals do no interrupt select */
#undef NO_SA_RESTART
/* Define to disable UID restoration test */
#undef NO_UID_RESTORATION_TEST
/* Define if X11 doesn't support AF_UNIX sockets on that system */
#undef NO_X11_UNIX_SOCKETS
/* Define if EVP_DigestUpdate returns void */
#undef OPENSSL_EVP_DIGESTUPDATE_VOID
/* OpenSSL has ECC */
#undef OPENSSL_HAS_ECC
/* libcrypto has NID_X9_62_prime256v1 */
#undef OPENSSL_HAS_NISTP256
/* libcrypto has NID_secp384r1 */
#undef OPENSSL_HAS_NISTP384
/* libcrypto has NID_secp521r1 */
#undef OPENSSL_HAS_NISTP521
-/* libcrypto has EVP AES CTR */
-#undef OPENSSL_HAVE_EVPCTR
-
-/* libcrypto has EVP AES GCM */
-#undef OPENSSL_HAVE_EVPGCM
-
/* libcrypto is missing AES 192 and 256 bit functions */
#undef OPENSSL_LOBOTOMISED_AES
/* Define if you want the OpenSSL internally seeded PRNG only */
#undef OPENSSL_PRNG_ONLY
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define if you are using Solaris-derived PAM which passes pam_messages to
the conversation function with an extra level of indirection */
#undef PAM_SUN_CODEBASE
/* Work around problematic Linux PAM modules handling of PAM_TTY */
#undef PAM_TTY_KLUDGE
/* must supply username to passwd */
#undef PASSWD_NEEDS_USERNAME
/* System dirs owned by bin (uid 2) */
#undef PLATFORM_SYS_DIR_UID
/* Port number of PRNGD/EGD random number socket */
#undef PRNGD_PORT
/* Location of PRNGD/EGD random number socket */
#undef PRNGD_SOCKET
/* read(1) can return 0 for a non-closed fd */
#undef PTY_ZEROREAD
/* Sandbox using capsicum */
#undef SANDBOX_CAPSICUM
/* Sandbox using Darwin sandbox_init(3) */
#undef SANDBOX_DARWIN
/* no privsep sandboxing */
#undef SANDBOX_NULL
/* Sandbox using pledge(2) */
#undef SANDBOX_PLEDGE
/* Sandbox using setrlimit(2) */
#undef SANDBOX_RLIMIT
/* Sandbox using seccomp filter */
#undef SANDBOX_SECCOMP_FILTER
/* setrlimit RLIMIT_FSIZE works */
#undef SANDBOX_SKIP_RLIMIT_FSIZE
/* define if setrlimit RLIMIT_NOFILE breaks things */
#undef SANDBOX_SKIP_RLIMIT_NOFILE
/* Sandbox using Solaris/Illumos privileges */
#undef SANDBOX_SOLARIS
/* Sandbox using systrace(4) */
#undef SANDBOX_SYSTRACE
/* Specify the system call convention in use */
#undef SECCOMP_AUDIT_ARCH
/* Define if your platform breaks doing a seteuid before a setuid */
#undef SETEUID_BREAKS_SETUID
/* The size of `int', as computed by sizeof. */
#undef SIZEOF_INT
/* The size of `long int', as computed by sizeof. */
#undef SIZEOF_LONG_INT
/* The size of `long long int', as computed by sizeof. */
#undef SIZEOF_LONG_LONG_INT
/* The size of `short int', as computed by sizeof. */
#undef SIZEOF_SHORT_INT
/* The size of `time_t', as computed by sizeof. */
#undef SIZEOF_TIME_T
/* Define as const if snprintf() can declare const char *fmt */
#undef SNPRINTF_CONST
/* Define to a Set Process Title type if your system is supported by
bsd-setproctitle.c */
#undef SPT_TYPE
/* Define if sshd somehow reacquires a controlling TTY after setsid() */
#undef SSHD_ACQUIRES_CTTY
/* sshd PAM service name */
#undef SSHD_PAM_SERVICE
/* Define if pam_chauthtok wants real uid set to the unpriv'ed user */
#undef SSHPAM_CHAUTHTOK_NEEDS_RUID
/* Use audit debugging module */
#undef SSH_AUDIT_EVENTS
/* Windows is sensitive to read buffer size */
#undef SSH_IOBUFSZ
/* non-privileged user for privilege separation */
#undef SSH_PRIVSEP_USER
/* Use tunnel device compatibility to OpenBSD */
#undef SSH_TUN_COMPAT_AF
/* Open tunnel devices the FreeBSD way */
#undef SSH_TUN_FREEBSD
/* Open tunnel devices the Linux tun/tap way */
#undef SSH_TUN_LINUX
/* No layer 2 tunnel support */
#undef SSH_TUN_NO_L2
/* Open tunnel devices the OpenBSD way */
#undef SSH_TUN_OPENBSD
/* Prepend the address family to IP tunnel traffic */
#undef SSH_TUN_PREPEND_AF
-/* Define to 1 if you have the ANSI C header files. */
+/* Define to 1 if all of the C90 standard headers exist (not just the ones
+ required in a freestanding environment). This macro is provided for
+ backward compatibility; new code need not use it. */
#undef STDC_HEADERS
/* Define if you want a different $PATH for the superuser */
#undef SUPERUSER_PATH
/* syslog_r function is safe to use in in a signal handler */
#undef SYSLOG_R_SAFE_IN_SIGHAND
/* Support routing domains using Linux VRF */
#undef SYS_RDOMAIN_LINUX
/* Support passwords > 8 chars */
#undef UNIXWARE_LONG_PASSWORDS
/* Specify default $PATH */
#undef USER_PATH
/* Define this if you want to use libkafs' AFS support */
#undef USE_AFS
/* Use BSM audit module */
#undef USE_BSM_AUDIT
/* Use btmp to log bad logins */
#undef USE_BTMP
/* Use libedit for sftp */
#undef USE_LIBEDIT
/* Use Linux audit module */
#undef USE_LINUX_AUDIT
/* Enable OpenSSL engine support */
#undef USE_OPENSSL_ENGINE
/* Define if you want to enable PAM support */
#undef USE_PAM
/* Use PIPES instead of a socketpair() */
#undef USE_PIPES
/* Define if you have Solaris privileges */
#undef USE_SOLARIS_PRIVS
/* Define if you have Solaris process contracts */
#undef USE_SOLARIS_PROCESS_CONTRACTS
/* Define if you have Solaris projects */
#undef USE_SOLARIS_PROJECTS
/* compiler variable declarations after code */
#undef VARIABLE_DECLARATION_AFTER_CODE
/* compiler supports variable length arrays */
#undef VARIABLE_LENGTH_ARRAYS
/* Define if you shouldn't strip 'tty' from your ttyname in [uw]tmp */
#undef WITH_ABBREV_NO_TTY
/* Define if you want to enable AIX4's authenticate function */
#undef WITH_AIXAUTHENTICATE
/* Define if you have/want arrays (cluster-wide session management, not C
arrays) */
#undef WITH_IRIX_ARRAY
/* Define if you want IRIX audit trails */
#undef WITH_IRIX_AUDIT
/* Define if you want IRIX kernel jobs */
#undef WITH_IRIX_JOBS
/* Define if you want IRIX project management */
#undef WITH_IRIX_PROJECT
/* use libcrypto for cryptography */
#undef WITH_OPENSSL
/* Define if you want SELinux support. */
#undef WITH_SELINUX
/* Enable zlib */
#undef WITH_ZLIB
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
# undef WORDS_BIGENDIAN
# endif
#endif
/* Define if xauth is found in your path */
#undef XAUTH_PATH
-/* Enable large inode numbers on Mac OS X 10.5. */
-#ifndef _DARWIN_USE_64_BIT_INODE
-# define _DARWIN_USE_64_BIT_INODE 1
-#endif
-
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Define for large files, on AIX-style hosts. */
#undef _LARGE_FILES
/* log for bad login attempts */
#undef _PATH_BTMP
/* Full path of your "passwd" program */
#undef _PATH_PASSWD_PROG
/* Specify location of ssh.pid */
#undef _PATH_SSH_PIDDIR
/* Define if we don't have struct __res_state in resolv.h */
#undef __res_state
/* Define to rpl_calloc if the replacement function should be used. */
#undef calloc
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
#undef inline
#endif
/* Define to rpl_malloc if the replacement function should be used. */
#undef malloc
/* Define to rpl_realloc if the replacement function should be used. */
#undef realloc
/* type to use in place of socklen_t if not defined */
#undef socklen_t
diff --git a/configure b/configure
index 8a31d27c27bb..ba87c9bb2c37 100755
--- a/configure
+++ b/configure
@@ -1,22490 +1,24137 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for OpenSSH Portable.
+# Generated by GNU Autoconf 2.71 for OpenSSH Portable.
#
# Report bugs to <openssh-unix-dev@mindrot.org>.
#
#
-# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
+# Inc.
#
#
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
## -------------------- ##
## M4sh Initialization. ##
## -------------------- ##
# Be more Bourne compatible
DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+as_nop=:
+if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
+then :
emulate sh
NULLCMD=:
# Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
# is contrary to our usage. Disable this feature.
alias -g '${1+"$@"}'='"$@"'
setopt NO_GLOB_SUBST
-else
+else $as_nop
case `(set -o) 2>/dev/null` in #(
*posix*) :
set -o posix ;; #(
*) :
;;
esac
fi
+
+# Reset variables that may have inherited troublesome values from
+# the environment.
+
+# IFS needs to be set, to space, tab, and newline, in precisely that order.
+# (If _AS_PATH_WALK were called with IFS unset, it would have the
+# side effect of setting IFS to empty, thus disabling word splitting.)
+# Quoting is to prevent editors from complaining about space-tab.
as_nl='
'
export as_nl
-# Printing a long string crashes Solaris 7 /usr/bin/printf.
-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-# Prefer a ksh shell builtin over an external printf program on Solaris,
-# but without wasting forks for bash or zsh.
-if test -z "$BASH_VERSION$ZSH_VERSION" \
- && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
- as_echo='print -r --'
- as_echo_n='print -rn --'
-elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
- as_echo='printf %s\n'
- as_echo_n='printf %s'
-else
- if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
- as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
- as_echo_n='/usr/ucb/echo -n'
- else
- as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
- as_echo_n_body='eval
- arg=$1;
- case $arg in #(
- *"$as_nl"*)
- expr "X$arg" : "X\\(.*\\)$as_nl";
- arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
- esac;
- expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
- '
- export as_echo_n_body
- as_echo_n='sh -c $as_echo_n_body as_echo'
- fi
- export as_echo_body
- as_echo='sh -c $as_echo_body as_echo'
-fi
+IFS=" "" $as_nl"
+
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# Ensure predictable behavior from utilities with locale-dependent output.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# We cannot yet rely on "unset" to work, but we need these variables
+# to be unset--not just set to an empty or harmless value--now, to
+# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
+# also avoids known problems related to "unset" and subshell syntax
+# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
+for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
+do eval test \${$as_var+y} \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+
+# Ensure that fds 0, 1, and 2 are open.
+if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
+if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
+if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
+if ${PATH_SEPARATOR+false} :; then
PATH_SEPARATOR=:
(PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
(PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
PATH_SEPARATOR=';'
}
fi
-# IFS
-# We need space, tab and new line, in precisely that order. Quoting is
-# there to prevent editors from complaining about space-tab.
-# (If _AS_PATH_WALK were called with IFS unset, it would disable word
-# splitting by setting IFS to empty value.)
-IFS=" "" $as_nl"
-
# Find who we are. Look in the path if we contain no directory separator.
as_myself=
case $0 in #((
*[\\/]* ) as_myself=$0 ;;
*) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ test -r "$as_dir$0" && as_myself=$as_dir$0 && break
done
IFS=$as_save_IFS
;;
esac
# We did not find ourselves, most probably we were run as `sh COMMAND'
# in which case we are not to be found in the path.
if test "x$as_myself" = x; then
as_myself=$0
fi
if test ! -f "$as_myself"; then
- $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
exit 1
fi
-# Unset variables that we do not need and which cause bugs (e.g. in
-# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
-# suppresses any "Segmentation fault" message there. '((' could
-# trigger a bug in pdksh 5.2.14.
-for as_var in BASH_ENV ENV MAIL MAILPATH
-do eval test x\${$as_var+set} = xset \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# NLS nuisances.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# CDPATH.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
# Use a proper internal environment variable to ensure we don't fall
# into an infinite loop, continuously re-executing ourselves.
if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
_as_can_reexec=no; export _as_can_reexec;
# We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
BASH_ENV=/dev/null
ENV=/dev/null
(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
case $- in # ((((
*v*x* | *x*v* ) as_opts=-vx ;;
*v* ) as_opts=-v ;;
*x* ) as_opts=-x ;;
* ) as_opts= ;;
esac
exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
# Admittedly, this is quite paranoid, since all the known shells bail
# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-as_fn_exit 255
+printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
fi
# We don't want this to propagate to other subprocesses.
{ _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
- as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ as_bourne_compatible="as_nop=:
+if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
+then :
emulate sh
NULLCMD=:
# Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
# is contrary to our usage. Disable this feature.
alias -g '\${1+\"\$@\"}'='\"\$@\"'
setopt NO_GLOB_SUBST
-else
+else \$as_nop
case \`(set -o) 2>/dev/null\` in #(
*posix*) :
set -o posix ;; #(
*) :
;;
esac
fi
"
as_required="as_fn_return () { (exit \$1); }
as_fn_success () { as_fn_return 0; }
as_fn_failure () { as_fn_return 1; }
as_fn_ret_success () { return 0; }
as_fn_ret_failure () { return 1; }
exitcode=0
as_fn_success || { exitcode=1; echo as_fn_success failed.; }
as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
-if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+if ( set x; as_fn_ret_success y && test x = \"\$1\" )
+then :
-else
+else \$as_nop
exitcode=1; echo positional parameters were not saved.
fi
test x\$exitcode = x0 || exit 1
+blah=\$(echo \$(echo blah))
+test x\"\$blah\" = xblah || exit 1
test -x / || exit 1"
as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
test \$(( 1 + 1 )) = 2 || exit 1"
- if (eval "$as_required") 2>/dev/null; then :
+ if (eval "$as_required") 2>/dev/null
+then :
as_have_required=yes
-else
+else $as_nop
as_have_required=no
fi
- if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null
+then :
-else
+else $as_nop
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
as_found=false
for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
as_found=:
case $as_dir in #(
/*)
for as_base in sh bash ksh sh5; do
# Try only shells that exist, to save several forks.
- as_shell=$as_dir/$as_base
+ as_shell=$as_dir$as_base
if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
- { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null
+then :
CONFIG_SHELL=$as_shell as_have_required=yes
- if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null
+then :
break 2
fi
fi
done;;
esac
as_found=false
done
-$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
- { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
- CONFIG_SHELL=$SHELL as_have_required=yes
-fi; }
IFS=$as_save_IFS
+if $as_found
+then :
+
+else $as_nop
+ if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null
+then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi
+fi
- if test "x$CONFIG_SHELL" != x; then :
+ if test "x$CONFIG_SHELL" != x
+then :
export CONFIG_SHELL
# We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
BASH_ENV=/dev/null
ENV=/dev/null
(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
case $- in # ((((
*v*x* | *x*v* ) as_opts=-vx ;;
*v* ) as_opts=-v ;;
*x* ) as_opts=-x ;;
* ) as_opts= ;;
esac
exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
# Admittedly, this is quite paranoid, since all the known shells bail
# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
exit 255
fi
- if test x$as_have_required = xno; then :
- $as_echo "$0: This script requires a shell more modern than all"
- $as_echo "$0: the shells that I found on your system."
- if test x${ZSH_VERSION+set} = xset ; then
- $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
- $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ if test x$as_have_required = xno
+then :
+ printf "%s\n" "$0: This script requires a shell more modern than all"
+ printf "%s\n" "$0: the shells that I found on your system."
+ if test ${ZSH_VERSION+y} ; then
+ printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later."
else
- $as_echo "$0: Please tell bug-autoconf@gnu.org and
+ printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and
$0: openssh-unix-dev@mindrot.org about your system,
$0: including any error possibly output before this
$0: message. Then install a modern shell, or manually run
$0: the script under such a shell if you do have one."
fi
exit 1
fi
fi
fi
SHELL=${CONFIG_SHELL-/bin/sh}
export SHELL
# Unset more variables known to interfere with behavior of common tools.
CLICOLOR_FORCE= GREP_OPTIONS=
unset CLICOLOR_FORCE GREP_OPTIONS
## --------------------- ##
## M4sh Shell Functions. ##
## --------------------- ##
# as_fn_unset VAR
# ---------------
# Portably unset VAR.
as_fn_unset ()
{
{ eval $1=; unset $1;}
}
as_unset=as_fn_unset
+
# as_fn_set_status STATUS
# -----------------------
# Set $? to STATUS, without forking.
as_fn_set_status ()
{
return $1
} # as_fn_set_status
# as_fn_exit STATUS
# -----------------
# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
as_fn_exit ()
{
set +e
as_fn_set_status $1
exit $1
} # as_fn_exit
+# as_fn_nop
+# ---------
+# Do nothing but, unlike ":", preserve the value of $?.
+as_fn_nop ()
+{
+ return $?
+}
+as_nop=as_fn_nop
# as_fn_mkdir_p
# -------------
# Create "$as_dir" as a directory, including parents if necessary.
as_fn_mkdir_p ()
{
case $as_dir in #(
-*) as_dir=./$as_dir;;
esac
test -d "$as_dir" || eval $as_mkdir_p || {
as_dirs=
while :; do
case $as_dir in #(
- *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
*) as_qdir=$as_dir;;
esac
as_dirs="'$as_qdir' $as_dirs"
as_dir=`$as_dirname -- "$as_dir" ||
$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$as_dir" : 'X\(//\)[^/]' \| \
X"$as_dir" : 'X\(//\)$' \| \
X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_dir" |
+printf "%s\n" X"$as_dir" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'`
test -d "$as_dir" && break
done
test -z "$as_dirs" || eval "mkdir $as_dirs"
} || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
} # as_fn_mkdir_p
# as_fn_executable_p FILE
# -----------------------
# Test if FILE is an executable regular file.
as_fn_executable_p ()
{
test -f "$1" && test -x "$1"
} # as_fn_executable_p
# as_fn_append VAR VALUE
# ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take
# advantage of any shell optimizations that allow amortized linear growth over
# repeated appends, instead of the typical quadratic growth present in naive
# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null
+then :
eval 'as_fn_append ()
{
eval $1+=\$2
}'
-else
+else $as_nop
as_fn_append ()
{
eval $1=\$$1\$2
}
fi # as_fn_append
# as_fn_arith ARG...
# ------------------
# Perform arithmetic evaluation on the ARGs, and store the result in the
# global $as_val. Take advantage of shells that can avoid forks. The arguments
# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null
+then :
eval 'as_fn_arith ()
{
as_val=$(( $* ))
}'
-else
+else $as_nop
as_fn_arith ()
{
as_val=`expr "$@" || test $? -eq 1`
}
fi # as_fn_arith
+# as_fn_nop
+# ---------
+# Do nothing but, unlike ":", preserve the value of $?.
+as_fn_nop ()
+{
+ return $?
+}
+as_nop=as_fn_nop
# as_fn_error STATUS ERROR [LINENO LOG_FD]
# ----------------------------------------
# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
# script with STATUS, using 1 if that was 0.
as_fn_error ()
{
as_status=$1; test $as_status -eq 0 && as_status=1
if test "$4"; then
as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
fi
- $as_echo "$as_me: error: $2" >&2
+ printf "%s\n" "$as_me: error: $2" >&2
as_fn_exit $as_status
} # as_fn_error
if expr a : '\(a\)' >/dev/null 2>&1 &&
test "X`expr 00001 : '.*\(...\)'`" = X001; then
as_expr=expr
else
as_expr=false
fi
if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
as_basename=basename
else
as_basename=false
fi
if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
as_dirname=dirname
else
as_dirname=false
fi
as_me=`$as_basename -- "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
X"$0" : 'X\(//\)$' \| \
X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X/"$0" |
+printf "%s\n" X/"$0" |
sed '/^.*\/\([^/][^/]*\)\/*$/{
s//\1/
q
}
/^X\/\(\/\/\)$/{
s//\1/
q
}
/^X\/\(\/\).*/{
s//\1/
q
}
s/.*/./; q'`
# Avoid depending upon Character Ranges.
as_cr_letters='abcdefghijklmnopqrstuvwxyz'
as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
as_cr_Letters=$as_cr_letters$as_cr_LETTERS
as_cr_digits='0123456789'
as_cr_alnum=$as_cr_Letters$as_cr_digits
as_lineno_1=$LINENO as_lineno_1a=$LINENO
as_lineno_2=$LINENO as_lineno_2a=$LINENO
eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
# Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
sed -n '
p
/[$]LINENO/=
' <$as_myself |
sed '
s/[$]LINENO.*/&-/
t lineno
b
:lineno
N
:loop
s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
t loop
s/-\n.*//
' >$as_me.lineno &&
chmod +x "$as_me.lineno" ||
- { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+ { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
# If we had to re-execute with $CONFIG_SHELL, we're ensured to have
# already done that, so ensure we don't try to do so again and fall
# in an infinite loop. This has already happened in practice.
_as_can_reexec=no; export _as_can_reexec
# Don't try to exec as it changes $[0], causing all sort of problems
# (the dirname of $[0] is not the place where we might find the
# original and so on. Autoconf is especially sensitive to this).
. "./$as_me.lineno"
# Exit status is that of the last command.
exit
}
+
+# Determine whether it's possible to make 'echo' print without a newline.
+# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
+# for compatibility with existing Makefiles.
ECHO_C= ECHO_N= ECHO_T=
case `echo -n x` in #(((((
-n*)
case `echo 'xy\c'` in
*c*) ECHO_T=' ';; # ECHO_T is single tab character.
xy) ECHO_C='\c';;
*) echo `echo ksh88 bug on AIX 6.1` > /dev/null
ECHO_T=' ';;
esac;;
*)
ECHO_N='-n';;
esac
+# For backward compatibility with old third-party macros, we provide
+# the shell variables $as_echo and $as_echo_n. New code should use
+# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
+as_echo='printf %s\n'
+as_echo_n='printf %s'
+
+
rm -f conf$$ conf$$.exe conf$$.file
if test -d conf$$.dir; then
rm -f conf$$.dir/conf$$.file
else
rm -f conf$$.dir
mkdir conf$$.dir 2>/dev/null
fi
if (echo >conf$$.file) 2>/dev/null; then
if ln -s conf$$.file conf$$ 2>/dev/null; then
as_ln_s='ln -s'
# ... but there are two gotchas:
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
# In both cases, we have to default to `cp -pR'.
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
as_ln_s='cp -pR'
elif ln conf$$.file conf$$ 2>/dev/null; then
as_ln_s=ln
else
as_ln_s='cp -pR'
fi
else
as_ln_s='cp -pR'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null
if mkdir -p . 2>/dev/null; then
as_mkdir_p='mkdir -p "$as_dir"'
else
test -d ./-p && rmdir ./-p
as_mkdir_p=false
fi
as_test_x='test -x'
as_executable_p=as_fn_executable_p
# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
# Sed expression to map a string onto a valid variable name.
as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
test -n "$DJDIR" || exec 7<&0 </dev/null
exec 6>&1
# Name of the host.
# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
# so uname gets run too.
ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
#
# Initializations.
#
ac_default_prefix=/usr/local
ac_clean_files=
ac_config_libobj_dir=.
LIBOBJS=
cross_compiling=no
subdirs=
MFLAGS=
MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='OpenSSH'
PACKAGE_TARNAME='openssh'
PACKAGE_VERSION='Portable'
PACKAGE_STRING='OpenSSH Portable'
PACKAGE_BUGREPORT='openssh-unix-dev@mindrot.org'
PACKAGE_URL=''
ac_unique_file="ssh.c"
# Factoring default headers for most tests.
ac_includes_default="\
-#include <stdio.h>
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-# include <sys/stat.h>
+#include <stddef.h>
+#ifdef HAVE_STDIO_H
+# include <stdio.h>
#endif
-#ifdef STDC_HEADERS
+#ifdef HAVE_STDLIB_H
# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-# endif
#endif
#ifdef HAVE_STRING_H
-# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
-# include <memory.h>
-# endif
# include <string.h>
#endif
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif"
+ac_header_c_list=
ac_subst_vars='LTLIBOBJS
CFLAGS_NOPIE
LDFLAGS_NOPIE
DEPEND
UNSUPPORTED_ALGORITHMS
TEST_MALLOC_OPTIONS
TEST_SSH_UTF8
TEST_SSH_IPV6
piddir
user_path
mansubdir
MANTYPE
XAUTH_PATH
STRIP_OPT
xauth_path
PRIVSEP_PATH
+CHANNELLIBS
K5LIBS
GSSLIBS
KRB5CONF
SSHDLIBS
SSH_PRIVSEP_USER
LIBFIDO2
SK_DUMMY_LIBRARY
PICFLAG
LIBEDIT
-PKGCONFIG
LDNSCONFIG
LIBOBJS
LD
PATH_PASSWD_PROG
STARTUP_SCRIPT_SHELL
MAKE_PACKAGE_SUPPORTED
PATH_USERADD_PROG
PATH_GROUPADD_PROG
MANFMT
TEST_SHELL
+PKGCONFIG
MANDOC
NROFF
GROFF
SH
TEST_MINUS_S_SH
SED
KILL
CAT
ac_ct_AR
AR
MKDIR_P
+EGREP
+GREP
INSTALL_DATA
INSTALL_SCRIPT
INSTALL_PROGRAM
RANLIB
-AWK
-EGREP
-GREP
CPP
+AWK
host_os
host_vendor
host_cpu
host
build_os
build_vendor
build_cpu
build
OBJEXT
EXEEXT
ac_ct_CC
CPPFLAGS
LDFLAGS
CFLAGS
CC
target_alias
host_alias
build_alias
LIBS
ECHO_T
ECHO_N
ECHO_C
DEFS
mandir
localedir
libdir
psdir
pdfdir
dvidir
htmldir
infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
datadir
datarootdir
libexecdir
sbindir
bindir
program_transform_name
prefix
exec_prefix
PACKAGE_URL
PACKAGE_BUGREPORT
PACKAGE_STRING
PACKAGE_VERSION
PACKAGE_TARNAME
PACKAGE_NAME
PATH_SEPARATOR
SHELL'
ac_subst_files=''
ac_user_opts='
enable_option_checking
enable_largefile
with_openssl
with_stackprotect
with_hardening
with_rpath
with_cflags
with_cflags_after
with_cppflags
with_ldflags
with_ldflags_after
with_libs
with_Werror
with_solaris_contracts
with_solaris_projects
with_solaris_privs
with_osfsia
with_zlib
with_zlib_version_check
with_ldns
with_libedit
with_audit
with_pie
enable_pkcs11
enable_security_key
with_security_key_builtin
with_ssl_dir
with_openssl_header_check
with_ssl_engine
with_prngd_port
with_prngd_socket
with_pam
with_pam_service
with_privsep_user
with_sandbox
with_selinux
with_kerberos5
with_privsep_path
with_xauth
enable_strip
with_maildir
with_mantype
with_shadow
with_ipaddr_display
enable_etc_default_login
with_default_path
with_superuser_path
with_4in6
with_bsd_auth
with_pid_dir
enable_lastlog
enable_utmp
enable_utmpx
enable_wtmp
enable_wtmpx
enable_libutil
enable_pututline
enable_pututxline
with_lastlog
'
ac_precious_vars='build_alias
host_alias
target_alias
CC
CFLAGS
LDFLAGS
LIBS
CPPFLAGS
CPP'
# Initialize some variables set by options.
ac_init_help=
ac_init_version=false
ac_unrecognized_opts=
ac_unrecognized_sep=
# The variables have the same names as the options, with
# dashes changed to underlines.
cache_file=/dev/null
exec_prefix=NONE
no_create=
no_recursion=
prefix=NONE
program_prefix=NONE
program_suffix=NONE
program_transform_name=s,x,x,
silent=
site=
srcdir=
verbose=
x_includes=NONE
x_libraries=NONE
# Installation directory options.
# These are left unexpanded so users can "make install exec_prefix=/foo"
# and all the variables that are supposed to be based on exec_prefix
# by default will actually change.
# Use braces instead of parens because sh, perl, etc. also accept them.
# (The list follows the same order as the GNU Coding Standards.)
bindir='${exec_prefix}/bin'
sbindir='${exec_prefix}/sbin'
libexecdir='${exec_prefix}/libexec'
datarootdir='${prefix}/share'
datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
infodir='${datarootdir}/info'
htmldir='${docdir}'
dvidir='${docdir}'
pdfdir='${docdir}'
psdir='${docdir}'
libdir='${exec_prefix}/lib'
localedir='${datarootdir}/locale'
mandir='${datarootdir}/man'
ac_prev=
ac_dashdash=
for ac_option
do
# If the previous option needs an argument, assign it.
if test -n "$ac_prev"; then
eval $ac_prev=\$ac_option
ac_prev=
continue
fi
case $ac_option in
*=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
*=) ac_optarg= ;;
*) ac_optarg=yes ;;
esac
- # Accept the important Cygnus configure options, so we can diagnose typos.
-
case $ac_dashdash$ac_option in
--)
ac_dashdash=yes ;;
-bindir | --bindir | --bindi | --bind | --bin | --bi)
ac_prev=bindir ;;
-bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
bindir=$ac_optarg ;;
-build | --build | --buil | --bui | --bu)
ac_prev=build_alias ;;
-build=* | --build=* | --buil=* | --bui=* | --bu=*)
build_alias=$ac_optarg ;;
-cache-file | --cache-file | --cache-fil | --cache-fi \
| --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
ac_prev=cache_file ;;
-cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
| --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
cache_file=$ac_optarg ;;
--config-cache | -C)
cache_file=config.cache ;;
-datadir | --datadir | --datadi | --datad)
ac_prev=datadir ;;
-datadir=* | --datadir=* | --datadi=* | --datad=*)
datadir=$ac_optarg ;;
-datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
| --dataroo | --dataro | --datar)
ac_prev=datarootdir ;;
-datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
| --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
datarootdir=$ac_optarg ;;
-disable-* | --disable-*)
ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid feature name: $ac_useropt"
+ as_fn_error $? "invalid feature name: \`$ac_useropt'"
ac_useropt_orig=$ac_useropt
- ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"enable_$ac_useropt"
"*) ;;
*) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
ac_unrecognized_sep=', ';;
esac
eval enable_$ac_useropt=no ;;
-docdir | --docdir | --docdi | --doc | --do)
ac_prev=docdir ;;
-docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
docdir=$ac_optarg ;;
-dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
ac_prev=dvidir ;;
-dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
dvidir=$ac_optarg ;;
-enable-* | --enable-*)
ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid feature name: $ac_useropt"
+ as_fn_error $? "invalid feature name: \`$ac_useropt'"
ac_useropt_orig=$ac_useropt
- ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"enable_$ac_useropt"
"*) ;;
*) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
ac_unrecognized_sep=', ';;
esac
eval enable_$ac_useropt=\$ac_optarg ;;
-exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
| --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
| --exec | --exe | --ex)
ac_prev=exec_prefix ;;
-exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
| --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
| --exec=* | --exe=* | --ex=*)
exec_prefix=$ac_optarg ;;
-gas | --gas | --ga | --g)
# Obsolete; use --with-gas.
with_gas=yes ;;
-help | --help | --hel | --he | -h)
ac_init_help=long ;;
-help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
ac_init_help=recursive ;;
-help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
ac_init_help=short ;;
-host | --host | --hos | --ho)
ac_prev=host_alias ;;
-host=* | --host=* | --hos=* | --ho=*)
host_alias=$ac_optarg ;;
-htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
ac_prev=htmldir ;;
-htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
| --ht=*)
htmldir=$ac_optarg ;;
-includedir | --includedir | --includedi | --included | --include \
| --includ | --inclu | --incl | --inc)
ac_prev=includedir ;;
-includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
| --includ=* | --inclu=* | --incl=* | --inc=*)
includedir=$ac_optarg ;;
-infodir | --infodir | --infodi | --infod | --info | --inf)
ac_prev=infodir ;;
-infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
infodir=$ac_optarg ;;
-libdir | --libdir | --libdi | --libd)
ac_prev=libdir ;;
-libdir=* | --libdir=* | --libdi=* | --libd=*)
libdir=$ac_optarg ;;
-libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
| --libexe | --libex | --libe)
ac_prev=libexecdir ;;
-libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
| --libexe=* | --libex=* | --libe=*)
libexecdir=$ac_optarg ;;
-localedir | --localedir | --localedi | --localed | --locale)
ac_prev=localedir ;;
-localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
localedir=$ac_optarg ;;
-localstatedir | --localstatedir | --localstatedi | --localstated \
| --localstate | --localstat | --localsta | --localst | --locals)
ac_prev=localstatedir ;;
-localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
| --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
localstatedir=$ac_optarg ;;
-mandir | --mandir | --mandi | --mand | --man | --ma | --m)
ac_prev=mandir ;;
-mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
mandir=$ac_optarg ;;
-nfp | --nfp | --nf)
# Obsolete; use --without-fp.
with_fp=no ;;
-no-create | --no-create | --no-creat | --no-crea | --no-cre \
| --no-cr | --no-c | -n)
no_create=yes ;;
-no-recursion | --no-recursion | --no-recursio | --no-recursi \
| --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
no_recursion=yes ;;
-oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
| --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
| --oldin | --oldi | --old | --ol | --o)
ac_prev=oldincludedir ;;
-oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
| --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
| --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
oldincludedir=$ac_optarg ;;
-prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
ac_prev=prefix ;;
-prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
prefix=$ac_optarg ;;
-program-prefix | --program-prefix | --program-prefi | --program-pref \
| --program-pre | --program-pr | --program-p)
ac_prev=program_prefix ;;
-program-prefix=* | --program-prefix=* | --program-prefi=* \
| --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
program_prefix=$ac_optarg ;;
-program-suffix | --program-suffix | --program-suffi | --program-suff \
| --program-suf | --program-su | --program-s)
ac_prev=program_suffix ;;
-program-suffix=* | --program-suffix=* | --program-suffi=* \
| --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
program_suffix=$ac_optarg ;;
-program-transform-name | --program-transform-name \
| --program-transform-nam | --program-transform-na \
| --program-transform-n | --program-transform- \
| --program-transform | --program-transfor \
| --program-transfo | --program-transf \
| --program-trans | --program-tran \
| --progr-tra | --program-tr | --program-t)
ac_prev=program_transform_name ;;
-program-transform-name=* | --program-transform-name=* \
| --program-transform-nam=* | --program-transform-na=* \
| --program-transform-n=* | --program-transform-=* \
| --program-transform=* | --program-transfor=* \
| --program-transfo=* | --program-transf=* \
| --program-trans=* | --program-tran=* \
| --progr-tra=* | --program-tr=* | --program-t=*)
program_transform_name=$ac_optarg ;;
-pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
ac_prev=pdfdir ;;
-pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
pdfdir=$ac_optarg ;;
-psdir | --psdir | --psdi | --psd | --ps)
ac_prev=psdir ;;
-psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
psdir=$ac_optarg ;;
-q | -quiet | --quiet | --quie | --qui | --qu | --q \
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
| --sbi=* | --sb=*)
sbindir=$ac_optarg ;;
-sharedstatedir | --sharedstatedir | --sharedstatedi \
| --sharedstated | --sharedstate | --sharedstat | --sharedsta \
| --sharedst | --shareds | --shared | --share | --shar \
| --sha | --sh)
ac_prev=sharedstatedir ;;
-sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
| --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
| --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
| --sha=* | --sh=*)
sharedstatedir=$ac_optarg ;;
-site | --site | --sit)
ac_prev=site ;;
-site=* | --site=* | --sit=*)
site=$ac_optarg ;;
-srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
ac_prev=srcdir ;;
-srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
srcdir=$ac_optarg ;;
-sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
| --syscon | --sysco | --sysc | --sys | --sy)
ac_prev=sysconfdir ;;
-sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
| --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
sysconfdir=$ac_optarg ;;
-target | --target | --targe | --targ | --tar | --ta | --t)
ac_prev=target_alias ;;
-target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
target_alias=$ac_optarg ;;
-v | -verbose | --verbose | --verbos | --verbo | --verb)
verbose=yes ;;
-version | --version | --versio | --versi | --vers | -V)
ac_init_version=: ;;
-with-* | --with-*)
ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid package name: $ac_useropt"
+ as_fn_error $? "invalid package name: \`$ac_useropt'"
ac_useropt_orig=$ac_useropt
- ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"with_$ac_useropt"
"*) ;;
*) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
ac_unrecognized_sep=', ';;
esac
eval with_$ac_useropt=\$ac_optarg ;;
-without-* | --without-*)
ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid package name: $ac_useropt"
+ as_fn_error $? "invalid package name: \`$ac_useropt'"
ac_useropt_orig=$ac_useropt
- ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"with_$ac_useropt"
"*) ;;
*) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
ac_unrecognized_sep=', ';;
esac
eval with_$ac_useropt=no ;;
--x)
# Obsolete; use --with-x.
with_x=yes ;;
-x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
| --x-incl | --x-inc | --x-in | --x-i)
ac_prev=x_includes ;;
-x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
| --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
x_includes=$ac_optarg ;;
-x-libraries | --x-libraries | --x-librarie | --x-librari \
| --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
ac_prev=x_libraries ;;
-x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
| --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
x_libraries=$ac_optarg ;;
-*) as_fn_error $? "unrecognized option: \`$ac_option'
Try \`$0 --help' for more information"
;;
*=*)
ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
# Reject names that are not valid shell variable names.
case $ac_envvar in #(
'' | [0-9]* | *[!_$as_cr_alnum]* )
as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
esac
eval $ac_envvar=\$ac_optarg
export $ac_envvar ;;
*)
# FIXME: should be removed in autoconf 3.0.
- $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2
expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
- $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2
: "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
;;
esac
done
if test -n "$ac_prev"; then
ac_option=--`echo $ac_prev | sed 's/_/-/g'`
as_fn_error $? "missing argument to $ac_option"
fi
if test -n "$ac_unrecognized_opts"; then
case $enable_option_checking in
no) ;;
fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
- *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
esac
fi
# Check all directory arguments for consistency.
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
case $ac_val in
*/ )
ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
eval $ac_var=\$ac_val;;
esac
# Be sure to have absolute directory names.
case $ac_val in
[\\/$]* | ?:[\\/]* ) continue;;
NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
esac
as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
done
# There might be people who depend on the old broken behavior: `$host'
# used to hold the argument of --host etc.
# FIXME: To remove some day.
build=$build_alias
host=$host_alias
target=$target_alias
# FIXME: To remove some day.
if test "x$host_alias" != x; then
if test "x$build_alias" = x; then
cross_compiling=maybe
elif test "x$build_alias" != "x$host_alias"; then
cross_compiling=yes
fi
fi
ac_tool_prefix=
test -n "$host_alias" && ac_tool_prefix=$host_alias-
test "$silent" = yes && exec 6>/dev/null
ac_pwd=`pwd` && test -n "$ac_pwd" &&
ac_ls_di=`ls -di .` &&
ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
as_fn_error $? "working directory cannot be determined"
test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
as_fn_error $? "pwd does not report name of working directory"
# Find the source files, if location was not specified.
if test -z "$srcdir"; then
ac_srcdir_defaulted=yes
# Try the directory containing this script, then the parent directory.
ac_confdir=`$as_dirname -- "$as_myself" ||
$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$as_myself" : 'X\(//\)[^/]' \| \
X"$as_myself" : 'X\(//\)$' \| \
X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_myself" |
+printf "%s\n" X"$as_myself" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'`
srcdir=$ac_confdir
if test ! -r "$srcdir/$ac_unique_file"; then
srcdir=..
fi
else
ac_srcdir_defaulted=no
fi
if test ! -r "$srcdir/$ac_unique_file"; then
test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
fi
ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
ac_abs_confdir=`(
cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
pwd)`
# When building in place, set srcdir=.
if test "$ac_abs_confdir" = "$ac_pwd"; then
srcdir=.
fi
# Remove unnecessary trailing slashes from srcdir.
# Double slashes in file names in object file debugging info
# mess up M-x gdb in Emacs.
case $srcdir in
*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
esac
for ac_var in $ac_precious_vars; do
eval ac_env_${ac_var}_set=\${${ac_var}+set}
eval ac_env_${ac_var}_value=\$${ac_var}
eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
eval ac_cv_env_${ac_var}_value=\$${ac_var}
done
#
# Report the --help message.
#
if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures OpenSSH Portable to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE. See below for descriptions of some of the useful variables.
Defaults for the options are specified in brackets.
Configuration:
-h, --help display this help and exit
--help=short display options specific to this package
--help=recursive display the short help of all the included packages
-V, --version display version information and exit
-q, --quiet, --silent do not print \`checking ...' messages
--cache-file=FILE cache test results in FILE [disabled]
-C, --config-cache alias for \`--cache-file=config.cache'
-n, --no-create do not create output files
--srcdir=DIR find the sources in DIR [configure dir or \`..']
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
[$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
[PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
an installation prefix other than \`$ac_default_prefix' using \`--prefix',
for instance \`--prefix=\$HOME'.
For better control, use the options below.
Fine tuning of the installation directories:
--bindir=DIR user executables [EPREFIX/bin]
--sbindir=DIR system admin executables [EPREFIX/sbin]
--libexecdir=DIR program executables [EPREFIX/libexec]
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
--datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
--datadir=DIR read-only architecture-independent data [DATAROOTDIR]
--infodir=DIR info documentation [DATAROOTDIR/info]
--localedir=DIR locale-dependent data [DATAROOTDIR/locale]
--mandir=DIR man documentation [DATAROOTDIR/man]
--docdir=DIR documentation root [DATAROOTDIR/doc/openssh]
--htmldir=DIR html documentation [DOCDIR]
--dvidir=DIR dvi documentation [DOCDIR]
--pdfdir=DIR pdf documentation [DOCDIR]
--psdir=DIR ps documentation [DOCDIR]
_ACEOF
cat <<\_ACEOF
System types:
--build=BUILD configure for building on BUILD [guessed]
--host=HOST cross-compile to build programs to run on HOST [BUILD]
_ACEOF
fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of OpenSSH Portable:";;
esac
cat <<\_ACEOF
Optional Features:
--disable-option-checking ignore unrecognized --enable/--with options
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--disable-largefile omit support for large files
--disable-pkcs11 disable PKCS#11 support code [no]
--disable-security-key disable U2F/FIDO support code no
--disable-strip Disable calling strip(1) on install
--disable-etc-default-login Disable using PATH from /etc/default/login no
--disable-lastlog disable use of lastlog even if detected no
--disable-utmp disable use of utmp even if detected no
--disable-utmpx disable use of utmpx even if detected no
--disable-wtmp disable use of wtmp even if detected no
--disable-wtmpx disable use of wtmpx even if detected no
--disable-libutil disable use of libutil (login() etc.) no
--disable-pututline disable use of pututline() etc. (uwtmp) no
--disable-pututxline disable use of pututxline() etc. (uwtmpx) no
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--without-openssl Disable use of OpenSSL; use only limited internal crypto **EXPERIMENTAL**
--without-stackprotect Don't use compiler's stack protection
--without-hardening Don't use toolchain hardening flags
--without-rpath Disable auto-added -R linker paths
--with-cflags Specify additional flags to pass to compiler
--with-cflags-after Specify additional flags to pass to compiler after configure
--with-cppflags Specify additional flags to pass to preprocessor
--with-ldflags Specify additional flags to pass to linker
--with-ldflags-after Specify additional flags to pass to linker after configure
--with-libs Specify additional libraries to link with
--with-Werror Build main code with -Werror
--with-solaris-contracts Enable Solaris process contracts (experimental)
--with-solaris-projects Enable Solaris projects (experimental)
--with-solaris-privs Enable Solaris/Illumos privileges (experimental)
--with-osfsia Enable Digital Unix SIA
--with-zlib=PATH Use zlib in PATH
--without-zlib-version-check Disable zlib version check
--with-ldns[=PATH] Use ldns for DNSSEC support (optionally in PATH)
--with-libedit[=PATH] Enable libedit support for sftp
--with-audit=module Enable audit support (modules=debug,bsm,linux)
--with-pie Build Position Independent Executables if possible
--with-security-key-builtin include builtin U2F/FIDO support
--with-ssl-dir=PATH Specify path to OpenSSL installation
--without-openssl-header-check Disable OpenSSL version consistency check
--with-ssl-engine Enable OpenSSL (hardware) ENGINE support
--with-prngd-port=PORT read entropy from PRNGD/EGD TCP localhost:PORT
--with-prngd-socket=FILE read entropy from PRNGD/EGD socket FILE (default=/var/run/egd-pool)
--with-pam Enable PAM support
--with-pam-service=name Specify PAM service name
--with-privsep-user=user Specify non-privileged user for privilege separation
--with-sandbox=style Specify privilege separation sandbox (no, capsicum, darwin, rlimit, seccomp_filter, systrace, pledge)
--with-selinux Enable SELinux support
--with-kerberos5=PATH Enable Kerberos 5 support
--with-privsep-path=xxx Path for privilege separation chroot (default=/var/empty)
--with-xauth=PATH Specify path to xauth program
--with-maildir=/path/to/mail Specify your system mail directory
--with-mantype=man|cat|doc Set man page type
--without-shadow Disable shadow password support
--with-ipaddr-display Use ip address instead of hostname in $DISPLAY
--with-default-path= Specify default $PATH environment for server
--with-superuser-path= Specify different path for super-user
--with-4in6 Check for and convert IPv4 in IPv6 mapped addresses
--with-bsd-auth Enable BSD auth support
--with-pid-dir=PATH Specify location of sshd.pid file
--with-lastlog=FILE|DIR specify lastlog location common locations
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
Report bugs to <openssh-unix-dev@mindrot.org>.
_ACEOF
ac_status=$?
fi
if test "$ac_init_help" = "recursive"; then
# If there are subdirs, report their specific --help.
for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
test -d "$ac_dir" ||
{ cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
continue
ac_builddir=.
case "$ac_dir" in
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
*)
- ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
# A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
case $ac_top_builddir_sub in
"") ac_top_builddir_sub=. ac_top_build_prefix= ;;
*) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
esac ;;
esac
ac_abs_top_builddir=$ac_pwd
ac_abs_builddir=$ac_pwd$ac_dir_suffix
# for backward compatibility:
ac_top_builddir=$ac_top_build_prefix
case $srcdir in
.) # We are building in place.
ac_srcdir=.
ac_top_srcdir=$ac_top_builddir_sub
ac_abs_top_srcdir=$ac_pwd ;;
[\\/]* | ?:[\\/]* ) # Absolute name.
ac_srcdir=$srcdir$ac_dir_suffix;
ac_top_srcdir=$srcdir
ac_abs_top_srcdir=$srcdir ;;
*) # Relative name.
ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
ac_top_srcdir=$ac_top_build_prefix$srcdir
ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
esac
ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
cd "$ac_dir" || { ac_status=$?; continue; }
- # Check for guested configure.
+ # Check for configure.gnu first; this name is used for a wrapper for
+ # Metaconfig's "Configure" on case-insensitive file systems.
if test -f "$ac_srcdir/configure.gnu"; then
echo &&
$SHELL "$ac_srcdir/configure.gnu" --help=recursive
elif test -f "$ac_srcdir/configure"; then
echo &&
$SHELL "$ac_srcdir/configure" --help=recursive
else
- $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2
fi || ac_status=$?
cd "$ac_pwd" || { ac_status=$?; break; }
done
fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
OpenSSH configure Portable
-generated by GNU Autoconf 2.69
+generated by GNU Autoconf 2.71
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2021 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
exit
fi
## ------------------------ ##
## Autoconf initialization. ##
## ------------------------ ##
# ac_fn_c_try_compile LINENO
# --------------------------
# Try to compile conftest.$ac_ext, and return whether this succeeded.
ac_fn_c_try_compile ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext
+ rm -f conftest.$ac_objext conftest.beam
if { { ac_try="$ac_compile"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_compile") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
grep -v '^ *+' conftest.err >conftest.er1
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && {
test -z "$ac_c_werror_flag" ||
test ! -s conftest.err
- } && test -s conftest.$ac_objext; then :
+ } && test -s conftest.$ac_objext
+then :
ac_retval=0
-else
- $as_echo "$as_me: failed program was:" >&5
+else $as_nop
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
fi
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
as_fn_set_status $ac_retval
} # ac_fn_c_try_compile
# ac_fn_c_try_run LINENO
# ----------------------
-# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
-# that executables *can* be run.
+# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that
+# executables *can* be run.
ac_fn_c_try_run ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
if { { ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
{ { case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_try") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; }; then :
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }
+then :
ac_retval=0
-else
- $as_echo "$as_me: program exited with status $ac_status" >&5
- $as_echo "$as_me: failed program was:" >&5
+else $as_nop
+ printf "%s\n" "$as_me: program exited with status $ac_status" >&5
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=$ac_status
fi
rm -rf conftest.dSYM conftest_ipa8_conftest.oo
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
as_fn_set_status $ac_retval
} # ac_fn_c_try_run
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+printf %s "checking for $2... " >&6; }
+if eval test \${$3+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ eval "$3=yes"
+else $as_nop
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
# ac_fn_c_try_cpp LINENO
# ----------------------
# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
ac_fn_c_try_cpp ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
if { { ac_try="$ac_cpp conftest.$ac_ext"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
grep -v '^ *+' conftest.err >conftest.er1
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } > conftest.i && {
test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
test ! -s conftest.err
- }; then :
+ }
+then :
ac_retval=0
-else
- $as_echo "$as_me: failed program was:" >&5
+else $as_nop
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
fi
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
as_fn_set_status $ac_retval
} # ac_fn_c_try_cpp
-# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
-# -------------------------------------------------------
-# Tests whether HEADER exists and can be compiled using the include files in
-# INCLUDES, setting the cache variable VAR accordingly.
-ac_fn_c_check_header_compile ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-#include <$2>
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- eval "$3=yes"
-else
- eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_header_compile
-
-# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
-# ---------------------------------------------
+# ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR
+# ------------------------------------------------------------------
# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
-# accordingly.
-ac_fn_c_check_decl ()
+# accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR.
+ac_fn_check_decl ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
as_decl_name=`echo $2|sed 's/ *(.*//'`
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+printf %s "checking whether $as_decl_name is declared... " >&6; }
+if eval test \${$3+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
-$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ eval ac_save_FLAGS=\$$6
+ as_fn_append $6 " $5"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
int
-main ()
+main (void)
{
#ifndef $as_decl_name
#ifdef __cplusplus
(void) $as_decl_use;
#else
(void) $as_decl_name;
#endif
#endif
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
eval "$3=yes"
-else
+else $as_nop
eval "$3=no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ eval $6=\$ac_save_FLAGS
+
fi
eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-} # ac_fn_c_check_decl
+} # ac_fn_check_decl
# ac_fn_c_try_link LINENO
# -----------------------
# Try to link conftest.$ac_ext, and return whether this succeeded.
ac_fn_c_try_link ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext conftest$ac_exeext
+ rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext
if { { ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
grep -v '^ *+' conftest.err >conftest.er1
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && {
test -z "$ac_c_werror_flag" ||
test ! -s conftest.err
} && test -s conftest$ac_exeext && {
test "$cross_compiling" = yes ||
test -x conftest$ac_exeext
- }; then :
+ }
+then :
ac_retval=0
-else
- $as_echo "$as_me: failed program was:" >&5
+else $as_nop
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
fi
# Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
# created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
# interfere with the next link command; also delete a directory that is
# left behind by Apple's compiler. We do this before executing the actions.
rm -rf conftest.dSYM conftest_ipa8_conftest.oo
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
as_fn_set_status $ac_retval
} # ac_fn_c_try_link
-# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
-# -------------------------------------------------------
-# Tests whether HEADER exists, giving a warning if it cannot be compiled using
-# the include files in INCLUDES and setting the cache variable VAR
-# accordingly.
-ac_fn_c_check_header_mongrel ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- if eval \${$3+:} false; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-fi
-eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
- # Is the header compilable?
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
-$as_echo_n "checking $2 usability... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-#include <$2>
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_header_compiler=yes
-else
- ac_header_compiler=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
-$as_echo_n "checking $2 presence... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <$2>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
- ac_header_preproc=yes
-else
- ac_header_preproc=no
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So? What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
- yes:no: )
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
- ;;
- no:yes:* )
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
-( $as_echo "## ------------------------------------------- ##
-## Report this to openssh-unix-dev@mindrot.org ##
-## ------------------------------------------- ##"
- ) | sed "s/^/$as_me: WARNING: /" >&2
- ;;
-esac
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- eval "$3=\$ac_header_compiler"
-fi
-eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_header_mongrel
-
# ac_fn_c_check_func LINENO FUNC VAR
# ----------------------------------
# Tests whether FUNC exists, setting the cache variable VAR accordingly
ac_fn_c_check_func ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+printf %s "checking for $2... " >&6; }
+if eval test \${$3+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
For example, HP-UX 11i <limits.h> declares gettimeofday. */
#define $2 innocuous_$2
/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char $2 (); below.
- Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
- <limits.h> exists even on freestanding compilers. */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
+ which can conflict with char $2 (); below. */
+#include <limits.h>
#undef $2
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char $2 ();
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
#if defined __stub_$2 || defined __stub___$2
choke me
#endif
int
-main ()
+main (void)
{
return $2 ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
eval "$3=yes"
-else
+else $as_nop
eval "$3=no"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_func
# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
# -------------------------------------------
# Tests whether TYPE exists after having included INCLUDES, setting cache
# variable VAR accordingly.
ac_fn_c_check_type ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+printf %s "checking for $2... " >&6; }
+if eval test \${$3+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
eval "$3=no"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
int
-main ()
+main (void)
{
if (sizeof ($2))
return 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
int
-main ()
+main (void)
{
if (sizeof (($2)))
return 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
-else
+else $as_nop
eval "$3=yes"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_type
# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
# ----------------------------------------------------
# Tries to find if the field MEMBER exists in type AGGR, after including
# INCLUDES, setting cache variable VAR accordingly.
ac_fn_c_check_member ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
-$as_echo_n "checking for $2.$3... " >&6; }
-if eval \${$4+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
+printf %s "checking for $2.$3... " >&6; }
+if eval test \${$4+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$5
int
-main ()
+main (void)
{
static $2 ac_aggr;
if (ac_aggr.$3)
return 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
eval "$4=yes"
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$5
int
-main ()
+main (void)
{
static $2 ac_aggr;
if (sizeof ac_aggr.$3)
return 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
eval "$4=yes"
-else
+else $as_nop
eval "$4=no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
eval ac_res=\$$4
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_member
# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES
# --------------------------------------------
# Tries to find the compile-time value of EXPR in a program that includes
# INCLUDES, setting VAR accordingly. Returns whether the value could be
# computed
ac_fn_c_compute_int ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
if test "$cross_compiling" = yes; then
# Depending upon the size, compute the lo and hi bounds.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
int
-main ()
+main (void)
{
static int test_array [1 - 2 * !(($2) >= 0)];
test_array [0] = 0;
return test_array [0];
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_lo=0 ac_mid=0
while :; do
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
int
-main ()
+main (void)
{
static int test_array [1 - 2 * !(($2) <= $ac_mid)];
test_array [0] = 0;
return test_array [0];
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_hi=$ac_mid; break
-else
+else $as_nop
as_fn_arith $ac_mid + 1 && ac_lo=$as_val
if test $ac_lo -le $ac_mid; then
ac_lo= ac_hi=
break
fi
as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
done
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
int
-main ()
+main (void)
{
static int test_array [1 - 2 * !(($2) < 0)];
test_array [0] = 0;
return test_array [0];
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_hi=-1 ac_mid=-1
while :; do
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
int
-main ()
+main (void)
{
static int test_array [1 - 2 * !(($2) >= $ac_mid)];
test_array [0] = 0;
return test_array [0];
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_lo=$ac_mid; break
-else
+else $as_nop
as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val
if test $ac_mid -le $ac_hi; then
ac_lo= ac_hi=
break
fi
as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
done
-else
+else $as_nop
ac_lo= ac_hi=
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
# Binary search between lo and hi bounds.
while test "x$ac_lo" != "x$ac_hi"; do
as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
int
-main ()
+main (void)
{
static int test_array [1 - 2 * !(($2) <= $ac_mid)];
test_array [0] = 0;
return test_array [0];
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_hi=$ac_mid
-else
+else $as_nop
as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
done
case $ac_lo in #((
?*) eval "$3=\$ac_lo"; ac_retval=0 ;;
'') ac_retval=1 ;;
esac
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
-static long int longval () { return $2; }
-static unsigned long int ulongval () { return $2; }
+static long int longval (void) { return $2; }
+static unsigned long int ulongval (void) { return $2; }
#include <stdio.h>
#include <stdlib.h>
int
-main ()
+main (void)
{
FILE *f = fopen ("conftest.val", "w");
if (! f)
return 1;
if (($2) < 0)
{
long int i = longval ();
if (i != ($2))
return 1;
fprintf (f, "%ld", i);
}
else
{
unsigned long int i = ulongval ();
if (i != ($2))
return 1;
fprintf (f, "%lu", i);
}
/* Do not output a trailing newline, as this causes \r\n confusion
on some platforms. */
return ferror (f) || fclose (f) != 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_run "$LINENO"
+then :
echo >>conftest.val; read $3 <conftest.val; ac_retval=0
-else
+else $as_nop
ac_retval=1
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
rm -f conftest.val
fi
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
as_fn_set_status $ac_retval
} # ac_fn_c_compute_int
+ac_configure_args_raw=
+for ac_arg
+do
+ case $ac_arg in
+ *\'*)
+ ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append ac_configure_args_raw " '$ac_arg'"
+done
+
+case $ac_configure_args_raw in
+ *$as_nl*)
+ ac_safe_unquote= ;;
+ *)
+ ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab.
+ ac_unsafe_a="$ac_unsafe_z#~"
+ ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g"
+ ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;;
+esac
+
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by OpenSSH $as_me Portable, which was
-generated by GNU Autoconf 2.69. Invocation command line was
+generated by GNU Autoconf 2.71. Invocation command line was
- $ $0 $@
+ $ $0$ac_configure_args_raw
_ACEOF
exec 5>>config.log
{
cat <<_ASUNAME
## --------- ##
## Platform. ##
## --------- ##
hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
uname -m = `(uname -m) 2>/dev/null || echo unknown`
uname -r = `(uname -r) 2>/dev/null || echo unknown`
uname -s = `(uname -s) 2>/dev/null || echo unknown`
uname -v = `(uname -v) 2>/dev/null || echo unknown`
/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
_ASUNAME
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- $as_echo "PATH: $as_dir"
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ printf "%s\n" "PATH: $as_dir"
done
IFS=$as_save_IFS
} >&5
cat >&5 <<_ACEOF
## ----------- ##
## Core tests. ##
## ----------- ##
_ACEOF
# Keep a trace of the command line.
# Strip out --no-create and --no-recursion so they do not pile up.
# Strip out --silent because we don't want to record it for future runs.
# Also quote any args containing shell meta-characters.
# Make two passes to allow for proper duplicate-argument suppression.
ac_configure_args=
ac_configure_args0=
ac_configure_args1=
ac_must_keep_next=false
for ac_pass in 1 2
do
for ac_arg
do
case $ac_arg in
-no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
-q | -quiet | --quiet | --quie | --qui | --qu | --q \
| -silent | --silent | --silen | --sile | --sil)
continue ;;
*\'*)
- ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
esac
case $ac_pass in
1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
2)
as_fn_append ac_configure_args1 " '$ac_arg'"
if test $ac_must_keep_next = true; then
ac_must_keep_next=false # Got value, back to normal.
else
case $ac_arg in
*=* | --config-cache | -C | -disable-* | --disable-* \
| -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
| -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
| -with-* | --with-* | -without-* | --without-* | --x)
case "$ac_configure_args0 " in
"$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
esac
;;
-* ) ac_must_keep_next=true ;;
esac
fi
as_fn_append ac_configure_args " '$ac_arg'"
;;
esac
done
done
{ ac_configure_args0=; unset ac_configure_args0;}
{ ac_configure_args1=; unset ac_configure_args1;}
# When interrupted or exit'd, cleanup temporary files, and complete
# config.log. We remove comments because anyway the quotes in there
# would cause problems or look ugly.
# WARNING: Use '\'' to represent an apostrophe within the trap.
# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
trap 'exit_status=$?
+ # Sanitize IFS.
+ IFS=" "" $as_nl"
# Save into config.log some information that might help in debugging.
{
echo
- $as_echo "## ---------------- ##
+ printf "%s\n" "## ---------------- ##
## Cache variables. ##
## ---------------- ##"
echo
# The following way of writing the cache mishandles newlines in values,
(
for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
eval ac_val=\$$ac_var
case $ac_val in #(
*${as_nl}*)
case $ac_var in #(
- *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
esac
case $ac_var in #(
_ | IFS | as_nl) ;; #(
BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
*) { eval $ac_var=; unset $ac_var;} ;;
esac ;;
esac
done
(set) 2>&1 |
case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
*${as_nl}ac_space=\ *)
sed -n \
"s/'\''/'\''\\\\'\'''\''/g;
s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
;; #(
*)
sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
;;
esac |
sort
)
echo
- $as_echo "## ----------------- ##
+ printf "%s\n" "## ----------------- ##
## Output variables. ##
## ----------------- ##"
echo
for ac_var in $ac_subst_vars
do
eval ac_val=\$$ac_var
case $ac_val in
- *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
esac
- $as_echo "$ac_var='\''$ac_val'\''"
+ printf "%s\n" "$ac_var='\''$ac_val'\''"
done | sort
echo
if test -n "$ac_subst_files"; then
- $as_echo "## ------------------- ##
+ printf "%s\n" "## ------------------- ##
## File substitutions. ##
## ------------------- ##"
echo
for ac_var in $ac_subst_files
do
eval ac_val=\$$ac_var
case $ac_val in
- *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
esac
- $as_echo "$ac_var='\''$ac_val'\''"
+ printf "%s\n" "$ac_var='\''$ac_val'\''"
done | sort
echo
fi
if test -s confdefs.h; then
- $as_echo "## ----------- ##
+ printf "%s\n" "## ----------- ##
## confdefs.h. ##
## ----------- ##"
echo
cat confdefs.h
echo
fi
test "$ac_signal" != 0 &&
- $as_echo "$as_me: caught signal $ac_signal"
- $as_echo "$as_me: exit $exit_status"
+ printf "%s\n" "$as_me: caught signal $ac_signal"
+ printf "%s\n" "$as_me: exit $exit_status"
} >&5
rm -f core *.core core.conftest.* &&
rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
exit $exit_status
' 0
for ac_signal in 1 2 13 15; do
trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
done
ac_signal=0
# confdefs.h avoids OS command line length limits that DEFS can exceed.
rm -f -r conftest* confdefs.h
-$as_echo "/* confdefs.h */" > confdefs.h
+printf "%s\n" "/* confdefs.h */" > confdefs.h
# Predefined preprocessor variables.
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_NAME "$PACKAGE_NAME"
-_ACEOF
+printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
-_ACEOF
+printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_VERSION "$PACKAGE_VERSION"
-_ACEOF
+printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_STRING "$PACKAGE_STRING"
-_ACEOF
+printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
-_ACEOF
+printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_URL "$PACKAGE_URL"
-_ACEOF
+printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h
# Let the site file select an alternate cache file if it wants to.
# Prefer an explicitly selected file to automatically selected ones.
-ac_site_file1=NONE
-ac_site_file2=NONE
if test -n "$CONFIG_SITE"; then
- # We do not want a PATH search for config.site.
- case $CONFIG_SITE in #((
- -*) ac_site_file1=./$CONFIG_SITE;;
- */*) ac_site_file1=$CONFIG_SITE;;
- *) ac_site_file1=./$CONFIG_SITE;;
- esac
+ ac_site_files="$CONFIG_SITE"
elif test "x$prefix" != xNONE; then
- ac_site_file1=$prefix/share/config.site
- ac_site_file2=$prefix/etc/config.site
+ ac_site_files="$prefix/share/config.site $prefix/etc/config.site"
else
- ac_site_file1=$ac_default_prefix/share/config.site
- ac_site_file2=$ac_default_prefix/etc/config.site
+ ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
fi
-for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+
+for ac_site_file in $ac_site_files
do
- test "x$ac_site_file" = xNONE && continue
- if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
-$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ case $ac_site_file in #(
+ */*) :
+ ;; #(
+ *) :
+ ac_site_file=./$ac_site_file ;;
+esac
+ if test -f "$ac_site_file" && test -r "$ac_site_file"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;}
sed 's/^/| /' "$ac_site_file" >&5
. "$ac_site_file" \
- || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "failed to load site script $ac_site_file
See \`config.log' for more details" "$LINENO" 5; }
fi
done
if test -r "$cache_file"; then
# Some versions of bash will fail to source /dev/null (special files
# actually), so we avoid doing that. DJGPP emulates it as a regular file.
if test /dev/null != "$cache_file" && test -f "$cache_file"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
-$as_echo "$as_me: loading cache $cache_file" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+printf "%s\n" "$as_me: loading cache $cache_file" >&6;}
case $cache_file in
[\\/]* | ?:[\\/]* ) . "$cache_file";;
*) . "./$cache_file";;
esac
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
-$as_echo "$as_me: creating cache $cache_file" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+printf "%s\n" "$as_me: creating cache $cache_file" >&6;}
>$cache_file
fi
-# Check that the precious variables saved in the cache have kept the same
-# value.
-ac_cache_corrupted=false
-for ac_var in $ac_precious_vars; do
- eval ac_old_set=\$ac_cv_env_${ac_var}_set
- eval ac_new_set=\$ac_env_${ac_var}_set
- eval ac_old_val=\$ac_cv_env_${ac_var}_value
- eval ac_new_val=\$ac_env_${ac_var}_value
- case $ac_old_set,$ac_new_set in
- set,)
- { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
-$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
- ac_cache_corrupted=: ;;
- ,set)
- { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
-$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
- ac_cache_corrupted=: ;;
- ,);;
- *)
- if test "x$ac_old_val" != "x$ac_new_val"; then
- # differences in whitespace do not lead to failure.
- ac_old_val_w=`echo x $ac_old_val`
- ac_new_val_w=`echo x $ac_new_val`
- if test "$ac_old_val_w" != "$ac_new_val_w"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
-$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
- ac_cache_corrupted=:
- else
- { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
-$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
- eval $ac_var=\$ac_old_val
- fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
-$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
-$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
- fi;;
- esac
- # Pass precious variables to config.status.
- if test "$ac_new_set" = set; then
- case $ac_new_val in
- *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
- *) ac_arg=$ac_var=$ac_new_val ;;
- esac
- case " $ac_configure_args " in
- *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
- *) as_fn_append ac_configure_args " '$ac_arg'" ;;
- esac
- fi
-done
-if $ac_cache_corrupted; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
-$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
- as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
-fi
-## -------------------- ##
-## Main body of script. ##
-## -------------------- ##
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
+# Test code for whether the C compiler supports C89 (global declarations)
+ac_c_conftest_c89_globals='
+/* Does the compiler advertise C89 conformance?
+ Do not test the value of __STDC__, because some compilers set it to 0
+ while being otherwise adequately conformant. */
+#if !defined __STDC__
+# error "Compiler does not advertise C89 conformance"
+#endif
+
+#include <stddef.h>
+#include <stdarg.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */
+struct buf { int x; };
+struct buf * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not \xHH hex character constants.
+ These do not provoke an error unfortunately, instead are silently treated
+ as an "x". The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously \x00 != x always comes out true, for an
+ array size at least. It is necessary to write \x00 == 0 to get something
+ that is true only with -std. */
+int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) '\''x'\''
+int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int),
+ int, int);'
+
+# Test code for whether the C compiler supports C89 (body of main).
+ac_c_conftest_c89_main='
+ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]);
+'
+
+# Test code for whether the C compiler supports C99 (global declarations)
+ac_c_conftest_c99_globals='
+// Does the compiler advertise C99 conformance?
+#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
+# error "Compiler does not advertise C99 conformance"
+#endif
+
+#include <stdbool.h>
+extern int puts (const char *);
+extern int printf (const char *, ...);
+extern int dprintf (int, const char *, ...);
+extern void *malloc (size_t);
+
+// Check varargs macros. These examples are taken from C99 6.10.3.5.
+// dprintf is used instead of fprintf to avoid needing to declare
+// FILE and stderr.
+#define debug(...) dprintf (2, __VA_ARGS__)
+#define showlist(...) puts (#__VA_ARGS__)
+#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
+static void
+test_varargs_macros (void)
+{
+ int x = 1234;
+ int y = 5678;
+ debug ("Flag");
+ debug ("X = %d\n", x);
+ showlist (The first, second, and third items.);
+ report (x>y, "x is %d but y is %d", x, y);
+}
+
+// Check long long types.
+#define BIG64 18446744073709551615ull
+#define BIG32 4294967295ul
+#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
+#if !BIG_OK
+ #error "your preprocessor is broken"
+#endif
+#if BIG_OK
+#else
+ #error "your preprocessor is broken"
+#endif
+static long long int bignum = -9223372036854775807LL;
+static unsigned long long int ubignum = BIG64;
+
+struct incomplete_array
+{
+ int datasize;
+ double data[];
+};
+
+struct named_init {
+ int number;
+ const wchar_t *name;
+ double average;
+};
+
+typedef const char *ccp;
+
+static inline int
+test_restrict (ccp restrict text)
+{
+ // See if C++-style comments work.
+ // Iterate through items via the restricted pointer.
+ // Also check for declarations in for loops.
+ for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i)
+ continue;
+ return 0;
+}
+
+// Check varargs and va_copy.
+static bool
+test_varargs (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_list args_copy;
+ va_copy (args_copy, args);
+
+ const char *str = "";
+ int number = 0;
+ float fnumber = 0;
+
+ while (*format)
+ {
+ switch (*format++)
+ {
+ case '\''s'\'': // string
+ str = va_arg (args_copy, const char *);
+ break;
+ case '\''d'\'': // int
+ number = va_arg (args_copy, int);
+ break;
+ case '\''f'\'': // float
+ fnumber = va_arg (args_copy, double);
+ break;
+ default:
+ break;
+ }
+ }
+ va_end (args_copy);
+ va_end (args);
+
+ return *str && number && fnumber;
+}
+'
+
+# Test code for whether the C compiler supports C99 (body of main).
+ac_c_conftest_c99_main='
+ // Check bool.
+ _Bool success = false;
+ success |= (argc != 0);
+
+ // Check restrict.
+ if (test_restrict ("String literal") == 0)
+ success = true;
+ char *restrict newvar = "Another string";
+
+ // Check varargs.
+ success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234);
+ test_varargs_macros ();
+
+ // Check flexible array members.
+ struct incomplete_array *ia =
+ malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
+ ia->datasize = 10;
+ for (int i = 0; i < ia->datasize; ++i)
+ ia->data[i] = i * 1.234;
+
+ // Check named initializers.
+ struct named_init ni = {
+ .number = 34,
+ .name = L"Test wide string",
+ .average = 543.34343,
+ };
+
+ ni.number = 58;
+
+ int dynamic_array[ni.number];
+ dynamic_array[0] = argv[0][0];
+ dynamic_array[ni.number - 1] = 543;
+
+ // work around unused variable warnings
+ ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\''
+ || dynamic_array[ni.number - 1] != 543);
+'
+
+# Test code for whether the C compiler supports C11 (global declarations)
+ac_c_conftest_c11_globals='
+// Does the compiler advertise C11 conformance?
+#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
+# error "Compiler does not advertise C11 conformance"
+#endif
+
+// Check _Alignas.
+char _Alignas (double) aligned_as_double;
+char _Alignas (0) no_special_alignment;
+extern char aligned_as_int;
+char _Alignas (0) _Alignas (int) aligned_as_int;
+
+// Check _Alignof.
+enum
+{
+ int_alignment = _Alignof (int),
+ int_array_alignment = _Alignof (int[100]),
+ char_alignment = _Alignof (char)
+};
+_Static_assert (0 < -_Alignof (int), "_Alignof is signed");
+
+// Check _Noreturn.
+int _Noreturn does_not_return (void) { for (;;) continue; }
+
+// Check _Static_assert.
+struct test_static_assert
+{
+ int x;
+ _Static_assert (sizeof (int) <= sizeof (long int),
+ "_Static_assert does not work in struct");
+ long int y;
+};
+
+// Check UTF-8 literals.
+#define u8 syntax error!
+char const utf8_literal[] = u8"happens to be ASCII" "another string";
+
+// Check duplicate typedefs.
+typedef long *long_ptr;
+typedef long int *long_ptr;
+typedef long_ptr long_ptr;
+
+// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1.
+struct anonymous
+{
+ union {
+ struct { int i; int j; };
+ struct { int k; long int l; } w;
+ };
+ int m;
+} v1;
+'
+
+# Test code for whether the C compiler supports C11 (body of main).
+ac_c_conftest_c11_main='
+ _Static_assert ((offsetof (struct anonymous, i)
+ == offsetof (struct anonymous, w.k)),
+ "Anonymous union alignment botch");
+ v1.i = 2;
+ v1.w.k = 5;
+ ok |= v1.i != 5;
+'
+
+# Test code for whether the C compiler supports C11 (complete).
+ac_c_conftest_c11_program="${ac_c_conftest_c89_globals}
+${ac_c_conftest_c99_globals}
+${ac_c_conftest_c11_globals}
+
+int
+main (int argc, char **argv)
+{
+ int ok = 0;
+ ${ac_c_conftest_c89_main}
+ ${ac_c_conftest_c99_main}
+ ${ac_c_conftest_c11_main}
+ return ok;
+}
+"
+
+# Test code for whether the C compiler supports C99 (complete).
+ac_c_conftest_c99_program="${ac_c_conftest_c89_globals}
+${ac_c_conftest_c99_globals}
+
+int
+main (int argc, char **argv)
+{
+ int ok = 0;
+ ${ac_c_conftest_c89_main}
+ ${ac_c_conftest_c99_main}
+ return ok;
+}
+"
+
+# Test code for whether the C compiler supports C89 (complete).
+ac_c_conftest_c89_program="${ac_c_conftest_c89_globals}
+
+int
+main (int argc, char **argv)
+{
+ int ok = 0;
+ ${ac_c_conftest_c89_main}
+ return ok;
+}
+"
+
+as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H"
+as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H"
+as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H"
+as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H"
+as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H"
+as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H"
+as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H"
+as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H"
+as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H"
+
+# Auxiliary files required by this configure script.
+ac_aux_files="install-sh config.guess config.sub"
+
+# Locations in which to look for auxiliary files.
+ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.."
+
+# Search for a directory containing all of the required auxiliary files,
+# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates.
+# If we don't find one directory that contains all the files we need,
+# we report the set of missing files from the *first* directory in
+# $ac_aux_dir_candidates and give up.
+ac_missing_aux_files=""
+ac_first_candidate=:
+printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in $ac_aux_dir_candidates
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ as_found=:
+
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5
+ ac_aux_dir_found=yes
+ ac_install_sh=
+ for ac_aux in $ac_aux_files
+ do
+ # As a special case, if "install-sh" is required, that requirement
+ # can be satisfied by any of "install-sh", "install.sh", or "shtool",
+ # and $ac_install_sh is set appropriately for whichever one is found.
+ if test x"$ac_aux" = x"install-sh"
+ then
+ if test -f "${as_dir}install-sh"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5
+ ac_install_sh="${as_dir}install-sh -c"
+ elif test -f "${as_dir}install.sh"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5
+ ac_install_sh="${as_dir}install.sh -c"
+ elif test -f "${as_dir}shtool"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5
+ ac_install_sh="${as_dir}shtool install -c"
+ else
+ ac_aux_dir_found=no
+ if $ac_first_candidate; then
+ ac_missing_aux_files="${ac_missing_aux_files} install-sh"
+ else
+ break
+ fi
+ fi
+ else
+ if test -f "${as_dir}${ac_aux}"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5
+ else
+ ac_aux_dir_found=no
+ if $ac_first_candidate; then
+ ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}"
+ else
+ break
+ fi
+ fi
+ fi
+ done
+ if test "$ac_aux_dir_found" = yes; then
+ ac_aux_dir="$as_dir"
+ break
+ fi
+ ac_first_candidate=false
+
+ as_found=false
+done
+IFS=$as_save_IFS
+if $as_found
+then :
+
+else $as_nop
+ as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5
+fi
+
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+if test -f "${ac_aux_dir}config.guess"; then
+ ac_config_guess="$SHELL ${ac_aux_dir}config.guess"
+fi
+if test -f "${ac_aux_dir}config.sub"; then
+ ac_config_sub="$SHELL ${ac_aux_dir}config.sub"
+fi
+if test -f "$ac_aux_dir/configure"; then
+ ac_configure="$SHELL ${ac_aux_dir}configure"
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file'
+ and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+# Check for stale configure as early as possible.
+for i in $srcdir/configure.ac $srcdir/m4/*.m4; do
+ if test "$i" -nt "$srcdir/configure"; then
+ as_fn_error $? "$i newer than configure, run autoreconf" "$LINENO" 5
+ fi
+done
+
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
ac_config_headers="$ac_config_headers config.h"
+
+
+
+
+
+
+
+
+
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
if test -n "$ac_tool_prefix"; then
for ac_prog in cc gcc clang
do
# Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
test -n "$CC" && break
done
fi
if test -z "$CC"; then
ac_ct_CC=$CC
for ac_prog in cc gcc clang
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_CC"; then
ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CC="$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+printf "%s\n" "$ac_ct_CC" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
test -n "$ac_ct_CC" && break
done
if test "x$ac_ct_CC" = x; then
CC=""
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
CC=$ac_ct_CC
fi
fi
-test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "no acceptable C compiler found in \$PATH
See \`config.log' for more details" "$LINENO" 5; }
# Provide some information about the compiler.
-$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
set X $ac_compile
ac_compiler=$2
-for ac_option in --version -v -V -qversion; do
+for ac_option in --version -v -V -qversion -version; do
{ { ac_try="$ac_compiler $ac_option >&5"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_compiler $ac_option >&5") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
done
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
# Try to create an executable without -o first, disregard a.out.
# It will help us diagnose broken compilers, and finding out an intuition
# of exeext.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
-$as_echo_n "checking whether the C compiler works... " >&6; }
-ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+printf %s "checking whether the C compiler works... " >&6; }
+ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
# The possible output files:
ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
ac_rmfiles=
for ac_file in $ac_files
do
case $ac_file in
*.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
* ) ac_rmfiles="$ac_rmfiles $ac_file";;
esac
done
rm -f $ac_rmfiles
if { { ac_try="$ac_link_default"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link_default") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then :
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+then :
# Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
# in a Makefile. We should not override ac_cv_exeext if it was cached,
# so that the user can short-circuit this test for compilers unknown to
# Autoconf.
for ac_file in $ac_files ''
do
test -f "$ac_file" || continue
case $ac_file in
*.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
;;
[ab].out )
# We found the default executable, but exeext='' is most
# certainly right.
break;;
*.* )
- if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no;
then :; else
ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
fi
# We set ac_cv_exeext here because the later test for it is not
# safe: cross compilers may not add the suffix if given an `-o'
# argument, so we may need to know it at that point already.
# Even if this section looks crufty: it has the advantage of
# actually working.
break;;
* )
break;;
esac
done
test "$ac_cv_exeext" = no && ac_cv_exeext=
-else
+else $as_nop
ac_file=''
fi
-if test -z "$ac_file"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-$as_echo "$as_me: failed program was:" >&5
+if test -z "$ac_file"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
-{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "C compiler cannot create executables
See \`config.log' for more details" "$LINENO" 5; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
-$as_echo_n "checking for C compiler default output file name... " >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
-$as_echo "$ac_file" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+printf %s "checking for C compiler default output file name... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+printf "%s\n" "$ac_file" >&6; }
ac_exeext=$ac_cv_exeext
rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
ac_clean_files=$ac_clean_files_save
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
-$as_echo_n "checking for suffix of executables... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+printf %s "checking for suffix of executables... " >&6; }
if { { ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then :
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+then :
# If both `conftest.exe' and `conftest' are `present' (well, observable)
# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
# work properly (i.e., refer to `conftest.exe'), while it won't with
# `rm'.
for ac_file in conftest.exe conftest conftest.*; do
test -f "$ac_file" || continue
case $ac_file in
*.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
*.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
break;;
* ) break;;
esac
done
-else
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+else $as_nop
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot compute suffix of executables: cannot compile and link
See \`config.log' for more details" "$LINENO" 5; }
fi
rm -f conftest conftest$ac_cv_exeext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
-$as_echo "$ac_cv_exeext" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+printf "%s\n" "$ac_cv_exeext" >&6; }
rm -f conftest.$ac_ext
EXEEXT=$ac_cv_exeext
ac_exeext=$EXEEXT
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
int
-main ()
+main (void)
{
FILE *f = fopen ("conftest.out", "w");
return ferror (f) || fclose (f) != 0;
;
return 0;
}
_ACEOF
ac_clean_files="$ac_clean_files conftest.out"
# Check that the compiler produces executables we can run. If not, either
# the compiler is broken, or we cross compile.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
-$as_echo_n "checking whether we are cross compiling... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+printf %s "checking whether we are cross compiling... " >&6; }
if test "$cross_compiling" != yes; then
{ { ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
if { ac_try='./conftest$ac_cv_exeext'
{ { case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_try") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; }; then
cross_compiling=no
else
if test "$cross_compiling" = maybe; then
cross_compiling=yes
else
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot run C compiled programs.
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot run C compiled programs.
If you meant to cross compile, use \`--host'.
See \`config.log' for more details" "$LINENO" 5; }
fi
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
-$as_echo "$cross_compiling" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+printf "%s\n" "$cross_compiling" >&6; }
rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
ac_clean_files=$ac_clean_files_save
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
-$as_echo_n "checking for suffix of object files... " >&6; }
-if ${ac_cv_objext+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+printf %s "checking for suffix of object files... " >&6; }
+if test ${ac_cv_objext+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
rm -f conftest.o conftest.obj
if { { ac_try="$ac_compile"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_compile") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then :
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+then :
for ac_file in conftest.o conftest.obj conftest.*; do
test -f "$ac_file" || continue;
case $ac_file in
*.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
*) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
break;;
esac
done
-else
- $as_echo "$as_me: failed program was:" >&5
+else $as_nop
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
-{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot compute suffix of object files: cannot compile
See \`config.log' for more details" "$LINENO" 5; }
fi
rm -f conftest.$ac_cv_objext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
-$as_echo "$ac_cv_objext" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+printf "%s\n" "$ac_cv_objext" >&6; }
OBJEXT=$ac_cv_objext
ac_objext=$OBJEXT
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
-$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if ${ac_cv_c_compiler_gnu+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5
+printf %s "checking whether the compiler supports GNU C... " >&6; }
+if test ${ac_cv_c_compiler_gnu+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
#ifndef __GNUC__
choke me
#endif
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_compiler_gnu=yes
-else
+else $as_nop
ac_compiler_gnu=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
ac_cv_c_compiler_gnu=$ac_compiler_gnu
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
-$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; }
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
if test $ac_compiler_gnu = yes; then
GCC=yes
else
GCC=
fi
-ac_test_CFLAGS=${CFLAGS+set}
+ac_test_CFLAGS=${CFLAGS+y}
ac_save_CFLAGS=$CFLAGS
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-$as_echo_n "checking whether $CC accepts -g... " >&6; }
-if ${ac_cv_prog_cc_g+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+printf %s "checking whether $CC accepts -g... " >&6; }
+if test ${ac_cv_prog_cc_g+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_save_c_werror_flag=$ac_c_werror_flag
ac_c_werror_flag=yes
ac_cv_prog_cc_g=no
CFLAGS="-g"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_prog_cc_g=yes
-else
+else $as_nop
CFLAGS=""
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
-else
+else $as_nop
ac_c_werror_flag=$ac_save_c_werror_flag
CFLAGS="-g"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_prog_cc_g=yes
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
ac_c_werror_flag=$ac_save_c_werror_flag
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
-$as_echo "$ac_cv_prog_cc_g" >&6; }
-if test "$ac_test_CFLAGS" = set; then
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+printf "%s\n" "$ac_cv_prog_cc_g" >&6; }
+if test $ac_test_CFLAGS; then
CFLAGS=$ac_save_CFLAGS
elif test $ac_cv_prog_cc_g = yes; then
if test "$GCC" = yes; then
CFLAGS="-g -O2"
else
CFLAGS="-g"
fi
else
if test "$GCC" = yes; then
CFLAGS="-O2"
else
CFLAGS=
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
-$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if ${ac_cv_prog_cc_c89+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_cv_prog_cc_c89=no
+ac_prog_cc_stdc=no
+if test x$ac_prog_cc_stdc = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5
+printf %s "checking for $CC option to enable C11 features... " >&6; }
+if test ${ac_cv_prog_cc_c11+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_prog_cc_c11=no
ac_save_CC=$CC
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#include <stdarg.h>
-#include <stdio.h>
-struct stat;
-/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
-struct buf { int x; };
-FILE * (*rcsopen) (struct buf *, struct stat *, int);
-static char *e (p, i)
- char **p;
- int i;
-{
- return p[i];
-}
-static char *f (char * (*g) (char **, int), char **p, ...)
-{
- char *s;
- va_list v;
- va_start (v,p);
- s = g (p, va_arg (v,int));
- va_end (v);
- return s;
-}
-
-/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
- function prototypes and stuff, but not '\xHH' hex character constants.
- These don't provoke an error unfortunately, instead are silently treated
- as 'x'. The following induces an error, until -std is added to get
- proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
- array size at least. It's necessary to write '\x00'==0 to get something
- that's true only with -std. */
-int osf4_cc_array ['\x00' == 0 ? 1 : -1];
-
-/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
- inside strings and character constants. */
-#define FOO(x) 'x'
-int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
-
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};
-int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
-int argc;
-char **argv;
-int
-main ()
-{
-return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
- ;
- return 0;
-}
+$ac_c_conftest_c11_program
_ACEOF
-for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
- -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+for ac_arg in '' -std=gnu11
do
CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_c89=$ac_arg
+ if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_prog_cc_c11=$ac_arg
fi
-rm -f core conftest.err conftest.$ac_objext
- test "x$ac_cv_prog_cc_c89" != "xno" && break
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+ test "x$ac_cv_prog_cc_c11" != "xno" && break
done
rm -f conftest.$ac_ext
CC=$ac_save_CC
-
-fi
-# AC_CACHE_VAL
-case "x$ac_cv_prog_cc_c89" in
- x)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-$as_echo "none needed" >&6; } ;;
- xno)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-$as_echo "unsupported" >&6; } ;;
- *)
- CC="$CC $ac_cv_prog_cc_c89"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
-esac
-if test "x$ac_cv_prog_cc_c89" != xno; then :
-
fi
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-# XXX relax this after reimplementing logit() etc.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports C99-style variadic macros" >&5
-$as_echo_n "checking if $CC supports C99-style variadic macros... " >&6; }
-
+if test "x$ac_cv_prog_cc_c11" = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; }
+else $as_nop
+ if test "x$ac_cv_prog_cc_c11" = x
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5
+printf "%s\n" "$ac_cv_prog_cc_c11" >&6; }
+ CC="$CC $ac_cv_prog_cc_c11"
+fi
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11
+ ac_prog_cc_stdc=c11
+fi
+fi
+if test x$ac_prog_cc_stdc = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5
+printf %s "checking for $CC option to enable C99 features... " >&6; }
+if test ${ac_cv_prog_cc_c99+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_prog_cc_c99=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_c_conftest_c99_program
+_ACEOF
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99=
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_prog_cc_c99=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+ test "x$ac_cv_prog_cc_c99" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+fi
+
+if test "x$ac_cv_prog_cc_c99" = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; }
+else $as_nop
+ if test "x$ac_cv_prog_cc_c99" = x
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+printf "%s\n" "$ac_cv_prog_cc_c99" >&6; }
+ CC="$CC $ac_cv_prog_cc_c99"
+fi
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
+ ac_prog_cc_stdc=c99
+fi
+fi
+if test x$ac_prog_cc_stdc = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5
+printf %s "checking for $CC option to enable C89 features... " >&6; }
+if test ${ac_cv_prog_cc_c89+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_c_conftest_c89_program
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+fi
+
+if test "x$ac_cv_prog_cc_c89" = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; }
+else $as_nop
+ if test "x$ac_cv_prog_cc_c89" = x
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+printf "%s\n" "$ac_cv_prog_cc_c89" >&6; }
+ CC="$CC $ac_cv_prog_cc_c89"
+fi
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
+ ac_prog_cc_stdc=c89
+fi
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# XXX relax this after reimplementing logit() etc.
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports C99-style variadic macros" >&5
+printf %s "checking if $CC supports C99-style variadic macros... " >&6; }
+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int f(int a, int b, int c) { return a + b + c; }
#define F(a, ...) f(a, __VA_ARGS__)
int
-main ()
+main (void)
{
return F(1, 2, -3);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
as_fn_error $? "*** OpenSSH requires support for C99-style variadic macros" "$LINENO" 5
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-ac_aux_dir=
-for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
- if test -f "$ac_dir/install-sh"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install-sh -c"
- break
- elif test -f "$ac_dir/install.sh"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install.sh -c"
- break
- elif test -f "$ac_dir/shtool"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/shtool install -c"
- break
- fi
-done
-if test -z "$ac_aux_dir"; then
- as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
-fi
-# These three variables are undocumented and unsupported,
-# and are intended to be withdrawn in a future Autoconf release.
-# They can cause serious problems if a builder's source tree is in a directory
-# whose full name contains unusual characters.
-ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
-ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
-ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
-# Make sure we can run config.sub.
-$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
- as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+ # Make sure we can run config.sub.
+$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
-$as_echo_n "checking build system type... " >&6; }
-if ${ac_cv_build+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+printf %s "checking build system type... " >&6; }
+if test ${ac_cv_build+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_build_alias=$build_alias
test "x$ac_build_alias" = x &&
- ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+ ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"`
test "x$ac_build_alias" = x &&
as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
-ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
- as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
-$as_echo "$ac_cv_build" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+printf "%s\n" "$ac_cv_build" >&6; }
case $ac_cv_build in
*-*-*) ;;
*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
esac
build=$ac_cv_build
ac_save_IFS=$IFS; IFS='-'
set x $ac_cv_build
shift
build_cpu=$1
build_vendor=$2
shift; shift
# Remember, the first character of IFS is used to create $*,
# except with old shells:
build_os=$*
IFS=$ac_save_IFS
case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
-$as_echo_n "checking host system type... " >&6; }
-if ${ac_cv_host+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+printf %s "checking host system type... " >&6; }
+if test ${ac_cv_host+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test "x$host_alias" = x; then
ac_cv_host=$ac_cv_build
else
- ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
- as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+ ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
-$as_echo "$ac_cv_host" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+printf "%s\n" "$ac_cv_host" >&6; }
case $ac_cv_host in
*-*-*) ;;
*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
esac
host=$ac_cv_host
ac_save_IFS=$IFS; IFS='-'
set x $ac_cv_host
shift
host_cpu=$1
host_vendor=$2
shift; shift
# Remember, the first character of IFS is used to create $*,
# except with old shells:
host_os=$*
IFS=$ac_save_IFS
case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
-$as_echo_n "checking how to run the C preprocessor... " >&6; }
-# On Suns, sometimes $CPP names a directory.
-if test -n "$CPP" && test -d "$CPP"; then
- CPP=
-fi
-if test -z "$CPP"; then
- if ${ac_cv_prog_CPP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- # Double quotes because CPP needs to be expanded
- for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
- do
- ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
+ac_header= ac_cache=
+for ac_item in $ac_header_c_list
do
- # Use a header file that comes with gcc, so configuring glibc
- # with a fresh cross-compiler works.
- # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
- # <limits.h> exists even on freestanding compilers.
- # On the NeXT, cc -E runs the code through the compiler's parser,
- # not just through cpp. "Syntax error" is here to catch this case.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
- Syntax error
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
+ if test $ac_cache; then
+ ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default"
+ if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then
+ printf "%s\n" "#define $ac_item 1" >> confdefs.h
+ fi
+ ac_header= ac_cache=
+ elif test $ac_header; then
+ ac_cache=$ac_item
+ else
+ ac_header=$ac_item
+ fi
+done
-else
- # Broken: fails on valid input.
-continue
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
- # OK, works on sane cases. Now check whether nonexistent headers
- # can be detected and how.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <ac_nonexistent.h>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
- # Broken: success on invalid input.
-continue
-else
- # Passes both tests.
-ac_preproc_ok=:
-break
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then :
- break
-fi
- done
- ac_cv_prog_CPP=$CPP
+
+
+
+
+if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes
+then :
+
+printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
fi
- CPP=$ac_cv_prog_CPP
-else
- ac_cv_prog_CPP=$CPP
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
-$as_echo "$CPP" >&6; }
-ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
-do
- # Use a header file that comes with gcc, so configuring glibc
- # with a fresh cross-compiler works.
- # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
- # <limits.h> exists even on freestanding compilers.
- # On the NeXT, cc -E runs the code through the compiler's parser,
- # not just through cpp. "Syntax error" is here to catch this case.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+printf %s "checking whether byte ordering is bigendian... " >&6; }
+if test ${ac_cv_c_bigendian+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_c_bigendian=unknown
+ # See if we're dealing with a universal compiler.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
- Syntax error
+#ifndef __APPLE_CC__
+ not a universal capable compiler
+ #endif
+ typedef int dummy;
+
_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
-else
- # Broken: fails on valid input.
-continue
+ # Check for potential -arch flags. It is not universal unless
+ # there are at least two -arch flags with different values.
+ ac_arch=
+ ac_prev=
+ for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+ if test -n "$ac_prev"; then
+ case $ac_word in
+ i?86 | x86_64 | ppc | ppc64)
+ if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+ ac_arch=$ac_word
+ else
+ ac_cv_c_bigendian=universal
+ break
+ fi
+ ;;
+ esac
+ ac_prev=
+ elif test "x$ac_word" = "x-arch"; then
+ ac_prev=arch
+ fi
+ done
fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
- # OK, works on sane cases. Now check whether nonexistent headers
- # can be detected and how.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if sys/param.h defines the BYTE_ORDER macro.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#include <ac_nonexistent.h>
+#include <sys/types.h>
+ #include <sys/param.h>
+
+int
+main (void)
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+ && LITTLE_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
- # Broken: success on invalid input.
-continue
-else
- # Passes both tests.
-ac_preproc_ok=:
-break
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+if ac_fn_c_try_compile "$LINENO"
+then :
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ #include <sys/param.h>
-done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then :
+int
+main (void)
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+ #endif
-else
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details" "$LINENO" 5; }
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_c_bigendian=yes
+else $as_nop
+ ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
+int
+main (void)
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+ bogus endian macros
+ #endif
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
-$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
-if ${ac_cv_path_GREP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -z "$GREP"; then
- ac_path_GREP_found=false
- # Loop through the user's path and test for each of PROGNAME-LIST
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_prog in grep ggrep; do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_GREP" || continue
-# Check for GNU ac_path_GREP and select it if it is found.
- # Check for GNU $ac_path_GREP
-case `"$ac_path_GREP" --version 2>&1` in
-*GNU*)
- ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
-*)
- ac_count=0
- $as_echo_n 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- $as_echo 'GREP' >> "conftest.nl"
- "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_GREP_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_GREP="$ac_path_GREP"
- ac_path_GREP_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_GREP_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_GREP"; then
- as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
- fi
-else
- ac_cv_path_GREP=$GREP
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
-$as_echo "$ac_cv_path_GREP" >&6; }
- GREP="$ac_cv_path_GREP"
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
-$as_echo_n "checking for egrep... " >&6; }
-if ${ac_cv_path_EGREP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
- then ac_cv_path_EGREP="$GREP -E"
- else
- if test -z "$EGREP"; then
- ac_path_EGREP_found=false
- # Loop through the user's path and test for each of PROGNAME-LIST
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_prog in egrep; do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_EGREP" || continue
-# Check for GNU ac_path_EGREP and select it if it is found.
- # Check for GNU $ac_path_EGREP
-case `"$ac_path_EGREP" --version 2>&1` in
-*GNU*)
- ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
-*)
- ac_count=0
- $as_echo_n 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- $as_echo 'EGREP' >> "conftest.nl"
- "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_EGREP_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_EGREP="$ac_path_EGREP"
- ac_path_EGREP_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_EGREP_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_EGREP"; then
- as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
- fi
-else
- ac_cv_path_EGREP=$EGREP
-fi
-
- fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
-$as_echo "$ac_cv_path_EGREP" >&6; }
- EGREP="$ac_cv_path_EGREP"
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
-$as_echo_n "checking for ANSI C header files... " >&6; }
-if ${ac_cv_header_stdc+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <float.h>
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_header_stdc=yes
-else
- ac_cv_header_stdc=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-if test $ac_cv_header_stdc = yes; then
- # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <string.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "memchr" >/dev/null 2>&1; then :
-
-else
- ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
- # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdlib.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "free" >/dev/null 2>&1; then :
-
-else
- ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
- # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
- if test "$cross_compiling" = yes; then :
- :
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <ctype.h>
-#include <stdlib.h>
-#if ((' ' & 0x0FF) == 0x020)
-# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#else
-# define ISLOWER(c) \
- (('a' <= (c) && (c) <= 'i') \
- || ('j' <= (c) && (c) <= 'r') \
- || ('s' <= (c) && (c) <= 'z'))
-# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
-#endif
-
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int
-main ()
-{
- int i;
- for (i = 0; i < 256; i++)
- if (XOR (islower (i), ISLOWER (i))
- || toupper (i) != TOUPPER (i))
- return 2;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
-
-else
- ac_cv_header_stdc=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
-$as_echo "$ac_cv_header_stdc" >&6; }
-if test $ac_cv_header_stdc = yes; then
-
-$as_echo "#define STDC_HEADERS 1" >>confdefs.h
-
-fi
-
-# On IRIX 5.3, sys/types and inttypes.h are conflicting.
-for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
- inttypes.h stdint.h unistd.h
-do :
- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
-"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-
-done
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
-$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
-if ${ac_cv_c_bigendian+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_cv_c_bigendian=unknown
- # See if we're dealing with a universal compiler.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#ifndef __APPLE_CC__
- not a universal capable compiler
- #endif
- typedef int dummy;
-
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
- # Check for potential -arch flags. It is not universal unless
- # there are at least two -arch flags with different values.
- ac_arch=
- ac_prev=
- for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
- if test -n "$ac_prev"; then
- case $ac_word in
- i?86 | x86_64 | ppc | ppc64)
- if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
- ac_arch=$ac_word
- else
- ac_cv_c_bigendian=universal
- break
- fi
- ;;
- esac
- ac_prev=
- elif test "x$ac_word" = "x-arch"; then
- ac_prev=arch
- fi
- done
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- if test $ac_cv_c_bigendian = unknown; then
- # See if sys/param.h defines the BYTE_ORDER macro.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/types.h>
- #include <sys/param.h>
-
-int
-main ()
-{
-#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
- && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
- && LITTLE_ENDIAN)
- bogus endian macros
- #endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- # It does; now see whether it defined to BIG_ENDIAN or not.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/types.h>
- #include <sys/param.h>
-
-int
-main ()
-{
-#if BYTE_ORDER != BIG_ENDIAN
- not big endian
- #endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_c_bigendian=yes
-else
- ac_cv_c_bigendian=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- fi
- if test $ac_cv_c_bigendian = unknown; then
- # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <limits.h>
-
-int
-main ()
-{
-#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
- bogus endian macros
- #endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- # It does; now see whether it defined to _BIG_ENDIAN or not.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <limits.h>
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ # It does; now see whether it defined to _BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
int
-main ()
+main (void)
{
#ifndef _BIG_ENDIAN
not big endian
#endif
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_c_bigendian=yes
-else
+else $as_nop
ac_cv_c_bigendian=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
if test $ac_cv_c_bigendian = unknown; then
# Compile a test program.
- if test "$cross_compiling" = yes; then :
+ if test "$cross_compiling" = yes
+then :
# Try to guess by grepping values from an object file.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-short int ascii_mm[] =
+unsigned short int ascii_mm[] =
{ 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
- short int ascii_ii[] =
+ unsigned short int ascii_ii[] =
{ 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
int use_ascii (int i) {
return ascii_mm[i] + ascii_ii[i];
}
- short int ebcdic_ii[] =
+ unsigned short int ebcdic_ii[] =
{ 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
- short int ebcdic_mm[] =
+ unsigned short int ebcdic_mm[] =
{ 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
int use_ebcdic (int i) {
return ebcdic_mm[i] + ebcdic_ii[i];
}
extern int foo;
int
-main ()
+main (void)
{
return use_ascii (foo) == use_ebcdic (foo);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
ac_cv_c_bigendian=yes
fi
if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
if test "$ac_cv_c_bigendian" = unknown; then
ac_cv_c_bigendian=no
else
# finding both strings is unlikely to happen, but who knows?
ac_cv_c_bigendian=unknown
fi
fi
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-else
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$ac_includes_default
int
-main ()
+main (void)
{
/* Are we little or big endian? From Harbison&Steele. */
union
{
long int l;
char c[sizeof (long int)];
} u;
u.l = 1;
return u.c[sizeof (long int) - 1] == 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_run "$LINENO"
+then :
ac_cv_c_bigendian=no
-else
+else $as_nop
ac_cv_c_bigendian=yes
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
-$as_echo "$ac_cv_c_bigendian" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+printf "%s\n" "$ac_cv_c_bigendian" >&6; }
case $ac_cv_c_bigendian in #(
yes)
- $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+ printf "%s\n" "#define WORDS_BIGENDIAN 1" >>confdefs.h
;; #(
no)
;; #(
universal)
-$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
;; #(
*)
as_fn_error $? "unknown endianness
presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
esac
# Checks for programs.
for ac_prog in gawk mawk nawk awk
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AWK+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_AWK+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$AWK"; then
ac_cv_prog_AWK="$AWK" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_AWK="$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
fi
fi
AWK=$ac_cv_prog_AWK
if test -n "$AWK"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
-$as_echo "$AWK" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+printf "%s\n" "$AWK" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
test -n "$AWK" && break
done
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
-$as_echo_n "checking how to run the C preprocessor... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+printf %s "checking how to run the C preprocessor... " >&6; }
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
CPP=
fi
if test -z "$CPP"; then
- if ${ac_cv_prog_CPP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- # Double quotes because CPP needs to be expanded
- for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ if test ${ac_cv_prog_CPP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ # Double quotes because $CC needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp
do
ac_preproc_ok=false
for ac_c_preproc_warn_flag in '' yes
do
# Use a header file that comes with gcc, so configuring glibc
# with a fresh cross-compiler works.
- # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
- # <limits.h> exists even on freestanding compilers.
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp. "Syntax error" is here to catch this case.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
+#include <limits.h>
Syntax error
_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
+if ac_fn_c_try_cpp "$LINENO"
+then :
-else
+else $as_nop
# Broken: fails on valid input.
continue
fi
rm -f conftest.err conftest.i conftest.$ac_ext
# OK, works on sane cases. Now check whether nonexistent headers
# can be detected and how.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <ac_nonexistent.h>
_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
+if ac_fn_c_try_cpp "$LINENO"
+then :
# Broken: success on invalid input.
continue
-else
+else $as_nop
# Passes both tests.
ac_preproc_ok=:
break
fi
rm -f conftest.err conftest.i conftest.$ac_ext
done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then :
+if $ac_preproc_ok
+then :
break
fi
done
ac_cv_prog_CPP=$CPP
fi
CPP=$ac_cv_prog_CPP
else
ac_cv_prog_CPP=$CPP
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
-$as_echo "$CPP" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+printf "%s\n" "$CPP" >&6; }
ac_preproc_ok=false
for ac_c_preproc_warn_flag in '' yes
do
# Use a header file that comes with gcc, so configuring glibc
# with a fresh cross-compiler works.
- # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
- # <limits.h> exists even on freestanding compilers.
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp. "Syntax error" is here to catch this case.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
+#include <limits.h>
Syntax error
_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
+if ac_fn_c_try_cpp "$LINENO"
+then :
-else
+else $as_nop
# Broken: fails on valid input.
continue
fi
rm -f conftest.err conftest.i conftest.$ac_ext
# OK, works on sane cases. Now check whether nonexistent headers
# can be detected and how.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <ac_nonexistent.h>
_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
+if ac_fn_c_try_cpp "$LINENO"
+then :
# Broken: success on invalid input.
continue
-else
+else $as_nop
# Passes both tests.
ac_preproc_ok=:
break
fi
rm -f conftest.err conftest.i conftest.$ac_ext
done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then :
+if $ac_preproc_ok
+then :
-else
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+else $as_nop
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
See \`config.log' for more details" "$LINENO" 5; }
fi
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_RANLIB+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_RANLIB+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$RANLIB"; then
ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
fi
fi
RANLIB=$ac_cv_prog_RANLIB
if test -n "$RANLIB"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
-$as_echo "$RANLIB" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+printf "%s\n" "$RANLIB" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
fi
if test -z "$ac_cv_prog_RANLIB"; then
ac_ct_RANLIB=$RANLIB
# Extract the first word of "ranlib", so it can be a program name with args.
set dummy ranlib; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_RANLIB+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_RANLIB"; then
ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_RANLIB="ranlib"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
fi
fi
ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
if test -n "$ac_ct_RANLIB"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
-$as_echo "$ac_ct_RANLIB" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+printf "%s\n" "$ac_ct_RANLIB" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_RANLIB" = x; then
RANLIB=":"
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
RANLIB=$ac_ct_RANLIB
fi
else
RANLIB="$ac_cv_prog_RANLIB"
fi
-# Find a good install program. We prefer a C program (faster),
+
+ # Find a good install program. We prefer a C program (faster),
# so one script is as good as another. But avoid the broken or
# incompatible versions:
# SysV /etc/install, /usr/sbin/install
# SunOS /usr/etc/install
# IRIX /sbin/install
# AIX /bin/install
# AmigaOS /C/install, which installs bootblocks on floppy discs
# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
# AFS /usr/afsws/bin/install, which mishandles nonexistent args
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# OS/2's system install, which has a completely different semantic
# ./install, which can be erroneously created by make from ./install.sh.
# Reject install programs that cannot install multiple files.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
-$as_echo_n "checking for a BSD-compatible install... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+printf %s "checking for a BSD-compatible install... " >&6; }
if test -z "$INSTALL"; then
-if ${ac_cv_path_install+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+if test ${ac_cv_path_install+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- # Account for people who put trailing slashes in PATH elements.
-case $as_dir/ in #((
- ./ | .// | /[cC]/* | \
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ # Account for fact that we put trailing slashes in our PATH walk.
+case $as_dir in #((
+ ./ | /[cC]/* | \
/etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
/usr/ucb/* ) ;;
*)
# OSF1 and SCO ODT 3.0 have their own names for install.
# Don't use installbsd from OSF since it installs stuff as root
# by default.
for ac_prog in ginstall scoinst install; do
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then
if test $ac_prog = install &&
- grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
# AIX install. It has an incompatible calling convention.
:
elif test $ac_prog = install &&
- grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
# program-specific install script used by HP pwplus--don't use.
:
else
rm -rf conftest.one conftest.two conftest.dir
echo one > conftest.one
echo two > conftest.two
mkdir conftest.dir
- if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" &&
test -s conftest.one && test -s conftest.two &&
test -s conftest.dir/conftest.one &&
test -s conftest.dir/conftest.two
then
- ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c"
break 3
fi
fi
fi
done
done
;;
esac
done
IFS=$as_save_IFS
rm -rf conftest.one conftest.two conftest.dir
fi
- if test "${ac_cv_path_install+set}" = set; then
+ if test ${ac_cv_path_install+y}; then
INSTALL=$ac_cv_path_install
else
# As a last resort, use the slow shell script. Don't cache a
# value for INSTALL within a source directory, because that will
# break other packages using the cache if that directory is
# removed, or if the value is a relative name.
INSTALL=$ac_install_sh
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
-$as_echo "$INSTALL" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+printf "%s\n" "$INSTALL" >&6; }
# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
# It thinks the first close brace ends the variable substitution.
test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
-$as_echo_n "checking for egrep... " >&6; }
-if ${ac_cv_path_EGREP+:} false; then :
- $as_echo_n "(cached) " >&6
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+printf %s "checking for grep that handles long lines and -e... " >&6; }
+if test ${ac_cv_path_GREP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_prog in grep ggrep
+ do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ printf %s 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ printf "%s\n" 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+printf "%s\n" "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+printf %s "checking for egrep... " >&6; }
+if test ${ac_cv_path_EGREP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
then ac_cv_path_EGREP="$GREP -E"
else
if test -z "$EGREP"; then
ac_path_EGREP_found=false
# Loop through the user's path and test for each of PROGNAME-LIST
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_prog in egrep; do
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_prog in egrep
+ do
for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext"
as_fn_executable_p "$ac_path_EGREP" || continue
# Check for GNU ac_path_EGREP and select it if it is found.
# Check for GNU $ac_path_EGREP
case `"$ac_path_EGREP" --version 2>&1` in
*GNU*)
ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
*)
ac_count=0
- $as_echo_n 0123456789 >"conftest.in"
+ printf %s 0123456789 >"conftest.in"
while :
do
cat "conftest.in" "conftest.in" >"conftest.tmp"
mv "conftest.tmp" "conftest.in"
cp "conftest.in" "conftest.nl"
- $as_echo 'EGREP' >> "conftest.nl"
+ printf "%s\n" 'EGREP' >> "conftest.nl"
"$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
as_fn_arith $ac_count + 1 && ac_count=$as_val
if test $ac_count -gt ${ac_path_EGREP_max-0}; then
# Best one so far, save it but keep looking for a better one
ac_cv_path_EGREP="$ac_path_EGREP"
ac_path_EGREP_max=$ac_count
fi
# 10*(2^10) chars as input seems more than enough
test $ac_count -gt 10 && break
done
rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
esac
$ac_path_EGREP_found && break 3
done
done
done
IFS=$as_save_IFS
if test -z "$ac_cv_path_EGREP"; then
as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
fi
else
ac_cv_path_EGREP=$EGREP
fi
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
-$as_echo "$ac_cv_path_EGREP" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+printf "%s\n" "$ac_cv_path_EGREP" >&6; }
EGREP="$ac_cv_path_EGREP"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
-$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5
+printf %s "checking for a race-free mkdir -p... " >&6; }
if test -z "$MKDIR_P"; then
- if ${ac_cv_path_mkdir+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ if test ${ac_cv_path_mkdir+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_prog in mkdir gmkdir; do
for ac_exec_ext in '' $ac_executable_extensions; do
- as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
- case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
- 'mkdir (GNU coreutils) '* | \
- 'mkdir (coreutils) '* | \
+ as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue
+ case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #(
+ 'mkdir ('*'coreutils) '* | \
+ 'BusyBox '* | \
'mkdir (fileutils) '4.1*)
- ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+ ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext
break 3;;
esac
done
done
done
IFS=$as_save_IFS
fi
test -d ./--version && rmdir ./--version
- if test "${ac_cv_path_mkdir+set}" = set; then
+ if test ${ac_cv_path_mkdir+y}; then
MKDIR_P="$ac_cv_path_mkdir -p"
else
# As a last resort, use the slow shell script. Don't cache a
# value for MKDIR_P within a source directory, because that will
# break other packages using the cache if that directory is
# removed, or if the value is a relative name.
MKDIR_P="$ac_install_sh -d"
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
-$as_echo "$MKDIR_P" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+printf "%s\n" "$MKDIR_P" >&6; }
if test -n "$ac_tool_prefix"; then
for ac_prog in ar
do
# Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AR+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_AR+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$AR"; then
ac_cv_prog_AR="$AR" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
fi
fi
AR=$ac_cv_prog_AR
if test -n "$AR"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
-$as_echo "$AR" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+printf "%s\n" "$AR" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
test -n "$AR" && break
done
fi
if test -z "$AR"; then
ac_ct_AR=$AR
for ac_prog in ar
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_AR+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_AR+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_AR"; then
ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_AR="$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
fi
fi
ac_ct_AR=$ac_cv_prog_ac_ct_AR
if test -n "$ac_ct_AR"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
-$as_echo "$ac_ct_AR" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+printf "%s\n" "$ac_ct_AR" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
test -n "$ac_ct_AR" && break
done
if test "x$ac_ct_AR" = x; then
AR=""
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
AR=$ac_ct_AR
fi
fi
# Extract the first word of "cat", so it can be a program name with args.
set dummy cat; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CAT+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_CAT+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $CAT in
[\\/]* | ?:[\\/]*)
ac_cv_path_CAT="$CAT" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_CAT="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_CAT="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
CAT=$ac_cv_path_CAT
if test -n "$CAT"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CAT" >&5
-$as_echo "$CAT" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CAT" >&5
+printf "%s\n" "$CAT" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# Extract the first word of "kill", so it can be a program name with args.
set dummy kill; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_KILL+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_KILL+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $KILL in
[\\/]* | ?:[\\/]*)
ac_cv_path_KILL="$KILL" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_KILL="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_KILL="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
KILL=$ac_cv_path_KILL
if test -n "$KILL"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $KILL" >&5
-$as_echo "$KILL" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $KILL" >&5
+printf "%s\n" "$KILL" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# Extract the first word of "sed", so it can be a program name with args.
set dummy sed; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_SED+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_SED+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $SED in
[\\/]* | ?:[\\/]*)
ac_cv_path_SED="$SED" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_SED="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_SED="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
SED=$ac_cv_path_SED
if test -n "$SED"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SED" >&5
-$as_echo "$SED" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SED" >&5
+printf "%s\n" "$SED" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# Extract the first word of "bash", so it can be a program name with args.
set dummy bash; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_TEST_MINUS_S_SH+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_TEST_MINUS_S_SH+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $TEST_MINUS_S_SH in
[\\/]* | ?:[\\/]*)
ac_cv_path_TEST_MINUS_S_SH="$TEST_MINUS_S_SH" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_TEST_MINUS_S_SH="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_TEST_MINUS_S_SH="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
TEST_MINUS_S_SH=$ac_cv_path_TEST_MINUS_S_SH
if test -n "$TEST_MINUS_S_SH"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TEST_MINUS_S_SH" >&5
-$as_echo "$TEST_MINUS_S_SH" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TEST_MINUS_S_SH" >&5
+printf "%s\n" "$TEST_MINUS_S_SH" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# Extract the first word of "ksh", so it can be a program name with args.
set dummy ksh; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_TEST_MINUS_S_SH+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_TEST_MINUS_S_SH+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $TEST_MINUS_S_SH in
[\\/]* | ?:[\\/]*)
ac_cv_path_TEST_MINUS_S_SH="$TEST_MINUS_S_SH" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_TEST_MINUS_S_SH="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_TEST_MINUS_S_SH="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
TEST_MINUS_S_SH=$ac_cv_path_TEST_MINUS_S_SH
if test -n "$TEST_MINUS_S_SH"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TEST_MINUS_S_SH" >&5
-$as_echo "$TEST_MINUS_S_SH" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TEST_MINUS_S_SH" >&5
+printf "%s\n" "$TEST_MINUS_S_SH" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# Extract the first word of "sh", so it can be a program name with args.
set dummy sh; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_TEST_MINUS_S_SH+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_TEST_MINUS_S_SH+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $TEST_MINUS_S_SH in
[\\/]* | ?:[\\/]*)
ac_cv_path_TEST_MINUS_S_SH="$TEST_MINUS_S_SH" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_TEST_MINUS_S_SH="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_TEST_MINUS_S_SH="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
TEST_MINUS_S_SH=$ac_cv_path_TEST_MINUS_S_SH
if test -n "$TEST_MINUS_S_SH"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TEST_MINUS_S_SH" >&5
-$as_echo "$TEST_MINUS_S_SH" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TEST_MINUS_S_SH" >&5
+printf "%s\n" "$TEST_MINUS_S_SH" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# Extract the first word of "bash", so it can be a program name with args.
set dummy bash; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_SH+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_SH+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $SH in
[\\/]* | ?:[\\/]*)
ac_cv_path_SH="$SH" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_SH="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_SH="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
SH=$ac_cv_path_SH
if test -n "$SH"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SH" >&5
-$as_echo "$SH" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SH" >&5
+printf "%s\n" "$SH" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# Extract the first word of "ksh", so it can be a program name with args.
set dummy ksh; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_SH+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_SH+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $SH in
[\\/]* | ?:[\\/]*)
ac_cv_path_SH="$SH" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_SH="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_SH="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
SH=$ac_cv_path_SH
if test -n "$SH"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SH" >&5
-$as_echo "$SH" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SH" >&5
+printf "%s\n" "$SH" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# Extract the first word of "sh", so it can be a program name with args.
set dummy sh; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_SH+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_SH+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $SH in
[\\/]* | ?:[\\/]*)
ac_cv_path_SH="$SH" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_SH="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_SH="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
SH=$ac_cv_path_SH
if test -n "$SH"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SH" >&5
-$as_echo "$SH" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SH" >&5
+printf "%s\n" "$SH" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# Extract the first word of "groff", so it can be a program name with args.
set dummy groff; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_GROFF+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_GROFF+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $GROFF in
[\\/]* | ?:[\\/]*)
ac_cv_path_GROFF="$GROFF" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_GROFF="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_GROFF="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
GROFF=$ac_cv_path_GROFF
if test -n "$GROFF"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GROFF" >&5
-$as_echo "$GROFF" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GROFF" >&5
+printf "%s\n" "$GROFF" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# Extract the first word of "nroff awf", so it can be a program name with args.
set dummy nroff awf; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_NROFF+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_NROFF+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $NROFF in
[\\/]* | ?:[\\/]*)
ac_cv_path_NROFF="$NROFF" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_NROFF="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_NROFF="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
NROFF=$ac_cv_path_NROFF
if test -n "$NROFF"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NROFF" >&5
-$as_echo "$NROFF" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NROFF" >&5
+printf "%s\n" "$NROFF" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# Extract the first word of "mandoc", so it can be a program name with args.
set dummy mandoc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_MANDOC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_MANDOC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $MANDOC in
[\\/]* | ?:[\\/]*)
ac_cv_path_MANDOC="$MANDOC" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_MANDOC="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_MANDOC="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
-fi
-MANDOC=$ac_cv_path_MANDOC
-if test -n "$MANDOC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANDOC" >&5
-$as_echo "$MANDOC" >&6; }
+fi
+MANDOC=$ac_cv_path_MANDOC
+if test -n "$MANDOC"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MANDOC" >&5
+printf "%s\n" "$MANDOC" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_PKGCONFIG+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $PKGCONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_PKGCONFIG="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+PKGCONFIG=$ac_cv_path_PKGCONFIG
+if test -n "$PKGCONFIG"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5
+printf "%s\n" "$PKGCONFIG" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKGCONFIG"; then
+ ac_pt_PKGCONFIG=$PKGCONFIG
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_ac_pt_PKGCONFIG+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $ac_pt_PKGCONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_ac_pt_PKGCONFIG="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG
+if test -n "$ac_pt_PKGCONFIG"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5
+printf "%s\n" "$ac_pt_PKGCONFIG" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+ if test "x$ac_pt_PKGCONFIG" = x; then
+ PKGCONFIG="no"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ PKGCONFIG=$ac_pt_PKGCONFIG
+ fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ PKGCONFIG="$ac_cv_path_PKGCONFIG"
fi
-
TEST_SHELL=sh
if test "x$MANDOC" != "x" ; then
MANFMT="$MANDOC"
elif test "x$NROFF" != "x" ; then
MANFMT="$NROFF -mandoc"
elif test "x$GROFF" != "x" ; then
MANFMT="$GROFF -mandoc -Tascii"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no manpage formatter found" >&5
-$as_echo "$as_me: WARNING: no manpage formatter found" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: no manpage formatter found" >&5
+printf "%s\n" "$as_me: WARNING: no manpage formatter found" >&2;}
MANFMT="false"
fi
# Extract the first word of "groupadd", so it can be a program name with args.
set dummy groupadd; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PATH_GROUPADD_PROG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_PATH_GROUPADD_PROG+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $PATH_GROUPADD_PROG in
[\\/]* | ?:[\\/]*)
ac_cv_path_PATH_GROUPADD_PROG="$PATH_GROUPADD_PROG" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in /usr/sbin${PATH_SEPARATOR}/etc
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_PATH_GROUPADD_PROG="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_PATH_GROUPADD_PROG="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
test -z "$ac_cv_path_PATH_GROUPADD_PROG" && ac_cv_path_PATH_GROUPADD_PROG="groupadd"
;;
esac
fi
PATH_GROUPADD_PROG=$ac_cv_path_PATH_GROUPADD_PROG
if test -n "$PATH_GROUPADD_PROG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PATH_GROUPADD_PROG" >&5
-$as_echo "$PATH_GROUPADD_PROG" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PATH_GROUPADD_PROG" >&5
+printf "%s\n" "$PATH_GROUPADD_PROG" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# Extract the first word of "useradd", so it can be a program name with args.
set dummy useradd; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PATH_USERADD_PROG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_PATH_USERADD_PROG+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $PATH_USERADD_PROG in
[\\/]* | ?:[\\/]*)
ac_cv_path_PATH_USERADD_PROG="$PATH_USERADD_PROG" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in /usr/sbin${PATH_SEPARATOR}/etc
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_PATH_USERADD_PROG="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_PATH_USERADD_PROG="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
test -z "$ac_cv_path_PATH_USERADD_PROG" && ac_cv_path_PATH_USERADD_PROG="useradd"
;;
esac
fi
PATH_USERADD_PROG=$ac_cv_path_PATH_USERADD_PROG
if test -n "$PATH_USERADD_PROG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PATH_USERADD_PROG" >&5
-$as_echo "$PATH_USERADD_PROG" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PATH_USERADD_PROG" >&5
+printf "%s\n" "$PATH_USERADD_PROG" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# Extract the first word of "pkgmk", so it can be a program name with args.
set dummy pkgmk; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_MAKE_PACKAGE_SUPPORTED+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_MAKE_PACKAGE_SUPPORTED+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$MAKE_PACKAGE_SUPPORTED"; then
ac_cv_prog_MAKE_PACKAGE_SUPPORTED="$MAKE_PACKAGE_SUPPORTED" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_MAKE_PACKAGE_SUPPORTED="yes"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
test -z "$ac_cv_prog_MAKE_PACKAGE_SUPPORTED" && ac_cv_prog_MAKE_PACKAGE_SUPPORTED="no"
fi
fi
MAKE_PACKAGE_SUPPORTED=$ac_cv_prog_MAKE_PACKAGE_SUPPORTED
if test -n "$MAKE_PACKAGE_SUPPORTED"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAKE_PACKAGE_SUPPORTED" >&5
-$as_echo "$MAKE_PACKAGE_SUPPORTED" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAKE_PACKAGE_SUPPORTED" >&5
+printf "%s\n" "$MAKE_PACKAGE_SUPPORTED" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test -x /sbin/sh; then
STARTUP_SCRIPT_SHELL=/sbin/sh
else
STARTUP_SCRIPT_SHELL=/bin/sh
fi
# System features
# Check whether --enable-largefile was given.
-if test "${enable_largefile+set}" = set; then :
+if test ${enable_largefile+y}
+then :
enableval=$enable_largefile;
fi
if test "$enable_largefile" != no; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
-$as_echo_n "checking for special C compiler options needed for large files... " >&6; }
-if ${ac_cv_sys_largefile_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
+printf %s "checking for special C compiler options needed for large files... " >&6; }
+if test ${ac_cv_sys_largefile_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_cv_sys_largefile_CC=no
if test "$GCC" != yes; then
ac_save_CC=$CC
while :; do
# IRIX 6.2 and later do not support large files by default,
# so use the C compiler's -n32 option if that helps.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
/* Check that off_t can represent 2**63 - 1 correctly.
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
- if ac_fn_c_try_compile "$LINENO"; then :
+ if ac_fn_c_try_compile "$LINENO"
+then :
break
fi
-rm -f core conftest.err conftest.$ac_objext
+rm -f core conftest.err conftest.$ac_objext conftest.beam
CC="$CC -n32"
- if ac_fn_c_try_compile "$LINENO"; then :
+ if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_sys_largefile_CC=' -n32'; break
fi
-rm -f core conftest.err conftest.$ac_objext
+rm -f core conftest.err conftest.$ac_objext conftest.beam
break
done
CC=$ac_save_CC
rm -f conftest.$ac_ext
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5
-$as_echo "$ac_cv_sys_largefile_CC" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5
+printf "%s\n" "$ac_cv_sys_largefile_CC" >&6; }
if test "$ac_cv_sys_largefile_CC" != no; then
CC=$CC$ac_cv_sys_largefile_CC
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
-$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
-if ${ac_cv_sys_file_offset_bits+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
+printf %s "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
+if test ${ac_cv_sys_file_offset_bits+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
while :; do
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
/* Check that off_t can represent 2**63 - 1 correctly.
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_sys_file_offset_bits=no; break
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#define _FILE_OFFSET_BITS 64
#include <sys/types.h>
/* Check that off_t can represent 2**63 - 1 correctly.
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_sys_file_offset_bits=64; break
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
ac_cv_sys_file_offset_bits=unknown
break
done
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5
-$as_echo "$ac_cv_sys_file_offset_bits" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5
+printf "%s\n" "$ac_cv_sys_file_offset_bits" >&6; }
case $ac_cv_sys_file_offset_bits in #(
no | unknown) ;;
*)
-cat >>confdefs.h <<_ACEOF
-#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits
-_ACEOF
+printf "%s\n" "#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits" >>confdefs.h
;;
esac
rm -rf conftest*
if test $ac_cv_sys_file_offset_bits = unknown; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
-$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; }
-if ${ac_cv_sys_large_files+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
+printf %s "checking for _LARGE_FILES value needed for large files... " >&6; }
+if test ${ac_cv_sys_large_files+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
while :; do
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
/* Check that off_t can represent 2**63 - 1 correctly.
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_sys_large_files=no; break
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#define _LARGE_FILES 1
#include <sys/types.h>
/* Check that off_t can represent 2**63 - 1 correctly.
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_sys_large_files=1; break
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
ac_cv_sys_large_files=unknown
break
done
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5
-$as_echo "$ac_cv_sys_large_files" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5
+printf "%s\n" "$ac_cv_sys_large_files" >&6; }
case $ac_cv_sys_large_files in #(
no | unknown) ;;
*)
-cat >>confdefs.h <<_ACEOF
-#define _LARGE_FILES $ac_cv_sys_large_files
-_ACEOF
+printf "%s\n" "#define _LARGE_FILES $ac_cv_sys_large_files" >>confdefs.h
;;
esac
rm -rf conftest*
fi
-
-
fi
if test -z "$AR" ; then
as_fn_error $? "*** 'ar' missing, please install or fix your \$PATH ***" "$LINENO" 5
fi
# Extract the first word of "passwd", so it can be a program name with args.
set dummy passwd; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PATH_PASSWD_PROG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_PATH_PASSWD_PROG+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $PATH_PASSWD_PROG in
[\\/]* | ?:[\\/]*)
ac_cv_path_PATH_PASSWD_PROG="$PATH_PASSWD_PROG" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_PATH_PASSWD_PROG="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_PATH_PASSWD_PROG="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
PATH_PASSWD_PROG=$ac_cv_path_PATH_PASSWD_PROG
if test -n "$PATH_PASSWD_PROG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PATH_PASSWD_PROG" >&5
-$as_echo "$PATH_PASSWD_PROG" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PATH_PASSWD_PROG" >&5
+printf "%s\n" "$PATH_PASSWD_PROG" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test ! -z "$PATH_PASSWD_PROG" ; then
-cat >>confdefs.h <<_ACEOF
-#define _PATH_PASSWD_PROG "$PATH_PASSWD_PROG"
-_ACEOF
+printf "%s\n" "#define _PATH_PASSWD_PROG \"$PATH_PASSWD_PROG\"" >>confdefs.h
fi
LD="$CC"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
-$as_echo_n "checking for inline... " >&6; }
-if ${ac_cv_c_inline+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+printf %s "checking for inline... " >&6; }
+if test ${ac_cv_c_inline+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_cv_c_inline=no
for ac_kw in inline __inline__ __inline; do
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#ifndef __cplusplus
typedef int foo_t;
-static $ac_kw foo_t static_foo () {return 0; }
-$ac_kw foo_t foo () {return 0; }
+static $ac_kw foo_t static_foo (void) {return 0; }
+$ac_kw foo_t foo (void) {return 0; }
#endif
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_c_inline=$ac_kw
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
test "$ac_cv_c_inline" != no && break
done
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
-$as_echo "$ac_cv_c_inline" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
+printf "%s\n" "$ac_cv_c_inline" >&6; }
case $ac_cv_c_inline in
inline | yes) ;;
*)
case $ac_cv_c_inline in
no) ac_val=;;
*) ac_val=$ac_cv_c_inline;;
esac
cat >>confdefs.h <<_ACEOF
#ifndef __cplusplus
#define inline $ac_val
#endif
_ACEOF
;;
esac
-ac_fn_c_check_decl "$LINENO" "LLONG_MAX" "ac_cv_have_decl_LLONG_MAX" "#include <limits.h>
-"
-if test "x$ac_cv_have_decl_LLONG_MAX" = xyes; then :
- have_llong_max=1
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5
+printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; }
+if test ${ac_cv_c_undeclared_builtin_options+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_save_CFLAGS=$CFLAGS
+ ac_cv_c_undeclared_builtin_options='cannot detect'
+ for ac_arg in '' -fno-builtin; do
+ CFLAGS="$ac_save_CFLAGS $ac_arg"
+ # This test program should *not* compile successfully.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+(void) strchr;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+else $as_nop
+ # This test program should compile successfully.
+ # No library function is consistently available on
+ # freestanding implementations, so test against a dummy
+ # declaration. Include always-available headers on the
+ # off chance that they somehow elicit warnings.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <float.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+extern void ac_decl (int, char *);
+
+int
+main (void)
+{
+(void) ac_decl (0, (char *) 0);
+ (void) ac_decl;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ if test x"$ac_arg" = x
+then :
+ ac_cv_c_undeclared_builtin_options='none needed'
+else $as_nop
+ ac_cv_c_undeclared_builtin_options=$ac_arg
fi
+ break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+ CFLAGS=$ac_save_CFLAGS
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5
+printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; }
+ case $ac_cv_c_undeclared_builtin_options in #(
+ 'cannot detect') :
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot make $CC report undeclared builtins
+See \`config.log' for more details" "$LINENO" 5; } ;; #(
+ 'none needed') :
+ ac_c_undeclared_builtin_options='' ;; #(
+ *) :
+ ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;;
+esac
-ac_fn_c_check_decl "$LINENO" "LONG_LONG_MAX" "ac_cv_have_decl_LONG_LONG_MAX" "#include <limits.h>
-"
-if test "x$ac_cv_have_decl_LONG_LONG_MAX" = xyes; then :
+ac_fn_check_decl "$LINENO" "LLONG_MAX" "ac_cv_have_decl_LLONG_MAX" "#include <limits.h>
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_LLONG_MAX" = xyes
+then :
+ have_llong_max=1
+fi
+ac_fn_check_decl "$LINENO" "LONG_LONG_MAX" "ac_cv_have_decl_LONG_LONG_MAX" "#include <limits.h>
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_LONG_LONG_MAX" = xyes
+then :
have_long_long_max=1
fi
-
-ac_fn_c_check_decl "$LINENO" "SYSTR_POLICY_KILL" "ac_cv_have_decl_SYSTR_POLICY_KILL" "
+ac_fn_check_decl "$LINENO" "SYSTR_POLICY_KILL" "ac_cv_have_decl_SYSTR_POLICY_KILL" "
#include <sys/types.h>
#include <sys/param.h>
#include <dev/systrace.h>
-"
-if test "x$ac_cv_have_decl_SYSTR_POLICY_KILL" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_SYSTR_POLICY_KILL" = xyes
+then :
have_systr_policy_kill=1
fi
-
-ac_fn_c_check_decl "$LINENO" "RLIMIT_NPROC" "ac_cv_have_decl_RLIMIT_NPROC" "
+ac_fn_check_decl "$LINENO" "RLIMIT_NPROC" "ac_cv_have_decl_RLIMIT_NPROC" "
#include <sys/types.h>
#include <sys/resource.h>
-"
-if test "x$ac_cv_have_decl_RLIMIT_NPROC" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_RLIMIT_NPROC" = xyes
+then :
-$as_echo "#define HAVE_RLIMIT_NPROC /**/" >>confdefs.h
+printf "%s\n" "#define HAVE_RLIMIT_NPROC /**/" >>confdefs.h
fi
-
-ac_fn_c_check_decl "$LINENO" "PR_SET_NO_NEW_PRIVS" "ac_cv_have_decl_PR_SET_NO_NEW_PRIVS" "
+ac_fn_check_decl "$LINENO" "PR_SET_NO_NEW_PRIVS" "ac_cv_have_decl_PR_SET_NO_NEW_PRIVS" "
#include <sys/types.h>
#include <linux/prctl.h>
-"
-if test "x$ac_cv_have_decl_PR_SET_NO_NEW_PRIVS" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_PR_SET_NO_NEW_PRIVS" = xyes
+then :
have_linux_no_new_privs=1
fi
-
openssl=yes
# Check whether --with-openssl was given.
-if test "${with_openssl+set}" = set; then :
+if test ${with_openssl+y}
+then :
withval=$with_openssl; if test "x$withval" = "xno" ; then
openssl=no
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL will be used for cryptography" >&5
-$as_echo_n "checking whether OpenSSL will be used for cryptography... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL will be used for cryptography" >&5
+printf %s "checking whether OpenSSL will be used for cryptography... " >&6; }
if test "x$openssl" = "xyes" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-cat >>confdefs.h <<_ACEOF
-#define WITH_OPENSSL 1
-_ACEOF
+printf "%s\n" "#define WITH_OPENSSL 1" >>confdefs.h
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
use_stack_protector=1
use_toolchain_hardening=1
# Check whether --with-stackprotect was given.
-if test "${with_stackprotect+set}" = set; then :
+if test ${with_stackprotect+y}
+then :
withval=$with_stackprotect;
if test "x$withval" = "xno"; then
use_stack_protector=0
fi
fi
# Check whether --with-hardening was given.
-if test "${with_hardening+set}" = set; then :
+if test ${with_hardening+y}
+then :
withval=$with_hardening;
if test "x$withval" = "xno"; then
use_toolchain_hardening=0
fi
fi
# We use -Werror for the tests only so that we catch warnings like "this is
# on by default" for things like -fPIE.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror" >&5
-$as_echo_n "checking if $CC supports -Werror... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Werror" >&5
+printf %s "checking if $CC supports -Werror... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Werror"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int main(void) { return 0; }
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
WERROR="-Werror"
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
WERROR=""
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
CFLAGS="$saved_CFLAGS"
if test "$GCC" = "yes" || test "$GCC" = "egcs"; then
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -pipe" >&5
-$as_echo_n "checking if $CC supports compile flag -pipe... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -pipe" >&5
+printf %s "checking if $CC supports compile flag -pipe... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -pipe"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-pipe"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wunknown-warning-option" >&5
-$as_echo_n "checking if $CC supports compile flag -Wunknown-warning-option... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wunknown-warning-option" >&5
+printf %s "checking if $CC supports compile flag -Wunknown-warning-option... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wunknown-warning-option"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wunknown-warning-option"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wno-error=format-truncation" >&5
-$as_echo_n "checking if $CC supports compile flag -Wno-error=format-truncation... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wno-error=format-truncation" >&5
+printf %s "checking if $CC supports compile flag -Wno-error=format-truncation... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wno-error=format-truncation"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wno-error=format-truncation"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Qunused-arguments" >&5
-$as_echo_n "checking if $CC supports compile flag -Qunused-arguments... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Qunused-arguments" >&5
+printf %s "checking if $CC supports compile flag -Qunused-arguments... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Qunused-arguments"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Qunused-arguments"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wall" >&5
-$as_echo_n "checking if $CC supports compile flag -Wall... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wall" >&5
+printf %s "checking if $CC supports compile flag -Wall... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wall"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wall"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wextra" >&5
-$as_echo_n "checking if $CC supports compile flag -Wextra... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wextra" >&5
+printf %s "checking if $CC supports compile flag -Wextra... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wextra"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wextra"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wpointer-arith" >&5
-$as_echo_n "checking if $CC supports compile flag -Wpointer-arith... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wpointer-arith" >&5
+printf %s "checking if $CC supports compile flag -Wpointer-arith... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wpointer-arith"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wpointer-arith"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wuninitialized" >&5
-$as_echo_n "checking if $CC supports compile flag -Wuninitialized... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wuninitialized" >&5
+printf %s "checking if $CC supports compile flag -Wuninitialized... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wuninitialized"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wuninitialized"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wsign-compare" >&5
-$as_echo_n "checking if $CC supports compile flag -Wsign-compare... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wsign-compare" >&5
+printf %s "checking if $CC supports compile flag -Wsign-compare... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wsign-compare"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wsign-compare"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wformat-security" >&5
-$as_echo_n "checking if $CC supports compile flag -Wformat-security... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wformat-security" >&5
+printf %s "checking if $CC supports compile flag -Wformat-security... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wformat-security"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wformat-security"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wsizeof-pointer-memaccess" >&5
-$as_echo_n "checking if $CC supports compile flag -Wsizeof-pointer-memaccess... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wsizeof-pointer-memaccess" >&5
+printf %s "checking if $CC supports compile flag -Wsizeof-pointer-memaccess... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wsizeof-pointer-memaccess"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wsizeof-pointer-memaccess"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wpointer-sign" >&5
-$as_echo_n "checking if $CC supports compile flag -Wpointer-sign... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wpointer-sign" >&5
+printf %s "checking if $CC supports compile flag -Wpointer-sign... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wpointer-sign"
_define_flag="-Wno-pointer-sign"
test "x$_define_flag" = "x" && _define_flag="-Wpointer-sign"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wunused-parameter" >&5
-$as_echo_n "checking if $CC supports compile flag -Wunused-parameter... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wunused-parameter" >&5
+printf %s "checking if $CC supports compile flag -Wunused-parameter... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wunused-parameter"
_define_flag="-Wno-unused-parameter"
test "x$_define_flag" = "x" && _define_flag="-Wunused-parameter"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wunused-result" >&5
-$as_echo_n "checking if $CC supports compile flag -Wunused-result... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wunused-result" >&5
+printf %s "checking if $CC supports compile flag -Wunused-result... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wunused-result"
_define_flag="-Wno-unused-result"
test "x$_define_flag" = "x" && _define_flag="-Wunused-result"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wimplicit-fallthrough" >&5
-$as_echo_n "checking if $CC supports compile flag -Wimplicit-fallthrough... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wimplicit-fallthrough" >&5
+printf %s "checking if $CC supports compile flag -Wimplicit-fallthrough... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wimplicit-fallthrough"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wimplicit-fallthrough"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wmisleading-indentation" >&5
-$as_echo_n "checking if $CC supports compile flag -Wmisleading-indentation... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wmisleading-indentation" >&5
+printf %s "checking if $CC supports compile flag -Wmisleading-indentation... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wmisleading-indentation"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wmisleading-indentation"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wbitwise-instead-of-logical" >&5
-$as_echo_n "checking if $CC supports compile flag -Wbitwise-instead-of-logical... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wbitwise-instead-of-logical" >&5
+printf %s "checking if $CC supports compile flag -Wbitwise-instead-of-logical... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wbitwise-instead-of-logical"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wbitwise-instead-of-logical"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -fno-strict-aliasing" >&5
-$as_echo_n "checking if $CC supports compile flag -fno-strict-aliasing... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -fno-strict-aliasing" >&5
+printf %s "checking if $CC supports compile flag -fno-strict-aliasing... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -fno-strict-aliasing"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-fno-strict-aliasing"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
if test "x$use_toolchain_hardening" = "x1"; then
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -mretpoline" >&5
-$as_echo_n "checking if $CC supports compile flag -mretpoline... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -mretpoline" >&5
+printf %s "checking if $CC supports compile flag -mretpoline... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -mretpoline"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-mretpoline"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
} # clang
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $LD supports link flag -Wl,-z,retpolineplt" >&5
-$as_echo_n "checking if $LD supports link flag -Wl,-z,retpolineplt... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $LD supports link flag -Wl,-z,retpolineplt" >&5
+printf %s "checking if $LD supports link flag -Wl,-z,retpolineplt... " >&6; }
saved_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS $WERROR -Wl,-z,retpolineplt"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wl,-z,retpolineplt"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
long long p = n * o;
printf("%d %d %d %f %f %lld %lld %lld\n", i, j, k, l, m, n, o, p);
exit(0);
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
LDFLAGS="$saved_LDFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
LDFLAGS="$saved_LDFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
LDFLAGS="$saved_LDFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -D_FORTIFY_SOURCE=2" >&5
-$as_echo_n "checking if $CC supports compile flag -D_FORTIFY_SOURCE=2... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -D_FORTIFY_SOURCE=2" >&5
+printf %s "checking if $CC supports compile flag -D_FORTIFY_SOURCE=2... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -D_FORTIFY_SOURCE=2"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-D_FORTIFY_SOURCE=2"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $LD supports link flag -Wl,-z,relro" >&5
-$as_echo_n "checking if $LD supports link flag -Wl,-z,relro... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $LD supports link flag -Wl,-z,relro" >&5
+printf %s "checking if $LD supports link flag -Wl,-z,relro... " >&6; }
saved_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS $WERROR -Wl,-z,relro"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wl,-z,relro"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
long long p = n * o;
printf("%d %d %d %f %f %lld %lld %lld\n", i, j, k, l, m, n, o, p);
exit(0);
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
LDFLAGS="$saved_LDFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
LDFLAGS="$saved_LDFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
LDFLAGS="$saved_LDFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $LD supports link flag -Wl,-z,now" >&5
-$as_echo_n "checking if $LD supports link flag -Wl,-z,now... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $LD supports link flag -Wl,-z,now" >&5
+printf %s "checking if $LD supports link flag -Wl,-z,now... " >&6; }
saved_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS $WERROR -Wl,-z,now"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wl,-z,now"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
long long p = n * o;
printf("%d %d %d %f %f %lld %lld %lld\n", i, j, k, l, m, n, o, p);
exit(0);
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
LDFLAGS="$saved_LDFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
LDFLAGS="$saved_LDFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
LDFLAGS="$saved_LDFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $LD supports link flag -Wl,-z,noexecstack" >&5
-$as_echo_n "checking if $LD supports link flag -Wl,-z,noexecstack... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $LD supports link flag -Wl,-z,noexecstack" >&5
+printf %s "checking if $LD supports link flag -Wl,-z,noexecstack... " >&6; }
saved_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS $WERROR -Wl,-z,noexecstack"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wl,-z,noexecstack"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
long long p = n * o;
printf("%d %d %d %f %f %lld %lld %lld\n", i, j, k, l, m, n, o, p);
exit(0);
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
LDFLAGS="$saved_LDFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
LDFLAGS="$saved_LDFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
LDFLAGS="$saved_LDFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
}
# NB. -ftrapv expects certain support functions to be present in
# the compiler library (libgcc or similar) to detect integer operations
# that can overflow. We must check that the result of enabling it
# actually links. The test program compiled/linked includes a number
# of integer operations that should exercise this.
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -ftrapv and linking succeeds" >&5
-$as_echo_n "checking if $CC supports compile flag -ftrapv and linking succeeds... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -ftrapv and linking succeeds" >&5
+printf %s "checking if $CC supports compile flag -ftrapv and linking succeeds... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -ftrapv"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-ftrapv"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
long long int p = n * o;
printf("%d %d %d %f %f %lld %lld %lld\n", i, j, k, l, m, n, o, p);
exit(0);
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -fzero-call-used-regs=all" >&5
-$as_echo_n "checking if $CC supports compile flag -fzero-call-used-regs=all... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -fzero-call-used-regs=all" >&5
+printf %s "checking if $CC supports compile flag -fzero-call-used-regs=all... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -fzero-call-used-regs=all"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-fzero-call-used-regs=all"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -ftrivial-auto-var-init=zero" >&5
-$as_echo_n "checking if $CC supports compile flag -ftrivial-auto-var-init=zero... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -ftrivial-auto-var-init=zero" >&5
+printf %s "checking if $CC supports compile flag -ftrivial-auto-var-init=zero... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -ftrivial-auto-var-init=zero"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-ftrivial-auto-var-init=zero"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking gcc version" >&5
-$as_echo_n "checking gcc version... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking gcc version" >&5
+printf %s "checking gcc version... " >&6; }
GCC_VER=`$CC -v 2>&1 | $AWK '/gcc version /{print $3}'`
case $GCC_VER in
1.*) no_attrib_nonnull=1 ;;
2.8* | 2.9*)
no_attrib_nonnull=1
;;
2.*) no_attrib_nonnull=1 ;;
*) ;;
esac
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GCC_VER" >&5
-$as_echo "$GCC_VER" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GCC_VER" >&5
+printf "%s\n" "$GCC_VER" >&6; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC accepts -fno-builtin-memset" >&5
-$as_echo_n "checking if $CC accepts -fno-builtin-memset... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC accepts -fno-builtin-memset" >&5
+printf %s "checking if $CC accepts -fno-builtin-memset... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -fno-builtin-memset"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <string.h>
int
-main ()
+main (void)
{
char b[10]; memset(b, 0, sizeof(b));
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if ac_fn_c_try_link "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
# -fstack-protector-all doesn't always work for some GCC versions
# and/or platforms, so we test if we can. If it's not supported
# on a given platform gcc will emit a warning so we use -Werror.
if test "x$use_stack_protector" = "x1"; then
for t in -fstack-protector-strong -fstack-protector-all \
-fstack-protector; do
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports $t" >&5
-$as_echo_n "checking if $CC supports $t... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports $t" >&5
+printf %s "checking if $CC supports $t... " >&6; }
saved_CFLAGS="$CFLAGS"
saved_LDFLAGS="$LDFLAGS"
CFLAGS="$CFLAGS $t -Werror"
LDFLAGS="$LDFLAGS $t -Werror"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
int func (int t) {char b[100]; snprintf(b,sizeof b,"%d",t); return t;}
int
-main ()
+main (void)
{
char x[256];
snprintf(x, sizeof(x), "XXX%d", func(1));
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_link "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $t"
LDFLAGS="$saved_LDFLAGS $t"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $t works" >&5
-$as_echo_n "checking if $t works... " >&6; }
- if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: cannot test" >&5
-$as_echo "$as_me: WARNING: cross compiling: cannot test" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $t works" >&5
+printf %s "checking if $t works... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: cannot test" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: cannot test" >&2;}
break
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
int func (int t) {char b[100]; snprintf(b,sizeof b,"%d",t); return t;}
int
-main ()
+main (void)
{
char x[256];
snprintf(x, sizeof(x), "XXX%d", func(1));
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
break
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CFLAGS="$saved_CFLAGS"
LDFLAGS="$saved_LDFLAGS"
done
fi
if test -z "$have_llong_max"; then
# retry LLONG_MAX with -std=gnu99, needed on some Linuxes
unset ac_cv_have_decl_LLONG_MAX
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -std=gnu99"
- ac_fn_c_check_decl "$LINENO" "LLONG_MAX" "ac_cv_have_decl_LLONG_MAX" "#include <limits.h>
+ ac_fn_check_decl "$LINENO" "LLONG_MAX" "ac_cv_have_decl_LLONG_MAX" "#include <limits.h>
-"
-if test "x$ac_cv_have_decl_LLONG_MAX" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_LLONG_MAX" = xyes
+then :
have_llong_max=1
-else
+else $as_nop
CFLAGS="$saved_CFLAGS"
fi
-
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler allows __attribute__ on return types" >&5
-$as_echo_n "checking if compiler allows __attribute__ on return types... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler allows __attribute__ on return types" >&5
+printf %s "checking if compiler allows __attribute__ on return types... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
__attribute__((__unused__)) static void foo(void){return;}
int
-main ()
+main (void)
{
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
-$as_echo "#define NO_ATTRIBUTE_ON_RETURN_TYPE 1" >>confdefs.h
+printf "%s\n" "#define NO_ATTRIBUTE_ON_RETURN_TYPE 1" >>confdefs.h
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler allows __attribute__ prototype args" >&5
-$as_echo_n "checking if compiler allows __attribute__ prototype args... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler allows __attribute__ prototype args" >&5
+printf %s "checking if compiler allows __attribute__ prototype args... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
typedef void foo(const char *, ...) __attribute__((format(printf, 1, 2)));
int
-main ()
+main (void)
{
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
-$as_echo "#define NO_ATTRIBUTE_ON_PROTOTYPE_ARGS 1" >>confdefs.h
+printf "%s\n" "#define NO_ATTRIBUTE_ON_PROTOTYPE_ARGS 1" >>confdefs.h
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler supports variable length arrays" >&5
-$as_echo_n "checking if compiler supports variable length arrays... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler supports variable length arrays" >&5
+printf %s "checking if compiler supports variable length arrays... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
int
-main ()
+main (void)
{
int i; for (i=0; i<3; i++){int a[i]; a[i-1]=0;} exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define VARIABLE_LENGTH_ARRAYS 1" >>confdefs.h
+printf "%s\n" "#define VARIABLE_LENGTH_ARRAYS 1" >>confdefs.h
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts variable declarations after code" >&5
-$as_echo_n "checking if compiler accepts variable declarations after code... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts variable declarations after code" >&5
+printf %s "checking if compiler accepts variable declarations after code... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
int
-main ()
+main (void)
{
int a; a = 1; int b = 1; exit(a-b);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define VARIABLE_DECLARATION_AFTER_CODE 1" >>confdefs.h
+printf "%s\n" "#define VARIABLE_DECLARATION_AFTER_CODE 1" >>confdefs.h
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
if test "x$no_attrib_nonnull" != "x1" ; then
-$as_echo "#define HAVE_ATTRIBUTE__NONNULL__ 1" >>confdefs.h
+printf "%s\n" "#define HAVE_ATTRIBUTE__NONNULL__ 1" >>confdefs.h
fi
# Check whether --with-rpath was given.
-if test "${with_rpath+set}" = set; then :
+if test ${with_rpath+y}
+then :
withval=$with_rpath;
if test "x$withval" = "xno" ; then
rpath_opt=""
elif test "x$withval" = "xyes" ; then
rpath_opt="-R"
else
rpath_opt="$withval"
fi
fi
# Allow user to specify flags
# Check whether --with-cflags was given.
-if test "${with_cflags+set}" = set; then :
+if test ${with_cflags+y}
+then :
withval=$with_cflags;
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
CFLAGS="$CFLAGS $withval"
fi
fi
# Check whether --with-cflags-after was given.
-if test "${with_cflags_after+set}" = set; then :
+if test ${with_cflags_after+y}
+then :
withval=$with_cflags_after;
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
CFLAGS_AFTER="$withval"
fi
fi
# Check whether --with-cppflags was given.
-if test "${with_cppflags+set}" = set; then :
+if test ${with_cppflags+y}
+then :
withval=$with_cppflags;
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
CPPFLAGS="$CPPFLAGS $withval"
fi
fi
# Check whether --with-ldflags was given.
-if test "${with_ldflags+set}" = set; then :
+if test ${with_ldflags+y}
+then :
withval=$with_ldflags;
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
LDFLAGS="$LDFLAGS $withval"
fi
fi
# Check whether --with-ldflags-after was given.
-if test "${with_ldflags_after+set}" = set; then :
+if test ${with_ldflags_after+y}
+then :
withval=$with_ldflags_after;
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
LDFLAGS_AFTER="$withval"
fi
fi
-# Check whether --with-libs was given.
-if test "${with_libs+set}" = set; then :
- withval=$with_libs;
- if test -n "$withval" && test "x$withval" != "xno" && \
- test "x${withval}" != "xyes"; then
- LIBS="$LIBS $withval"
- fi
+# Check whether --with-libs was given.
+if test ${with_libs+y}
+then :
+ withval=$with_libs;
+ if test -n "$withval" && test "x$withval" != "xno" && \
+ test "x${withval}" != "xyes"; then
+ LIBS="$LIBS $withval"
+ fi
+
+
+fi
+
+
+# Check whether --with-Werror was given.
+if test ${with_Werror+y}
+then :
+ withval=$with_Werror;
+ if test -n "$withval" && test "x$withval" != "xno"; then
+ werror_flags="-Werror"
+ if test "x${withval}" != "xyes"; then
+ werror_flags="$withval"
+ fi
+ fi
+
+
+fi
+
+
+ac_fn_c_check_header_compile "$LINENO" "blf.h" "ac_cv_header_blf_h" "$ac_includes_default"
+if test "x$ac_cv_header_blf_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_BLF_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "bstring.h" "ac_cv_header_bstring_h" "$ac_includes_default"
+if test "x$ac_cv_header_bstring_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_BSTRING_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "crypt.h" "ac_cv_header_crypt_h" "$ac_includes_default"
+if test "x$ac_cv_header_crypt_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_CRYPT_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "crypto/sha2.h" "ac_cv_header_crypto_sha2_h" "$ac_includes_default"
+if test "x$ac_cv_header_crypto_sha2_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_CRYPTO_SHA2_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "dirent.h" "ac_cv_header_dirent_h" "$ac_includes_default"
+if test "x$ac_cv_header_dirent_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_DIRENT_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "endian.h" "ac_cv_header_endian_h" "$ac_includes_default"
+if test "x$ac_cv_header_endian_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_ENDIAN_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "elf.h" "ac_cv_header_elf_h" "$ac_includes_default"
+if test "x$ac_cv_header_elf_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_ELF_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "err.h" "ac_cv_header_err_h" "$ac_includes_default"
+if test "x$ac_cv_header_err_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_ERR_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "features.h" "ac_cv_header_features_h" "$ac_includes_default"
+if test "x$ac_cv_header_features_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_FEATURES_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$ac_includes_default"
+if test "x$ac_cv_header_fcntl_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_FCNTL_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "floatingpoint.h" "ac_cv_header_floatingpoint_h" "$ac_includes_default"
+if test "x$ac_cv_header_floatingpoint_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_FLOATINGPOINT_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "fnmatch.h" "ac_cv_header_fnmatch_h" "$ac_includes_default"
+if test "x$ac_cv_header_fnmatch_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_FNMATCH_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "getopt.h" "ac_cv_header_getopt_h" "$ac_includes_default"
+if test "x$ac_cv_header_getopt_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETOPT_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "glob.h" "ac_cv_header_glob_h" "$ac_includes_default"
+if test "x$ac_cv_header_glob_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_GLOB_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "ia.h" "ac_cv_header_ia_h" "$ac_includes_default"
+if test "x$ac_cv_header_ia_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_IA_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "iaf.h" "ac_cv_header_iaf_h" "$ac_includes_default"
+if test "x$ac_cv_header_iaf_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_IAF_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "ifaddrs.h" "ac_cv_header_ifaddrs_h" "$ac_includes_default"
+if test "x$ac_cv_header_ifaddrs_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_IFADDRS_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "inttypes.h" "ac_cv_header_inttypes_h" "$ac_includes_default"
+if test "x$ac_cv_header_inttypes_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_INTTYPES_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "langinfo.h" "ac_cv_header_langinfo_h" "$ac_includes_default"
+if test "x$ac_cv_header_langinfo_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LANGINFO_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default"
+if test "x$ac_cv_header_limits_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIMITS_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "locale.h" "ac_cv_header_locale_h" "$ac_includes_default"
+if test "x$ac_cv_header_locale_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LOCALE_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "login.h" "ac_cv_header_login_h" "$ac_includes_default"
+if test "x$ac_cv_header_login_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LOGIN_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "maillock.h" "ac_cv_header_maillock_h" "$ac_includes_default"
+if test "x$ac_cv_header_maillock_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_MAILLOCK_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "ndir.h" "ac_cv_header_ndir_h" "$ac_includes_default"
+if test "x$ac_cv_header_ndir_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_NDIR_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "net/if_tun.h" "ac_cv_header_net_if_tun_h" "$ac_includes_default"
+if test "x$ac_cv_header_net_if_tun_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_NET_IF_TUN_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$ac_includes_default"
+if test "x$ac_cv_header_netdb_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_NETDB_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "netgroup.h" "ac_cv_header_netgroup_h" "$ac_includes_default"
+if test "x$ac_cv_header_netgroup_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_NETGROUP_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "pam/pam_appl.h" "ac_cv_header_pam_pam_appl_h" "$ac_includes_default"
+if test "x$ac_cv_header_pam_pam_appl_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_PAM_PAM_APPL_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "paths.h" "ac_cv_header_paths_h" "$ac_includes_default"
+if test "x$ac_cv_header_paths_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_PATHS_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "poll.h" "ac_cv_header_poll_h" "$ac_includes_default"
+if test "x$ac_cv_header_poll_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_POLL_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "pty.h" "ac_cv_header_pty_h" "$ac_includes_default"
+if test "x$ac_cv_header_pty_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_PTY_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "readpassphrase.h" "ac_cv_header_readpassphrase_h" "$ac_includes_default"
+if test "x$ac_cv_header_readpassphrase_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_READPASSPHRASE_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "rpc/types.h" "ac_cv_header_rpc_types_h" "$ac_includes_default"
+if test "x$ac_cv_header_rpc_types_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_RPC_TYPES_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "security/pam_appl.h" "ac_cv_header_security_pam_appl_h" "$ac_includes_default"
+if test "x$ac_cv_header_security_pam_appl_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SECURITY_PAM_APPL_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sha2.h" "ac_cv_header_sha2_h" "$ac_includes_default"
+if test "x$ac_cv_header_sha2_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SHA2_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "shadow.h" "ac_cv_header_shadow_h" "$ac_includes_default"
+if test "x$ac_cv_header_shadow_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SHADOW_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "stddef.h" "ac_cv_header_stddef_h" "$ac_includes_default"
+if test "x$ac_cv_header_stddef_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_STDDEF_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default"
+if test "x$ac_cv_header_stdint_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_STDINT_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default"
+if test "x$ac_cv_header_string_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRING_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "strings.h" "ac_cv_header_strings_h" "$ac_includes_default"
+if test "x$ac_cv_header_strings_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRINGS_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/bitypes.h" "ac_cv_header_sys_bitypes_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_bitypes_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_BITYPES_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/byteorder.h" "ac_cv_header_sys_byteorder_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_byteorder_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_BYTEORDER_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/bsdtty.h" "ac_cv_header_sys_bsdtty_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_bsdtty_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_BSDTTY_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/cdefs.h" "ac_cv_header_sys_cdefs_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_cdefs_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_CDEFS_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/dir.h" "ac_cv_header_sys_dir_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_dir_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_DIR_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/file.h" "ac_cv_header_sys_file_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_file_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_FILE_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_mman_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_MMAN_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/label.h" "ac_cv_header_sys_label_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_label_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_LABEL_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/ndir.h" "ac_cv_header_sys_ndir_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_ndir_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_NDIR_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_param_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_poll_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_POLL_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/prctl.h" "ac_cv_header_sys_prctl_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_prctl_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_PRCTL_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/procctl.h" "ac_cv_header_sys_procctl_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_procctl_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_PROCCTL_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/pstat.h" "ac_cv_header_sys_pstat_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_pstat_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_PSTAT_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/ptrace.h" "ac_cv_header_sys_ptrace_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_ptrace_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_PTRACE_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_random_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_RANDOM_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_select_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_SELECT_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/stat.h" "ac_cv_header_sys_stat_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_stat_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_STAT_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/stream.h" "ac_cv_header_sys_stream_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_stream_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_STREAM_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/stropts.h" "ac_cv_header_sys_stropts_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_stropts_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_STROPTS_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/strtio.h" "ac_cv_header_sys_strtio_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_strtio_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_STRTIO_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/statvfs.h" "ac_cv_header_sys_statvfs_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_statvfs_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_STATVFS_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_sysmacros_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_SYSMACROS_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_time_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/timers.h" "ac_cv_header_sys_timers_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_timers_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_TIMERS_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "sys/vfs.h" "ac_cv_header_sys_vfs_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_vfs_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_VFS_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "time.h" "ac_cv_header_time_h" "$ac_includes_default"
+if test "x$ac_cv_header_time_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_TIME_H 1" >>confdefs.h
+fi
+ac_fn_c_check_header_compile "$LINENO" "tmpdir.h" "ac_cv_header_tmpdir_h" "$ac_includes_default"
+if test "x$ac_cv_header_tmpdir_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_TMPDIR_H 1" >>confdefs.h
fi
+ac_fn_c_check_header_compile "$LINENO" "ttyent.h" "ac_cv_header_ttyent_h" "$ac_includes_default"
+if test "x$ac_cv_header_ttyent_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_TTYENT_H 1" >>confdefs.h
+fi
+ac_fn_c_check_header_compile "$LINENO" "ucred.h" "ac_cv_header_ucred_h" "$ac_includes_default"
+if test "x$ac_cv_header_ucred_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_UCRED_H 1" >>confdefs.h
-# Check whether --with-Werror was given.
-if test "${with_Werror+set}" = set; then :
- withval=$with_Werror;
- if test -n "$withval" && test "x$withval" != "xno"; then
- werror_flags="-Werror"
- if test "x${withval}" != "xyes"; then
- werror_flags="$withval"
- fi
- fi
+fi
+ac_fn_c_check_header_compile "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default"
+if test "x$ac_cv_header_unistd_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_UNISTD_H 1" >>confdefs.h
+fi
+ac_fn_c_check_header_compile "$LINENO" "usersec.h" "ac_cv_header_usersec_h" "$ac_includes_default"
+if test "x$ac_cv_header_usersec_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_USERSEC_H 1" >>confdefs.h
fi
+ac_fn_c_check_header_compile "$LINENO" "util.h" "ac_cv_header_util_h" "$ac_includes_default"
+if test "x$ac_cv_header_util_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_UTIL_H 1" >>confdefs.h
+fi
+ac_fn_c_check_header_compile "$LINENO" "utime.h" "ac_cv_header_utime_h" "$ac_includes_default"
+if test "x$ac_cv_header_utime_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_UTIME_H 1" >>confdefs.h
-for ac_header in \
- blf.h \
- bstring.h \
- crypt.h \
- crypto/sha2.h \
- dirent.h \
- endian.h \
- elf.h \
- err.h \
- features.h \
- fcntl.h \
- floatingpoint.h \
- fnmatch.h \
- getopt.h \
- glob.h \
- ia.h \
- iaf.h \
- ifaddrs.h \
- inttypes.h \
- langinfo.h \
- limits.h \
- locale.h \
- login.h \
- maillock.h \
- ndir.h \
- net/if_tun.h \
- netdb.h \
- netgroup.h \
- pam/pam_appl.h \
- paths.h \
- poll.h \
- pty.h \
- readpassphrase.h \
- rpc/types.h \
- security/pam_appl.h \
- sha2.h \
- shadow.h \
- stddef.h \
- stdint.h \
- string.h \
- strings.h \
- sys/bitypes.h \
- sys/byteorder.h \
- sys/bsdtty.h \
- sys/cdefs.h \
- sys/dir.h \
- sys/file.h \
- sys/mman.h \
- sys/label.h \
- sys/ndir.h \
- sys/param.h \
- sys/poll.h \
- sys/prctl.h \
- sys/procctl.h \
- sys/pstat.h \
- sys/ptrace.h \
- sys/random.h \
- sys/select.h \
- sys/stat.h \
- sys/stream.h \
- sys/stropts.h \
- sys/strtio.h \
- sys/statvfs.h \
- sys/sysmacros.h \
- sys/time.h \
- sys/timers.h \
- sys/vfs.h \
- time.h \
- tmpdir.h \
- ttyent.h \
- ucred.h \
- unistd.h \
- usersec.h \
- util.h \
- utime.h \
- utmp.h \
- utmpx.h \
- vis.h \
- wchar.h \
+fi
+ac_fn_c_check_header_compile "$LINENO" "utmp.h" "ac_cv_header_utmp_h" "$ac_includes_default"
+if test "x$ac_cv_header_utmp_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_UTMP_H 1" >>confdefs.h
-do :
- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
+fi
+ac_fn_c_check_header_compile "$LINENO" "utmpx.h" "ac_cv_header_utmpx_h" "$ac_includes_default"
+if test "x$ac_cv_header_utmpx_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_UTMPX_H 1" >>confdefs.h
fi
+ac_fn_c_check_header_compile "$LINENO" "vis.h" "ac_cv_header_vis_h" "$ac_includes_default"
+if test "x$ac_cv_header_vis_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_VIS_H 1" >>confdefs.h
-done
+fi
+ac_fn_c_check_header_compile "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default"
+if test "x$ac_cv_header_wchar_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_WCHAR_H 1" >>confdefs.h
+
+fi
# On some platforms (eg SunOS4) sys/audit.h requires sys/[time|types|label.h]
# to be included first.
-for ac_header in sys/audit.h
-do :
- ac_fn_c_check_header_compile "$LINENO" "sys/audit.h" "ac_cv_header_sys_audit_h" "
+ac_fn_c_check_header_compile "$LINENO" "sys/audit.h" "ac_cv_header_sys_audit_h" "
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_LABEL_H
# include <sys/label.h>
#endif
"
-if test "x$ac_cv_header_sys_audit_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_SYS_AUDIT_H 1
-_ACEOF
+if test "x$ac_cv_header_sys_audit_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_AUDIT_H 1" >>confdefs.h
fi
-done
-
# sys/capsicum.h requires sys/types.h
-for ac_header in sys/capsicum.h
-do :
- ac_fn_c_check_header_compile "$LINENO" "sys/capsicum.h" "ac_cv_header_sys_capsicum_h" "
+ac_fn_c_check_header_compile "$LINENO" "sys/capsicum.h" "ac_cv_header_sys_capsicum_h" "
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
"
-if test "x$ac_cv_header_sys_capsicum_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_SYS_CAPSICUM_H 1
-_ACEOF
+if test "x$ac_cv_header_sys_capsicum_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_CAPSICUM_H 1" >>confdefs.h
fi
+ac_fn_c_check_header_compile "$LINENO" "capsicum_helpers.h" "ac_cv_header_capsicum_helpers_h" "
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+"
+if test "x$ac_cv_header_capsicum_helpers_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_CAPSICUM_HELPERS_H 1" >>confdefs.h
+
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for caph_cache_tzdata" >&5
+printf %s "checking for caph_cache_tzdata... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+ #include <capsicum_helpers.h>
+int
+main (void)
+{
+caph_cache_tzdata();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+printf "%s\n" "#define HAVE_CAPH_CACHE_TZDATA 1" >>confdefs.h
-done
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
# net/route.h requires sys/socket.h and sys/types.h.
# sys/sysctl.h also requires sys/param.h
-for ac_header in net/route.h sys/sysctl.h
-do :
- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "
+ac_fn_c_check_header_compile "$LINENO" "net/route.h" "ac_cv_header_net_route_h" "
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <sys/param.h>
#include <sys/socket.h>
"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
+if test "x$ac_cv_header_net_route_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_NET_ROUTE_H 1" >>confdefs.h
fi
+ac_fn_c_check_header_compile "$LINENO" "sys/sysctl.h" "ac_cv_header_sys_sysctl_h" "
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#include <sys/param.h>
+#include <sys/socket.h>
-done
+"
+if test "x$ac_cv_header_sys_sysctl_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_SYSCTL_H 1" >>confdefs.h
+
+fi
# lastlog.h requires sys/time.h to be included first on Solaris
-for ac_header in lastlog.h
-do :
- ac_fn_c_check_header_compile "$LINENO" "lastlog.h" "ac_cv_header_lastlog_h" "
+ac_fn_c_check_header_compile "$LINENO" "lastlog.h" "ac_cv_header_lastlog_h" "
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
"
-if test "x$ac_cv_header_lastlog_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LASTLOG_H 1
-_ACEOF
+if test "x$ac_cv_header_lastlog_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LASTLOG_H 1" >>confdefs.h
fi
-done
-
# sys/ptms.h requires sys/stream.h to be included first on Solaris
-for ac_header in sys/ptms.h
-do :
- ac_fn_c_check_header_compile "$LINENO" "sys/ptms.h" "ac_cv_header_sys_ptms_h" "
+ac_fn_c_check_header_compile "$LINENO" "sys/ptms.h" "ac_cv_header_sys_ptms_h" "
#ifdef HAVE_SYS_STREAM_H
# include <sys/stream.h>
#endif
"
-if test "x$ac_cv_header_sys_ptms_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_SYS_PTMS_H 1
-_ACEOF
+if test "x$ac_cv_header_sys_ptms_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_PTMS_H 1" >>confdefs.h
fi
-done
-
# login_cap.h requires sys/types.h on NetBSD
-for ac_header in login_cap.h
-do :
- ac_fn_c_check_header_compile "$LINENO" "login_cap.h" "ac_cv_header_login_cap_h" "
+ac_fn_c_check_header_compile "$LINENO" "login_cap.h" "ac_cv_header_login_cap_h" "
#include <sys/types.h>
"
-if test "x$ac_cv_header_login_cap_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LOGIN_CAP_H 1
-_ACEOF
+if test "x$ac_cv_header_login_cap_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LOGIN_CAP_H 1" >>confdefs.h
fi
-done
-
# older BSDs need sys/param.h before sys/mount.h
-for ac_header in sys/mount.h
-do :
- ac_fn_c_check_header_compile "$LINENO" "sys/mount.h" "ac_cv_header_sys_mount_h" "
+ac_fn_c_check_header_compile "$LINENO" "sys/mount.h" "ac_cv_header_sys_mount_h" "
#include <sys/param.h>
"
-if test "x$ac_cv_header_sys_mount_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_SYS_MOUNT_H 1
-_ACEOF
+if test "x$ac_cv_header_sys_mount_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_MOUNT_H 1" >>confdefs.h
fi
-done
-
# Android requires sys/socket.h to be included before sys/un.h
-for ac_header in sys/un.h
-do :
- ac_fn_c_check_header_compile "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" "
+ac_fn_c_check_header_compile "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" "
#include <sys/types.h>
#include <sys/socket.h>
"
-if test "x$ac_cv_header_sys_un_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_SYS_UN_H 1
-_ACEOF
+if test "x$ac_cv_header_sys_un_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_UN_H 1" >>confdefs.h
fi
-done
-
# Messages for features tested for in target-specific section
SIA_MSG="no"
SPC_MSG="no"
SP_MSG="no"
SPP_MSG="no"
# Support for Solaris/Illumos privileges (this test is used by both
# the --with-solaris-privs option and --with-sandbox=solaris).
SOLARIS_PRIVS="no"
# Check for some target-specific stuff
case "$host" in
*-*-aix*)
# Some versions of VAC won't allow macro redefinitions at
# -qlanglevel=ansi, and autoconf 2.60 sometimes insists on using that
# particularly with older versions of vac or xlc.
# It also throws errors about null macro arguments, but these are
# not fatal.
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler allows macro redefinitions" >&5
-$as_echo_n "checking if compiler allows macro redefinitions... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler allows macro redefinitions" >&5
+printf %s "checking if compiler allows macro redefinitions... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#define testmacro foo
#define testmacro bar
int
-main ()
+main (void)
{
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CC="`echo $CC | sed 's/-qlanglvl\=ansi//g'`"
CFLAGS="`echo $CFLAGS | sed 's/-qlanglvl\=ansi//g'`"
CPPFLAGS="`echo $CPPFLAGS | sed 's/-qlanglvl\=ansi//g'`"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to specify blibpath for linker ($LD)" >&5
-$as_echo_n "checking how to specify blibpath for linker ($LD)... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to specify blibpath for linker ($LD)" >&5
+printf %s "checking how to specify blibpath for linker ($LD)... " >&6; }
if (test -z "$blibpath"); then
blibpath="/usr/lib:/lib"
fi
saved_LDFLAGS="$LDFLAGS"
if test "$GCC" = "yes"; then
flags="-Wl,-blibpath: -Wl,-rpath, -blibpath:"
else
flags="-blibpath: -Wl,-blibpath: -Wl,-rpath,"
fi
for tryflags in $flags ;do
if (test -z "$blibflags"); then
LDFLAGS="$saved_LDFLAGS $tryflags$blibpath"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
blibflags=$tryflags
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
done
if (test -z "$blibflags"); then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
-$as_echo "not found" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+printf "%s\n" "not found" >&6; }
as_fn_error $? "*** must be able to specify blibpath on AIX - check config.log" "$LINENO" 5
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $blibflags" >&5
-$as_echo "$blibflags" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $blibflags" >&5
+printf "%s\n" "$blibflags" >&6; }
fi
LDFLAGS="$saved_LDFLAGS"
ac_fn_c_check_func "$LINENO" "authenticate" "ac_cv_func_authenticate"
-if test "x$ac_cv_func_authenticate" = xyes; then :
-
-$as_echo "#define WITH_AIXAUTHENTICATE 1" >>confdefs.h
-
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for authenticate in -ls" >&5
-$as_echo_n "checking for authenticate in -ls... " >&6; }
-if ${ac_cv_lib_s_authenticate+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+if test "x$ac_cv_func_authenticate" = xyes
+then :
+
+printf "%s\n" "#define WITH_AIXAUTHENTICATE 1" >>confdefs.h
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for authenticate in -ls" >&5
+printf %s "checking for authenticate in -ls... " >&6; }
+if test ${ac_cv_lib_s_authenticate+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-ls $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char authenticate ();
int
-main ()
+main (void)
{
return authenticate ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_s_authenticate=yes
-else
+else $as_nop
ac_cv_lib_s_authenticate=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_s_authenticate" >&5
-$as_echo "$ac_cv_lib_s_authenticate" >&6; }
-if test "x$ac_cv_lib_s_authenticate" = xyes; then :
- $as_echo "#define WITH_AIXAUTHENTICATE 1" >>confdefs.h
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_s_authenticate" >&5
+printf "%s\n" "$ac_cv_lib_s_authenticate" >&6; }
+if test "x$ac_cv_lib_s_authenticate" = xyes
+then :
+ printf "%s\n" "#define WITH_AIXAUTHENTICATE 1" >>confdefs.h
LIBS="$LIBS -ls"
fi
fi
- ac_fn_c_check_decl "$LINENO" "authenticate" "ac_cv_have_decl_authenticate" "#include <usersec.h>
-"
-if test "x$ac_cv_have_decl_authenticate" = xyes; then :
+ ac_fn_check_decl "$LINENO" "authenticate" "ac_cv_have_decl_authenticate" "#include <usersec.h>
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_authenticate" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_AUTHENTICATE $ac_have_decl
-_ACEOF
-ac_fn_c_check_decl "$LINENO" "loginrestrictions" "ac_cv_have_decl_loginrestrictions" "#include <usersec.h>
-"
-if test "x$ac_cv_have_decl_loginrestrictions" = xyes; then :
+printf "%s\n" "#define HAVE_DECL_AUTHENTICATE $ac_have_decl" >>confdefs.h
+ac_fn_check_decl "$LINENO" "loginrestrictions" "ac_cv_have_decl_loginrestrictions" "#include <usersec.h>
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_loginrestrictions" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_LOGINRESTRICTIONS $ac_have_decl
-_ACEOF
-ac_fn_c_check_decl "$LINENO" "loginsuccess" "ac_cv_have_decl_loginsuccess" "#include <usersec.h>
-"
-if test "x$ac_cv_have_decl_loginsuccess" = xyes; then :
+printf "%s\n" "#define HAVE_DECL_LOGINRESTRICTIONS $ac_have_decl" >>confdefs.h
+ac_fn_check_decl "$LINENO" "loginsuccess" "ac_cv_have_decl_loginsuccess" "#include <usersec.h>
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_loginsuccess" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_LOGINSUCCESS $ac_have_decl
-_ACEOF
-ac_fn_c_check_decl "$LINENO" "passwdexpired" "ac_cv_have_decl_passwdexpired" "#include <usersec.h>
-"
-if test "x$ac_cv_have_decl_passwdexpired" = xyes; then :
+printf "%s\n" "#define HAVE_DECL_LOGINSUCCESS $ac_have_decl" >>confdefs.h
+ac_fn_check_decl "$LINENO" "passwdexpired" "ac_cv_have_decl_passwdexpired" "#include <usersec.h>
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_passwdexpired" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_PASSWDEXPIRED $ac_have_decl
-_ACEOF
-ac_fn_c_check_decl "$LINENO" "setauthdb" "ac_cv_have_decl_setauthdb" "#include <usersec.h>
-"
-if test "x$ac_cv_have_decl_setauthdb" = xyes; then :
+printf "%s\n" "#define HAVE_DECL_PASSWDEXPIRED $ac_have_decl" >>confdefs.h
+ac_fn_check_decl "$LINENO" "setauthdb" "ac_cv_have_decl_setauthdb" "#include <usersec.h>
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_setauthdb" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
+printf "%s\n" "#define HAVE_DECL_SETAUTHDB $ac_have_decl" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_SETAUTHDB $ac_have_decl
-_ACEOF
-
- ac_fn_c_check_decl "$LINENO" "loginfailed" "ac_cv_have_decl_loginfailed" "#include <usersec.h>
+ ac_fn_check_decl "$LINENO" "loginfailed" "ac_cv_have_decl_loginfailed" "#include <usersec.h>
-"
-if test "x$ac_cv_have_decl_loginfailed" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_loginfailed" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_LOGINFAILED $ac_have_decl
-_ACEOF
-if test $ac_have_decl = 1; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if loginfailed takes 4 arguments" >&5
-$as_echo_n "checking if loginfailed takes 4 arguments... " >&6; }
+printf "%s\n" "#define HAVE_DECL_LOGINFAILED $ac_have_decl" >>confdefs.h
+if test $ac_have_decl = 1
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if loginfailed takes 4 arguments" >&5
+printf %s "checking if loginfailed takes 4 arguments... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <usersec.h>
int
-main ()
+main (void)
{
(void)loginfailed("user","host","tty",0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define AIX_LOGINFAILED_4ARG 1" >>confdefs.h
+printf "%s\n" "#define AIX_LOGINFAILED_4ARG 1" >>confdefs.h
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
- for ac_func in getgrset setauthdb
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "getgrset" "ac_cv_func_getgrset"
+if test "x$ac_cv_func_getgrset" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETGRSET 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "setauthdb" "ac_cv_func_setauthdb"
+if test "x$ac_cv_func_setauthdb" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETAUTHDB 1" >>confdefs.h
fi
-done
- ac_fn_c_check_decl "$LINENO" "F_CLOSEM" "ac_cv_have_decl_F_CLOSEM" " #include <limits.h>
+ ac_fn_check_decl "$LINENO" "F_CLOSEM" "ac_cv_have_decl_F_CLOSEM" " #include <limits.h>
#include <fcntl.h>
-"
-if test "x$ac_cv_have_decl_F_CLOSEM" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_F_CLOSEM" = xyes
+then :
-$as_echo "#define HAVE_FCNTL_CLOSEM 1" >>confdefs.h
+printf "%s\n" "#define HAVE_FCNTL_CLOSEM 1" >>confdefs.h
fi
-
check_for_aix_broken_getaddrinfo=1
-$as_echo "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
+printf "%s\n" "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
-$as_echo "#define BROKEN_SETREUID 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_SETREUID 1" >>confdefs.h
-$as_echo "#define BROKEN_SETREGID 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_SETREGID 1" >>confdefs.h
-$as_echo "#define DISABLE_LASTLOG 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_LASTLOG 1" >>confdefs.h
-$as_echo "#define LOGIN_NEEDS_UTMPX 1" >>confdefs.h
+printf "%s\n" "#define LOGIN_NEEDS_UTMPX 1" >>confdefs.h
-$as_echo "#define SPT_TYPE SPT_REUSEARGV" >>confdefs.h
+printf "%s\n" "#define SPT_TYPE SPT_REUSEARGV" >>confdefs.h
-$as_echo "#define SSHPAM_CHAUTHTOK_NEEDS_RUID 1" >>confdefs.h
+printf "%s\n" "#define SSHPAM_CHAUTHTOK_NEEDS_RUID 1" >>confdefs.h
-$as_echo "#define PTY_ZEROREAD 1" >>confdefs.h
+printf "%s\n" "#define PTY_ZEROREAD 1" >>confdefs.h
-$as_echo "#define PLATFORM_SYS_DIR_UID 2" >>confdefs.h
+printf "%s\n" "#define PLATFORM_SYS_DIR_UID 2" >>confdefs.h
-$as_echo "#define BROKEN_STRNDUP 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_STRNDUP 1" >>confdefs.h
-$as_echo "#define BROKEN_STRNLEN 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_STRNLEN 1" >>confdefs.h
;;
*-*-android*)
-$as_echo "#define DISABLE_UTMP 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_UTMP 1" >>confdefs.h
-$as_echo "#define DISABLE_WTMP 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_WTMP 1" >>confdefs.h
;;
*-*-cygwin*)
- check_for_libcrypt_later=1
LIBS="$LIBS /usr/lib/textreadmode.o"
-$as_echo "#define HAVE_CYGWIN 1" >>confdefs.h
+printf "%s\n" "#define HAVE_CYGWIN 1" >>confdefs.h
-$as_echo "#define USE_PIPES 1" >>confdefs.h
+printf "%s\n" "#define USE_PIPES 1" >>confdefs.h
-$as_echo "#define NO_UID_RESTORATION_TEST 1" >>confdefs.h
+printf "%s\n" "#define NO_UID_RESTORATION_TEST 1" >>confdefs.h
-$as_echo "#define DISABLE_SHADOW 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_SHADOW 1" >>confdefs.h
-$as_echo "#define NO_X11_UNIX_SOCKETS 1" >>confdefs.h
+printf "%s\n" "#define NO_X11_UNIX_SOCKETS 1" >>confdefs.h
-$as_echo "#define DISABLE_FD_PASSING 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_FD_PASSING 1" >>confdefs.h
-$as_echo "#define SSH_IOBUFSZ 65535" >>confdefs.h
+printf "%s\n" "#define SSH_IOBUFSZ 65535" >>confdefs.h
-$as_echo "#define FILESYSTEM_NO_BACKSLASH 1" >>confdefs.h
+printf "%s\n" "#define FILESYSTEM_NO_BACKSLASH 1" >>confdefs.h
# Cygwin defines optargs, optargs as declspec(dllimport) for historical
# reasons which cause compile warnings, so we disable those warnings.
{
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wno-attributes" >&5
-$as_echo_n "checking if $CC supports compile flag -Wno-attributes... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wno-attributes" >&5
+printf %s "checking if $CC supports compile flag -Wno-attributes... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WERROR -Wno-attributes"
_define_flag=""
test "x$_define_flag" = "x" && _define_flag="-Wno-attributes"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
/* Trivial function to help test for -fzero-call-used-regs */
void f(int n) {}
int main(int argc, char **argv) {
(void)argv;
/* Some math to catch -ftrapv problems in the toolchain */
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
float l = i * 2.1;
double m = l / 0.5;
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
f(0);
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
/*
* Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
* not understand comments and we don't use the "fallthrough" attribute
* that it's looking for.
*/
switch(i){
case 0: j += i;
/* FALLTHROUGH */
default: j += k;
}
exit(0);
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
CFLAGS="$saved_CFLAGS"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
}
;;
*-*-dgux*)
-$as_echo "#define IP_TOS_IS_BROKEN 1" >>confdefs.h
+printf "%s\n" "#define IP_TOS_IS_BROKEN 1" >>confdefs.h
- $as_echo "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
+ printf "%s\n" "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREUID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREGID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREGID 1" >>confdefs.h
;;
*-*-darwin*)
use_pie=auto
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have working getaddrinfo" >&5
-$as_echo_n "checking if we have working getaddrinfo... " >&6; }
- if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: assume it is working" >&5
-$as_echo "assume it is working" >&6; }
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we have working getaddrinfo" >&5
+printf %s "checking if we have working getaddrinfo... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: assume it is working" >&5
+printf "%s\n" "assume it is working" >&6; }
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <mach-o/dyld.h>
#include <stdlib.h>
main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
exit(0);
else
exit(1);
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: working" >&5
-$as_echo "working" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: buggy" >&5
-$as_echo "buggy" >&6; }
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: working" >&5
+printf "%s\n" "working" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: buggy" >&5
+printf "%s\n" "buggy" >&6; }
-$as_echo "#define BROKEN_GETADDRINFO 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_GETADDRINFO 1" >>confdefs.h
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
- $as_echo "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
+ printf "%s\n" "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREUID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREGID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREGID 1" >>confdefs.h
-$as_echo "#define BROKEN_GLOB 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_GLOB 1" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define BIND_8_COMPAT 1
-_ACEOF
+printf "%s\n" "#define BIND_8_COMPAT 1" >>confdefs.h
-$as_echo "#define SSH_TUN_FREEBSD 1" >>confdefs.h
+printf "%s\n" "#define SSH_TUN_FREEBSD 1" >>confdefs.h
-$as_echo "#define SSH_TUN_COMPAT_AF 1" >>confdefs.h
+printf "%s\n" "#define SSH_TUN_COMPAT_AF 1" >>confdefs.h
-$as_echo "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h
+printf "%s\n" "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h
- ac_fn_c_check_decl "$LINENO" "AU_IPv4" "ac_cv_have_decl_AU_IPv4" "$ac_includes_default"
-if test "x$ac_cv_have_decl_AU_IPv4" = xyes; then :
+ ac_fn_check_decl "$LINENO" "AU_IPv4" "ac_cv_have_decl_AU_IPv4" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_AU_IPv4" = xyes
+then :
-else
+else $as_nop
-$as_echo "#define AU_IPv4 0" >>confdefs.h
+printf "%s\n" "#define AU_IPv4 0" >>confdefs.h
#include <bsm/audit.h>
-$as_echo "#define LASTLOG_WRITE_PUTUTXLINE 1" >>confdefs.h
+printf "%s\n" "#define LASTLOG_WRITE_PUTUTXLINE 1" >>confdefs.h
fi
+printf "%s\n" "#define SPT_TYPE SPT_REUSEARGV" >>confdefs.h
-$as_echo "#define SPT_TYPE SPT_REUSEARGV" >>confdefs.h
-
- for ac_func in sandbox_init
-do :
- ac_fn_c_check_func "$LINENO" "sandbox_init" "ac_cv_func_sandbox_init"
-if test "x$ac_cv_func_sandbox_init" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_SANDBOX_INIT 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "sandbox_init" "ac_cv_func_sandbox_init"
+if test "x$ac_cv_func_sandbox_init" = xyes
+then :
+ printf "%s\n" "#define HAVE_SANDBOX_INIT 1" >>confdefs.h
fi
-done
- for ac_header in sandbox.h
-do :
- ac_fn_c_check_header_mongrel "$LINENO" "sandbox.h" "ac_cv_header_sandbox_h" "$ac_includes_default"
-if test "x$ac_cv_header_sandbox_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_SANDBOX_H 1
-_ACEOF
+ ac_fn_c_check_header_compile "$LINENO" "sandbox.h" "ac_cv_header_sandbox_h" "$ac_includes_default"
+if test "x$ac_cv_header_sandbox_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SANDBOX_H 1" >>confdefs.h
fi
-done
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sandbox_apply in -lsandbox" >&5
-$as_echo_n "checking for sandbox_apply in -lsandbox... " >&6; }
-if ${ac_cv_lib_sandbox_sandbox_apply+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sandbox_apply in -lsandbox" >&5
+printf %s "checking for sandbox_apply in -lsandbox... " >&6; }
+if test ${ac_cv_lib_sandbox_sandbox_apply+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lsandbox $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char sandbox_apply ();
int
-main ()
+main (void)
{
return sandbox_apply ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_sandbox_sandbox_apply=yes
-else
+else $as_nop
ac_cv_lib_sandbox_sandbox_apply=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sandbox_sandbox_apply" >&5
-$as_echo "$ac_cv_lib_sandbox_sandbox_apply" >&6; }
-if test "x$ac_cv_lib_sandbox_sandbox_apply" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sandbox_sandbox_apply" >&5
+printf "%s\n" "$ac_cv_lib_sandbox_sandbox_apply" >&6; }
+if test "x$ac_cv_lib_sandbox_sandbox_apply" = xyes
+then :
SSHDLIBS="$SSHDLIBS -lsandbox"
fi
# proc_pidinfo()-based closefrom() replacement.
- for ac_header in libproc.h
-do :
- ac_fn_c_check_header_mongrel "$LINENO" "libproc.h" "ac_cv_header_libproc_h" "$ac_includes_default"
-if test "x$ac_cv_header_libproc_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBPROC_H 1
-_ACEOF
+ ac_fn_c_check_header_compile "$LINENO" "libproc.h" "ac_cv_header_libproc_h" "$ac_includes_default"
+if test "x$ac_cv_header_libproc_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBPROC_H 1" >>confdefs.h
fi
-done
-
- for ac_func in proc_pidinfo
-do :
- ac_fn_c_check_func "$LINENO" "proc_pidinfo" "ac_cv_func_proc_pidinfo"
-if test "x$ac_cv_func_proc_pidinfo" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_PROC_PIDINFO 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "proc_pidinfo" "ac_cv_func_proc_pidinfo"
+if test "x$ac_cv_func_proc_pidinfo" = xyes
+then :
+ printf "%s\n" "#define HAVE_PROC_PIDINFO 1" >>confdefs.h
fi
-done
# poll(2) is broken for character-special devices (at least).
# cf. Apple bug 3710161 (not public, but searchable)
-$as_echo "#define BROKEN_POLL 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_POLL 1" >>confdefs.h
;;
*-*-dragonfly*)
- SSHDLIBS="$SSHDLIBS -lcrypt"
+ SSHDLIBS="$SSHDLIBS"
TEST_MALLOC_OPTIONS="AFGJPRX"
;;
*-*-haiku*)
LIBS="$LIBS -lbsd "
CFLAGS="$CFLAGS -D_BSD_SOURCE"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lnetwork" >&5
-$as_echo_n "checking for socket in -lnetwork... " >&6; }
-if ${ac_cv_lib_network_socket+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for socket in -lnetwork" >&5
+printf %s "checking for socket in -lnetwork... " >&6; }
+if test ${ac_cv_lib_network_socket+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lnetwork $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char socket ();
int
-main ()
+main (void)
{
return socket ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_network_socket=yes
-else
+else $as_nop
ac_cv_lib_network_socket=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_socket" >&5
-$as_echo "$ac_cv_lib_network_socket" >&6; }
-if test "x$ac_cv_lib_network_socket" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBNETWORK 1
-_ACEOF
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_socket" >&5
+printf "%s\n" "$ac_cv_lib_network_socket" >&6; }
+if test "x$ac_cv_lib_network_socket" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBNETWORK 1" >>confdefs.h
LIBS="-lnetwork $LIBS"
fi
- $as_echo "#define HAVE_U_INT64_T 1" >>confdefs.h
+ printf "%s\n" "#define HAVE_U_INT64_T 1" >>confdefs.h
-$as_echo "#define DISABLE_UTMPX 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_UTMPX 1" >>confdefs.h
MANTYPE=man
;;
*-*-hpux*)
# first we define all of the options common to all HP-UX releases
CPPFLAGS="$CPPFLAGS -D_HPUX_SOURCE -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1"
IPADDR_IN_DISPLAY=yes
- $as_echo "#define USE_PIPES 1" >>confdefs.h
+ printf "%s\n" "#define USE_PIPES 1" >>confdefs.h
- $as_echo "#define LOGIN_NEEDS_UTMPX 1" >>confdefs.h
+ printf "%s\n" "#define LOGIN_NEEDS_UTMPX 1" >>confdefs.h
-$as_echo "#define LOCKED_PASSWD_STRING \"*\"" >>confdefs.h
+printf "%s\n" "#define LOCKED_PASSWD_STRING \"*\"" >>confdefs.h
- $as_echo "#define SPT_TYPE SPT_PSTAT" >>confdefs.h
+ printf "%s\n" "#define SPT_TYPE SPT_PSTAT" >>confdefs.h
-$as_echo "#define PLATFORM_SYS_DIR_UID 2" >>confdefs.h
+printf "%s\n" "#define PLATFORM_SYS_DIR_UID 2" >>confdefs.h
maildir="/var/mail"
LIBS="$LIBS -lsec"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for t_error in -lxnet" >&5
-$as_echo_n "checking for t_error in -lxnet... " >&6; }
-if ${ac_cv_lib_xnet_t_error+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for t_error in -lxnet" >&5
+printf %s "checking for t_error in -lxnet... " >&6; }
+if test ${ac_cv_lib_xnet_t_error+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lxnet $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char t_error ();
int
-main ()
+main (void)
{
return t_error ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_xnet_t_error=yes
-else
+else $as_nop
ac_cv_lib_xnet_t_error=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xnet_t_error" >&5
-$as_echo "$ac_cv_lib_xnet_t_error" >&6; }
-if test "x$ac_cv_lib_xnet_t_error" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBXNET 1
-_ACEOF
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xnet_t_error" >&5
+printf "%s\n" "$ac_cv_lib_xnet_t_error" >&6; }
+if test "x$ac_cv_lib_xnet_t_error" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBXNET 1" >>confdefs.h
LIBS="-lxnet $LIBS"
-else
+else $as_nop
as_fn_error $? "*** -lxnet needed on HP-UX - check config.log ***" "$LINENO" 5
fi
# next, we define all of the options specific to major releases
case "$host" in
*-*-hpux10*)
if test -z "$GCC"; then
CFLAGS="$CFLAGS -Ae"
fi
-$as_echo "#define BROKEN_GETLINE 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_GETLINE 1" >>confdefs.h
;;
*-*-hpux11*)
-$as_echo "#define PAM_SUN_CODEBASE 1" >>confdefs.h
+printf "%s\n" "#define PAM_SUN_CODEBASE 1" >>confdefs.h
-$as_echo "#define DISABLE_UTMP 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_UTMP 1" >>confdefs.h
-$as_echo "#define USE_BTMP 1" >>confdefs.h
+printf "%s\n" "#define USE_BTMP 1" >>confdefs.h
check_for_hpux_broken_getaddrinfo=1
check_for_conflicting_getspnam=1
;;
esac
# lastly, we define options specific to minor releases
case "$host" in
*-*-hpux10.26)
-$as_echo "#define HAVE_SECUREWARE 1" >>confdefs.h
+printf "%s\n" "#define HAVE_SECUREWARE 1" >>confdefs.h
disable_ptmx_check=yes
LIBS="$LIBS -lsecpw"
;;
esac
;;
*-*-irix5*)
PATH="$PATH:/usr/etc"
-$as_echo "#define BROKEN_INET_NTOA 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_INET_NTOA 1" >>confdefs.h
- $as_echo "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
+ printf "%s\n" "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREUID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREGID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREGID 1" >>confdefs.h
-$as_echo "#define WITH_ABBREV_NO_TTY 1" >>confdefs.h
+printf "%s\n" "#define WITH_ABBREV_NO_TTY 1" >>confdefs.h
- $as_echo "#define LOCKED_PASSWD_STRING \"*LK*\"" >>confdefs.h
+ printf "%s\n" "#define LOCKED_PASSWD_STRING \"*LK*\"" >>confdefs.h
;;
*-*-irix6*)
PATH="$PATH:/usr/etc"
-$as_echo "#define WITH_IRIX_ARRAY 1" >>confdefs.h
+printf "%s\n" "#define WITH_IRIX_ARRAY 1" >>confdefs.h
-$as_echo "#define WITH_IRIX_PROJECT 1" >>confdefs.h
+printf "%s\n" "#define WITH_IRIX_PROJECT 1" >>confdefs.h
-$as_echo "#define WITH_IRIX_AUDIT 1" >>confdefs.h
+printf "%s\n" "#define WITH_IRIX_AUDIT 1" >>confdefs.h
ac_fn_c_check_func "$LINENO" "jlimit_startjob" "ac_cv_func_jlimit_startjob"
-if test "x$ac_cv_func_jlimit_startjob" = xyes; then :
+if test "x$ac_cv_func_jlimit_startjob" = xyes
+then :
-$as_echo "#define WITH_IRIX_JOBS 1" >>confdefs.h
+printf "%s\n" "#define WITH_IRIX_JOBS 1" >>confdefs.h
fi
- $as_echo "#define BROKEN_INET_NTOA 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_INET_NTOA 1" >>confdefs.h
- $as_echo "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
+ printf "%s\n" "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREUID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREGID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREGID 1" >>confdefs.h
-$as_echo "#define BROKEN_UPDWTMPX 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_UPDWTMPX 1" >>confdefs.h
- $as_echo "#define WITH_ABBREV_NO_TTY 1" >>confdefs.h
+ printf "%s\n" "#define WITH_ABBREV_NO_TTY 1" >>confdefs.h
- $as_echo "#define LOCKED_PASSWD_STRING \"*LK*\"" >>confdefs.h
+ printf "%s\n" "#define LOCKED_PASSWD_STRING \"*LK*\"" >>confdefs.h
;;
*-*-k*bsd*-gnu | *-*-kopensolaris*-gnu)
- check_for_libcrypt_later=1
- $as_echo "#define PAM_TTY_KLUDGE 1" >>confdefs.h
+ printf "%s\n" "#define PAM_TTY_KLUDGE 1" >>confdefs.h
- $as_echo "#define LOCKED_PASSWD_PREFIX \"!\"" >>confdefs.h
+ printf "%s\n" "#define LOCKED_PASSWD_PREFIX \"!\"" >>confdefs.h
- $as_echo "#define SPT_TYPE SPT_REUSEARGV" >>confdefs.h
+ printf "%s\n" "#define SPT_TYPE SPT_REUSEARGV" >>confdefs.h
-$as_echo "#define _PATH_BTMP \"/var/log/btmp\"" >>confdefs.h
+printf "%s\n" "#define _PATH_BTMP \"/var/log/btmp\"" >>confdefs.h
-$as_echo "#define USE_BTMP 1" >>confdefs.h
+printf "%s\n" "#define USE_BTMP 1" >>confdefs.h
;;
*-*-linux*)
no_dev_ptmx=1
use_pie=auto
- check_for_libcrypt_later=1
check_for_openpty_ctty_bug=1
CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_DEFAULT_SOURCE"
-$as_echo "#define BROKEN_CLOSEFROM 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_CLOSEFROM 1" >>confdefs.h
-$as_echo "#define PAM_TTY_KLUDGE 1" >>confdefs.h
+printf "%s\n" "#define PAM_TTY_KLUDGE 1" >>confdefs.h
-$as_echo "#define LOCKED_PASSWD_PREFIX \"!\"" >>confdefs.h
+printf "%s\n" "#define LOCKED_PASSWD_PREFIX \"!\"" >>confdefs.h
- $as_echo "#define SPT_TYPE SPT_REUSEARGV" >>confdefs.h
+ printf "%s\n" "#define SPT_TYPE SPT_REUSEARGV" >>confdefs.h
-$as_echo "#define LINK_OPNOTSUPP_ERRNO EPERM" >>confdefs.h
+printf "%s\n" "#define LINK_OPNOTSUPP_ERRNO EPERM" >>confdefs.h
-$as_echo "#define _PATH_BTMP \"/var/log/btmp\"" >>confdefs.h
+printf "%s\n" "#define _PATH_BTMP \"/var/log/btmp\"" >>confdefs.h
- $as_echo "#define USE_BTMP 1" >>confdefs.h
+ printf "%s\n" "#define USE_BTMP 1" >>confdefs.h
-$as_echo "#define LINUX_OOM_ADJUST 1" >>confdefs.h
+printf "%s\n" "#define LINUX_OOM_ADJUST 1" >>confdefs.h
inet6_default_4in6=yes
case `uname -r` in
1.*|2.0.*)
-$as_echo "#define BROKEN_CMSG_TYPE 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_CMSG_TYPE 1" >>confdefs.h
;;
esac
# tun(4) forwarding compat code
- for ac_header in linux/if_tun.h
-do :
- ac_fn_c_check_header_mongrel "$LINENO" "linux/if_tun.h" "ac_cv_header_linux_if_tun_h" "$ac_includes_default"
-if test "x$ac_cv_header_linux_if_tun_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LINUX_IF_TUN_H 1
-_ACEOF
+ ac_fn_c_check_header_compile "$LINENO" "linux/if_tun.h" "ac_cv_header_linux_if_tun_h" "$ac_includes_default"
+if test "x$ac_cv_header_linux_if_tun_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LINUX_IF_TUN_H 1" >>confdefs.h
fi
-done
-
if test "x$ac_cv_header_linux_if_tun_h" = "xyes" ; then
-$as_echo "#define SSH_TUN_LINUX 1" >>confdefs.h
+printf "%s\n" "#define SSH_TUN_LINUX 1" >>confdefs.h
-$as_echo "#define SSH_TUN_COMPAT_AF 1" >>confdefs.h
+printf "%s\n" "#define SSH_TUN_COMPAT_AF 1" >>confdefs.h
-$as_echo "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h
+printf "%s\n" "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h
fi
ac_fn_c_check_header_compile "$LINENO" "linux/if.h" "ac_cv_header_linux_if_h" "
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
"
-if test "x$ac_cv_header_linux_if_h" = xyes; then :
+if test "x$ac_cv_header_linux_if_h" = xyes
+then :
-$as_echo "#define SYS_RDOMAIN_LINUX 1" >>confdefs.h
+printf "%s\n" "#define SYS_RDOMAIN_LINUX 1" >>confdefs.h
fi
+ ac_fn_c_check_header_compile "$LINENO" "linux/seccomp.h" "ac_cv_header_linux_seccomp_h" "#include <linux/types.h>
+"
+if test "x$ac_cv_header_linux_seccomp_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LINUX_SECCOMP_H 1" >>confdefs.h
- for ac_header in linux/seccomp.h linux/filter.h linux/audit.h
-do :
- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include <linux/types.h>
+fi
+ac_fn_c_check_header_compile "$LINENO" "linux/filter.h" "ac_cv_header_linux_filter_h" "#include <linux/types.h>
"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
+if test "x$ac_cv_header_linux_filter_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LINUX_FILTER_H 1" >>confdefs.h
fi
+ac_fn_c_check_header_compile "$LINENO" "linux/audit.h" "ac_cv_header_linux_audit_h" "#include <linux/types.h>
+"
+if test "x$ac_cv_header_linux_audit_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LINUX_AUDIT_H 1" >>confdefs.h
-done
+fi
# Obtain MIPS ABI
case "$host" in
mips*)
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#if _MIPS_SIM != _ABIO32
#error
#endif
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
mips_abi="o32"
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#if _MIPS_SIM != _ABIN32
#error
#endif
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
mips_abi="n32"
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#if _MIPS_SIM != _ABI64
#error
#endif
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
mips_abi="n64"
-else
+else $as_nop
as_fn_error $? "unknown MIPS ABI" "$LINENO" 5
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
;;
esac
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for seccomp architecture" >&5
-$as_echo_n "checking for seccomp architecture... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for seccomp architecture" >&5
+printf %s "checking for seccomp architecture... " >&6; }
seccomp_audit_arch=
case "$host" in
x86_64-*)
seccomp_audit_arch=AUDIT_ARCH_X86_64
;;
i*86-*)
seccomp_audit_arch=AUDIT_ARCH_I386
;;
arm*-*)
seccomp_audit_arch=AUDIT_ARCH_ARM
;;
aarch64*-*)
seccomp_audit_arch=AUDIT_ARCH_AARCH64
;;
s390x-*)
seccomp_audit_arch=AUDIT_ARCH_S390X
;;
s390-*)
seccomp_audit_arch=AUDIT_ARCH_S390
;;
+ powerpc-*)
+ seccomp_audit_arch=AUDIT_ARCH_PPC
+ ;;
powerpc64-*)
seccomp_audit_arch=AUDIT_ARCH_PPC64
;;
powerpc64le-*)
seccomp_audit_arch=AUDIT_ARCH_PPC64LE
;;
mips-*)
seccomp_audit_arch=AUDIT_ARCH_MIPS
;;
mipsel-*)
seccomp_audit_arch=AUDIT_ARCH_MIPSEL
;;
mips64-*)
case "$mips_abi" in
"n32")
seccomp_audit_arch=AUDIT_ARCH_MIPS64N32
;;
"n64")
seccomp_audit_arch=AUDIT_ARCH_MIPS64
;;
esac
;;
mips64el-*)
case "$mips_abi" in
"n32")
seccomp_audit_arch=AUDIT_ARCH_MIPSEL64N32
;;
"n64")
seccomp_audit_arch=AUDIT_ARCH_MIPSEL64
;;
esac
;;
riscv64-*)
seccomp_audit_arch=AUDIT_ARCH_RISCV64
;;
esac
if test "x$seccomp_audit_arch" != "x" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$seccomp_audit_arch\"" >&5
-$as_echo "\"$seccomp_audit_arch\"" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$seccomp_audit_arch\"" >&5
+printf "%s\n" "\"$seccomp_audit_arch\"" >&6; }
-cat >>confdefs.h <<_ACEOF
-#define SECCOMP_AUDIT_ARCH $seccomp_audit_arch
-_ACEOF
+printf "%s\n" "#define SECCOMP_AUDIT_ARCH $seccomp_audit_arch" >>confdefs.h
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: architecture not supported" >&5
-$as_echo "architecture not supported" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: architecture not supported" >&5
+printf "%s\n" "architecture not supported" >&6; }
fi
;;
*-*-minix)
- $as_echo "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
+ printf "%s\n" "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
# poll(2) seems to choke on /dev/null; "Bad file descriptor"
-$as_echo "#define BROKEN_POLL 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_POLL 1" >>confdefs.h
;;
mips-sony-bsd|mips-sony-newsos4)
-$as_echo "#define NEED_SETPGRP 1" >>confdefs.h
+printf "%s\n" "#define NEED_SETPGRP 1" >>confdefs.h
SONY=1
;;
*-*-netbsd*)
- check_for_libcrypt_before=1
if test "x$withval" != "xno" ; then
rpath_opt="-R"
fi
CPPFLAGS="$CPPFLAGS -D_OPENBSD_SOURCE"
-$as_echo "#define SSH_TUN_FREEBSD 1" >>confdefs.h
+printf "%s\n" "#define SSH_TUN_FREEBSD 1" >>confdefs.h
- ac_fn_c_check_header_mongrel "$LINENO" "net/if_tap.h" "ac_cv_header_net_if_tap_h" "$ac_includes_default"
-if test "x$ac_cv_header_net_if_tap_h" = xyes; then :
+ ac_fn_c_check_header_compile "$LINENO" "net/if_tap.h" "ac_cv_header_net_if_tap_h" "$ac_includes_default"
+if test "x$ac_cv_header_net_if_tap_h" = xyes
+then :
-else
+else $as_nop
-$as_echo "#define SSH_TUN_NO_L2 1" >>confdefs.h
+printf "%s\n" "#define SSH_TUN_NO_L2 1" >>confdefs.h
fi
-
-$as_echo "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h
+printf "%s\n" "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h
TEST_MALLOC_OPTIONS="AJRX"
-$as_echo "#define BROKEN_READ_COMPARISON 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_READ_COMPARISON 1" >>confdefs.h
;;
*-*-freebsd*)
- check_for_libcrypt_later=1
-$as_echo "#define LOCKED_PASSWD_PREFIX \"*LOCKED*\"" >>confdefs.h
+printf "%s\n" "#define LOCKED_PASSWD_PREFIX \"*LOCKED*\"" >>confdefs.h
-$as_echo "#define SSH_TUN_FREEBSD 1" >>confdefs.h
+printf "%s\n" "#define SSH_TUN_FREEBSD 1" >>confdefs.h
- ac_fn_c_check_header_mongrel "$LINENO" "net/if_tap.h" "ac_cv_header_net_if_tap_h" "$ac_includes_default"
-if test "x$ac_cv_header_net_if_tap_h" = xyes; then :
+ ac_fn_c_check_header_compile "$LINENO" "net/if_tap.h" "ac_cv_header_net_if_tap_h" "$ac_includes_default"
+if test "x$ac_cv_header_net_if_tap_h" = xyes
+then :
-else
+else $as_nop
-$as_echo "#define SSH_TUN_NO_L2 1" >>confdefs.h
+printf "%s\n" "#define SSH_TUN_NO_L2 1" >>confdefs.h
fi
-
-$as_echo "#define BROKEN_GLOB 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_GLOB 1" >>confdefs.h
TEST_MALLOC_OPTIONS="AJRX"
# Preauth crypto occasionally uses file descriptors for crypto offload
# and will crash if they cannot be opened.
-$as_echo "#define SANDBOX_SKIP_RLIMIT_NOFILE 1" >>confdefs.h
+printf "%s\n" "#define SANDBOX_SKIP_RLIMIT_NOFILE 1" >>confdefs.h
case "$host" in
*-*-freebsd9.*|*-*-freebsd10.*)
# Capsicum on 9 and 10 do not allow ppoll() so don't auto-enable.
disable_capsicum=yes
esac
;;
*-*-bsdi*)
- $as_echo "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
+ printf "%s\n" "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREUID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREGID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREGID 1" >>confdefs.h
;;
*-next-*)
conf_lastlog_location="/usr/adm/lastlog"
conf_utmp_location=/etc/utmp
conf_wtmp_location=/usr/adm/wtmp
maildir=/usr/spool/mail
-$as_echo "#define HAVE_NEXT 1" >>confdefs.h
+printf "%s\n" "#define HAVE_NEXT 1" >>confdefs.h
- $as_echo "#define USE_PIPES 1" >>confdefs.h
+ printf "%s\n" "#define USE_PIPES 1" >>confdefs.h
-$as_echo "#define BROKEN_SAVED_UIDS 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_SAVED_UIDS 1" >>confdefs.h
;;
*-*-openbsd*)
use_pie=auto
-$as_echo "#define HAVE_ATTRIBUTE__SENTINEL__ 1" >>confdefs.h
+printf "%s\n" "#define HAVE_ATTRIBUTE__SENTINEL__ 1" >>confdefs.h
-$as_echo "#define HAVE_ATTRIBUTE__BOUNDED__ 1" >>confdefs.h
+printf "%s\n" "#define HAVE_ATTRIBUTE__BOUNDED__ 1" >>confdefs.h
-$as_echo "#define SSH_TUN_OPENBSD 1" >>confdefs.h
+printf "%s\n" "#define SSH_TUN_OPENBSD 1" >>confdefs.h
-$as_echo "#define SYSLOG_R_SAFE_IN_SIGHAND 1" >>confdefs.h
+printf "%s\n" "#define SYSLOG_R_SAFE_IN_SIGHAND 1" >>confdefs.h
TEST_MALLOC_OPTIONS="AFGJPRX"
;;
*-*-solaris*)
if test "x$withval" != "xno" ; then
rpath_opt="-R"
fi
- $as_echo "#define PAM_SUN_CODEBASE 1" >>confdefs.h
+ printf "%s\n" "#define PAM_SUN_CODEBASE 1" >>confdefs.h
- $as_echo "#define LOGIN_NEEDS_UTMPX 1" >>confdefs.h
+ printf "%s\n" "#define LOGIN_NEEDS_UTMPX 1" >>confdefs.h
- $as_echo "#define PAM_TTY_KLUDGE 1" >>confdefs.h
+ printf "%s\n" "#define PAM_TTY_KLUDGE 1" >>confdefs.h
-$as_echo "#define SSHPAM_CHAUTHTOK_NEEDS_RUID 1" >>confdefs.h
+printf "%s\n" "#define SSHPAM_CHAUTHTOK_NEEDS_RUID 1" >>confdefs.h
- $as_echo "#define LOCKED_PASSWD_STRING \"*LK*\"" >>confdefs.h
+ printf "%s\n" "#define LOCKED_PASSWD_STRING \"*LK*\"" >>confdefs.h
# Pushing STREAMS modules will cause sshd to acquire a controlling tty.
-$as_echo "#define SSHD_ACQUIRES_CTTY 1" >>confdefs.h
+printf "%s\n" "#define SSHD_ACQUIRES_CTTY 1" >>confdefs.h
-$as_echo "#define PASSWD_NEEDS_USERNAME 1" >>confdefs.h
+printf "%s\n" "#define PASSWD_NEEDS_USERNAME 1" >>confdefs.h
-$as_echo "#define BROKEN_TCGETATTR_ICANON 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_TCGETATTR_ICANON 1" >>confdefs.h
external_path_file=/etc/default/login
# hardwire lastlog location (can't detect it on some versions)
conf_lastlog_location="/var/adm/lastlog"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for obsolete utmp and wtmp in solaris2.x" >&5
-$as_echo_n "checking for obsolete utmp and wtmp in solaris2.x... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for obsolete utmp and wtmp in solaris2.x" >&5
+printf %s "checking for obsolete utmp and wtmp in solaris2.x... " >&6; }
sol2ver=`echo "$host"| sed -e 's/.*[0-9]\.//'`
if test "$sol2ver" -ge 8; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- $as_echo "#define DISABLE_UTMP 1" >>confdefs.h
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ printf "%s\n" "#define DISABLE_UTMP 1" >>confdefs.h
-$as_echo "#define DISABLE_WTMP 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_WTMP 1" >>confdefs.h
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
- for ac_func in setpflags
-do :
- ac_fn_c_check_func "$LINENO" "setpflags" "ac_cv_func_setpflags"
-if test "x$ac_cv_func_setpflags" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_SETPFLAGS 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "setpflags" "ac_cv_func_setpflags"
+if test "x$ac_cv_func_setpflags" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETPFLAGS 1" >>confdefs.h
fi
-done
- for ac_func in setppriv
-do :
- ac_fn_c_check_func "$LINENO" "setppriv" "ac_cv_func_setppriv"
-if test "x$ac_cv_func_setppriv" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_SETPPRIV 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "setppriv" "ac_cv_func_setppriv"
+if test "x$ac_cv_func_setppriv" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETPPRIV 1" >>confdefs.h
fi
-done
- for ac_func in priv_basicset
-do :
- ac_fn_c_check_func "$LINENO" "priv_basicset" "ac_cv_func_priv_basicset"
-if test "x$ac_cv_func_priv_basicset" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_PRIV_BASICSET 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "priv_basicset" "ac_cv_func_priv_basicset"
+if test "x$ac_cv_func_priv_basicset" = xyes
+then :
+ printf "%s\n" "#define HAVE_PRIV_BASICSET 1" >>confdefs.h
fi
-done
- for ac_header in priv.h
-do :
- ac_fn_c_check_header_mongrel "$LINENO" "priv.h" "ac_cv_header_priv_h" "$ac_includes_default"
-if test "x$ac_cv_header_priv_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_PRIV_H 1
-_ACEOF
+ ac_fn_c_check_header_compile "$LINENO" "priv.h" "ac_cv_header_priv_h" "$ac_includes_default"
+if test "x$ac_cv_header_priv_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_PRIV_H 1" >>confdefs.h
fi
-done
-
# Check whether --with-solaris-contracts was given.
-if test "${with_solaris_contracts+set}" = set; then :
+if test ${with_solaris_contracts+y}
+then :
withval=$with_solaris_contracts;
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ct_tmpl_activate in -lcontract" >&5
-$as_echo_n "checking for ct_tmpl_activate in -lcontract... " >&6; }
-if ${ac_cv_lib_contract_ct_tmpl_activate+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ct_tmpl_activate in -lcontract" >&5
+printf %s "checking for ct_tmpl_activate in -lcontract... " >&6; }
+if test ${ac_cv_lib_contract_ct_tmpl_activate+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lcontract $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char ct_tmpl_activate ();
int
-main ()
+main (void)
{
return ct_tmpl_activate ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_contract_ct_tmpl_activate=yes
-else
+else $as_nop
ac_cv_lib_contract_ct_tmpl_activate=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_contract_ct_tmpl_activate" >&5
-$as_echo "$ac_cv_lib_contract_ct_tmpl_activate" >&6; }
-if test "x$ac_cv_lib_contract_ct_tmpl_activate" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_contract_ct_tmpl_activate" >&5
+printf "%s\n" "$ac_cv_lib_contract_ct_tmpl_activate" >&6; }
+if test "x$ac_cv_lib_contract_ct_tmpl_activate" = xyes
+then :
-$as_echo "#define USE_SOLARIS_PROCESS_CONTRACTS 1" >>confdefs.h
+printf "%s\n" "#define USE_SOLARIS_PROCESS_CONTRACTS 1" >>confdefs.h
LIBS="$LIBS -lcontract"
SPC_MSG="yes"
fi
fi
# Check whether --with-solaris-projects was given.
-if test "${with_solaris_projects+set}" = set; then :
+if test ${with_solaris_projects+y}
+then :
withval=$with_solaris_projects;
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setproject in -lproject" >&5
-$as_echo_n "checking for setproject in -lproject... " >&6; }
-if ${ac_cv_lib_project_setproject+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for setproject in -lproject" >&5
+printf %s "checking for setproject in -lproject... " >&6; }
+if test ${ac_cv_lib_project_setproject+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lproject $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char setproject ();
int
-main ()
+main (void)
{
return setproject ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_project_setproject=yes
-else
+else $as_nop
ac_cv_lib_project_setproject=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_project_setproject" >&5
-$as_echo "$ac_cv_lib_project_setproject" >&6; }
-if test "x$ac_cv_lib_project_setproject" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_project_setproject" >&5
+printf "%s\n" "$ac_cv_lib_project_setproject" >&6; }
+if test "x$ac_cv_lib_project_setproject" = xyes
+then :
-$as_echo "#define USE_SOLARIS_PROJECTS 1" >>confdefs.h
+printf "%s\n" "#define USE_SOLARIS_PROJECTS 1" >>confdefs.h
LIBS="$LIBS -lproject"
SP_MSG="yes"
fi
fi
# Check whether --with-solaris-privs was given.
-if test "${with_solaris_privs+set}" = set; then :
+if test ${with_solaris_privs+y}
+then :
withval=$with_solaris_privs;
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Solaris/Illumos privilege support" >&5
-$as_echo_n "checking for Solaris/Illumos privilege support... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Solaris/Illumos privilege support" >&5
+printf %s "checking for Solaris/Illumos privilege support... " >&6; }
if test "x$ac_cv_func_setppriv" = "xyes" -a \
"x$ac_cv_header_priv_h" = "xyes" ; then
SOLARIS_PRIVS=yes
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5
-$as_echo "found" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5
+printf "%s\n" "found" >&6; }
-$as_echo "#define NO_UID_RESTORATION_TEST 1" >>confdefs.h
+printf "%s\n" "#define NO_UID_RESTORATION_TEST 1" >>confdefs.h
-$as_echo "#define USE_SOLARIS_PRIVS 1" >>confdefs.h
+printf "%s\n" "#define USE_SOLARIS_PRIVS 1" >>confdefs.h
SPP_MSG="yes"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
-$as_echo "not found" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+printf "%s\n" "not found" >&6; }
as_fn_error $? "*** must have support for Solaris privileges to use --with-solaris-privs" "$LINENO" 5
fi
fi
TEST_SHELL=$SHELL # let configure find us a capable shell
;;
*-*-sunos4*)
CPPFLAGS="$CPPFLAGS -DSUNOS4"
- for ac_func in getpwanam
-do :
- ac_fn_c_check_func "$LINENO" "getpwanam" "ac_cv_func_getpwanam"
-if test "x$ac_cv_func_getpwanam" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_GETPWANAM 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "getpwanam" "ac_cv_func_getpwanam"
+if test "x$ac_cv_func_getpwanam" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETPWANAM 1" >>confdefs.h
fi
-done
- $as_echo "#define PAM_SUN_CODEBASE 1" >>confdefs.h
+ printf "%s\n" "#define PAM_SUN_CODEBASE 1" >>confdefs.h
conf_utmp_location=/etc/utmp
conf_wtmp_location=/var/adm/wtmp
conf_lastlog_location=/var/adm/lastlog
- $as_echo "#define USE_PIPES 1" >>confdefs.h
+ printf "%s\n" "#define USE_PIPES 1" >>confdefs.h
-$as_echo "#define DISABLE_UTMPX 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_UTMPX 1" >>confdefs.h
;;
*-ncr-sysv*)
LIBS="$LIBS -lc89"
- $as_echo "#define USE_PIPES 1" >>confdefs.h
+ printf "%s\n" "#define USE_PIPES 1" >>confdefs.h
- $as_echo "#define SSHD_ACQUIRES_CTTY 1" >>confdefs.h
+ printf "%s\n" "#define SSHD_ACQUIRES_CTTY 1" >>confdefs.h
- $as_echo "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
+ printf "%s\n" "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREUID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREGID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREGID 1" >>confdefs.h
;;
*-sni-sysv*)
# /usr/ucblib MUST NOT be searched on ReliantUNIX
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlsym in -ldl" >&5
-$as_echo_n "checking for dlsym in -ldl... " >&6; }
-if ${ac_cv_lib_dl_dlsym+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlsym in -ldl" >&5
+printf %s "checking for dlsym in -ldl... " >&6; }
+if test ${ac_cv_lib_dl_dlsym+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-ldl $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char dlsym ();
int
-main ()
+main (void)
{
return dlsym ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_dl_dlsym=yes
-else
+else $as_nop
ac_cv_lib_dl_dlsym=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlsym" >&5
-$as_echo "$ac_cv_lib_dl_dlsym" >&6; }
-if test "x$ac_cv_lib_dl_dlsym" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBDL 1
-_ACEOF
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlsym" >&5
+printf "%s\n" "$ac_cv_lib_dl_dlsym" >&6; }
+if test "x$ac_cv_lib_dl_dlsym" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBDL 1" >>confdefs.h
LIBS="-ldl $LIBS"
fi
# -lresolv needs to be at the end of LIBS or DNS lookups break
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for res_query in -lresolv" >&5
-$as_echo_n "checking for res_query in -lresolv... " >&6; }
-if ${ac_cv_lib_resolv_res_query+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for res_query in -lresolv" >&5
+printf %s "checking for res_query in -lresolv... " >&6; }
+if test ${ac_cv_lib_resolv_res_query+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lresolv $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char res_query ();
int
-main ()
+main (void)
{
return res_query ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_resolv_res_query=yes
-else
+else $as_nop
ac_cv_lib_resolv_res_query=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_res_query" >&5
-$as_echo "$ac_cv_lib_resolv_res_query" >&6; }
-if test "x$ac_cv_lib_resolv_res_query" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_res_query" >&5
+printf "%s\n" "$ac_cv_lib_resolv_res_query" >&6; }
+if test "x$ac_cv_lib_resolv_res_query" = xyes
+then :
LIBS="$LIBS -lresolv"
fi
IPADDR_IN_DISPLAY=yes
- $as_echo "#define USE_PIPES 1" >>confdefs.h
+ printf "%s\n" "#define USE_PIPES 1" >>confdefs.h
- $as_echo "#define IP_TOS_IS_BROKEN 1" >>confdefs.h
+ printf "%s\n" "#define IP_TOS_IS_BROKEN 1" >>confdefs.h
- $as_echo "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
+ printf "%s\n" "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREUID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREGID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREGID 1" >>confdefs.h
- $as_echo "#define SSHD_ACQUIRES_CTTY 1" >>confdefs.h
+ printf "%s\n" "#define SSHD_ACQUIRES_CTTY 1" >>confdefs.h
external_path_file=/etc/default/login
# /usr/ucblib/libucb.a no longer needed on ReliantUNIX
# Attention: always take care to bind libsocket and libnsl before libc,
# otherwise you will find lots of "SIOCGPGRP errno 22" on syslog
;;
# UnixWare 1.x, UnixWare 2.x, and others based on code from Univel.
*-*-sysv4.2*)
- $as_echo "#define USE_PIPES 1" >>confdefs.h
+ printf "%s\n" "#define USE_PIPES 1" >>confdefs.h
- $as_echo "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
+ printf "%s\n" "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREUID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREGID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREGID 1" >>confdefs.h
-$as_echo "#define PASSWD_NEEDS_USERNAME 1" >>confdefs.h
+printf "%s\n" "#define PASSWD_NEEDS_USERNAME 1" >>confdefs.h
- $as_echo "#define LOCKED_PASSWD_STRING \"*LK*\"" >>confdefs.h
+ printf "%s\n" "#define LOCKED_PASSWD_STRING \"*LK*\"" >>confdefs.h
TEST_SHELL=$SHELL # let configure find us a capable shell
;;
# UnixWare 7.x, OpenUNIX 8
*-*-sysv5*)
CPPFLAGS="$CPPFLAGS -Dvsnprintf=_xvsnprintf -Dsnprintf=_xsnprintf"
-$as_echo "#define UNIXWARE_LONG_PASSWORDS 1" >>confdefs.h
+printf "%s\n" "#define UNIXWARE_LONG_PASSWORDS 1" >>confdefs.h
- $as_echo "#define USE_PIPES 1" >>confdefs.h
+ printf "%s\n" "#define USE_PIPES 1" >>confdefs.h
- $as_echo "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
+ printf "%s\n" "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
- $as_echo "#define BROKEN_GETADDRINFO 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_GETADDRINFO 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREUID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREGID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREGID 1" >>confdefs.h
- $as_echo "#define PASSWD_NEEDS_USERNAME 1" >>confdefs.h
+ printf "%s\n" "#define PASSWD_NEEDS_USERNAME 1" >>confdefs.h
- $as_echo "#define BROKEN_TCGETATTR_ICANON 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_TCGETATTR_ICANON 1" >>confdefs.h
TEST_SHELL=$SHELL # let configure find us a capable shell
- check_for_libcrypt_later=1
case "$host" in
*-*-sysv5SCO_SV*) # SCO OpenServer 6.x
maildir=/var/spool/mail
- $as_echo "#define BROKEN_UPDWTMPX 1" >>confdefs.h
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getluid in -lprot" >&5
-$as_echo_n "checking for getluid in -lprot... " >&6; }
-if ${ac_cv_lib_prot_getluid+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ printf "%s\n" "#define BROKEN_UPDWTMPX 1" >>confdefs.h
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getluid in -lprot" >&5
+printf %s "checking for getluid in -lprot... " >&6; }
+if test ${ac_cv_lib_prot_getluid+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lprot $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char getluid ();
int
-main ()
+main (void)
{
return getluid ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_prot_getluid=yes
-else
+else $as_nop
ac_cv_lib_prot_getluid=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_prot_getluid" >&5
-$as_echo "$ac_cv_lib_prot_getluid" >&6; }
-if test "x$ac_cv_lib_prot_getluid" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_prot_getluid" >&5
+printf "%s\n" "$ac_cv_lib_prot_getluid" >&6; }
+if test "x$ac_cv_lib_prot_getluid" = xyes
+then :
LIBS="$LIBS -lprot"
- for ac_func in getluid setluid
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "getluid" "ac_cv_func_getluid"
+if test "x$ac_cv_func_getluid" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETLUID 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "setluid" "ac_cv_func_setluid"
+if test "x$ac_cv_func_setluid" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETLUID 1" >>confdefs.h
fi
-done
fi
;;
- *) $as_echo "#define LOCKED_PASSWD_STRING \"*LK*\"" >>confdefs.h
+ *) printf "%s\n" "#define LOCKED_PASSWD_STRING \"*LK*\"" >>confdefs.h
;;
esac
;;
*-*-sysv*)
;;
# SCO UNIX and OEM versions of SCO UNIX
*-*-sco3.2v4*)
as_fn_error $? "\"This Platform is no longer supported.\"" "$LINENO" 5
;;
# SCO OpenServer 5.x
*-*-sco3.2v5*)
if test -z "$GCC"; then
CFLAGS="$CFLAGS -belf"
fi
LIBS="$LIBS -lprot -lx -ltinfo -lm"
no_dev_ptmx=1
- $as_echo "#define USE_PIPES 1" >>confdefs.h
+ printf "%s\n" "#define USE_PIPES 1" >>confdefs.h
- $as_echo "#define HAVE_SECUREWARE 1" >>confdefs.h
+ printf "%s\n" "#define HAVE_SECUREWARE 1" >>confdefs.h
- $as_echo "#define DISABLE_SHADOW 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_SHADOW 1" >>confdefs.h
- $as_echo "#define DISABLE_FD_PASSING 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_FD_PASSING 1" >>confdefs.h
- $as_echo "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
+ printf "%s\n" "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
- $as_echo "#define BROKEN_GETADDRINFO 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_GETADDRINFO 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREUID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREGID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREGID 1" >>confdefs.h
- $as_echo "#define WITH_ABBREV_NO_TTY 1" >>confdefs.h
+ printf "%s\n" "#define WITH_ABBREV_NO_TTY 1" >>confdefs.h
- $as_echo "#define BROKEN_UPDWTMPX 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_UPDWTMPX 1" >>confdefs.h
- $as_echo "#define PASSWD_NEEDS_USERNAME 1" >>confdefs.h
+ printf "%s\n" "#define PASSWD_NEEDS_USERNAME 1" >>confdefs.h
- for ac_func in getluid setluid
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "getluid" "ac_cv_func_getluid"
+if test "x$ac_cv_func_getluid" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETLUID 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "setluid" "ac_cv_func_setluid"
+if test "x$ac_cv_func_setluid" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETLUID 1" >>confdefs.h
fi
-done
MANTYPE=man
TEST_SHELL=$SHELL # let configure find us a capable shell
SKIP_DISABLE_LASTLOG_DEFINE=yes
;;
*-dec-osf*)
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Digital Unix SIA" >&5
-$as_echo_n "checking for Digital Unix SIA... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Digital Unix SIA" >&5
+printf %s "checking for Digital Unix SIA... " >&6; }
no_osfsia=""
# Check whether --with-osfsia was given.
-if test "${with_osfsia+set}" = set; then :
+if test ${with_osfsia+y}
+then :
withval=$with_osfsia;
if test "x$withval" = "xno" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
-$as_echo "disabled" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
+printf "%s\n" "disabled" >&6; }
no_osfsia=1
fi
fi
if test -z "$no_osfsia" ; then
if test -f /etc/sia/matrix.conf; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_OSF_SIA 1" >>confdefs.h
+printf "%s\n" "#define HAVE_OSF_SIA 1" >>confdefs.h
-$as_echo "#define DISABLE_LOGIN 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_LOGIN 1" >>confdefs.h
- $as_echo "#define DISABLE_FD_PASSING 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_FD_PASSING 1" >>confdefs.h
LIBS="$LIBS -lsecurity -ldb -lm -laud"
SIA_MSG="yes"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
-$as_echo "#define LOCKED_PASSWD_SUBSTR \"Nologin\"" >>confdefs.h
+printf "%s\n" "#define LOCKED_PASSWD_SUBSTR \"Nologin\"" >>confdefs.h
fi
fi
- $as_echo "#define BROKEN_GETADDRINFO 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_GETADDRINFO 1" >>confdefs.h
- $as_echo "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
+ printf "%s\n" "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREUID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREUID 1" >>confdefs.h
- $as_echo "#define BROKEN_SETREGID 1" >>confdefs.h
+ printf "%s\n" "#define BROKEN_SETREGID 1" >>confdefs.h
-$as_echo "#define BROKEN_READV_COMPARISON 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_READV_COMPARISON 1" >>confdefs.h
;;
*-*-nto-qnx*)
- $as_echo "#define USE_PIPES 1" >>confdefs.h
+ printf "%s\n" "#define USE_PIPES 1" >>confdefs.h
- $as_echo "#define NO_X11_UNIX_SOCKETS 1" >>confdefs.h
+ printf "%s\n" "#define NO_X11_UNIX_SOCKETS 1" >>confdefs.h
- $as_echo "#define DISABLE_LASTLOG 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_LASTLOG 1" >>confdefs.h
- $as_echo "#define SSHD_ACQUIRES_CTTY 1" >>confdefs.h
+ printf "%s\n" "#define SSHD_ACQUIRES_CTTY 1" >>confdefs.h
-$as_echo "#define BROKEN_SHADOW_EXPIRE 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_SHADOW_EXPIRE 1" >>confdefs.h
enable_etc_default_login=no # has incompatible /etc/default/login
case "$host" in
*-*-nto-qnx6*)
- $as_echo "#define DISABLE_FD_PASSING 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_FD_PASSING 1" >>confdefs.h
;;
esac
;;
*-*-ultrix*)
-$as_echo "#define BROKEN_GETGROUPS 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_GETGROUPS 1" >>confdefs.h
-$as_echo "#define NEED_SETPGRP 1" >>confdefs.h
+printf "%s\n" "#define NEED_SETPGRP 1" >>confdefs.h
-$as_echo "#define HAVE_SYS_SYSLOG_H 1" >>confdefs.h
+printf "%s\n" "#define HAVE_SYS_SYSLOG_H 1" >>confdefs.h
-$as_echo "#define DISABLE_UTMPX 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_UTMPX 1" >>confdefs.h
# DISABLE_FD_PASSING so that we call setpgrp as root, otherwise we
# don't get a controlling tty.
-$as_echo "#define DISABLE_FD_PASSING 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_FD_PASSING 1" >>confdefs.h
# On Ultrix some headers are not protected against multiple includes,
# so we create wrappers and put it where the compiler will find it.
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: creating compat wrappers for headers" >&5
-$as_echo "$as_me: WARNING: creating compat wrappers for headers" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: creating compat wrappers for headers" >&5
+printf "%s\n" "$as_me: WARNING: creating compat wrappers for headers" >&2;}
mkdir -p netinet
for header in netinet/ip.h netdb.h resolv.h; do
name=`echo $header | tr 'a-z/.' 'A-Z__'`
cat >$header <<EOD
#ifndef _SSH_COMPAT_${name}
#define _SSH_COMPAT_${name}
#include "/usr/include/${header}"
#endif
EOD
done
;;
*-*-lynxos)
CFLAGS="$CFLAGS -D__NO_INCLUDE_WARN__"
-$as_echo "#define BROKEN_SETVBUF 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_SETVBUF 1" >>confdefs.h
;;
esac
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking compiler and flags for sanity" >&5
-$as_echo_n "checking compiler and flags for sanity... " >&6; }
-if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking compiler sanity" >&5
-$as_echo "$as_me: WARNING: cross compiling: not checking compiler sanity" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking compiler and flags for sanity" >&5
+printf %s "checking compiler and flags for sanity... " >&6; }
+if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking compiler sanity" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: not checking compiler sanity" >&2;}
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
int
-main ()
+main (void)
{
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
as_fn_error $? "*** compiler cannot create working executables, check config.log ***" "$LINENO" 5
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
# Checks for libraries.
ac_fn_c_check_func "$LINENO" "setsockopt" "ac_cv_func_setsockopt"
-if test "x$ac_cv_func_setsockopt" = xyes; then :
-
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setsockopt in -lsocket" >&5
-$as_echo_n "checking for setsockopt in -lsocket... " >&6; }
-if ${ac_cv_lib_socket_setsockopt+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+if test "x$ac_cv_func_setsockopt" = xyes
+then :
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for setsockopt in -lsocket" >&5
+printf %s "checking for setsockopt in -lsocket... " >&6; }
+if test ${ac_cv_lib_socket_setsockopt+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lsocket $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char setsockopt ();
int
-main ()
+main (void)
{
return setsockopt ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_socket_setsockopt=yes
-else
+else $as_nop
ac_cv_lib_socket_setsockopt=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_setsockopt" >&5
-$as_echo "$ac_cv_lib_socket_setsockopt" >&6; }
-if test "x$ac_cv_lib_socket_setsockopt" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBSOCKET 1
-_ACEOF
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_setsockopt" >&5
+printf "%s\n" "$ac_cv_lib_socket_setsockopt" >&6; }
+if test "x$ac_cv_lib_socket_setsockopt" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBSOCKET 1" >>confdefs.h
LIBS="-lsocket $LIBS"
fi
fi
-for ac_func in dirname
-do :
- ac_fn_c_check_func "$LINENO" "dirname" "ac_cv_func_dirname"
-if test "x$ac_cv_func_dirname" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_DIRNAME 1
-_ACEOF
- for ac_header in libgen.h
+
+ for ac_func in dirname
do :
- ac_fn_c_check_header_mongrel "$LINENO" "libgen.h" "ac_cv_header_libgen_h" "$ac_includes_default"
-if test "x$ac_cv_header_libgen_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBGEN_H 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "dirname" "ac_cv_func_dirname"
+if test "x$ac_cv_func_dirname" = xyes
+then :
+ printf "%s\n" "#define HAVE_DIRNAME 1" >>confdefs.h
+ ac_fn_c_check_header_compile "$LINENO" "libgen.h" "ac_cv_header_libgen_h" "$ac_includes_default"
+if test "x$ac_cv_header_libgen_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBGEN_H 1" >>confdefs.h
fi
-done
-
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dirname in -lgen" >&5
-$as_echo_n "checking for dirname in -lgen... " >&6; }
-if ${ac_cv_lib_gen_dirname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dirname in -lgen" >&5
+printf %s "checking for dirname in -lgen... " >&6; }
+if test ${ac_cv_lib_gen_dirname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lgen $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char dirname ();
int
-main ()
+main (void)
{
return dirname ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_gen_dirname=yes
-else
+else $as_nop
ac_cv_lib_gen_dirname=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gen_dirname" >&5
-$as_echo "$ac_cv_lib_gen_dirname" >&6; }
-if test "x$ac_cv_lib_gen_dirname" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gen_dirname" >&5
+printf "%s\n" "$ac_cv_lib_gen_dirname" >&6; }
+if test "x$ac_cv_lib_gen_dirname" = xyes
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken dirname" >&5
-$as_echo_n "checking for broken dirname... " >&6; }
-if ${ac_cv_have_broken_dirname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for broken dirname" >&5
+printf %s "checking for broken dirname... " >&6; }
+if test ${ac_cv_have_broken_dirname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
save_LIBS="$LIBS"
LIBS="$LIBS -lgen"
- if test "$cross_compiling" = yes; then :
+ if test "$cross_compiling" = yes
+then :
ac_cv_have_broken_dirname="no"
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <libgen.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv) {
char *s, buf[32];
strncpy(buf,"/etc", 32);
s = dirname(buf);
if (!s || strncmp(s, "/", 32) != 0) {
exit(1);
} else {
exit(0);
}
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_run "$LINENO"
+then :
ac_cv_have_broken_dirname="no"
-else
+else $as_nop
ac_cv_have_broken_dirname="yes"
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
LIBS="$save_LIBS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_broken_dirname" >&5
-$as_echo "$ac_cv_have_broken_dirname" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_broken_dirname" >&5
+printf "%s\n" "$ac_cv_have_broken_dirname" >&6; }
if test "x$ac_cv_have_broken_dirname" = "xno" ; then
LIBS="$LIBS -lgen"
- $as_echo "#define HAVE_DIRNAME 1" >>confdefs.h
+ printf "%s\n" "#define HAVE_DIRNAME 1" >>confdefs.h
- for ac_header in libgen.h
-do :
- ac_fn_c_check_header_mongrel "$LINENO" "libgen.h" "ac_cv_header_libgen_h" "$ac_includes_default"
-if test "x$ac_cv_header_libgen_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBGEN_H 1
-_ACEOF
+ ac_fn_c_check_header_compile "$LINENO" "libgen.h" "ac_cv_header_libgen_h" "$ac_includes_default"
+if test "x$ac_cv_header_libgen_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBGEN_H 1" >>confdefs.h
fi
-done
-
fi
fi
fi
-done
+done
ac_fn_c_check_func "$LINENO" "getspnam" "ac_cv_func_getspnam"
-if test "x$ac_cv_func_getspnam" = xyes; then :
-
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getspnam in -lgen" >&5
-$as_echo_n "checking for getspnam in -lgen... " >&6; }
-if ${ac_cv_lib_gen_getspnam+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+if test "x$ac_cv_func_getspnam" = xyes
+then :
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getspnam in -lgen" >&5
+printf %s "checking for getspnam in -lgen... " >&6; }
+if test ${ac_cv_lib_gen_getspnam+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lgen $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char getspnam ();
int
-main ()
+main (void)
{
return getspnam ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_gen_getspnam=yes
-else
+else $as_nop
ac_cv_lib_gen_getspnam=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gen_getspnam" >&5
-$as_echo "$ac_cv_lib_gen_getspnam" >&6; }
-if test "x$ac_cv_lib_gen_getspnam" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gen_getspnam" >&5
+printf "%s\n" "$ac_cv_lib_gen_getspnam" >&6; }
+if test "x$ac_cv_lib_gen_getspnam" = xyes
+then :
LIBS="$LIBS -lgen"
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing basename" >&5
-$as_echo_n "checking for library containing basename... " >&6; }
-if ${ac_cv_search_basename+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing basename" >&5
+printf %s "checking for library containing basename... " >&6; }
+if test ${ac_cv_search_basename+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char basename ();
int
-main ()
+main (void)
{
return basename ();
;
return 0;
}
_ACEOF
-for ac_lib in '' gen; do
+for ac_lib in '' gen
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
+ if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_search_basename=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_basename+:} false; then :
+ if test ${ac_cv_search_basename+y}
+then :
break
fi
done
-if ${ac_cv_search_basename+:} false; then :
+if test ${ac_cv_search_basename+y}
+then :
-else
+else $as_nop
ac_cv_search_basename=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_basename" >&5
-$as_echo "$ac_cv_search_basename" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_basename" >&5
+printf "%s\n" "$ac_cv_search_basename" >&6; }
ac_res=$ac_cv_search_basename
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-$as_echo "#define HAVE_BASENAME 1" >>confdefs.h
+printf "%s\n" "#define HAVE_BASENAME 1" >>confdefs.h
fi
zlib=yes
# Check whether --with-zlib was given.
-if test "${with_zlib+set}" = set; then :
+if test ${with_zlib+y}
+then :
withval=$with_zlib; if test "x$withval" = "xno" ; then
zlib=no
elif test "x$withval" != "xyes"; then
if test -d "$withval/lib"; then
if test -n "${rpath_opt}"; then
LDFLAGS="-L${withval}/lib ${rpath_opt}${withval}/lib ${LDFLAGS}"
else
LDFLAGS="-L${withval}/lib ${LDFLAGS}"
fi
else
if test -n "${rpath_opt}"; then
LDFLAGS="-L${withval} ${rpath_opt}${withval} ${LDFLAGS}"
else
LDFLAGS="-L${withval} ${LDFLAGS}"
fi
fi
if test -d "$withval/include"; then
CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
else
CPPFLAGS="-I${withval} ${CPPFLAGS}"
fi
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for zlib" >&5
-$as_echo_n "checking for zlib... " >&6; }
+# These libraries are needed for anything that links in the channel code.
+CHANNELLIBS=""
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for zlib" >&5
+printf %s "checking for zlib... " >&6; }
if test "x${zlib}" = "xno"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ saved_LIBS="$LIBS"
+ CHANNELLIBS="$CHANNELLIBS -lz"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define WITH_ZLIB 1" >>confdefs.h
+printf "%s\n" "#define WITH_ZLIB 1" >>confdefs.h
- ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_zlib_h" = xyes; then :
+ ac_fn_c_check_header_compile "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
+if test "x$ac_cv_header_zlib_h" = xyes
+then :
-else
+else $as_nop
as_fn_error $? "*** zlib.h missing - please install first or check config.log ***" "$LINENO" 5
fi
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for deflate in -lz" >&5
-$as_echo_n "checking for deflate in -lz... " >&6; }
-if ${ac_cv_lib_z_deflate+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for deflate in -lz" >&5
+printf %s "checking for deflate in -lz... " >&6; }
+if test ${ac_cv_lib_z_deflate+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lz $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char deflate ();
int
-main ()
+main (void)
{
return deflate ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_z_deflate=yes
-else
+else $as_nop
ac_cv_lib_z_deflate=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_deflate" >&5
-$as_echo "$ac_cv_lib_z_deflate" >&6; }
-if test "x$ac_cv_lib_z_deflate" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBZ 1
-_ACEOF
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_deflate" >&5
+printf "%s\n" "$ac_cv_lib_z_deflate" >&6; }
+if test "x$ac_cv_lib_z_deflate" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBZ 1" >>confdefs.h
LIBS="-lz $LIBS"
-else
+else $as_nop
saved_CPPFLAGS="$CPPFLAGS"
saved_LDFLAGS="$LDFLAGS"
- save_LIBS="$LIBS"
if test -n "${rpath_opt}"; then
LDFLAGS="-L/usr/local/lib ${rpath_opt}/usr/local/lib ${saved_LDFLAGS}"
else
LDFLAGS="-L/usr/local/lib ${saved_LDFLAGS}"
fi
CPPFLAGS="-I/usr/local/include ${saved_CPPFLAGS}"
- LIBS="$LIBS -lz"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char deflate ();
int
-main ()
+main (void)
{
return deflate ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- $as_echo "#define HAVE_LIBZ 1" >>confdefs.h
+if ac_fn_c_try_link "$LINENO"
+then :
+ printf "%s\n" "#define HAVE_LIBZ 1" >>confdefs.h
-else
+else $as_nop
as_fn_error $? "*** zlib missing - please install first or check config.log ***" "$LINENO" 5
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
# Check whether --with-zlib-version-check was given.
-if test "${with_zlib_version_check+set}" = set; then :
+if test ${with_zlib_version_check+y}
+then :
withval=$with_zlib_version_check; if test "x$withval" = "xno" ; then
zlib_check_nonfatal=1
fi
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for possibly buggy zlib" >&5
-$as_echo_n "checking for possibly buggy zlib... " >&6; }
- if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking zlib version" >&5
-$as_echo "$as_me: WARNING: cross compiling: not checking zlib version" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for possibly buggy zlib" >&5
+printf %s "checking for possibly buggy zlib... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking zlib version" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: not checking zlib version" >&2;}
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
#include <stdlib.h>
#include <zlib.h>
int
-main ()
+main (void)
{
int a=0, b=0, c=0, d=0, n, v;
n = sscanf(ZLIB_VERSION, "%d.%d.%d.%d", &a, &b, &c, &d);
if (n != 3 && n != 4)
exit(1);
v = a*1000000 + b*10000 + c*100 + d;
fprintf(stderr, "found zlib version %s (%d)\n", ZLIB_VERSION, v);
/* 1.1.4 is OK */
if (a == 1 && b == 1 && c >= 4)
exit(0);
/* 1.2.3 and up are OK */
if (v >= 1020300)
exit(0);
exit(2);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
if test -z "$zlib_check_nonfatal" ; then
as_fn_error $? "*** zlib too old - check config.log ***
Your reported zlib version has known security problems. It's possible your
vendor has fixed these problems without changing the version number. If you
are sure this is the case, you can disable the check by running
\"./configure --without-zlib-version-check\".
If you are in doubt, upgrade zlib to version 1.2.3 or greater.
See http://www.gzip.org/zlib/ for details." "$LINENO" 5
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: zlib version may have security problems" >&5
-$as_echo "$as_me: WARNING: zlib version may have security problems" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: zlib version may have security problems" >&5
+printf "%s\n" "$as_me: WARNING: zlib version may have security problems" >&2;}
fi
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
+ LIBS="$saved_LIBS"
fi
ac_fn_c_check_func "$LINENO" "strcasecmp" "ac_cv_func_strcasecmp"
-if test "x$ac_cv_func_strcasecmp" = xyes; then :
-
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strcasecmp in -lresolv" >&5
-$as_echo_n "checking for strcasecmp in -lresolv... " >&6; }
-if ${ac_cv_lib_resolv_strcasecmp+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+if test "x$ac_cv_func_strcasecmp" = xyes
+then :
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for strcasecmp in -lresolv" >&5
+printf %s "checking for strcasecmp in -lresolv... " >&6; }
+if test ${ac_cv_lib_resolv_strcasecmp+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lresolv $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char strcasecmp ();
int
-main ()
+main (void)
{
return strcasecmp ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_resolv_strcasecmp=yes
-else
+else $as_nop
ac_cv_lib_resolv_strcasecmp=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_strcasecmp" >&5
-$as_echo "$ac_cv_lib_resolv_strcasecmp" >&6; }
-if test "x$ac_cv_lib_resolv_strcasecmp" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_strcasecmp" >&5
+printf "%s\n" "$ac_cv_lib_resolv_strcasecmp" >&6; }
+if test "x$ac_cv_lib_resolv_strcasecmp" = xyes
+then :
LIBS="$LIBS -lresolv"
fi
fi
-for ac_func in utimes
+
+ for ac_func in utimes
do :
ac_fn_c_check_func "$LINENO" "utimes" "ac_cv_func_utimes"
-if test "x$ac_cv_func_utimes" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_UTIMES 1
-_ACEOF
-
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for utimes in -lc89" >&5
-$as_echo_n "checking for utimes in -lc89... " >&6; }
-if ${ac_cv_lib_c89_utimes+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+if test "x$ac_cv_func_utimes" = xyes
+then :
+ printf "%s\n" "#define HAVE_UTIMES 1" >>confdefs.h
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for utimes in -lc89" >&5
+printf %s "checking for utimes in -lc89... " >&6; }
+if test ${ac_cv_lib_c89_utimes+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lc89 $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char utimes ();
int
-main ()
+main (void)
{
return utimes ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_c89_utimes=yes
-else
+else $as_nop
ac_cv_lib_c89_utimes=no
fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c89_utimes" >&5
+printf "%s\n" "$ac_cv_lib_c89_utimes" >&6; }
+if test "x$ac_cv_lib_c89_utimes" = xyes
+then :
+ printf "%s\n" "#define HAVE_UTIMES 1" >>confdefs.h
+
+ LIBS="$LIBS -lc89"
+fi
+
+
+fi
+
+done
+
+ac_fn_c_check_header_compile "$LINENO" "bsd/libutil.h" "ac_cv_header_bsd_libutil_h" "$ac_includes_default"
+if test "x$ac_cv_header_bsd_libutil_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_BSD_LIBUTIL_H 1" >>confdefs.h
+
+fi
+ac_fn_c_check_header_compile "$LINENO" "libutil.h" "ac_cv_header_libutil_h" "$ac_includes_default"
+if test "x$ac_cv_header_libutil_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBUTIL_H 1" >>confdefs.h
+
+fi
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing fmt_scaled" >&5
+printf %s "checking for library containing fmt_scaled... " >&6; }
+if test ${ac_cv_search_fmt_scaled+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+char fmt_scaled ();
+int
+main (void)
+{
+return fmt_scaled ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' util bsd
+do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_search_fmt_scaled=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext
+ if test ${ac_cv_search_fmt_scaled+y}
+then :
+ break
+fi
+done
+if test ${ac_cv_search_fmt_scaled+y}
+then :
+
+else $as_nop
+ ac_cv_search_fmt_scaled=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_fmt_scaled" >&5
+printf "%s\n" "$ac_cv_search_fmt_scaled" >&6; }
+ac_res=$ac_cv_search_fmt_scaled
+if test "$ac_res" != no
+then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing scan_scaled" >&5
+printf %s "checking for library containing scan_scaled... " >&6; }
+if test ${ac_cv_search_scan_scaled+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+char scan_scaled ();
+int
+main (void)
+{
+return scan_scaled ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' util bsd
+do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_search_scan_scaled=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext
+ if test ${ac_cv_search_scan_scaled+y}
+then :
+ break
+fi
+done
+if test ${ac_cv_search_scan_scaled+y}
+then :
+
+else $as_nop
+ ac_cv_search_scan_scaled=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_scan_scaled" >&5
+printf "%s\n" "$ac_cv_search_scan_scaled" >&6; }
+ac_res=$ac_cv_search_scan_scaled
+if test "$ac_res" != no
+then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing login" >&5
+printf %s "checking for library containing login... " >&6; }
+if test ${ac_cv_search_login+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+char login ();
+int
+main (void)
+{
+return login ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' util bsd
+do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_search_login=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext
+ if test ${ac_cv_search_login+y}
+then :
+ break
+fi
+done
+if test ${ac_cv_search_login+y}
+then :
+
+else $as_nop
+ ac_cv_search_login=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_login" >&5
+printf "%s\n" "$ac_cv_search_login" >&6; }
+ac_res=$ac_cv_search_login
+if test "$ac_res" != no
+then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing logout" >&5
+printf %s "checking for library containing logout... " >&6; }
+if test ${ac_cv_search_logout+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+char logout ();
+int
+main (void)
+{
+return logout ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' util bsd
+do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_search_logout=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext
+ if test ${ac_cv_search_logout+y}
+then :
+ break
+fi
+done
+if test ${ac_cv_search_logout+y}
+then :
+
+else $as_nop
+ ac_cv_search_logout=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_logout" >&5
+printf "%s\n" "$ac_cv_search_logout" >&6; }
+ac_res=$ac_cv_search_logout
+if test "$ac_res" != no
+then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing logwtmp" >&5
+printf %s "checking for library containing logwtmp... " >&6; }
+if test ${ac_cv_search_logwtmp+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+char logwtmp ();
+int
+main (void)
+{
+return logwtmp ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' util bsd
+do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_search_logwtmp=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext
+ if test ${ac_cv_search_logwtmp+y}
+then :
+ break
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c89_utimes" >&5
-$as_echo "$ac_cv_lib_c89_utimes" >&6; }
-if test "x$ac_cv_lib_c89_utimes" = xyes; then :
- $as_echo "#define HAVE_UTIMES 1" >>confdefs.h
+done
+if test ${ac_cv_search_logwtmp+y}
+then :
- LIBS="$LIBS -lc89"
+else $as_nop
+ ac_cv_search_logwtmp=no
fi
-
-
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
fi
-done
-
-
-for ac_header in bsd/libutil.h libutil.h
-do :
- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_logwtmp" >&5
+printf "%s\n" "$ac_cv_search_logwtmp" >&6; }
+ac_res=$ac_cv_search_logwtmp
+if test "$ac_res" != no
+then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
-done
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing fmt_scaled" >&5
-$as_echo_n "checking for library containing fmt_scaled... " >&6; }
-if ${ac_cv_search_fmt_scaled+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing openpty" >&5
+printf %s "checking for library containing openpty... " >&6; }
+if test ${ac_cv_search_openpty+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char fmt_scaled ();
+char openpty ();
int
-main ()
+main (void)
{
-return fmt_scaled ();
+return openpty ();
;
return 0;
}
_ACEOF
-for ac_lib in '' util bsd; do
+for ac_lib in '' util bsd
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_search_fmt_scaled=$ac_res
+ if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_search_openpty=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_fmt_scaled+:} false; then :
+ if test ${ac_cv_search_openpty+y}
+then :
break
fi
done
-if ${ac_cv_search_fmt_scaled+:} false; then :
+if test ${ac_cv_search_openpty+y}
+then :
-else
- ac_cv_search_fmt_scaled=no
+else $as_nop
+ ac_cv_search_openpty=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_fmt_scaled" >&5
-$as_echo "$ac_cv_search_fmt_scaled" >&6; }
-ac_res=$ac_cv_search_fmt_scaled
-if test "$ac_res" != no; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_openpty" >&5
+printf "%s\n" "$ac_cv_search_openpty" >&6; }
+ac_res=$ac_cv_search_openpty
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing scan_scaled" >&5
-$as_echo_n "checking for library containing scan_scaled... " >&6; }
-if ${ac_cv_search_scan_scaled+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing updwtmp" >&5
+printf %s "checking for library containing updwtmp... " >&6; }
+if test ${ac_cv_search_updwtmp+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char scan_scaled ();
+char updwtmp ();
int
-main ()
+main (void)
{
-return scan_scaled ();
+return updwtmp ();
;
return 0;
}
_ACEOF
-for ac_lib in '' util bsd; do
+for ac_lib in '' util bsd
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_search_scan_scaled=$ac_res
+ if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_search_updwtmp=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_scan_scaled+:} false; then :
+ if test ${ac_cv_search_updwtmp+y}
+then :
break
fi
done
-if ${ac_cv_search_scan_scaled+:} false; then :
+if test ${ac_cv_search_updwtmp+y}
+then :
-else
- ac_cv_search_scan_scaled=no
+else $as_nop
+ ac_cv_search_updwtmp=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_scan_scaled" >&5
-$as_echo "$ac_cv_search_scan_scaled" >&6; }
-ac_res=$ac_cv_search_scan_scaled
-if test "$ac_res" != no; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_updwtmp" >&5
+printf "%s\n" "$ac_cv_search_updwtmp" >&6; }
+ac_res=$ac_cv_search_updwtmp
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing login" >&5
-$as_echo_n "checking for library containing login... " >&6; }
-if ${ac_cv_search_login+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ac_fn_c_check_func "$LINENO" "fmt_scaled" "ac_cv_func_fmt_scaled"
+if test "x$ac_cv_func_fmt_scaled" = xyes
+then :
+ printf "%s\n" "#define HAVE_FMT_SCALED 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "scan_scaled" "ac_cv_func_scan_scaled"
+if test "x$ac_cv_func_scan_scaled" = xyes
+then :
+ printf "%s\n" "#define HAVE_SCAN_SCALED 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "login" "ac_cv_func_login"
+if test "x$ac_cv_func_login" = xyes
+then :
+ printf "%s\n" "#define HAVE_LOGIN 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "logout" "ac_cv_func_logout"
+if test "x$ac_cv_func_logout" = xyes
+then :
+ printf "%s\n" "#define HAVE_LOGOUT 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "openpty" "ac_cv_func_openpty"
+if test "x$ac_cv_func_openpty" = xyes
+then :
+ printf "%s\n" "#define HAVE_OPENPTY 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "updwtmp" "ac_cv_func_updwtmp"
+if test "x$ac_cv_func_updwtmp" = xyes
+then :
+ printf "%s\n" "#define HAVE_UPDWTMP 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "logwtmp" "ac_cv_func_logwtmp"
+if test "x$ac_cv_func_logwtmp" = xyes
+then :
+ printf "%s\n" "#define HAVE_LOGWTMP 1" >>confdefs.h
+
+fi
+
+
+# On some platforms, inet_ntop and gethostbyname may be found in libresolv
+# or libnsl.
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing inet_ntop" >&5
+printf %s "checking for library containing inet_ntop... " >&6; }
+if test ${ac_cv_search_inet_ntop+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char login ();
+char inet_ntop ();
int
-main ()
+main (void)
{
-return login ();
+return inet_ntop ();
;
return 0;
}
_ACEOF
-for ac_lib in '' util bsd; do
+for ac_lib in '' resolv nsl
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_search_login=$ac_res
+ if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_search_inet_ntop=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_login+:} false; then :
+ if test ${ac_cv_search_inet_ntop+y}
+then :
break
fi
done
-if ${ac_cv_search_login+:} false; then :
+if test ${ac_cv_search_inet_ntop+y}
+then :
-else
- ac_cv_search_login=no
+else $as_nop
+ ac_cv_search_inet_ntop=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_login" >&5
-$as_echo "$ac_cv_search_login" >&6; }
-ac_res=$ac_cv_search_login
-if test "$ac_res" != no; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_ntop" >&5
+printf "%s\n" "$ac_cv_search_inet_ntop" >&6; }
+ac_res=$ac_cv_search_inet_ntop
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing logout" >&5
-$as_echo_n "checking for library containing logout... " >&6; }
-if ${ac_cv_search_logout+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyname" >&5
+printf %s "checking for library containing gethostbyname... " >&6; }
+if test ${ac_cv_search_gethostbyname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char logout ();
+char gethostbyname ();
int
-main ()
+main (void)
{
-return logout ();
+return gethostbyname ();
;
return 0;
}
_ACEOF
-for ac_lib in '' util bsd; do
+for ac_lib in '' resolv nsl
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_search_logout=$ac_res
+ if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_search_gethostbyname=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_logout+:} false; then :
+ if test ${ac_cv_search_gethostbyname+y}
+then :
break
fi
done
-if ${ac_cv_search_logout+:} false; then :
+if test ${ac_cv_search_gethostbyname+y}
+then :
-else
- ac_cv_search_logout=no
+else $as_nop
+ ac_cv_search_gethostbyname=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_logout" >&5
-$as_echo "$ac_cv_search_logout" >&6; }
-ac_res=$ac_cv_search_logout
-if test "$ac_res" != no; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyname" >&5
+printf "%s\n" "$ac_cv_search_gethostbyname" >&6; }
+ac_res=$ac_cv_search_gethostbyname
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing logwtmp" >&5
-$as_echo_n "checking for library containing logwtmp... " >&6; }
-if ${ac_cv_search_logwtmp+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+
+# Some Linux distribtions ship the BSD libc hashing functions in
+# separate libraries.
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing SHA256Update" >&5
+printf %s "checking for library containing SHA256Update... " >&6; }
+if test ${ac_cv_search_SHA256Update+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char logwtmp ();
+char SHA256Update ();
int
-main ()
+main (void)
{
-return logwtmp ();
+return SHA256Update ();
;
return 0;
}
_ACEOF
-for ac_lib in '' util bsd; do
+for ac_lib in '' md bsd
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_search_logwtmp=$ac_res
+ if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_search_SHA256Update=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_logwtmp+:} false; then :
+ if test ${ac_cv_search_SHA256Update+y}
+then :
break
fi
done
-if ${ac_cv_search_logwtmp+:} false; then :
+if test ${ac_cv_search_SHA256Update+y}
+then :
-else
- ac_cv_search_logwtmp=no
+else $as_nop
+ ac_cv_search_SHA256Update=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_logwtmp" >&5
-$as_echo "$ac_cv_search_logwtmp" >&6; }
-ac_res=$ac_cv_search_logwtmp
-if test "$ac_res" != no; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_SHA256Update" >&5
+printf "%s\n" "$ac_cv_search_SHA256Update" >&6; }
+ac_res=$ac_cv_search_SHA256Update
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing openpty" >&5
-$as_echo_n "checking for library containing openpty... " >&6; }
-if ${ac_cv_search_openpty+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_func_search_save_LIBS=$LIBS
+
+# "Particular Function Checks"
+# see https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Particular-Functions.html
+
+ for ac_func in strftime
+do :
+ ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime"
+if test "x$ac_cv_func_strftime" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRFTIME 1" >>confdefs.h
+
+else $as_nop
+ # strftime is in -lintl on SCO UNIX.
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for strftime in -lintl" >&5
+printf %s "checking for strftime in -lintl... " >&6; }
+if test ${ac_cv_lib_intl_strftime+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lintl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+char strftime ();
+int
+main (void)
+{
+return strftime ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_intl_strftime=yes
+else $as_nop
+ ac_cv_lib_intl_strftime=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_strftime" >&5
+printf "%s\n" "$ac_cv_lib_intl_strftime" >&6; }
+if test "x$ac_cv_lib_intl_strftime" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRFTIME 1" >>confdefs.h
+
+LIBS="-lintl $LIBS"
+fi
+
+fi
+
+done
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5
+printf %s "checking for GNU libc compatible malloc... " >&6; }
+if test ${ac_cv_func_malloc_0_nonnull+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test "$cross_compiling" = yes
+then :
+ case "$host_os" in # ((
+ # Guess yes on platforms where we know the result.
+ *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \
+ | hpux* | solaris* | cygwin* | mingw* | msys* )
+ ac_cv_func_malloc_0_nonnull=yes ;;
+ # If we don't know, assume the worst.
+ *) ac_cv_func_malloc_0_nonnull=no ;;
+ esac
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+int
+main (void)
+{
+void *p = malloc (0);
+ int result = !p;
+ free (p);
+ return result;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"
+then :
+ ac_cv_func_malloc_0_nonnull=yes
+else $as_nop
+ ac_cv_func_malloc_0_nonnull=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5
+printf "%s\n" "$ac_cv_func_malloc_0_nonnull" >&6; }
+if test $ac_cv_func_malloc_0_nonnull = yes
+then :
+
+printf "%s\n" "#define HAVE_MALLOC 1" >>confdefs.h
+
+else $as_nop
+ printf "%s\n" "#define HAVE_MALLOC 0" >>confdefs.h
+
+ case " $LIBOBJS " in
+ *" malloc.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS malloc.$ac_objext"
+ ;;
+esac
+
+
+printf "%s\n" "#define malloc rpl_malloc" >>confdefs.h
+
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5
+printf %s "checking for GNU libc compatible realloc... " >&6; }
+if test ${ac_cv_func_realloc_0_nonnull+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test "$cross_compiling" = yes
+then :
+ case "$host_os" in # ((
+ # Guess yes on platforms where we know the result.
+ *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \
+ | hpux* | solaris* | cygwin* | mingw* | msys* )
+ ac_cv_func_realloc_0_nonnull=yes ;;
+ # If we don't know, assume the worst.
+ *) ac_cv_func_realloc_0_nonnull=no ;;
+ esac
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+int
+main (void)
+{
+void *p = realloc (0, 0);
+ int result = !p;
+ free (p);
+ return result;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"
+then :
+ ac_cv_func_realloc_0_nonnull=yes
+else $as_nop
+ ac_cv_func_realloc_0_nonnull=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5
+printf "%s\n" "$ac_cv_func_realloc_0_nonnull" >&6; }
+if test $ac_cv_func_realloc_0_nonnull = yes
+then :
+
+printf "%s\n" "#define HAVE_REALLOC 1" >>confdefs.h
+
+else $as_nop
+ printf "%s\n" "#define HAVE_REALLOC 0" >>confdefs.h
+
+ case " $LIBOBJS " in
+ *" realloc.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS realloc.$ac_objext"
+ ;;
+esac
+
+
+printf "%s\n" "#define realloc rpl_realloc" >>confdefs.h
+
+fi
+
+
+# autoconf doesn't have AC_FUNC_CALLOC so fake it if malloc returns NULL;
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if calloc(0, N) returns non-null" >&5
+printf %s "checking if calloc(0, N) returns non-null... " >&6; }
+if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming same as malloc" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: assuming same as malloc" >&2;}
+ func_calloc_0_nonnull="$ac_cv_func_malloc_0_nonnull"
+
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+ #include <stdlib.h>
+int
+main (void)
+{
+ void *p = calloc(0, 1); exit(p == NULL);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"
+then :
+ func_calloc_0_nonnull=yes
+else $as_nop
+ func_calloc_0_nonnull=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $func_calloc_0_nonnull" >&5
+printf "%s\n" "$func_calloc_0_nonnull" >&6; }
+
+if test "x$func_calloc_0_nonnull" = "xyes"; then
+
+printf "%s\n" "#define HAVE_CALLOC 1" >>confdefs.h
+
+else
+
+printf "%s\n" "#define HAVE_CALLOC 0" >>confdefs.h
+
+
+printf "%s\n" "#define calloc rpl_calloc" >>confdefs.h
+
+fi
+
+# Check for ALTDIRFUNC glob() extension
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GLOB_ALTDIRFUNC support" >&5
+printf %s "checking for GLOB_ALTDIRFUNC support... " >&6; }
+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char openpty ();
+ #include <glob.h>
+ #ifdef GLOB_ALTDIRFUNC
+ FOUNDIT
+ #endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "FOUNDIT" >/dev/null 2>&1
+then :
+
+
+printf "%s\n" "#define GLOB_HAS_ALTDIRFUNC 1" >>confdefs.h
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+else $as_nop
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+
+fi
+rm -rf conftest*
+
+
+# Check for g.gl_matchc glob() extension
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gl_matchc field in glob_t" >&5
+printf %s "checking for gl_matchc field in glob_t... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+ #include <glob.h>
int
-main ()
+main (void)
{
-return openpty ();
+ glob_t g; g.gl_matchc = 1;
;
return 0;
}
_ACEOF
-for ac_lib in '' util bsd; do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_search_openpty=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext
- if ${ac_cv_search_openpty+:} false; then :
- break
-fi
-done
-if ${ac_cv_search_openpty+:} false; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
-else
- ac_cv_search_openpty=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_openpty" >&5
-$as_echo "$ac_cv_search_openpty" >&6; }
-ac_res=$ac_cv_search_openpty
-if test "$ac_res" != no; then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+printf "%s\n" "#define GLOB_HAS_GL_MATCHC 1" >>confdefs.h
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+else $as_nop
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing updwtmp" >&5
-$as_echo_n "checking for library containing updwtmp... " >&6; }
-if ${ac_cv_search_updwtmp+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_func_search_save_LIBS=$LIBS
+# Check for g.gl_statv glob() extension
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gl_statv and GLOB_KEEPSTAT extensions for glob" >&5
+printf %s "checking for gl_statv and GLOB_KEEPSTAT extensions for glob... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char updwtmp ();
+ #include <glob.h>
int
-main ()
+main (void)
{
-return updwtmp ();
+
+#ifndef GLOB_KEEPSTAT
+#error "glob does not support GLOB_KEEPSTAT extension"
+#endif
+glob_t g;
+g.gl_statv = NULL;
+
;
return 0;
}
_ACEOF
-for ac_lib in '' util bsd; do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_search_updwtmp=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext
- if ${ac_cv_search_updwtmp+:} false; then :
- break
-fi
-done
-if ${ac_cv_search_updwtmp+:} false; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+
+printf "%s\n" "#define GLOB_HAS_GL_STATV 1" >>confdefs.h
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+else $as_nop
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
-else
- ac_cv_search_updwtmp=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_updwtmp" >&5
-$as_echo "$ac_cv_search_updwtmp" >&6; }
-ac_res=$ac_cv_search_updwtmp
-if test "$ac_res" != no; then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ac_fn_check_decl "$LINENO" "GLOB_NOMATCH" "ac_cv_have_decl_GLOB_NOMATCH" "#include <glob.h>
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_GLOB_NOMATCH" = xyes
+then :
+ ac_have_decl=1
+else $as_nop
+ ac_have_decl=0
fi
+printf "%s\n" "#define HAVE_DECL_GLOB_NOMATCH $ac_have_decl" >>confdefs.h
-for ac_func in fmt_scaled scan_scaled login logout openpty updwtmp logwtmp
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+
+ac_fn_check_decl "$LINENO" "VIS_ALL" "ac_cv_have_decl_VIS_ALL" "#include <vis.h>
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_VIS_ALL" = xyes
+then :
+
+else $as_nop
+
+printf "%s\n" "#define BROKEN_STRNVIS 1" >>confdefs.h
fi
-done
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether struct dirent allocates space for d_name" >&5
+printf %s "checking whether struct dirent allocates space for d_name... " >&6; }
+if test "$cross_compiling" = yes
+then :
-# On some platforms, inet_ntop and gethostbyname may be found in libresolv
-# or libnsl.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing inet_ntop" >&5
-$as_echo_n "checking for library containing inet_ntop... " >&6; }
-if ${ac_cv_search_inet_ntop+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming BROKEN_ONE_BYTE_DIRENT_D_NAME" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: assuming BROKEN_ONE_BYTE_DIRENT_D_NAME" >&2;}
+ printf "%s\n" "#define BROKEN_ONE_BYTE_DIRENT_D_NAME 1" >>confdefs.h
+
+
+
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char inet_ntop ();
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdlib.h>
+
int
-main ()
+main (void)
{
-return inet_ntop ();
+
+ struct dirent d;
+ exit(sizeof(d.d_name)<=sizeof(char));
+
;
return 0;
}
_ACEOF
-for ac_lib in '' resolv nsl; do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_search_inet_ntop=$ac_res
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+printf "%s\n" "#define BROKEN_ONE_BYTE_DIRENT_D_NAME 1" >>confdefs.h
+
+
fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext
- if ${ac_cv_search_inet_ntop+:} false; then :
- break
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-done
-if ${ac_cv_search_inet_ntop+:} false; then :
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /proc/pid/fd directory" >&5
+printf %s "checking for /proc/pid/fd directory... " >&6; }
+if test -d "/proc/$$/fd" ; then
+
+printf "%s\n" "#define HAVE_PROC_PID 1" >>confdefs.h
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
else
- ac_cv_search_inet_ntop=no
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
+
+# Check whether user wants to use ldns
+LDNS_MSG="no"
+
+# Check whether --with-ldns was given.
+if test ${with_ldns+y}
+then :
+ withval=$with_ldns;
+ ldns=""
+ if test "x$withval" = "xyes" ; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ldns-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ldns-config; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_LDNSCONFIG+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $LDNSCONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_LDNSCONFIG="$LDNSCONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_LDNSCONFIG="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_ntop" >&5
-$as_echo "$ac_cv_search_inet_ntop" >&6; }
-ac_res=$ac_cv_search_inet_ntop
-if test "$ac_res" != no; then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+LDNSCONFIG=$ac_cv_path_LDNSCONFIG
+if test -n "$LDNSCONFIG"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LDNSCONFIG" >&5
+printf "%s\n" "$LDNSCONFIG" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
fi
+if test -z "$ac_cv_path_LDNSCONFIG"; then
+ ac_pt_LDNSCONFIG=$LDNSCONFIG
+ # Extract the first word of "ldns-config", so it can be a program name with args.
+set dummy ldns-config; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_ac_pt_LDNSCONFIG+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ case $ac_pt_LDNSCONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_pt_LDNSCONFIG="$ac_pt_LDNSCONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_ac_pt_LDNSCONFIG="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyname" >&5
-$as_echo_n "checking for library containing gethostbyname... " >&6; }
-if ${ac_cv_search_gethostbyname+:} false; then :
- $as_echo_n "(cached) " >&6
+ ;;
+esac
+fi
+ac_pt_LDNSCONFIG=$ac_cv_path_ac_pt_LDNSCONFIG
+if test -n "$ac_pt_LDNSCONFIG"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LDNSCONFIG" >&5
+printf "%s\n" "$ac_pt_LDNSCONFIG" >&6; }
else
- ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char gethostbyname ();
-int
-main ()
-{
-return gethostbyname ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' resolv nsl; do
- if test -z "$ac_lib"; then
- ac_res="none required"
+ if test "x$ac_pt_LDNSCONFIG" = x; then
+ LDNSCONFIG="no"
else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ LDNSCONFIG=$ac_pt_LDNSCONFIG
fi
- if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_search_gethostbyname=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext
- if ${ac_cv_search_gethostbyname+:} false; then :
- break
-fi
-done
-if ${ac_cv_search_gethostbyname+:} false; then :
-
else
- ac_cv_search_gethostbyname=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
+ LDNSCONFIG="$ac_cv_path_LDNSCONFIG"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyname" >&5
-$as_echo "$ac_cv_search_gethostbyname" >&6; }
-ac_res=$ac_cv_search_gethostbyname
-if test "$ac_res" != no; then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-fi
+ if test "x$LDNSCONFIG" = "xno"; then
+ LIBS="-lldns $LIBS"
+ ldns=yes
+ else
+ LIBS="$LIBS `$LDNSCONFIG --libs`"
+ CPPFLAGS="$CPPFLAGS `$LDNSCONFIG --cflags`"
+ ldns=yes
+ fi
+ elif test "x$withval" != "xno" ; then
+ CPPFLAGS="$CPPFLAGS -I${withval}/include"
+ LDFLAGS="$LDFLAGS -L${withval}/lib"
+ LIBS="-lldns $LIBS"
+ ldns=yes
+ fi
+ # Verify that it works.
+ if test "x$ldns" = "xyes" ; then
-# Some Linux distribtions ship the BSD libc hashing functions in
-# separate libraries.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing SHA256Update" >&5
-$as_echo_n "checking for library containing SHA256Update... " >&6; }
-if ${ac_cv_search_SHA256Update+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+printf "%s\n" "#define HAVE_LDNS 1" >>confdefs.h
+
+ LDNS_MSG="yes"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ldns support" >&5
+printf %s "checking for ldns support... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
#endif
-char SHA256Update ();
-int
-main ()
-{
-return SHA256Update ();
- ;
- return 0;
-}
+#include <ldns/ldns.h>
+int main() { ldns_status status = ldns_verify_trusted(NULL, NULL, NULL, NULL); status=LDNS_STATUS_OK; exit(0); }
+
+
_ACEOF
-for ac_lib in '' md bsd; do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_search_SHA256Update=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext
- if ${ac_cv_search_SHA256Update+:} false; then :
- break
-fi
-done
-if ${ac_cv_search_SHA256Update+:} false; then :
+if ac_fn_c_try_link "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ as_fn_error $? "** Incomplete or missing ldns libraries." "$LINENO" 5
-else
- ac_cv_search_SHA256Update=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_SHA256Update" >&5
-$as_echo "$ac_cv_search_SHA256Update" >&6; }
-ac_res=$ac_cv_search_SHA256Update
-if test "$ac_res" != no; then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ fi
fi
-# "Particular Function Checks"
-# see https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Particular-Functions.html
-for ac_func in strftime
-do :
- ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime"
-if test "x$ac_cv_func_strftime" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_STRFTIME 1
-_ACEOF
+# Check whether user wants libedit support
+LIBEDIT_MSG="no"
-else
- # strftime is in -lintl on SCO UNIX.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strftime in -lintl" >&5
-$as_echo_n "checking for strftime in -lintl... " >&6; }
-if ${ac_cv_lib_intl_strftime+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+# Check whether --with-libedit was given.
+if test ${with_libedit+y}
+then :
+ withval=$with_libedit; if test "x$withval" != "xno" ; then
+ if test "x$withval" = "xyes" ; then
+ if test "x$PKGCONFIG" != "xno"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $PKGCONFIG knows about libedit" >&5
+printf %s "checking if $PKGCONFIG knows about libedit... " >&6; }
+ if "$PKGCONFIG" libedit; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ use_pkgconfig_for_libedit=yes
+ else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ fi
+ fi
+ else
+ CPPFLAGS="$CPPFLAGS -I${withval}/include"
+ if test -n "${rpath_opt}"; then
+ LDFLAGS="-L${withval}/lib ${rpath_opt}${withval}/lib ${LDFLAGS}"
+ else
+ LDFLAGS="-L${withval}/lib ${LDFLAGS}"
+ fi
+ fi
+ if test "x$use_pkgconfig_for_libedit" = "xyes"; then
+ LIBEDIT=`$PKGCONFIG --libs libedit`
+ CPPFLAGS="$CPPFLAGS `$PKGCONFIG --cflags libedit`"
+ else
+ LIBEDIT="-ledit -lcurses"
+ fi
+ OTHERLIBS=`echo $LIBEDIT | sed 's/-ledit//'`
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for el_init in -ledit" >&5
+printf %s "checking for el_init in -ledit... " >&6; }
+if test ${ac_cv_lib_edit_el_init+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
-LIBS="-lintl $LIBS"
+LIBS="-ledit $OTHERLIBS
+ $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char strftime ();
+char el_init ();
int
-main ()
+main (void)
{
-return strftime ();
+return el_init ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_intl_strftime=yes
-else
- ac_cv_lib_intl_strftime=no
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_edit_el_init=yes
+else $as_nop
+ ac_cv_lib_edit_el_init=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_strftime" >&5
-$as_echo "$ac_cv_lib_intl_strftime" >&6; }
-if test "x$ac_cv_lib_intl_strftime" = xyes; then :
- $as_echo "#define HAVE_STRFTIME 1" >>confdefs.h
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_edit_el_init" >&5
+printf "%s\n" "$ac_cv_lib_edit_el_init" >&6; }
+if test "x$ac_cv_lib_edit_el_init" = xyes
+then :
-LIBS="-lintl $LIBS"
-fi
+printf "%s\n" "#define USE_LIBEDIT 1" >>confdefs.h
-fi
-done
+ LIBEDIT_MSG="yes"
-for ac_header in stdlib.h
-do :
- ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_stdlib_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_STDLIB_H 1
-_ACEOF
+else $as_nop
+ as_fn_error $? "libedit not found" "$LINENO" 5
fi
-done
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5
-$as_echo_n "checking for GNU libc compatible malloc... " >&6; }
-if ${ac_cv_func_malloc_0_nonnull+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test "$cross_compiling" = yes; then :
- ac_cv_func_malloc_0_nonnull=no
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libedit version is compatible" >&5
+printf %s "checking if libedit version is compatible... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#if defined STDC_HEADERS || defined HAVE_STDLIB_H
-# include <stdlib.h>
-#else
-char *malloc ();
-#endif
+
+#include <histedit.h>
+#include <stdlib.h>
int
-main ()
+main (void)
{
-return ! malloc (0);
+
+ int i = H_SETSIZE;
+ el_init("", NULL, NULL, NULL);
+ exit(0);
+
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- ac_cv_func_malloc_0_nonnull=yes
-else
- ac_cv_func_malloc_0_nonnull=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ as_fn_error $? "libedit version is not compatible" "$LINENO" 5
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5
-$as_echo "$ac_cv_func_malloc_0_nonnull" >&6; }
-if test $ac_cv_func_malloc_0_nonnull = yes; then :
-
-$as_echo "#define HAVE_MALLOC 1" >>confdefs.h
-
-else
- $as_echo "#define HAVE_MALLOC 0" >>confdefs.h
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ fi
- case " $LIBOBJS " in
- *" malloc.$ac_objext "* ) ;;
- *) LIBOBJS="$LIBOBJS malloc.$ac_objext"
- ;;
-esac
+fi
-$as_echo "#define malloc rpl_malloc" >>confdefs.h
+AUDIT_MODULE=none
-fi
+# Check whether --with-audit was given.
+if test ${with_audit+y}
+then :
+ withval=$with_audit;
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for supported audit module" >&5
+printf %s "checking for supported audit module... " >&6; }
+ case "$withval" in
+ bsm)
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: bsm" >&5
+printf "%s\n" "bsm" >&6; }
+ AUDIT_MODULE=bsm
+ for ac_header in bsm/audit.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "bsm/audit.h" "ac_cv_header_bsm_audit_h" "
+#ifdef HAVE_TIME_H
+# include <time.h>
+#endif
-for ac_header in stdlib.h
-do :
- ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_stdlib_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_STDLIB_H 1
-_ACEOF
+"
+if test "x$ac_cv_header_bsm_audit_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_BSM_AUDIT_H 1" >>confdefs.h
+else $as_nop
+ as_fn_error $? "BSM enabled and bsm/audit.h not found" "$LINENO" 5
fi
done
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5
-$as_echo_n "checking for GNU libc compatible realloc... " >&6; }
-if ${ac_cv_func_realloc_0_nonnull+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test "$cross_compiling" = yes; then :
- ac_cv_func_realloc_0_nonnull=no
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getaudit in -lbsm" >&5
+printf %s "checking for getaudit in -lbsm... " >&6; }
+if test ${ac_cv_lib_bsm_getaudit+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbsm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#if defined STDC_HEADERS || defined HAVE_STDLIB_H
-# include <stdlib.h>
-#else
-char *realloc ();
-#endif
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+char getaudit ();
int
-main ()
+main (void)
{
-return ! realloc (0, 0);
+return getaudit ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- ac_cv_func_realloc_0_nonnull=yes
-else
- ac_cv_func_realloc_0_nonnull=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_bsm_getaudit=yes
+else $as_nop
+ ac_cv_lib_bsm_getaudit=no
fi
-
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5
-$as_echo "$ac_cv_func_realloc_0_nonnull" >&6; }
-if test $ac_cv_func_realloc_0_nonnull = yes; then :
-
-$as_echo "#define HAVE_REALLOC 1" >>confdefs.h
-
-else
- $as_echo "#define HAVE_REALLOC 0" >>confdefs.h
-
- case " $LIBOBJS " in
- *" realloc.$ac_objext "* ) ;;
- *) LIBOBJS="$LIBOBJS realloc.$ac_objext"
- ;;
-esac
-
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsm_getaudit" >&5
+printf "%s\n" "$ac_cv_lib_bsm_getaudit" >&6; }
+if test "x$ac_cv_lib_bsm_getaudit" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBBSM 1" >>confdefs.h
-$as_echo "#define realloc rpl_realloc" >>confdefs.h
+ LIBS="-lbsm $LIBS"
+else $as_nop
+ as_fn_error $? "BSM enabled and required library not found" "$LINENO" 5
fi
-# autoconf doesn't have AC_FUNC_CALLOC so fake it if malloc returns NULL;
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if calloc(0, N) returns non-null" >&5
-$as_echo_n "checking if calloc(0, N) returns non-null... " >&6; }
-if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming same as malloc" >&5
-$as_echo "$as_me: WARNING: cross compiling: assuming same as malloc" >&2;}
- func_calloc_0_nonnull="$ac_cv_func_malloc_0_nonnull"
-
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
- #include <stdlib.h>
-int
-main ()
-{
- void *p = calloc(0, 1); exit(p == NULL);
+ for ac_func in getaudit
+do :
+ ac_fn_c_check_func "$LINENO" "getaudit" "ac_cv_func_getaudit"
+if test "x$ac_cv_func_getaudit" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETAUDIT 1" >>confdefs.h
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- func_calloc_0_nonnull=yes
-else
- func_calloc_0_nonnull=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
+else $as_nop
+ as_fn_error $? "BSM enabled and required function not found" "$LINENO" 5
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $func_calloc_0_nonnull" >&5
-$as_echo "$func_calloc_0_nonnull" >&6; }
+done
+ # These are optional
+ ac_fn_c_check_func "$LINENO" "getaudit_addr" "ac_cv_func_getaudit_addr"
+if test "x$ac_cv_func_getaudit_addr" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETAUDIT_ADDR 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "aug_get_machine" "ac_cv_func_aug_get_machine"
+if test "x$ac_cv_func_aug_get_machine" = xyes
+then :
+ printf "%s\n" "#define HAVE_AUG_GET_MACHINE 1" >>confdefs.h
-if test "x$func_calloc_0_nonnull" = "xyes"; then
+fi
-$as_echo "#define HAVE_CALLOC 1" >>confdefs.h
-else
+printf "%s\n" "#define USE_BSM_AUDIT 1" >>confdefs.h
-$as_echo "#define HAVE_CALLOC 0" >>confdefs.h
+ if test "$sol2ver" -ge 11; then
+ SSHDLIBS="$SSHDLIBS -lscf"
+printf "%s\n" "#define BROKEN_BSM_API 1" >>confdefs.h
-$as_echo "#define calloc rpl_calloc" >>confdefs.h
+ fi
+ ;;
+ linux)
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: linux" >&5
+printf "%s\n" "linux" >&6; }
+ AUDIT_MODULE=linux
+ ac_fn_c_check_header_compile "$LINENO" "libaudit.h" "ac_cv_header_libaudit_h" "$ac_includes_default"
+if test "x$ac_cv_header_libaudit_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBAUDIT_H 1" >>confdefs.h
fi
-# Check for ALTDIRFUNC glob() extension
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLOB_ALTDIRFUNC support" >&5
-$as_echo_n "checking for GLOB_ALTDIRFUNC support... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ SSHDLIBS="$SSHDLIBS -laudit"
- #include <glob.h>
- #ifdef GLOB_ALTDIRFUNC
- FOUNDIT
- #endif
+printf "%s\n" "#define USE_LINUX_AUDIT 1" >>confdefs.h
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "FOUNDIT" >/dev/null 2>&1; then :
+ ;;
+ debug)
+ AUDIT_MODULE=debug
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: debug" >&5
+printf "%s\n" "debug" >&6; }
+printf "%s\n" "#define SSH_AUDIT_EVENTS 1" >>confdefs.h
-$as_echo "#define GLOB_HAS_ALTDIRFUNC 1" >>confdefs.h
+ ;;
+ no)
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ ;;
+ *)
+ as_fn_error $? "Unknown audit module $withval" "$LINENO" 5
+ ;;
+ esac
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+# Check whether --with-pie was given.
+if test ${with_pie+y}
+then :
+ withval=$with_pie;
+ if test "x$withval" = "xno"; then
+ use_pie=no
+ fi
+ if test "x$withval" = "xyes"; then
+ use_pie=yes
+ fi
+
+fi
+
+if test "x$use_pie" = "x"; then
+ use_pie=no
+fi
+if test "x$use_toolchain_hardening" != "x1" && test "x$use_pie" = "xauto"; then
+ # Turn off automatic PIE when toolchain hardening is off.
+ use_pie=no
fi
-rm -f conftest*
+if test "x$use_pie" = "xauto"; then
+ # Automatic PIE requires gcc >= 4.x
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gcc >= 4.x" >&5
+printf %s "checking for gcc >= 4.x... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#if !defined(__GNUC__) || __GNUC__ < 4
+#error gcc is too old
+#endif
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ use_pie=no
-# Check for g.gl_matchc glob() extension
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gl_matchc field in glob_t" >&5
-$as_echo_n "checking for gl_matchc field in glob_t... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+if test "x$use_pie" != "xno"; then
+ SAVED_CFLAGS="$CFLAGS"
+ SAVED_LDFLAGS="$LDFLAGS"
+ {
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -fPIE" >&5
+printf %s "checking if $CC supports compile flag -fPIE... " >&6; }
+ saved_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $WERROR -fPIE"
+ _define_flag=""
+ test "x$_define_flag" = "x" && _define_flag="-fPIE"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
- #include <glob.h>
-int
-main ()
-{
- glob_t g; g.gl_matchc = 1;
- ;
- return 0;
+
+#include <stdlib.h>
+#include <stdio.h>
+/* Trivial function to help test for -fzero-call-used-regs */
+void f(int n) {}
+int main(int argc, char **argv) {
+ (void)argv;
+ /* Some math to catch -ftrapv problems in the toolchain */
+ int i = 123 * argc, j = 456 + argc, k = 789 - argc;
+ float l = i * 2.1;
+ double m = l / 0.5;
+ long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
+ f(0);
+ printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
+ /*
+ * Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
+ * not understand comments and we don't use the "fallthrough" attribute
+ * that it's looking for.
+ */
+ switch(i){
+ case 0: j += i;
+ /* FALLTHROUGH */
+ default: j += k;
+ }
+ exit(0);
}
+
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
+
+if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
+then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ CFLAGS="$saved_CFLAGS"
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ CFLAGS="$saved_CFLAGS $_define_flag"
+fi
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ CFLAGS="$saved_CFLAGS"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+}
+ {
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $LD supports link flag -pie" >&5
+printf %s "checking if $LD supports link flag -pie... " >&6; }
+ saved_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $WERROR -pie"
+ _define_flag=""
+ test "x$_define_flag" = "x" && _define_flag="-pie"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
-$as_echo "#define GLOB_HAS_GL_MATCHC 1" >>confdefs.h
+#include <stdlib.h>
+#include <stdio.h>
+int main(int argc, char **argv) {
+ (void)argv;
+ /* Some math to catch -ftrapv problems in the toolchain */
+ int i = 123 * argc, j = 456 + argc, k = 789 - argc;
+ float l = i * 2.1;
+ double m = l / 0.5;
+ long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
+ long long p = n * o;
+ printf("%d %d %d %f %f %lld %lld %lld\n", i, j, k, l, m, n, o, p);
+ exit(0);
+}
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
+then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ LDFLAGS="$saved_LDFLAGS"
else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ LDFLAGS="$saved_LDFLAGS $_define_flag"
+fi
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ LDFLAGS="$saved_LDFLAGS"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+}
+ # We use both -fPIE and -pie or neither.
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether both -fPIE and -pie are supported" >&5
+printf %s "checking whether both -fPIE and -pie are supported... " >&6; }
+ if echo "x $CFLAGS" | grep ' -fPIE' >/dev/null 2>&1 && \
+ echo "x $LDFLAGS" | grep ' -pie' >/dev/null 2>&1 ; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ CFLAGS="$SAVED_CFLAGS"
+ LDFLAGS="$SAVED_LDFLAGS"
+ fi
+fi
-# Check for g.gl_statv glob() extension
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gl_statv and GLOB_KEEPSTAT extensions for glob" >&5
-$as_echo_n "checking for gl_statv and GLOB_KEEPSTAT extensions for glob... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -fPIC is accepted" >&5
+printf %s "checking whether -fPIC is accepted... " >&6; }
+SAVED_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -fPIC"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
- #include <glob.h>
+ #include <stdlib.h>
int
-main ()
+main (void)
{
-
-#ifndef GLOB_KEEPSTAT
-#error "glob does not support GLOB_KEEPSTAT extension"
-#endif
-glob_t g;
-g.gl_statv = NULL;
-
+ exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ PICFLAG="-fPIC";
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ PICFLAG="";
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+CFLAGS="$SAVED_CFLAGS"
-$as_echo "#define GLOB_HAS_GL_STATV 1" >>confdefs.h
+ac_fn_c_check_func "$LINENO" "Blowfish_initstate" "ac_cv_func_Blowfish_initstate"
+if test "x$ac_cv_func_Blowfish_initstate" = xyes
+then :
+ printf "%s\n" "#define HAVE_BLOWFISH_INITSTATE 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+fi
+ac_fn_c_check_func "$LINENO" "Blowfish_expandstate" "ac_cv_func_Blowfish_expandstate"
+if test "x$ac_cv_func_Blowfish_expandstate" = xyes
+then :
+ printf "%s\n" "#define HAVE_BLOWFISH_EXPANDSTATE 1" >>confdefs.h
-else
+fi
+ac_fn_c_check_func "$LINENO" "Blowfish_expand0state" "ac_cv_func_Blowfish_expand0state"
+if test "x$ac_cv_func_Blowfish_expand0state" = xyes
+then :
+ printf "%s\n" "#define HAVE_BLOWFISH_EXPAND0STATE 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+fi
+ac_fn_c_check_func "$LINENO" "Blowfish_stream2word" "ac_cv_func_Blowfish_stream2word"
+if test "x$ac_cv_func_Blowfish_stream2word" = xyes
+then :
+ printf "%s\n" "#define HAVE_BLOWFISH_STREAM2WORD 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "SHA256Update" "ac_cv_func_SHA256Update"
+if test "x$ac_cv_func_SHA256Update" = xyes
+then :
+ printf "%s\n" "#define HAVE_SHA256UPDATE 1" >>confdefs.h
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_fn_c_check_func "$LINENO" "SHA384Update" "ac_cv_func_SHA384Update"
+if test "x$ac_cv_func_SHA384Update" = xyes
+then :
+ printf "%s\n" "#define HAVE_SHA384UPDATE 1" >>confdefs.h
-ac_fn_c_check_decl "$LINENO" "GLOB_NOMATCH" "ac_cv_have_decl_GLOB_NOMATCH" "#include <glob.h>
-"
-if test "x$ac_cv_have_decl_GLOB_NOMATCH" = xyes; then :
- ac_have_decl=1
-else
- ac_have_decl=0
fi
+ac_fn_c_check_func "$LINENO" "SHA512Update" "ac_cv_func_SHA512Update"
+if test "x$ac_cv_func_SHA512Update" = xyes
+then :
+ printf "%s\n" "#define HAVE_SHA512UPDATE 1" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_GLOB_NOMATCH $ac_have_decl
-_ACEOF
+fi
+ac_fn_c_check_func "$LINENO" "asprintf" "ac_cv_func_asprintf"
+if test "x$ac_cv_func_asprintf" = xyes
+then :
+ printf "%s\n" "#define HAVE_ASPRINTF 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "b64_ntop" "ac_cv_func_b64_ntop"
+if test "x$ac_cv_func_b64_ntop" = xyes
+then :
+ printf "%s\n" "#define HAVE_B64_NTOP 1" >>confdefs.h
-ac_fn_c_check_decl "$LINENO" "VIS_ALL" "ac_cv_have_decl_VIS_ALL" "#include <vis.h>
-"
-if test "x$ac_cv_have_decl_VIS_ALL" = xyes; then :
+fi
+ac_fn_c_check_func "$LINENO" "__b64_ntop" "ac_cv_func___b64_ntop"
+if test "x$ac_cv_func___b64_ntop" = xyes
+then :
+ printf "%s\n" "#define HAVE___B64_NTOP 1" >>confdefs.h
-else
+fi
+ac_fn_c_check_func "$LINENO" "b64_pton" "ac_cv_func_b64_pton"
+if test "x$ac_cv_func_b64_pton" = xyes
+then :
+ printf "%s\n" "#define HAVE_B64_PTON 1" >>confdefs.h
-$as_echo "#define BROKEN_STRNVIS 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "__b64_pton" "ac_cv_func___b64_pton"
+if test "x$ac_cv_func___b64_pton" = xyes
+then :
+ printf "%s\n" "#define HAVE___B64_PTON 1" >>confdefs.h
fi
+ac_fn_c_check_func "$LINENO" "bcopy" "ac_cv_func_bcopy"
+if test "x$ac_cv_func_bcopy" = xyes
+then :
+ printf "%s\n" "#define HAVE_BCOPY 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "bcrypt_pbkdf" "ac_cv_func_bcrypt_pbkdf"
+if test "x$ac_cv_func_bcrypt_pbkdf" = xyes
+then :
+ printf "%s\n" "#define HAVE_BCRYPT_PBKDF 1" >>confdefs.h
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct dirent allocates space for d_name" >&5
-$as_echo_n "checking whether struct dirent allocates space for d_name... " >&6; }
-if test "$cross_compiling" = yes; then :
+fi
+ac_fn_c_check_func "$LINENO" "bindresvport_sa" "ac_cv_func_bindresvport_sa"
+if test "x$ac_cv_func_bindresvport_sa" = xyes
+then :
+ printf "%s\n" "#define HAVE_BINDRESVPORT_SA 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming BROKEN_ONE_BYTE_DIRENT_D_NAME" >&5
-$as_echo "$as_me: WARNING: cross compiling: assuming BROKEN_ONE_BYTE_DIRENT_D_NAME" >&2;}
- $as_echo "#define BROKEN_ONE_BYTE_DIRENT_D_NAME 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "blf_enc" "ac_cv_func_blf_enc"
+if test "x$ac_cv_func_blf_enc" = xyes
+then :
+ printf "%s\n" "#define HAVE_BLF_ENC 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "bzero" "ac_cv_func_bzero"
+if test "x$ac_cv_func_bzero" = xyes
+then :
+ printf "%s\n" "#define HAVE_BZERO 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "cap_rights_limit" "ac_cv_func_cap_rights_limit"
+if test "x$ac_cv_func_cap_rights_limit" = xyes
+then :
+ printf "%s\n" "#define HAVE_CAP_RIGHTS_LIMIT 1" >>confdefs.h
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+fi
+ac_fn_c_check_func "$LINENO" "clock" "ac_cv_func_clock"
+if test "x$ac_cv_func_clock" = xyes
+then :
+ printf "%s\n" "#define HAVE_CLOCK 1" >>confdefs.h
-#include <sys/types.h>
-#include <dirent.h>
-#include <stdlib.h>
+fi
+ac_fn_c_check_func "$LINENO" "closefrom" "ac_cv_func_closefrom"
+if test "x$ac_cv_func_closefrom" = xyes
+then :
+ printf "%s\n" "#define HAVE_CLOSEFROM 1" >>confdefs.h
-int
-main ()
-{
+fi
+ac_fn_c_check_func "$LINENO" "close_range" "ac_cv_func_close_range"
+if test "x$ac_cv_func_close_range" = xyes
+then :
+ printf "%s\n" "#define HAVE_CLOSE_RANGE 1" >>confdefs.h
- struct dirent d;
- exit(sizeof(d.d_name)<=sizeof(char));
+fi
+ac_fn_c_check_func "$LINENO" "dirfd" "ac_cv_func_dirfd"
+if test "x$ac_cv_func_dirfd" = xyes
+then :
+ printf "%s\n" "#define HAVE_DIRFD 1" >>confdefs.h
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
+fi
+ac_fn_c_check_func "$LINENO" "endgrent" "ac_cv_func_endgrent"
+if test "x$ac_cv_func_endgrent" = xyes
+then :
+ printf "%s\n" "#define HAVE_ENDGRENT 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+fi
+ac_fn_c_check_func "$LINENO" "err" "ac_cv_func_err"
+if test "x$ac_cv_func_err" = xyes
+then :
+ printf "%s\n" "#define HAVE_ERR 1" >>confdefs.h
-$as_echo "#define BROKEN_ONE_BYTE_DIRENT_D_NAME 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "errx" "ac_cv_func_errx"
+if test "x$ac_cv_func_errx" = xyes
+then :
+ printf "%s\n" "#define HAVE_ERRX 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero"
+if test "x$ac_cv_func_explicit_bzero" = xyes
+then :
+ printf "%s\n" "#define HAVE_EXPLICIT_BZERO 1" >>confdefs.h
fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
+ac_fn_c_check_func "$LINENO" "explicit_memset" "ac_cv_func_explicit_memset"
+if test "x$ac_cv_func_explicit_memset" = xyes
+then :
+ printf "%s\n" "#define HAVE_EXPLICIT_MEMSET 1" >>confdefs.h
+
fi
+ac_fn_c_check_func "$LINENO" "fchmod" "ac_cv_func_fchmod"
+if test "x$ac_cv_func_fchmod" = xyes
+then :
+ printf "%s\n" "#define HAVE_FCHMOD 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "fchmodat" "ac_cv_func_fchmodat"
+if test "x$ac_cv_func_fchmodat" = xyes
+then :
+ printf "%s\n" "#define HAVE_FCHMODAT 1" >>confdefs.h
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for /proc/pid/fd directory" >&5
-$as_echo_n "checking for /proc/pid/fd directory... " >&6; }
-if test -d "/proc/$$/fd" ; then
+fi
+ac_fn_c_check_func "$LINENO" "fchown" "ac_cv_func_fchown"
+if test "x$ac_cv_func_fchown" = xyes
+then :
+ printf "%s\n" "#define HAVE_FCHOWN 1" >>confdefs.h
-$as_echo "#define HAVE_PROC_PID 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "fchownat" "ac_cv_func_fchownat"
+if test "x$ac_cv_func_fchownat" = xyes
+then :
+ printf "%s\n" "#define HAVE_FCHOWNAT 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
fi
+ac_fn_c_check_func "$LINENO" "flock" "ac_cv_func_flock"
+if test "x$ac_cv_func_flock" = xyes
+then :
+ printf "%s\n" "#define HAVE_FLOCK 1" >>confdefs.h
-# Check whether user wants to use ldns
-LDNS_MSG="no"
+fi
+ac_fn_c_check_func "$LINENO" "fnmatch" "ac_cv_func_fnmatch"
+if test "x$ac_cv_func_fnmatch" = xyes
+then :
+ printf "%s\n" "#define HAVE_FNMATCH 1" >>confdefs.h
-# Check whether --with-ldns was given.
-if test "${with_ldns+set}" = set; then :
- withval=$with_ldns;
- ldns=""
- if test "x$withval" = "xyes" ; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}ldns-config", so it can be a program name with args.
-set dummy ${ac_tool_prefix}ldns-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_LDNSCONFIG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- case $LDNSCONFIG in
- [\\/]* | ?:[\\/]*)
- ac_cv_path_LDNSCONFIG="$LDNSCONFIG" # Let the user override the test with a path.
- ;;
- *)
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_LDNSCONFIG="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
+fi
+ac_fn_c_check_func "$LINENO" "freeaddrinfo" "ac_cv_func_freeaddrinfo"
+if test "x$ac_cv_func_freeaddrinfo" = xyes
+then :
+ printf "%s\n" "#define HAVE_FREEADDRINFO 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "freezero" "ac_cv_func_freezero"
+if test "x$ac_cv_func_freezero" = xyes
+then :
+ printf "%s\n" "#define HAVE_FREEZERO 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "fstatfs" "ac_cv_func_fstatfs"
+if test "x$ac_cv_func_fstatfs" = xyes
+then :
+ printf "%s\n" "#define HAVE_FSTATFS 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "fstatvfs" "ac_cv_func_fstatvfs"
+if test "x$ac_cv_func_fstatvfs" = xyes
+then :
+ printf "%s\n" "#define HAVE_FSTATVFS 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "futimes" "ac_cv_func_futimes"
+if test "x$ac_cv_func_futimes" = xyes
+then :
+ printf "%s\n" "#define HAVE_FUTIMES 1" >>confdefs.h
- ;;
-esac
fi
-LDNSCONFIG=$ac_cv_path_LDNSCONFIG
-if test -n "$LDNSCONFIG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LDNSCONFIG" >&5
-$as_echo "$LDNSCONFIG" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ac_fn_c_check_func "$LINENO" "getaddrinfo" "ac_cv_func_getaddrinfo"
+if test "x$ac_cv_func_getaddrinfo" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETADDRINFO 1" >>confdefs.h
+
fi
+ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd"
+if test "x$ac_cv_func_getcwd" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETCWD 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy"
+if test "x$ac_cv_func_getentropy" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETENTROPY 1" >>confdefs.h
fi
-if test -z "$ac_cv_path_LDNSCONFIG"; then
- ac_pt_LDNSCONFIG=$LDNSCONFIG
- # Extract the first word of "ldns-config", so it can be a program name with args.
-set dummy ldns-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_LDNSCONFIG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- case $ac_pt_LDNSCONFIG in
- [\\/]* | ?:[\\/]*)
- ac_cv_path_ac_pt_LDNSCONFIG="$ac_pt_LDNSCONFIG" # Let the user override the test with a path.
- ;;
- *)
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_ac_pt_LDNSCONFIG="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
+ac_fn_c_check_func "$LINENO" "getgrouplist" "ac_cv_func_getgrouplist"
+if test "x$ac_cv_func_getgrouplist" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETGROUPLIST 1" >>confdefs.h
- ;;
-esac
fi
-ac_pt_LDNSCONFIG=$ac_cv_path_ac_pt_LDNSCONFIG
-if test -n "$ac_pt_LDNSCONFIG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LDNSCONFIG" >&5
-$as_echo "$ac_pt_LDNSCONFIG" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ac_fn_c_check_func "$LINENO" "getline" "ac_cv_func_getline"
+if test "x$ac_cv_func_getline" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETLINE 1" >>confdefs.h
+
fi
+ac_fn_c_check_func "$LINENO" "getnameinfo" "ac_cv_func_getnameinfo"
+if test "x$ac_cv_func_getnameinfo" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETNAMEINFO 1" >>confdefs.h
- if test "x$ac_pt_LDNSCONFIG" = x; then
- LDNSCONFIG="no"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- LDNSCONFIG=$ac_pt_LDNSCONFIG
- fi
-else
- LDNSCONFIG="$ac_cv_path_LDNSCONFIG"
fi
+ac_fn_c_check_func "$LINENO" "getopt" "ac_cv_func_getopt"
+if test "x$ac_cv_func_getopt" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETOPT 1" >>confdefs.h
- if test "x$LDNSCONFIG" = "xno"; then
- LIBS="-lldns $LIBS"
- ldns=yes
- else
- LIBS="$LIBS `$LDNSCONFIG --libs`"
- CPPFLAGS="$CPPFLAGS `$LDNSCONFIG --cflags`"
- ldns=yes
- fi
- elif test "x$withval" != "xno" ; then
- CPPFLAGS="$CPPFLAGS -I${withval}/include"
- LDFLAGS="$LDFLAGS -L${withval}/lib"
- LIBS="-lldns $LIBS"
- ldns=yes
- fi
+fi
+ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize"
+if test "x$ac_cv_func_getpagesize" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETPAGESIZE 1" >>confdefs.h
- # Verify that it works.
- if test "x$ldns" = "xyes" ; then
+fi
+ac_fn_c_check_func "$LINENO" "getpeereid" "ac_cv_func_getpeereid"
+if test "x$ac_cv_func_getpeereid" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETPEEREID 1" >>confdefs.h
-$as_echo "#define HAVE_LDNS 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "getpeerucred" "ac_cv_func_getpeerucred"
+if test "x$ac_cv_func_getpeerucred" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETPEERUCRED 1" >>confdefs.h
- LDNS_MSG="yes"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldns support" >&5
-$as_echo_n "checking for ldns support... " >&6; }
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+fi
+ac_fn_c_check_func "$LINENO" "getpgid" "ac_cv_func_getpgid"
+if test "x$ac_cv_func_getpgid" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETPGID 1" >>confdefs.h
-#include <stdio.h>
-#include <stdlib.h>
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
-#endif
-#include <ldns/ldns.h>
-int main() { ldns_status status = ldns_verify_trusted(NULL, NULL, NULL, NULL); status=LDNS_STATUS_OK; exit(0); }
+fi
+ac_fn_c_check_func "$LINENO" "_getpty" "ac_cv_func__getpty"
+if test "x$ac_cv_func__getpty" = xyes
+then :
+ printf "%s\n" "#define HAVE__GETPTY 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "getrlimit" "ac_cv_func_getrlimit"
+if test "x$ac_cv_func_getrlimit" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETRLIMIT 1" >>confdefs.h
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
+fi
+ac_fn_c_check_func "$LINENO" "getrandom" "ac_cv_func_getrandom"
+if test "x$ac_cv_func_getrandom" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETRANDOM 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- as_fn_error $? "** Incomplete or missing ldns libraries." "$LINENO" 5
+fi
+ac_fn_c_check_func "$LINENO" "getsid" "ac_cv_func_getsid"
+if test "x$ac_cv_func_getsid" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETSID 1" >>confdefs.h
fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
- fi
+ac_fn_c_check_func "$LINENO" "getttyent" "ac_cv_func_getttyent"
+if test "x$ac_cv_func_getttyent" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETTTYENT 1" >>confdefs.h
fi
+ac_fn_c_check_func "$LINENO" "glob" "ac_cv_func_glob"
+if test "x$ac_cv_func_glob" = xyes
+then :
+ printf "%s\n" "#define HAVE_GLOB 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "group_from_gid" "ac_cv_func_group_from_gid"
+if test "x$ac_cv_func_group_from_gid" = xyes
+then :
+ printf "%s\n" "#define HAVE_GROUP_FROM_GID 1" >>confdefs.h
-# Check whether user wants libedit support
-LIBEDIT_MSG="no"
+fi
+ac_fn_c_check_func "$LINENO" "inet_aton" "ac_cv_func_inet_aton"
+if test "x$ac_cv_func_inet_aton" = xyes
+then :
+ printf "%s\n" "#define HAVE_INET_ATON 1" >>confdefs.h
-# Check whether --with-libedit was given.
-if test "${with_libedit+set}" = set; then :
- withval=$with_libedit; if test "x$withval" != "xno" ; then
- if test "x$withval" = "xyes" ; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
-set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PKGCONFIG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- case $PKGCONFIG in
- [\\/]* | ?:[\\/]*)
- ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path.
- ;;
- *)
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
+fi
+ac_fn_c_check_func "$LINENO" "inet_ntoa" "ac_cv_func_inet_ntoa"
+if test "x$ac_cv_func_inet_ntoa" = xyes
+then :
+ printf "%s\n" "#define HAVE_INET_NTOA 1" >>confdefs.h
- ;;
-esac
fi
-PKGCONFIG=$ac_cv_path_PKGCONFIG
-if test -n "$PKGCONFIG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5
-$as_echo "$PKGCONFIG" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ac_fn_c_check_func "$LINENO" "inet_ntop" "ac_cv_func_inet_ntop"
+if test "x$ac_cv_func_inet_ntop" = xyes
+then :
+ printf "%s\n" "#define HAVE_INET_NTOP 1" >>confdefs.h
+
fi
+ac_fn_c_check_func "$LINENO" "innetgr" "ac_cv_func_innetgr"
+if test "x$ac_cv_func_innetgr" = xyes
+then :
+ printf "%s\n" "#define HAVE_INNETGR 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "killpg" "ac_cv_func_killpg"
+if test "x$ac_cv_func_killpg" = xyes
+then :
+ printf "%s\n" "#define HAVE_KILLPG 1" >>confdefs.h
fi
-if test -z "$ac_cv_path_PKGCONFIG"; then
- ac_pt_PKGCONFIG=$PKGCONFIG
- # Extract the first word of "pkg-config", so it can be a program name with args.
-set dummy pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_PKGCONFIG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- case $ac_pt_PKGCONFIG in
- [\\/]* | ?:[\\/]*)
- ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path.
- ;;
- *)
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_ac_pt_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
+ac_fn_c_check_func "$LINENO" "llabs" "ac_cv_func_llabs"
+if test "x$ac_cv_func_llabs" = xyes
+then :
+ printf "%s\n" "#define HAVE_LLABS 1" >>confdefs.h
- ;;
-esac
fi
-ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG
-if test -n "$ac_pt_PKGCONFIG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5
-$as_echo "$ac_pt_PKGCONFIG" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ac_fn_c_check_func "$LINENO" "localtime_r" "ac_cv_func_localtime_r"
+if test "x$ac_cv_func_localtime_r" = xyes
+then :
+ printf "%s\n" "#define HAVE_LOCALTIME_R 1" >>confdefs.h
+
fi
+ac_fn_c_check_func "$LINENO" "login_getcapbool" "ac_cv_func_login_getcapbool"
+if test "x$ac_cv_func_login_getcapbool" = xyes
+then :
+ printf "%s\n" "#define HAVE_LOGIN_GETCAPBOOL 1" >>confdefs.h
- if test "x$ac_pt_PKGCONFIG" = x; then
- PKGCONFIG="no"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- PKGCONFIG=$ac_pt_PKGCONFIG
- fi
-else
- PKGCONFIG="$ac_cv_path_PKGCONFIG"
fi
+ac_fn_c_check_func "$LINENO" "login_getpwclass" "ac_cv_func_login_getpwclass"
+if test "x$ac_cv_func_login_getpwclass" = xyes
+then :
+ printf "%s\n" "#define HAVE_LOGIN_GETPWCLASS 1" >>confdefs.h
- if test "x$PKGCONFIG" != "xno"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $PKGCONFIG knows about libedit" >&5
-$as_echo_n "checking if $PKGCONFIG knows about libedit... " >&6; }
- if "$PKGCONFIG" libedit; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- use_pkgconfig_for_libedit=yes
- else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- fi
- fi
- else
- CPPFLAGS="$CPPFLAGS -I${withval}/include"
- if test -n "${rpath_opt}"; then
- LDFLAGS="-L${withval}/lib ${rpath_opt}${withval}/lib ${LDFLAGS}"
- else
- LDFLAGS="-L${withval}/lib ${LDFLAGS}"
- fi
- fi
- if test "x$use_pkgconfig_for_libedit" = "xyes"; then
- LIBEDIT=`$PKGCONFIG --libs libedit`
- CPPFLAGS="$CPPFLAGS `$PKGCONFIG --cflags libedit`"
- else
- LIBEDIT="-ledit -lcurses"
- fi
- OTHERLIBS=`echo $LIBEDIT | sed 's/-ledit//'`
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for el_init in -ledit" >&5
-$as_echo_n "checking for el_init in -ledit... " >&6; }
-if ${ac_cv_lib_edit_el_init+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ledit $OTHERLIBS
- $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+fi
+ac_fn_c_check_func "$LINENO" "memmem" "ac_cv_func_memmem"
+if test "x$ac_cv_func_memmem" = xyes
+then :
+ printf "%s\n" "#define HAVE_MEMMEM 1" >>confdefs.h
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char el_init ();
-int
-main ()
-{
-return el_init ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_edit_el_init=yes
-else
- ac_cv_lib_edit_el_init=no
fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+ac_fn_c_check_func "$LINENO" "memmove" "ac_cv_func_memmove"
+if test "x$ac_cv_func_memmove" = xyes
+then :
+ printf "%s\n" "#define HAVE_MEMMOVE 1" >>confdefs.h
+
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_edit_el_init" >&5
-$as_echo "$ac_cv_lib_edit_el_init" >&6; }
-if test "x$ac_cv_lib_edit_el_init" = xyes; then :
+ac_fn_c_check_func "$LINENO" "memset_s" "ac_cv_func_memset_s"
+if test "x$ac_cv_func_memset_s" = xyes
+then :
+ printf "%s\n" "#define HAVE_MEMSET_S 1" >>confdefs.h
-$as_echo "#define USE_LIBEDIT 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "mkdtemp" "ac_cv_func_mkdtemp"
+if test "x$ac_cv_func_mkdtemp" = xyes
+then :
+ printf "%s\n" "#define HAVE_MKDTEMP 1" >>confdefs.h
- LIBEDIT_MSG="yes"
+fi
+ac_fn_c_check_func "$LINENO" "ngetaddrinfo" "ac_cv_func_ngetaddrinfo"
+if test "x$ac_cv_func_ngetaddrinfo" = xyes
+then :
+ printf "%s\n" "#define HAVE_NGETADDRINFO 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "nsleep" "ac_cv_func_nsleep"
+if test "x$ac_cv_func_nsleep" = xyes
+then :
+ printf "%s\n" "#define HAVE_NSLEEP 1" >>confdefs.h
-else
- as_fn_error $? "libedit not found" "$LINENO" 5
fi
+ac_fn_c_check_func "$LINENO" "ogetaddrinfo" "ac_cv_func_ogetaddrinfo"
+if test "x$ac_cv_func_ogetaddrinfo" = xyes
+then :
+ printf "%s\n" "#define HAVE_OGETADDRINFO 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libedit version is compatible" >&5
-$as_echo_n "checking if libedit version is compatible... " >&6; }
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+fi
+ac_fn_c_check_func "$LINENO" "openlog_r" "ac_cv_func_openlog_r"
+if test "x$ac_cv_func_openlog_r" = xyes
+then :
+ printf "%s\n" "#define HAVE_OPENLOG_R 1" >>confdefs.h
-#include <histedit.h>
-#include <stdlib.h>
+fi
+ac_fn_c_check_func "$LINENO" "pledge" "ac_cv_func_pledge"
+if test "x$ac_cv_func_pledge" = xyes
+then :
+ printf "%s\n" "#define HAVE_PLEDGE 1" >>confdefs.h
-int
-main ()
-{
+fi
+ac_fn_c_check_func "$LINENO" "poll" "ac_cv_func_poll"
+if test "x$ac_cv_func_poll" = xyes
+then :
+ printf "%s\n" "#define HAVE_POLL 1" >>confdefs.h
- int i = H_SETSIZE;
- el_init("", NULL, NULL, NULL);
- exit(0);
+fi
+ac_fn_c_check_func "$LINENO" "ppoll" "ac_cv_func_ppoll"
+if test "x$ac_cv_func_ppoll" = xyes
+then :
+ printf "%s\n" "#define HAVE_PPOLL 1" >>confdefs.h
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- as_fn_error $? "libedit version is not compatible" "$LINENO" 5
+fi
+ac_fn_c_check_func "$LINENO" "prctl" "ac_cv_func_prctl"
+if test "x$ac_cv_func_prctl" = xyes
+then :
+ printf "%s\n" "#define HAVE_PRCTL 1" >>confdefs.h
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- fi
+ac_fn_c_check_func "$LINENO" "procctl" "ac_cv_func_procctl"
+if test "x$ac_cv_func_procctl" = xyes
+then :
+ printf "%s\n" "#define HAVE_PROCCTL 1" >>confdefs.h
fi
+ac_fn_c_check_func "$LINENO" "pselect" "ac_cv_func_pselect"
+if test "x$ac_cv_func_pselect" = xyes
+then :
+ printf "%s\n" "#define HAVE_PSELECT 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "pstat" "ac_cv_func_pstat"
+if test "x$ac_cv_func_pstat" = xyes
+then :
+ printf "%s\n" "#define HAVE_PSTAT 1" >>confdefs.h
-AUDIT_MODULE=none
+fi
+ac_fn_c_check_func "$LINENO" "raise" "ac_cv_func_raise"
+if test "x$ac_cv_func_raise" = xyes
+then :
+ printf "%s\n" "#define HAVE_RAISE 1" >>confdefs.h
-# Check whether --with-audit was given.
-if test "${with_audit+set}" = set; then :
- withval=$with_audit;
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for supported audit module" >&5
-$as_echo_n "checking for supported audit module... " >&6; }
- case "$withval" in
- bsm)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: bsm" >&5
-$as_echo "bsm" >&6; }
- AUDIT_MODULE=bsm
- for ac_header in bsm/audit.h
-do :
- ac_fn_c_check_header_compile "$LINENO" "bsm/audit.h" "ac_cv_header_bsm_audit_h" "
-#ifdef HAVE_TIME_H
-# include <time.h>
-#endif
+fi
+ac_fn_c_check_func "$LINENO" "readpassphrase" "ac_cv_func_readpassphrase"
+if test "x$ac_cv_func_readpassphrase" = xyes
+then :
+ printf "%s\n" "#define HAVE_READPASSPHRASE 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray"
+if test "x$ac_cv_func_reallocarray" = xyes
+then :
+ printf "%s\n" "#define HAVE_REALLOCARRAY 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "realpath" "ac_cv_func_realpath"
+if test "x$ac_cv_func_realpath" = xyes
+then :
+ printf "%s\n" "#define HAVE_REALPATH 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "recvmsg" "ac_cv_func_recvmsg"
+if test "x$ac_cv_func_recvmsg" = xyes
+then :
+ printf "%s\n" "#define HAVE_RECVMSG 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "recallocarray" "ac_cv_func_recallocarray"
+if test "x$ac_cv_func_recallocarray" = xyes
+then :
+ printf "%s\n" "#define HAVE_RECALLOCARRAY 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "rresvport_af" "ac_cv_func_rresvport_af"
+if test "x$ac_cv_func_rresvport_af" = xyes
+then :
+ printf "%s\n" "#define HAVE_RRESVPORT_AF 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "sendmsg" "ac_cv_func_sendmsg"
+if test "x$ac_cv_func_sendmsg" = xyes
+then :
+ printf "%s\n" "#define HAVE_SENDMSG 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "setdtablesize" "ac_cv_func_setdtablesize"
+if test "x$ac_cv_func_setdtablesize" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETDTABLESIZE 1" >>confdefs.h
-"
-if test "x$ac_cv_header_bsm_audit_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_BSM_AUDIT_H 1
-_ACEOF
+fi
+ac_fn_c_check_func "$LINENO" "setegid" "ac_cv_func_setegid"
+if test "x$ac_cv_func_setegid" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETEGID 1" >>confdefs.h
-else
- as_fn_error $? "BSM enabled and bsm/audit.h not found" "$LINENO" 5
fi
+ac_fn_c_check_func "$LINENO" "setenv" "ac_cv_func_setenv"
+if test "x$ac_cv_func_setenv" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETENV 1" >>confdefs.h
-done
+fi
+ac_fn_c_check_func "$LINENO" "seteuid" "ac_cv_func_seteuid"
+if test "x$ac_cv_func_seteuid" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETEUID 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getaudit in -lbsm" >&5
-$as_echo_n "checking for getaudit in -lbsm... " >&6; }
-if ${ac_cv_lib_bsm_getaudit+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lbsm $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+fi
+ac_fn_c_check_func "$LINENO" "setgroupent" "ac_cv_func_setgroupent"
+if test "x$ac_cv_func_setgroupent" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETGROUPENT 1" >>confdefs.h
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char getaudit ();
-int
-main ()
-{
-return getaudit ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_bsm_getaudit=yes
-else
- ac_cv_lib_bsm_getaudit=no
fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+ac_fn_c_check_func "$LINENO" "setgroups" "ac_cv_func_setgroups"
+if test "x$ac_cv_func_setgroups" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETGROUPS 1" >>confdefs.h
+
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsm_getaudit" >&5
-$as_echo "$ac_cv_lib_bsm_getaudit" >&6; }
-if test "x$ac_cv_lib_bsm_getaudit" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBBSM 1
-_ACEOF
+ac_fn_c_check_func "$LINENO" "setlinebuf" "ac_cv_func_setlinebuf"
+if test "x$ac_cv_func_setlinebuf" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETLINEBUF 1" >>confdefs.h
- LIBS="-lbsm $LIBS"
+fi
+ac_fn_c_check_func "$LINENO" "setlogin" "ac_cv_func_setlogin"
+if test "x$ac_cv_func_setlogin" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETLOGIN 1" >>confdefs.h
-else
- as_fn_error $? "BSM enabled and required library not found" "$LINENO" 5
fi
+ac_fn_c_check_func "$LINENO" "setpassent" "ac_cv_func_setpassent"
+if test "x$ac_cv_func_setpassent" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETPASSENT 1" >>confdefs.h
- for ac_func in getaudit
-do :
- ac_fn_c_check_func "$LINENO" "getaudit" "ac_cv_func_getaudit"
-if test "x$ac_cv_func_getaudit" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_GETAUDIT 1
-_ACEOF
+fi
+ac_fn_c_check_func "$LINENO" "setpcred" "ac_cv_func_setpcred"
+if test "x$ac_cv_func_setpcred" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETPCRED 1" >>confdefs.h
-else
- as_fn_error $? "BSM enabled and required function not found" "$LINENO" 5
fi
-done
+ac_fn_c_check_func "$LINENO" "setproctitle" "ac_cv_func_setproctitle"
+if test "x$ac_cv_func_setproctitle" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETPROCTITLE 1" >>confdefs.h
- # These are optional
- for ac_func in getaudit_addr aug_get_machine
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+fi
+ac_fn_c_check_func "$LINENO" "setregid" "ac_cv_func_setregid"
+if test "x$ac_cv_func_setregid" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETREGID 1" >>confdefs.h
fi
-done
+ac_fn_c_check_func "$LINENO" "setreuid" "ac_cv_func_setreuid"
+if test "x$ac_cv_func_setreuid" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETREUID 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "setrlimit" "ac_cv_func_setrlimit"
+if test "x$ac_cv_func_setrlimit" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETRLIMIT 1" >>confdefs.h
-$as_echo "#define USE_BSM_AUDIT 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "setsid" "ac_cv_func_setsid"
+if test "x$ac_cv_func_setsid" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETSID 1" >>confdefs.h
- if test "$sol2ver" -ge 11; then
- SSHDLIBS="$SSHDLIBS -lscf"
+fi
+ac_fn_c_check_func "$LINENO" "setvbuf" "ac_cv_func_setvbuf"
+if test "x$ac_cv_func_setvbuf" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETVBUF 1" >>confdefs.h
-$as_echo "#define BROKEN_BSM_API 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "sigaction" "ac_cv_func_sigaction"
+if test "x$ac_cv_func_sigaction" = xyes
+then :
+ printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h
- fi
- ;;
- linux)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: linux" >&5
-$as_echo "linux" >&6; }
- AUDIT_MODULE=linux
- for ac_header in libaudit.h
-do :
- ac_fn_c_check_header_mongrel "$LINENO" "libaudit.h" "ac_cv_header_libaudit_h" "$ac_includes_default"
-if test "x$ac_cv_header_libaudit_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBAUDIT_H 1
-_ACEOF
+fi
+ac_fn_c_check_func "$LINENO" "sigvec" "ac_cv_func_sigvec"
+if test "x$ac_cv_func_sigvec" = xyes
+then :
+ printf "%s\n" "#define HAVE_SIGVEC 1" >>confdefs.h
fi
+ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf"
+if test "x$ac_cv_func_snprintf" = xyes
+then :
+ printf "%s\n" "#define HAVE_SNPRINTF 1" >>confdefs.h
-done
+fi
+ac_fn_c_check_func "$LINENO" "socketpair" "ac_cv_func_socketpair"
+if test "x$ac_cv_func_socketpair" = xyes
+then :
+ printf "%s\n" "#define HAVE_SOCKETPAIR 1" >>confdefs.h
- SSHDLIBS="$SSHDLIBS -laudit"
+fi
+ac_fn_c_check_func "$LINENO" "statfs" "ac_cv_func_statfs"
+if test "x$ac_cv_func_statfs" = xyes
+then :
+ printf "%s\n" "#define HAVE_STATFS 1" >>confdefs.h
-$as_echo "#define USE_LINUX_AUDIT 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "statvfs" "ac_cv_func_statvfs"
+if test "x$ac_cv_func_statvfs" = xyes
+then :
+ printf "%s\n" "#define HAVE_STATVFS 1" >>confdefs.h
- ;;
- debug)
- AUDIT_MODULE=debug
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: debug" >&5
-$as_echo "debug" >&6; }
+fi
+ac_fn_c_check_func "$LINENO" "strcasestr" "ac_cv_func_strcasestr"
+if test "x$ac_cv_func_strcasestr" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRCASESTR 1" >>confdefs.h
-$as_echo "#define SSH_AUDIT_EVENTS 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "strdup" "ac_cv_func_strdup"
+if test "x$ac_cv_func_strdup" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRDUP 1" >>confdefs.h
- ;;
- no)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- ;;
- *)
- as_fn_error $? "Unknown audit module $withval" "$LINENO" 5
- ;;
- esac
+fi
+ac_fn_c_check_func "$LINENO" "strerror" "ac_cv_func_strerror"
+if test "x$ac_cv_func_strerror" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRERROR 1" >>confdefs.h
fi
+ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat"
+if test "x$ac_cv_func_strlcat" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRLCAT 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy"
+if test "x$ac_cv_func_strlcpy" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRLCPY 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "strmode" "ac_cv_func_strmode"
+if test "x$ac_cv_func_strmode" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRMODE 1" >>confdefs.h
-# Check whether --with-pie was given.
-if test "${with_pie+set}" = set; then :
- withval=$with_pie;
- if test "x$withval" = "xno"; then
- use_pie=no
- fi
- if test "x$withval" = "xyes"; then
- use_pie=yes
- fi
+fi
+ac_fn_c_check_func "$LINENO" "strndup" "ac_cv_func_strndup"
+if test "x$ac_cv_func_strndup" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRNDUP 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "strnlen" "ac_cv_func_strnlen"
+if test "x$ac_cv_func_strnlen" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRNLEN 1" >>confdefs.h
fi
+ac_fn_c_check_func "$LINENO" "strnvis" "ac_cv_func_strnvis"
+if test "x$ac_cv_func_strnvis" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRNVIS 1" >>confdefs.h
-if test "x$use_pie" = "x"; then
- use_pie=no
fi
-if test "x$use_toolchain_hardening" != "x1" && test "x$use_pie" = "xauto"; then
- # Turn off automatic PIE when toolchain hardening is off.
- use_pie=no
+ac_fn_c_check_func "$LINENO" "strptime" "ac_cv_func_strptime"
+if test "x$ac_cv_func_strptime" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRPTIME 1" >>confdefs.h
+
fi
-if test "x$use_pie" = "xauto"; then
- # Automatic PIE requires gcc >= 4.x
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc >= 4.x" >&5
-$as_echo_n "checking for gcc >= 4.x... " >&6; }
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ac_fn_c_check_func "$LINENO" "strsignal" "ac_cv_func_strsignal"
+if test "x$ac_cv_func_strsignal" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRSIGNAL 1" >>confdefs.h
-#if !defined(__GNUC__) || __GNUC__ < 4
-#error gcc is too old
-#endif
+fi
+ac_fn_c_check_func "$LINENO" "strtonum" "ac_cv_func_strtonum"
+if test "x$ac_cv_func_strtonum" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRTONUM 1" >>confdefs.h
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- use_pie=no
+fi
+ac_fn_c_check_func "$LINENO" "strtoll" "ac_cv_func_strtoll"
+if test "x$ac_cv_func_strtoll" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRTOLL 1" >>confdefs.h
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_fn_c_check_func "$LINENO" "strtoul" "ac_cv_func_strtoul"
+if test "x$ac_cv_func_strtoul" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRTOUL 1" >>confdefs.h
+
fi
-if test "x$use_pie" != "xno"; then
- SAVED_CFLAGS="$CFLAGS"
- SAVED_LDFLAGS="$LDFLAGS"
- {
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -fPIE" >&5
-$as_echo_n "checking if $CC supports compile flag -fPIE... " >&6; }
- saved_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS $WERROR -fPIE"
- _define_flag=""
- test "x$_define_flag" = "x" && _define_flag="-fPIE"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ac_fn_c_check_func "$LINENO" "strtoull" "ac_cv_func_strtoull"
+if test "x$ac_cv_func_strtoull" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRTOULL 1" >>confdefs.h
-#include <stdlib.h>
-#include <stdio.h>
-/* Trivial function to help test for -fzero-call-used-regs */
-void f(int n) {}
-int main(int argc, char **argv) {
- (void)argv;
- /* Some math to catch -ftrapv problems in the toolchain */
- int i = 123 * argc, j = 456 + argc, k = 789 - argc;
- float l = i * 2.1;
- double m = l / 0.5;
- long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
- f(0);
- printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
- /*
- * Test fallthrough behaviour. clang 10's -Wimplicit-fallthrough does
- * not understand comments and we don't use the "fallthrough" attribute
- * that it's looking for.
- */
- switch(i){
- case 0: j += i;
- /* FALLTHROUGH */
- default: j += k;
- }
- exit(0);
-}
+fi
+ac_fn_c_check_func "$LINENO" "swap32" "ac_cv_func_swap32"
+if test "x$ac_cv_func_swap32" = xyes
+then :
+ printf "%s\n" "#define HAVE_SWAP32 1" >>confdefs.h
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+fi
+ac_fn_c_check_func "$LINENO" "sysconf" "ac_cv_func_sysconf"
+if test "x$ac_cv_func_sysconf" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYSCONF 1" >>confdefs.h
-if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
-then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- CFLAGS="$saved_CFLAGS"
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- CFLAGS="$saved_CFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- CFLAGS="$saved_CFLAGS"
+ac_fn_c_check_func "$LINENO" "tcgetpgrp" "ac_cv_func_tcgetpgrp"
+if test "x$ac_cv_func_tcgetpgrp" = xyes
+then :
+ printf "%s\n" "#define HAVE_TCGETPGRP 1" >>confdefs.h
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-}
- {
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $LD supports link flag -pie" >&5
-$as_echo_n "checking if $LD supports link flag -pie... " >&6; }
- saved_LDFLAGS="$LDFLAGS"
- LDFLAGS="$LDFLAGS $WERROR -pie"
- _define_flag=""
- test "x$_define_flag" = "x" && _define_flag="-pie"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ac_fn_c_check_func "$LINENO" "timegm" "ac_cv_func_timegm"
+if test "x$ac_cv_func_timegm" = xyes
+then :
+ printf "%s\n" "#define HAVE_TIMEGM 1" >>confdefs.h
-#include <stdlib.h>
-#include <stdio.h>
-int main(int argc, char **argv) {
- (void)argv;
- /* Some math to catch -ftrapv problems in the toolchain */
- int i = 123 * argc, j = 456 + argc, k = 789 - argc;
- float l = i * 2.1;
- double m = l / 0.5;
- long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
- long long p = n * o;
- printf("%d %d %d %f %f %lld %lld %lld\n", i, j, k, l, m, n, o, p);
- exit(0);
-}
+fi
+ac_fn_c_check_func "$LINENO" "timingsafe_bcmp" "ac_cv_func_timingsafe_bcmp"
+if test "x$ac_cv_func_timingsafe_bcmp" = xyes
+then :
+ printf "%s\n" "#define HAVE_TIMINGSAFE_BCMP 1" >>confdefs.h
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+fi
+ac_fn_c_check_func "$LINENO" "truncate" "ac_cv_func_truncate"
+if test "x$ac_cv_func_truncate" = xyes
+then :
+ printf "%s\n" "#define HAVE_TRUNCATE 1" >>confdefs.h
-if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null
-then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- LDFLAGS="$saved_LDFLAGS"
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- LDFLAGS="$saved_LDFLAGS $_define_flag"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- LDFLAGS="$saved_LDFLAGS"
+ac_fn_c_check_func "$LINENO" "unsetenv" "ac_cv_func_unsetenv"
+if test "x$ac_cv_func_unsetenv" = xyes
+then :
+ printf "%s\n" "#define HAVE_UNSETENV 1" >>confdefs.h
fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-}
- # We use both -fPIE and -pie or neither.
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether both -fPIE and -pie are supported" >&5
-$as_echo_n "checking whether both -fPIE and -pie are supported... " >&6; }
- if echo "x $CFLAGS" | grep ' -fPIE' >/dev/null 2>&1 && \
- echo "x $LDFLAGS" | grep ' -pie' >/dev/null 2>&1 ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- CFLAGS="$SAVED_CFLAGS"
- LDFLAGS="$SAVED_LDFLAGS"
- fi
+ac_fn_c_check_func "$LINENO" "updwtmpx" "ac_cv_func_updwtmpx"
+if test "x$ac_cv_func_updwtmpx" = xyes
+then :
+ printf "%s\n" "#define HAVE_UPDWTMPX 1" >>confdefs.h
+
fi
+ac_fn_c_check_func "$LINENO" "utimensat" "ac_cv_func_utimensat"
+if test "x$ac_cv_func_utimensat" = xyes
+then :
+ printf "%s\n" "#define HAVE_UTIMENSAT 1" >>confdefs.h
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -fPIC is accepted" >&5
-$as_echo_n "checking whether -fPIC is accepted... " >&6; }
-SAVED_CFLAGS="$CFLAGS"
-CFLAGS="$CFLAGS -fPIC"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
- #include <stdlib.h>
-int
-main ()
-{
- exit(0);
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- PICFLAG="-fPIC";
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- PICFLAG="";
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-CFLAGS="$SAVED_CFLAGS"
+ac_fn_c_check_func "$LINENO" "user_from_uid" "ac_cv_func_user_from_uid"
+if test "x$ac_cv_func_user_from_uid" = xyes
+then :
+ printf "%s\n" "#define HAVE_USER_FROM_UID 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "usleep" "ac_cv_func_usleep"
+if test "x$ac_cv_func_usleep" = xyes
+then :
+ printf "%s\n" "#define HAVE_USLEEP 1" >>confdefs.h
-for ac_func in \
- Blowfish_initstate \
- Blowfish_expandstate \
- Blowfish_expand0state \
- Blowfish_stream2word \
- SHA256Update \
- SHA384Update \
- SHA512Update \
- asprintf \
- b64_ntop \
- __b64_ntop \
- b64_pton \
- __b64_pton \
- bcopy \
- bcrypt_pbkdf \
- bindresvport_sa \
- blf_enc \
- bzero \
- cap_rights_limit \
- clock \
- closefrom \
- close_range \
- dirfd \
- endgrent \
- err \
- errx \
- explicit_bzero \
- explicit_memset \
- fchmod \
- fchmodat \
- fchown \
- fchownat \
- flock \
- fnmatch \
- freeaddrinfo \
- freezero \
- fstatfs \
- fstatvfs \
- futimes \
- getaddrinfo \
- getcwd \
- getgrouplist \
- getline \
- getnameinfo \
- getopt \
- getpagesize \
- getpeereid \
- getpeerucred \
- getpgid \
- _getpty \
- getrlimit \
- getrandom \
- getsid \
- getttyent \
- glob \
- group_from_gid \
- inet_aton \
- inet_ntoa \
- inet_ntop \
- innetgr \
- killpg \
- llabs \
- localtime_r \
- login_getcapbool \
- login_getpwclass \
- memmem \
- memmove \
- memset_s \
- mkdtemp \
- ngetaddrinfo \
- nsleep \
- ogetaddrinfo \
- openlog_r \
- pledge \
- poll \
- ppoll \
- prctl \
- procctl \
- pselect \
- pstat \
- raise \
- readpassphrase \
- reallocarray \
- realpath \
- recvmsg \
- recallocarray \
- rresvport_af \
- sendmsg \
- setdtablesize \
- setegid \
- setenv \
- seteuid \
- setgroupent \
- setgroups \
- setlinebuf \
- setlogin \
- setpassent\
- setpcred \
- setproctitle \
- setregid \
- setreuid \
- setrlimit \
- setsid \
- setvbuf \
- sigaction \
- sigvec \
- snprintf \
- socketpair \
- statfs \
- statvfs \
- strcasestr \
- strdup \
- strerror \
- strlcat \
- strlcpy \
- strmode \
- strndup \
- strnlen \
- strnvis \
- strptime \
- strsignal \
- strtonum \
- strtoll \
- strtoul \
- strtoull \
- swap32 \
- sysconf \
- tcgetpgrp \
- timingsafe_bcmp \
- truncate \
- unsetenv \
- updwtmpx \
- utimensat \
- user_from_uid \
- usleep \
- vasprintf \
- vsnprintf \
- waitpid \
- warn \
+fi
+ac_fn_c_check_func "$LINENO" "vasprintf" "ac_cv_func_vasprintf"
+if test "x$ac_cv_func_vasprintf" = xyes
+then :
+ printf "%s\n" "#define HAVE_VASPRINTF 1" >>confdefs.h
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+fi
+ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf"
+if test "x$ac_cv_func_vsnprintf" = xyes
+then :
+ printf "%s\n" "#define HAVE_VSNPRINTF 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "waitpid" "ac_cv_func_waitpid"
+if test "x$ac_cv_func_waitpid" = xyes
+then :
+ printf "%s\n" "#define HAVE_WAITPID 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "warn" "ac_cv_func_warn"
+if test "x$ac_cv_func_warn" = xyes
+then :
+ printf "%s\n" "#define HAVE_WARN 1" >>confdefs.h
fi
-done
-ac_fn_c_check_decl "$LINENO" "bzero" "ac_cv_have_decl_bzero" "$ac_includes_default"
-if test "x$ac_cv_have_decl_bzero" = xyes; then :
+ac_fn_check_decl "$LINENO" "bzero" "ac_cv_have_decl_bzero" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_bzero" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_BZERO $ac_have_decl
-_ACEOF
-ac_fn_c_check_decl "$LINENO" "memmem" "ac_cv_have_decl_memmem" "$ac_includes_default"
-if test "x$ac_cv_have_decl_memmem" = xyes; then :
+printf "%s\n" "#define HAVE_DECL_BZERO $ac_have_decl" >>confdefs.h
+ac_fn_check_decl "$LINENO" "memmem" "ac_cv_have_decl_memmem" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_memmem" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
+printf "%s\n" "#define HAVE_DECL_MEMMEM $ac_have_decl" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_MEMMEM $ac_have_decl
-_ACEOF
+ac_fn_c_check_func "$LINENO" "mblen" "ac_cv_func_mblen"
+if test "x$ac_cv_func_mblen" = xyes
+then :
+ printf "%s\n" "#define HAVE_MBLEN 1" >>confdefs.h
-for ac_func in mblen mbtowc nl_langinfo wcwidth
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+fi
+ac_fn_c_check_func "$LINENO" "mbtowc" "ac_cv_func_mbtowc"
+if test "x$ac_cv_func_mbtowc" = xyes
+then :
+ printf "%s\n" "#define HAVE_MBTOWC 1" >>confdefs.h
fi
-done
+ac_fn_c_check_func "$LINENO" "nl_langinfo" "ac_cv_func_nl_langinfo"
+if test "x$ac_cv_func_nl_langinfo" = xyes
+then :
+ printf "%s\n" "#define HAVE_NL_LANGINFO 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "wcwidth" "ac_cv_func_wcwidth"
+if test "x$ac_cv_func_wcwidth" = xyes
+then :
+ printf "%s\n" "#define HAVE_WCWIDTH 1" >>confdefs.h
+fi
-TEST_SSH_UTF8=${TEST_SSH_UTF8:=yes}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for utf8 locale support" >&5
-$as_echo_n "checking for utf8 locale support... " >&6; }
-if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming yes" >&5
-$as_echo "$as_me: WARNING: cross compiling: assuming yes" >&2;}
-else
+TEST_SSH_UTF8=${TEST_SSH_UTF8:=yes}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for utf8 locale support" >&5
+printf %s "checking for utf8 locale support... " >&6; }
+if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming yes" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: assuming yes" >&2;}
+
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <locale.h>
#include <stdlib.h>
int
-main ()
+main (void)
{
char *loc = setlocale(LC_CTYPE, "en_US.UTF-8");
if (loc != NULL)
exit(0);
exit(1);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
TEST_SSH_UTF8=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <ctype.h>
int
-main ()
+main (void)
{
return (isblank('a'));
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
-$as_echo "#define HAVE_ISBLANK 1" >>confdefs.h
+printf "%s\n" "#define HAVE_ISBLANK 1" >>confdefs.h
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
disable_pkcs11=
# Check whether --enable-pkcs11 was given.
-if test "${enable_pkcs11+set}" = set; then :
+if test ${enable_pkcs11+y}
+then :
enableval=$enable_pkcs11;
if test "x$enableval" = "xno" ; then
disable_pkcs11=1
fi
fi
disable_sk=
# Check whether --enable-security-key was given.
-if test "${enable_security_key+set}" = set; then :
+if test ${enable_security_key+y}
+then :
enableval=$enable_security_key;
if test "x$enableval" = "xno" ; then
disable_sk=1
fi
fi
enable_sk_internal=
# Check whether --with-security-key-builtin was given.
-if test "${with_security_key_builtin+set}" = set; then :
- withval=$with_security_key_builtin;
- if test "x$withval" != "xno" ; then
- enable_sk_internal=yes
- fi
-
+if test ${with_security_key_builtin+y}
+then :
+ withval=$with_security_key_builtin; enable_sk_internal=$withval
fi
-test "x$disable_sk" != "x" && enable_sk_internal=""
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5
-$as_echo_n "checking for library containing dlopen... " >&6; }
-if ${ac_cv_search_dlopen+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5
+printf %s "checking for library containing dlopen... " >&6; }
+if test ${ac_cv_search_dlopen+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char dlopen ();
int
-main ()
+main (void)
{
return dlopen ();
;
return 0;
}
_ACEOF
-for ac_lib in '' dl; do
+for ac_lib in '' dl
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
+ if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_search_dlopen=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_dlopen+:} false; then :
+ if test ${ac_cv_search_dlopen+y}
+then :
break
fi
done
-if ${ac_cv_search_dlopen+:} false; then :
+if test ${ac_cv_search_dlopen+y}
+then :
-else
+else $as_nop
ac_cv_search_dlopen=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5
-$as_echo "$ac_cv_search_dlopen" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5
+printf "%s\n" "$ac_cv_search_dlopen" >&6; }
ac_res=$ac_cv_search_dlopen
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
-for ac_func in dlopen
-do :
- ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
-if test "x$ac_cv_func_dlopen" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_DLOPEN 1
-_ACEOF
-
-fi
-done
-
-ac_fn_c_check_decl "$LINENO" "RTLD_NOW" "ac_cv_have_decl_RTLD_NOW" "#include <dlfcn.h>
-"
-if test "x$ac_cv_have_decl_RTLD_NOW" = xyes; then :
+ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = xyes
+then :
+ printf "%s\n" "#define HAVE_DLOPEN 1" >>confdefs.h
fi
+ac_fn_check_decl "$LINENO" "RTLD_NOW" "ac_cv_have_decl_RTLD_NOW" "#include <dlfcn.h>
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_RTLD_NOW" = xyes
+then :
+
+fi
# IRIX has a const char return value for gai_strerror()
-for ac_func in gai_strerror
+
+ for ac_func in gai_strerror
do :
ac_fn_c_check_func "$LINENO" "gai_strerror" "ac_cv_func_gai_strerror"
-if test "x$ac_cv_func_gai_strerror" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_GAI_STRERROR 1
-_ACEOF
+if test "x$ac_cv_func_gai_strerror" = xyes
+then :
+ printf "%s\n" "#define HAVE_GAI_STRERROR 1" >>confdefs.h
- $as_echo "#define HAVE_GAI_STRERROR 1" >>confdefs.h
+ printf "%s\n" "#define HAVE_GAI_STRERROR 1" >>confdefs.h
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
const char *gai_strerror(int);
int
-main ()
+main (void)
{
char *str;
str = gai_strerror(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
-$as_echo "#define HAVE_CONST_GAI_STRERROR_PROTO 1" >>confdefs.h
+printf "%s\n" "#define HAVE_CONST_GAI_STRERROR_PROTO 1" >>confdefs.h
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-done
+done
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing nanosleep" >&5
-$as_echo_n "checking for library containing nanosleep... " >&6; }
-if ${ac_cv_search_nanosleep+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing nanosleep" >&5
+printf %s "checking for library containing nanosleep... " >&6; }
+if test ${ac_cv_search_nanosleep+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char nanosleep ();
int
-main ()
+main (void)
{
return nanosleep ();
;
return 0;
}
_ACEOF
-for ac_lib in '' rt posix4; do
+for ac_lib in '' rt posix4
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
+ if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_search_nanosleep=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_nanosleep+:} false; then :
+ if test ${ac_cv_search_nanosleep+y}
+then :
break
fi
done
-if ${ac_cv_search_nanosleep+:} false; then :
+if test ${ac_cv_search_nanosleep+y}
+then :
-else
+else $as_nop
ac_cv_search_nanosleep=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_nanosleep" >&5
-$as_echo "$ac_cv_search_nanosleep" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_nanosleep" >&5
+printf "%s\n" "$ac_cv_search_nanosleep" >&6; }
ac_res=$ac_cv_search_nanosleep
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-$as_echo "#define HAVE_NANOSLEEP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_NANOSLEEP 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5
-$as_echo_n "checking for library containing clock_gettime... " >&6; }
-if ${ac_cv_search_clock_gettime+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5
+printf %s "checking for library containing clock_gettime... " >&6; }
+if test ${ac_cv_search_clock_gettime+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char clock_gettime ();
int
-main ()
+main (void)
{
return clock_gettime ();
;
return 0;
}
_ACEOF
-for ac_lib in '' rt; do
+for ac_lib in '' rt
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
+ if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_search_clock_gettime=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_clock_gettime+:} false; then :
+ if test ${ac_cv_search_clock_gettime+y}
+then :
break
fi
done
-if ${ac_cv_search_clock_gettime+:} false; then :
+if test ${ac_cv_search_clock_gettime+y}
+then :
-else
+else $as_nop
ac_cv_search_clock_gettime=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5
-$as_echo "$ac_cv_search_clock_gettime" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5
+printf "%s\n" "$ac_cv_search_clock_gettime" >&6; }
ac_res=$ac_cv_search_clock_gettime
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-$as_echo "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h
+printf "%s\n" "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h
fi
-ac_fn_c_check_decl "$LINENO" "localtime_r" "ac_cv_have_decl_localtime_r" " #include <time.h>
+ac_fn_check_decl "$LINENO" "localtime_r" "ac_cv_have_decl_localtime_r" " #include <time.h>
-"
-if test "x$ac_cv_have_decl_localtime_r" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_localtime_r" = xyes
+then :
-else
+else $as_nop
saved_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS -D_REENTRANT"
unset ac_cv_have_decl_localtime_r
- ac_fn_c_check_decl "$LINENO" "localtime_r" "ac_cv_have_decl_localtime_r" " #include <time.h>
+ ac_fn_check_decl "$LINENO" "localtime_r" "ac_cv_have_decl_localtime_r" " #include <time.h>
-"
-if test "x$ac_cv_have_decl_localtime_r" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_localtime_r" = xyes
+then :
-else
+else $as_nop
CPPFLAGS="$saved_CPPFLAGS"
fi
-
fi
-
-ac_fn_c_check_decl "$LINENO" "strsep" "ac_cv_have_decl_strsep" "
+ac_fn_check_decl "$LINENO" "strsep" "ac_cv_have_decl_strsep" "
#ifdef HAVE_STRING_H
# include <string.h>
#endif
-"
-if test "x$ac_cv_have_decl_strsep" = xyes; then :
- for ac_func in strsep
-do :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_strsep" = xyes
+then :
ac_fn_c_check_func "$LINENO" "strsep" "ac_cv_func_strsep"
-if test "x$ac_cv_func_strsep" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_STRSEP 1
-_ACEOF
+if test "x$ac_cv_func_strsep" = xyes
+then :
+ printf "%s\n" "#define HAVE_STRSEP 1" >>confdefs.h
fi
-done
fi
+ac_fn_check_decl "$LINENO" "tcsendbreak" "ac_cv_have_decl_tcsendbreak" "#include <termios.h>
-ac_fn_c_check_decl "$LINENO" "tcsendbreak" "ac_cv_have_decl_tcsendbreak" "#include <termios.h>
-
-"
-if test "x$ac_cv_have_decl_tcsendbreak" = xyes; then :
- $as_echo "#define HAVE_TCSENDBREAK 1" >>confdefs.h
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_tcsendbreak" = xyes
+then :
+ printf "%s\n" "#define HAVE_TCSENDBREAK 1" >>confdefs.h
-else
- for ac_func in tcsendbreak
-do :
+else $as_nop
ac_fn_c_check_func "$LINENO" "tcsendbreak" "ac_cv_func_tcsendbreak"
-if test "x$ac_cv_func_tcsendbreak" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_TCSENDBREAK 1
-_ACEOF
+if test "x$ac_cv_func_tcsendbreak" = xyes
+then :
+ printf "%s\n" "#define HAVE_TCSENDBREAK 1" >>confdefs.h
fi
-done
fi
-
-ac_fn_c_check_decl "$LINENO" "h_errno" "ac_cv_have_decl_h_errno" "#include <netdb.h>
-"
-if test "x$ac_cv_have_decl_h_errno" = xyes; then :
+ac_fn_check_decl "$LINENO" "h_errno" "ac_cv_have_decl_h_errno" "#include <netdb.h>
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_h_errno" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_H_ERRNO $ac_have_decl
-_ACEOF
+printf "%s\n" "#define HAVE_DECL_H_ERRNO $ac_have_decl" >>confdefs.h
-ac_fn_c_check_decl "$LINENO" "SHUT_RD" "ac_cv_have_decl_SHUT_RD" "
+ac_fn_check_decl "$LINENO" "SHUT_RD" "ac_cv_have_decl_SHUT_RD" "
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
-"
-if test "x$ac_cv_have_decl_SHUT_RD" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_SHUT_RD" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_SHUT_RD $ac_have_decl
-_ACEOF
-ac_fn_c_check_decl "$LINENO" "getpeereid" "ac_cv_have_decl_getpeereid" "
+printf "%s\n" "#define HAVE_DECL_SHUT_RD $ac_have_decl" >>confdefs.h
+ac_fn_check_decl "$LINENO" "getpeereid" "ac_cv_have_decl_getpeereid" "
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
-"
-if test "x$ac_cv_have_decl_getpeereid" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_getpeereid" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_GETPEEREID $ac_have_decl
-_ACEOF
+printf "%s\n" "#define HAVE_DECL_GETPEEREID $ac_have_decl" >>confdefs.h
-ac_fn_c_check_decl "$LINENO" "O_NONBLOCK" "ac_cv_have_decl_O_NONBLOCK" "
+ac_fn_check_decl "$LINENO" "O_NONBLOCK" "ac_cv_have_decl_O_NONBLOCK" "
#include <sys/types.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
-"
-if test "x$ac_cv_have_decl_O_NONBLOCK" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_O_NONBLOCK" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_O_NONBLOCK $ac_have_decl
-_ACEOF
+printf "%s\n" "#define HAVE_DECL_O_NONBLOCK $ac_have_decl" >>confdefs.h
-ac_fn_c_check_decl "$LINENO" "ftruncate" "ac_cv_have_decl_ftruncate" "
+ac_fn_check_decl "$LINENO" "ftruncate" "ac_cv_have_decl_ftruncate" "
#include <sys/types.h>
#include <unistd.h>
-"
-if test "x$ac_cv_have_decl_ftruncate" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_ftruncate" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
+printf "%s\n" "#define HAVE_DECL_FTRUNCATE $ac_have_decl" >>confdefs.h
+ac_fn_check_decl "$LINENO" "getentropy" "ac_cv_have_decl_getentropy" "
+#include <sys/types.h>
+#include <unistd.h>
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_FTRUNCATE $ac_have_decl
-_ACEOF
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_getentropy" = xyes
+then :
+ ac_have_decl=1
+else $as_nop
+ ac_have_decl=0
+fi
+printf "%s\n" "#define HAVE_DECL_GETENTROPY $ac_have_decl" >>confdefs.h
-ac_fn_c_check_decl "$LINENO" "readv" "ac_cv_have_decl_readv" "
+ac_fn_check_decl "$LINENO" "readv" "ac_cv_have_decl_readv" "
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
-"
-if test "x$ac_cv_have_decl_readv" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_readv" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_READV $ac_have_decl
-_ACEOF
-ac_fn_c_check_decl "$LINENO" "writev" "ac_cv_have_decl_writev" "
+printf "%s\n" "#define HAVE_DECL_READV $ac_have_decl" >>confdefs.h
+ac_fn_check_decl "$LINENO" "writev" "ac_cv_have_decl_writev" "
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
-"
-if test "x$ac_cv_have_decl_writev" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_writev" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_WRITEV $ac_have_decl
-_ACEOF
+printf "%s\n" "#define HAVE_DECL_WRITEV $ac_have_decl" >>confdefs.h
-ac_fn_c_check_decl "$LINENO" "MAXSYMLINKS" "ac_cv_have_decl_MAXSYMLINKS" "
+ac_fn_check_decl "$LINENO" "MAXSYMLINKS" "ac_cv_have_decl_MAXSYMLINKS" "
#include <sys/param.h>
-"
-if test "x$ac_cv_have_decl_MAXSYMLINKS" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_MAXSYMLINKS" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_MAXSYMLINKS $ac_have_decl
-_ACEOF
+printf "%s\n" "#define HAVE_DECL_MAXSYMLINKS $ac_have_decl" >>confdefs.h
-ac_fn_c_check_decl "$LINENO" "offsetof" "ac_cv_have_decl_offsetof" "
+ac_fn_check_decl "$LINENO" "offsetof" "ac_cv_have_decl_offsetof" "
#include <stddef.h>
-"
-if test "x$ac_cv_have_decl_offsetof" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_offsetof" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_OFFSETOF $ac_have_decl
-_ACEOF
+printf "%s\n" "#define HAVE_DECL_OFFSETOF $ac_have_decl" >>confdefs.h
# extra bits for select(2)
-ac_fn_c_check_decl "$LINENO" "howmany" "ac_cv_have_decl_howmany" "
+ac_fn_check_decl "$LINENO" "howmany" "ac_cv_have_decl_howmany" "
#include <sys/param.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-"
-if test "x$ac_cv_have_decl_howmany" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_howmany" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_HOWMANY $ac_have_decl
-_ACEOF
-ac_fn_c_check_decl "$LINENO" "NFDBITS" "ac_cv_have_decl_NFDBITS" "
+printf "%s\n" "#define HAVE_DECL_HOWMANY $ac_have_decl" >>confdefs.h
+ac_fn_check_decl "$LINENO" "NFDBITS" "ac_cv_have_decl_NFDBITS" "
#include <sys/param.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-"
-if test "x$ac_cv_have_decl_NFDBITS" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_NFDBITS" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_NFDBITS $ac_have_decl
-_ACEOF
+printf "%s\n" "#define HAVE_DECL_NFDBITS $ac_have_decl" >>confdefs.h
ac_fn_c_check_type "$LINENO" "fd_mask" "ac_cv_type_fd_mask" "
#include <sys/param.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
"
-if test "x$ac_cv_type_fd_mask" = xyes; then :
+if test "x$ac_cv_type_fd_mask" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_FD_MASK 1
-_ACEOF
+printf "%s\n" "#define HAVE_FD_MASK 1" >>confdefs.h
fi
-for ac_func in setresuid
+
+ for ac_func in setresuid
do :
ac_fn_c_check_func "$LINENO" "setresuid" "ac_cv_func_setresuid"
-if test "x$ac_cv_func_setresuid" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_SETRESUID 1
-_ACEOF
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if setresuid seems to work" >&5
-$as_echo_n "checking if setresuid seems to work... " >&6; }
- if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking setresuid" >&5
-$as_echo "$as_me: WARNING: cross compiling: not checking setresuid" >&2;}
-
-else
+if test "x$ac_cv_func_setresuid" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETRESUID 1" >>confdefs.h
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if setresuid seems to work" >&5
+printf %s "checking if setresuid seems to work... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking setresuid" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: not checking setresuid" >&2;}
+
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <errno.h>
int
-main ()
+main (void)
{
errno=0;
setresuid(0,0,0);
if (errno==ENOSYS)
exit(1);
else
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
-$as_echo "#define BROKEN_SETRESUID 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_SETRESUID 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: not implemented" >&5
-$as_echo "not implemented" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not implemented" >&5
+printf "%s\n" "not implemented" >&6; }
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
+
done
-for ac_func in setresgid
+ for ac_func in setresgid
do :
ac_fn_c_check_func "$LINENO" "setresgid" "ac_cv_func_setresgid"
-if test "x$ac_cv_func_setresgid" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_SETRESGID 1
-_ACEOF
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if setresgid seems to work" >&5
-$as_echo_n "checking if setresgid seems to work... " >&6; }
- if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking setresuid" >&5
-$as_echo "$as_me: WARNING: cross compiling: not checking setresuid" >&2;}
-
-else
+if test "x$ac_cv_func_setresgid" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETRESGID 1" >>confdefs.h
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if setresgid seems to work" >&5
+printf %s "checking if setresgid seems to work... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking setresuid" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: not checking setresuid" >&2;}
+
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <errno.h>
int
-main ()
+main (void)
{
errno=0;
setresgid(0,0,0);
if (errno==ENOSYS)
exit(1);
else
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
-$as_echo "#define BROKEN_SETRESGID 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_SETRESGID 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: not implemented" >&5
-$as_echo "not implemented" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not implemented" >&5
+printf "%s\n" "not implemented" >&6; }
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
-done
+done
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fflush(NULL)" >&5
-$as_echo_n "checking for working fflush(NULL)... " >&6; }
-if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming working" >&5
-$as_echo "$as_me: WARNING: cross compiling: assuming working" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working fflush(NULL)" >&5
+printf %s "checking for working fflush(NULL)... " >&6; }
+if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming working" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: assuming working" >&2;}
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
#include <stdlib.h>
int
-main ()
+main (void)
{
fflush(NULL); exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
-$as_echo "#define FFLUSH_NULL_BUG 1" >>confdefs.h
+printf "%s\n" "#define FFLUSH_NULL_BUG 1" >>confdefs.h
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-for ac_func in gettimeofday time
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday"
+if test "x$ac_cv_func_gettimeofday" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETTIMEOFDAY 1" >>confdefs.h
fi
-done
+ac_fn_c_check_func "$LINENO" "time" "ac_cv_func_time"
+if test "x$ac_cv_func_time" = xyes
+then :
+ printf "%s\n" "#define HAVE_TIME 1" >>confdefs.h
-for ac_func in endutent getutent getutid getutline pututline setutent
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+fi
+
+ac_fn_c_check_func "$LINENO" "endutent" "ac_cv_func_endutent"
+if test "x$ac_cv_func_endutent" = xyes
+then :
+ printf "%s\n" "#define HAVE_ENDUTENT 1" >>confdefs.h
fi
-done
+ac_fn_c_check_func "$LINENO" "getutent" "ac_cv_func_getutent"
+if test "x$ac_cv_func_getutent" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETUTENT 1" >>confdefs.h
-for ac_func in utmpname
-do :
- ac_fn_c_check_func "$LINENO" "utmpname" "ac_cv_func_utmpname"
-if test "x$ac_cv_func_utmpname" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_UTMPNAME 1
-_ACEOF
+fi
+ac_fn_c_check_func "$LINENO" "getutid" "ac_cv_func_getutid"
+if test "x$ac_cv_func_getutid" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETUTID 1" >>confdefs.h
fi
-done
+ac_fn_c_check_func "$LINENO" "getutline" "ac_cv_func_getutline"
+if test "x$ac_cv_func_getutline" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETUTLINE 1" >>confdefs.h
-for ac_func in endutxent getutxent getutxid getutxline getutxuser pututxline
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+fi
+ac_fn_c_check_func "$LINENO" "pututline" "ac_cv_func_pututline"
+if test "x$ac_cv_func_pututline" = xyes
+then :
+ printf "%s\n" "#define HAVE_PUTUTLINE 1" >>confdefs.h
fi
-done
+ac_fn_c_check_func "$LINENO" "setutent" "ac_cv_func_setutent"
+if test "x$ac_cv_func_setutent" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETUTENT 1" >>confdefs.h
-for ac_func in setutxdb setutxent utmpxname
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+fi
+
+ac_fn_c_check_func "$LINENO" "utmpname" "ac_cv_func_utmpname"
+if test "x$ac_cv_func_utmpname" = xyes
+then :
+ printf "%s\n" "#define HAVE_UTMPNAME 1" >>confdefs.h
fi
-done
-for ac_func in getlastlogxbyname
-do :
- ac_fn_c_check_func "$LINENO" "getlastlogxbyname" "ac_cv_func_getlastlogxbyname"
-if test "x$ac_cv_func_getlastlogxbyname" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_GETLASTLOGXBYNAME 1
-_ACEOF
+ac_fn_c_check_func "$LINENO" "endutxent" "ac_cv_func_endutxent"
+if test "x$ac_cv_func_endutxent" = xyes
+then :
+ printf "%s\n" "#define HAVE_ENDUTXENT 1" >>confdefs.h
fi
-done
+ac_fn_c_check_func "$LINENO" "getutxent" "ac_cv_func_getutxent"
+if test "x$ac_cv_func_getutxent" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETUTXENT 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "getutxid" "ac_cv_func_getutxid"
+if test "x$ac_cv_func_getutxid" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETUTXID 1" >>confdefs.h
-ac_fn_c_check_func "$LINENO" "daemon" "ac_cv_func_daemon"
-if test "x$ac_cv_func_daemon" = xyes; then :
+fi
+ac_fn_c_check_func "$LINENO" "getutxline" "ac_cv_func_getutxline"
+if test "x$ac_cv_func_getutxline" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETUTXLINE 1" >>confdefs.h
-$as_echo "#define HAVE_DAEMON 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "getutxuser" "ac_cv_func_getutxuser"
+if test "x$ac_cv_func_getutxuser" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETUTXUSER 1" >>confdefs.h
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for daemon in -lbsd" >&5
-$as_echo_n "checking for daemon in -lbsd... " >&6; }
-if ${ac_cv_lib_bsd_daemon+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+fi
+ac_fn_c_check_func "$LINENO" "pututxline" "ac_cv_func_pututxline"
+if test "x$ac_cv_func_pututxline" = xyes
+then :
+ printf "%s\n" "#define HAVE_PUTUTXLINE 1" >>confdefs.h
+
+fi
+
+ac_fn_c_check_func "$LINENO" "setutxdb" "ac_cv_func_setutxdb"
+if test "x$ac_cv_func_setutxdb" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETUTXDB 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "setutxent" "ac_cv_func_setutxent"
+if test "x$ac_cv_func_setutxent" = xyes
+then :
+ printf "%s\n" "#define HAVE_SETUTXENT 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "utmpxname" "ac_cv_func_utmpxname"
+if test "x$ac_cv_func_utmpxname" = xyes
+then :
+ printf "%s\n" "#define HAVE_UTMPXNAME 1" >>confdefs.h
+
+fi
+
+ac_fn_c_check_func "$LINENO" "getlastlogxbyname" "ac_cv_func_getlastlogxbyname"
+if test "x$ac_cv_func_getlastlogxbyname" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETLASTLOGXBYNAME 1" >>confdefs.h
+
+fi
+
+
+ac_fn_c_check_func "$LINENO" "daemon" "ac_cv_func_daemon"
+if test "x$ac_cv_func_daemon" = xyes
+then :
+
+printf "%s\n" "#define HAVE_DAEMON 1" >>confdefs.h
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for daemon in -lbsd" >&5
+printf %s "checking for daemon in -lbsd... " >&6; }
+if test ${ac_cv_lib_bsd_daemon+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lbsd $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char daemon ();
int
-main ()
+main (void)
{
return daemon ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_bsd_daemon=yes
-else
+else $as_nop
ac_cv_lib_bsd_daemon=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_daemon" >&5
-$as_echo "$ac_cv_lib_bsd_daemon" >&6; }
-if test "x$ac_cv_lib_bsd_daemon" = xyes; then :
- LIBS="$LIBS -lbsd"; $as_echo "#define HAVE_DAEMON 1" >>confdefs.h
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_daemon" >&5
+printf "%s\n" "$ac_cv_lib_bsd_daemon" >&6; }
+if test "x$ac_cv_lib_bsd_daemon" = xyes
+then :
+ LIBS="$LIBS -lbsd"; printf "%s\n" "#define HAVE_DAEMON 1" >>confdefs.h
fi
fi
ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize"
-if test "x$ac_cv_func_getpagesize" = xyes; then :
-
-$as_echo "#define HAVE_GETPAGESIZE 1" >>confdefs.h
-
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getpagesize in -lucb" >&5
-$as_echo_n "checking for getpagesize in -lucb... " >&6; }
-if ${ac_cv_lib_ucb_getpagesize+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+if test "x$ac_cv_func_getpagesize" = xyes
+then :
+
+printf "%s\n" "#define HAVE_GETPAGESIZE 1" >>confdefs.h
+
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getpagesize in -lucb" >&5
+printf %s "checking for getpagesize in -lucb... " >&6; }
+if test ${ac_cv_lib_ucb_getpagesize+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lucb $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char getpagesize ();
int
-main ()
+main (void)
{
return getpagesize ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_ucb_getpagesize=yes
-else
+else $as_nop
ac_cv_lib_ucb_getpagesize=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ucb_getpagesize" >&5
-$as_echo "$ac_cv_lib_ucb_getpagesize" >&6; }
-if test "x$ac_cv_lib_ucb_getpagesize" = xyes; then :
- LIBS="$LIBS -lucb"; $as_echo "#define HAVE_GETPAGESIZE 1" >>confdefs.h
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ucb_getpagesize" >&5
+printf "%s\n" "$ac_cv_lib_ucb_getpagesize" >&6; }
+if test "x$ac_cv_lib_ucb_getpagesize" = xyes
+then :
+ LIBS="$LIBS -lucb"; printf "%s\n" "#define HAVE_GETPAGESIZE 1" >>confdefs.h
fi
fi
# Check for broken snprintf
if test "x$ac_cv_func_snprintf" = "xyes" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether snprintf correctly terminates long strings" >&5
-$as_echo_n "checking whether snprintf correctly terminates long strings... " >&6; }
- if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: Assuming working snprintf()" >&5
-$as_echo "$as_me: WARNING: cross compiling: Assuming working snprintf()" >&2;}
-
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether snprintf correctly terminates long strings" >&5
+printf %s "checking whether snprintf correctly terminates long strings... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: Assuming working snprintf()" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: Assuming working snprintf()" >&2;}
+
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
#include <stdlib.h>
int
-main ()
+main (void)
{
char b[5];
snprintf(b,5,"123456789");
exit(b[4]!='\0');
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
-$as_echo "#define BROKEN_SNPRINTF 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_SNPRINTF 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ****** Your snprintf() function is broken, complain to your vendor" >&5
-$as_echo "$as_me: WARNING: ****** Your snprintf() function is broken, complain to your vendor" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: ****** Your snprintf() function is broken, complain to your vendor" >&5
+printf "%s\n" "$as_me: WARNING: ****** Your snprintf() function is broken, complain to your vendor" >&2;}
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
if test "x$ac_cv_func_snprintf" = "xyes" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether snprintf understands %zu" >&5
-$as_echo_n "checking whether snprintf understands %zu... " >&6; }
- if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: Assuming working snprintf()" >&5
-$as_echo "$as_me: WARNING: cross compiling: Assuming working snprintf()" >&2;}
-
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether snprintf understands %zu" >&5
+printf %s "checking whether snprintf understands %zu... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: Assuming working snprintf()" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: Assuming working snprintf()" >&2;}
+
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
-main ()
+main (void)
{
size_t a = 1, b = 2;
char z[128];
snprintf(z, sizeof z, "%zu%zu", a, b);
exit(strcmp(z, "12"));
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
-$as_echo "#define BROKEN_SNPRINTF 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_SNPRINTF 1" >>confdefs.h
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
# We depend on vsnprintf returning the right thing on overflow: the
# number of characters it tried to create (as per SUSv3)
if test "x$ac_cv_func_vsnprintf" = "xyes" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether vsnprintf returns correct values on overflow" >&5
-$as_echo_n "checking whether vsnprintf returns correct values on overflow... " >&6; }
- if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: Assuming working vsnprintf()" >&5
-$as_echo "$as_me: WARNING: cross compiling: Assuming working vsnprintf()" >&2;}
-
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether vsnprintf returns correct values on overflow" >&5
+printf %s "checking whether vsnprintf returns correct values on overflow... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: Assuming working vsnprintf()" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: Assuming working vsnprintf()" >&2;}
+
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <stdio.h>
#include <stdarg.h>
int x_snprintf(char *str, size_t count, const char *fmt, ...)
{
size_t ret;
va_list ap;
va_start(ap, fmt);
ret = vsnprintf(str, count, fmt, ap);
va_end(ap);
return ret;
}
int
-main ()
+main (void)
{
char x[1];
if (x_snprintf(x, 1, "%s %d", "hello", 12345) != 11)
return 1;
if (x_snprintf(NULL, 0, "%s %d", "hello", 12345) != 11)
return 1;
return 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
-$as_echo "#define BROKEN_SNPRINTF 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_SNPRINTF 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ****** Your vsnprintf() function is broken, complain to your vendor" >&5
-$as_echo "$as_me: WARNING: ****** Your vsnprintf() function is broken, complain to your vendor" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: ****** Your vsnprintf() function is broken, complain to your vendor" >&5
+printf "%s\n" "$as_me: WARNING: ****** Your vsnprintf() function is broken, complain to your vendor" >&2;}
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
# On systems where [v]snprintf is broken, but is declared in stdio,
# check that the fmt argument is const char * or just char *.
# This is only useful for when BROKEN_SNPRINTF
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether snprintf can declare const char *fmt" >&5
-$as_echo_n "checking whether snprintf can declare const char *fmt... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether snprintf can declare const char *fmt" >&5
+printf %s "checking whether snprintf can declare const char *fmt... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
int snprintf(char *a, size_t b, const char *c, ...) { return 0; }
int
-main ()
+main (void)
{
snprintf(0, 0, 0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define SNPRINTF_CONST const" >>confdefs.h
+printf "%s\n" "#define SNPRINTF_CONST const" >>confdefs.h
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- $as_echo "#define SNPRINTF_CONST /* not const */" >>confdefs.h
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ printf "%s\n" "#define SNPRINTF_CONST /* not const */" >>confdefs.h
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
# Check for missing getpeereid (or equiv) support
NO_PEERCHECK=""
if test "x$ac_cv_func_getpeereid" != "xyes" -a "x$ac_cv_func_getpeerucred" != "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether system supports SO_PEERCRED getsockopt" >&5
-$as_echo_n "checking whether system supports SO_PEERCRED getsockopt... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether system supports SO_PEERCRED getsockopt" >&5
+printf %s "checking whether system supports SO_PEERCRED getsockopt... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/socket.h>
int
-main ()
+main (void)
{
int i = SO_PEERCRED;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_SO_PEERCRED 1" >>confdefs.h
+printf "%s\n" "#define HAVE_SO_PEERCRED 1" >>confdefs.h
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
NO_PEERCHECK=1
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
if test ! -z "$check_for_openpty_ctty_bug"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if openpty correctly handles controlling tty" >&5
-$as_echo_n "checking if openpty correctly handles controlling tty... " >&6; }
- if test "$cross_compiling" = yes; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if openpty correctly handles controlling tty" >&5
+printf %s "checking if openpty correctly handles controlling tty... " >&6; }
+ if test "$cross_compiling" = yes
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross-compiling, assuming yes" >&5
-$as_echo "cross-compiling, assuming yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cross-compiling, assuming yes" >&5
+printf "%s\n" "cross-compiling, assuming yes" >&6; }
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
int
-main ()
+main (void)
{
pid_t pid;
int fd, ptyfd, ttyfd, status;
pid = fork();
if (pid < 0) { /* failed */
exit(1);
} else if (pid > 0) { /* parent */
waitpid(pid, &status, 0);
if (WIFEXITED(status))
exit(WEXITSTATUS(status));
else
exit(2);
} else { /* child */
close(0); close(1); close(2);
setsid();
openpty(&ptyfd, &ttyfd, NULL, NULL, NULL);
fd = open("/dev/tty", O_RDWR | O_NOCTTY);
if (fd >= 0)
exit(3); /* Acquired ctty: broken */
else
exit(0); /* Did not acquire ctty: OK */
}
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_run "$LINENO"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- $as_echo "#define SSHD_ACQUIRES_CTTY 1" >>confdefs.h
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ printf "%s\n" "#define SSHD_ACQUIRES_CTTY 1" >>confdefs.h
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
if test "x$ac_cv_func_getaddrinfo" = "xyes" && \
test "x$check_for_hpux_broken_getaddrinfo" = "x1"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if getaddrinfo seems to work" >&5
-$as_echo_n "checking if getaddrinfo seems to work... " >&6; }
- if test "$cross_compiling" = yes; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getaddrinfo seems to work" >&5
+printf %s "checking if getaddrinfo seems to work... " >&6; }
+ if test "$cross_compiling" = yes
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross-compiling, assuming yes" >&5
-$as_echo "cross-compiling, assuming yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cross-compiling, assuming yes" >&5
+printf "%s\n" "cross-compiling, assuming yes" >&6; }
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <netinet/in.h>
#define TEST_PORT "2222"
int
-main ()
+main (void)
{
int err, sock;
struct addrinfo *gai_ai, *ai, hints;
char ntop[NI_MAXHOST], strport[NI_MAXSERV], *name = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
err = getaddrinfo(name, TEST_PORT, &hints, &gai_ai);
if (err != 0) {
fprintf(stderr, "getaddrinfo failed (%s)", gai_strerror(err));
exit(1);
}
for (ai = gai_ai; ai != NULL; ai = ai->ai_next) {
if (ai->ai_family != AF_INET6)
continue;
err = getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop,
sizeof(ntop), strport, sizeof(strport),
NI_NUMERICHOST|NI_NUMERICSERV);
if (err != 0) {
if (err == EAI_SYSTEM)
perror("getnameinfo EAI_SYSTEM");
else
fprintf(stderr, "getnameinfo failed: %s\n",
gai_strerror(err));
exit(2);
}
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sock < 0)
perror("socket");
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
if (errno == EBADF)
exit(3);
}
}
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_run "$LINENO"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- $as_echo "#define BROKEN_GETADDRINFO 1" >>confdefs.h
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ printf "%s\n" "#define BROKEN_GETADDRINFO 1" >>confdefs.h
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
if test "x$ac_cv_func_getaddrinfo" = "xyes" && \
test "x$check_for_aix_broken_getaddrinfo" = "x1"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if getaddrinfo seems to work" >&5
-$as_echo_n "checking if getaddrinfo seems to work... " >&6; }
- if test "$cross_compiling" = yes; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getaddrinfo seems to work" >&5
+printf %s "checking if getaddrinfo seems to work... " >&6; }
+ if test "$cross_compiling" = yes
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross-compiling, assuming no" >&5
-$as_echo "cross-compiling, assuming no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cross-compiling, assuming no" >&5
+printf "%s\n" "cross-compiling, assuming no" >&6; }
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <netinet/in.h>
#define TEST_PORT "2222"
int
-main ()
+main (void)
{
int err, sock;
struct addrinfo *gai_ai, *ai, hints;
char ntop[NI_MAXHOST], strport[NI_MAXSERV], *name = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
err = getaddrinfo(name, TEST_PORT, &hints, &gai_ai);
if (err != 0) {
fprintf(stderr, "getaddrinfo failed (%s)", gai_strerror(err));
exit(1);
}
for (ai = gai_ai; ai != NULL; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
continue;
err = getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop,
sizeof(ntop), strport, sizeof(strport),
NI_NUMERICHOST|NI_NUMERICSERV);
if (ai->ai_family == AF_INET && err != 0) {
perror("getnameinfo");
exit(2);
}
}
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_run "$LINENO"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define AIX_GETNAMEINFO_HACK 1" >>confdefs.h
+printf "%s\n" "#define AIX_GETNAMEINFO_HACK 1" >>confdefs.h
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- $as_echo "#define BROKEN_GETADDRINFO 1" >>confdefs.h
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ printf "%s\n" "#define BROKEN_GETADDRINFO 1" >>confdefs.h
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
if test "x$ac_cv_func_getaddrinfo" = "xyes"; then
- ac_fn_c_check_decl "$LINENO" "AI_NUMERICSERV" "ac_cv_have_decl_AI_NUMERICSERV" "#include <sys/types.h>
+ ac_fn_check_decl "$LINENO" "AI_NUMERICSERV" "ac_cv_have_decl_AI_NUMERICSERV" "#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
-"
-if test "x$ac_cv_have_decl_AI_NUMERICSERV" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_AI_NUMERICSERV" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_AI_NUMERICSERV $ac_have_decl
-_ACEOF
+printf "%s\n" "#define HAVE_DECL_AI_NUMERICSERV $ac_have_decl" >>confdefs.h
fi
if test "x$check_for_conflicting_getspnam" = "x1"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for conflicting getspnam in shadow.h" >&5
-$as_echo_n "checking for conflicting getspnam in shadow.h... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for conflicting getspnam in shadow.h" >&5
+printf %s "checking for conflicting getspnam in shadow.h... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <shadow.h>
#include <stdlib.h>
int
-main ()
+main (void)
{
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define GETSPNAM_CONFLICTING_DEFS 1" >>confdefs.h
+printf "%s\n" "#define GETSPNAM_CONFLICTING_DEFS 1" >>confdefs.h
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
if test "x$ac_cv_func_strnvis" = "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working strnvis" >&5
-$as_echo_n "checking for working strnvis... " >&6; }
- if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming broken" >&5
-$as_echo "$as_me: WARNING: cross compiling: assuming broken" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working strnvis" >&5
+printf %s "checking for working strnvis... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming broken" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: assuming broken" >&2;}
-$as_echo "#define BROKEN_STRNVIS 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_STRNVIS 1" >>confdefs.h
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <vis.h>
static void sighandler(int sig) { _exit(1); }
int
-main ()
+main (void)
{
char dst[16];
signal(SIGSEGV, sighandler);
if (strnvis(dst, "src", 4, 0) && strcmp(dst, "src") == 0)
exit(0);
exit(1)
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
-$as_echo "#define BROKEN_STRNVIS 1" >>confdefs.h
+printf "%s\n" "#define BROKEN_STRNVIS 1" >>confdefs.h
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if SA_RESTARTed signals interrupt select()" >&5
-$as_echo_n "checking if SA_RESTARTed signals interrupt select()... " >&6; }
-if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming yes" >&5
-$as_echo "$as_me: WARNING: cross compiling: assuming yes" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if SA_RESTARTed signals interrupt select()" >&5
+printf %s "checking if SA_RESTARTed signals interrupt select()... " >&6; }
+if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming yes" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: assuming yes" >&2;}
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#ifdef HAVE_SYS_SELECT
# include <sys/select.h>
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
static void sighandler(int sig) { }
int
-main ()
+main (void)
{
int r;
pid_t pid;
struct sigaction sa;
sa.sa_handler = sighandler;
sa.sa_flags = SA_RESTART;
(void)sigaction(SIGTERM, &sa, NULL);
if ((pid = fork()) == 0) { /* child */
pid = getppid();
sleep(1);
kill(pid, SIGTERM);
sleep(1);
if (getppid() == pid) /* if parent did not exit, shoot it */
kill(pid, SIGKILL);
exit(0);
} else { /* parent */
r = select(0, NULL, NULL, NULL, NULL);
}
exit(r == -1 ? 0 : 1);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
-$as_echo "#define NO_SA_RESTART 1" >>confdefs.h
+printf "%s\n" "#define NO_SA_RESTART 1" >>confdefs.h
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-for ac_func in getpgrp
+
+ for ac_func in getpgrp
do :
ac_fn_c_check_func "$LINENO" "getpgrp" "ac_cv_func_getpgrp"
-if test "x$ac_cv_func_getpgrp" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_GETPGRP 1
-_ACEOF
+if test "x$ac_cv_func_getpgrp" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETPGRP 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if getpgrp accepts zero args" >&5
-$as_echo_n "checking if getpgrp accepts zero args... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if getpgrp accepts zero args" >&5
+printf %s "checking if getpgrp accepts zero args... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$ac_includes_default
int
-main ()
+main (void)
{
getpgrp();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define GETPGRP_VOID 1" >>confdefs.h
+printf "%s\n" "#define GETPGRP_VOID 1" >>confdefs.h
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
-$as_echo "#define GETPGRP_VOID 0" >>confdefs.h
+printf "%s\n" "#define GETPGRP_VOID 0" >>confdefs.h
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-done
+done
# Search for OpenSSL
saved_CPPFLAGS="$CPPFLAGS"
saved_LDFLAGS="$LDFLAGS"
# Check whether --with-ssl-dir was given.
-if test "${with_ssl_dir+set}" = set; then :
+if test ${with_ssl_dir+y}
+then :
withval=$with_ssl_dir;
if test "x$openssl" = "xno" ; then
as_fn_error $? "cannot use --with-ssl-dir when OpenSSL disabled" "$LINENO" 5
fi
if test "x$withval" != "xno" ; then
case "$withval" in
# Relative paths
./*|../*) withval="`pwd`/$withval"
esac
if test -d "$withval/lib"; then
libcrypto_path="${withval}/lib"
elif test -d "$withval/lib64"; then
libcrypto_path="$withval/lib64"
else
# Built but not installed
libcrypto_path="${withval}"
fi
if test -n "${rpath_opt}"; then
LDFLAGS="-L${libcrypto_path} ${rpath_opt}${libcrypto_path} ${LDFLAGS}"
else
LDFLAGS="-L${libcrypto_path} ${LDFLAGS}"
fi
if test -d "$withval/include"; then
CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
else
CPPFLAGS="-I${withval} ${CPPFLAGS}"
fi
fi
fi
# Check whether --with-openssl-header-check was given.
-if test "${with_openssl_header_check+set}" = set; then :
+if test ${with_openssl_header_check+y}
+then :
withval=$with_openssl_header_check;
if test "x$withval" = "xno" ; then
openssl_check_nonfatal=1
fi
fi
openssl_engine=no
# Check whether --with-ssl-engine was given.
-if test "${with_ssl_engine+set}" = set; then :
+if test ${with_ssl_engine+y}
+then :
withval=$with_ssl_engine;
if test "x$withval" != "xno" ; then
if test "x$openssl" = "xno" ; then
as_fn_error $? "cannot use --with-ssl-engine when OpenSSL disabled" "$LINENO" 5
fi
openssl_engine=yes
fi
fi
+nocrypto_saved_LIBS="$LIBS"
if test "x$openssl" = "xyes" ; then
LIBS="-lcrypto $LIBS"
+ CHANNELLIBS="-lcrypto $CHANNELLIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char RAND_add ();
int
-main ()
+main (void)
{
return RAND_add ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
-else
+else $as_nop
as_fn_error $? "*** working libcrypto not found, check config.log" "$LINENO" 5
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
- ac_fn_c_check_header_mongrel "$LINENO" "openssl/opensslv.h" "ac_cv_header_openssl_opensslv_h" "$ac_includes_default"
-if test "x$ac_cv_header_openssl_opensslv_h" = xyes; then :
+ ac_fn_c_check_header_compile "$LINENO" "openssl/opensslv.h" "ac_cv_header_openssl_opensslv_h" "$ac_includes_default"
+if test "x$ac_cv_header_openssl_opensslv_h" = xyes
+then :
-else
+else $as_nop
as_fn_error $? "*** OpenSSL headers missing - please install first or check config.log ***" "$LINENO" 5
fi
-
# Determine OpenSSL header version
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking OpenSSL header version" >&5
-$as_echo_n "checking OpenSSL header version... " >&6; }
- if test "$cross_compiling" = yes; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking OpenSSL header version" >&5
+printf %s "checking OpenSSL header version... " >&6; }
+ if test "$cross_compiling" = yes
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking" >&5
-$as_echo "$as_me: WARNING: cross compiling: not checking" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: not checking" >&2;}
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <openssl/opensslv.h>
#define DATA "conftest.sslincver"
int
-main ()
+main (void)
{
FILE *fd;
int rc;
fd = fopen(DATA,"w");
if(fd == NULL)
exit(1);
if ((rc = fprintf(fd, "%08lx (%s)\n",
(unsigned long)OPENSSL_VERSION_NUMBER,
OPENSSL_VERSION_TEXT)) < 0)
exit(1);
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_run "$LINENO"
+then :
ssl_header_ver=`cat conftest.sslincver`
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ssl_header_ver" >&5
-$as_echo "$ssl_header_ver" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ssl_header_ver" >&5
+printf "%s\n" "$ssl_header_ver" >&6; }
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
-$as_echo "not found" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+printf "%s\n" "not found" >&6; }
as_fn_error $? "OpenSSL version header not found." "$LINENO" 5
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
# Determining OpenSSL library version is version dependent.
- for ac_func in OpenSSL_version OpenSSL_version_num
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "OpenSSL_version" "ac_cv_func_OpenSSL_version"
+if test "x$ac_cv_func_OpenSSL_version" = xyes
+then :
+ printf "%s\n" "#define HAVE_OPENSSL_VERSION 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "OpenSSL_version_num" "ac_cv_func_OpenSSL_version_num"
+if test "x$ac_cv_func_OpenSSL_version_num" = xyes
+then :
+ printf "%s\n" "#define HAVE_OPENSSL_VERSION_NUM 1" >>confdefs.h
fi
-done
# Determine OpenSSL library version
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking OpenSSL library version" >&5
-$as_echo_n "checking OpenSSL library version... " >&6; }
- if test "$cross_compiling" = yes; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking OpenSSL library version" >&5
+printf %s "checking OpenSSL library version... " >&6; }
+ if test "$cross_compiling" = yes
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking" >&5
-$as_echo "$as_me: WARNING: cross compiling: not checking" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: not checking" >&2;}
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
#define DATA "conftest.ssllibver"
int
-main ()
+main (void)
{
FILE *fd;
int rc;
fd = fopen(DATA,"w");
if(fd == NULL)
exit(1);
#ifndef OPENSSL_VERSION
# define OPENSSL_VERSION SSLEAY_VERSION
#endif
#ifndef HAVE_OPENSSL_VERSION
# define OpenSSL_version SSLeay_version
#endif
#ifndef HAVE_OPENSSL_VERSION_NUM
# define OpenSSL_version_num SSLeay
#endif
if ((rc = fprintf(fd, "%08lx (%s)\n",
(unsigned long)OpenSSL_version_num(),
OpenSSL_version(OPENSSL_VERSION))) < 0)
exit(1);
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_run "$LINENO"
+then :
ssl_library_ver=`cat conftest.ssllibver`
# Check version is supported.
case "$ssl_library_ver" in
10000*|0*)
as_fn_error $? "OpenSSL >= 1.0.1 required (have \"$ssl_library_ver\")" "$LINENO" 5
;;
100*) ;; # 1.0.x
101000[0123456]*)
# https://github.com/openssl/openssl/pull/4613
as_fn_error $? "OpenSSL 1.1.x versions prior to 1.1.0g have a bug that breaks their use with OpenSSH (have \"$ssl_library_ver\")" "$LINENO" 5
;;
101*) ;; # 1.1.x
200*) ;; # LibreSSL
- 300*) ;; # OpenSSL 3
- 301*) ;; # OpenSSL development branch.
+ 300*)
+ # OpenSSL 3; we use the 1.1x API
+ CPPFLAGS="$CPPFLAGS -DOPENSSL_API_COMPAT=0x10100000L"
+ ;;
+ 301*)
+ # OpenSSL development branch; request 1.1x API
+ CPPFLAGS="$CPPFLAGS -DOPENSSL_API_COMPAT=0x10100000L"
+ ;;
*)
as_fn_error $? "Unknown/unsupported OpenSSL version (\"$ssl_library_ver\")" "$LINENO" 5
;;
esac
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ssl_library_ver" >&5
-$as_echo "$ssl_library_ver" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ssl_library_ver" >&5
+printf "%s\n" "$ssl_library_ver" >&6; }
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
-$as_echo "not found" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+printf "%s\n" "not found" >&6; }
as_fn_error $? "OpenSSL library not found." "$LINENO" 5
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
+ case "$host" in
+ x86_64-*)
+ case "$ssl_library_ver" in
+ 3000004*)
+ as_fn_error $? "OpenSSL 3.0.4 has a potential RCE in its RSA implementation (CVE-2022-2274)" "$LINENO" 5
+ ;;
+ esac
+ esac
+
# Sanity check OpenSSL headers
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL's headers match the library" >&5
-$as_echo_n "checking whether OpenSSL's headers match the library... " >&6; }
- if test "$cross_compiling" = yes; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL's headers match the library" >&5
+printf %s "checking whether OpenSSL's headers match the library... " >&6; }
+ if test "$cross_compiling" = yes
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking" >&5
-$as_echo "$as_me: WARNING: cross compiling: not checking" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: not checking" >&2;}
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <string.h>
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
int
-main ()
+main (void)
{
#ifndef HAVE_OPENSSL_VERSION_NUM
# define OpenSSL_version_num SSLeay
#endif
exit(OpenSSL_version_num() == OPENSSL_VERSION_NUMBER ? 0 : 1);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_run "$LINENO"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if test "x$openssl_check_nonfatal" = "x"; then
as_fn_error $? "Your OpenSSL headers do not match your
library. Check config.log for details.
If you are sure your installation is consistent, you can disable the check
by running \"./configure --without-openssl-header-check\".
Also see contrib/findssl.sh for help identifying header/library mismatches.
" "$LINENO" 5
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Your OpenSSL headers do not match your
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Your OpenSSL headers do not match your
library. Check config.log for details.
Also see contrib/findssl.sh for help identifying header/library mismatches." >&5
-$as_echo "$as_me: WARNING: Your OpenSSL headers do not match your
+printf "%s\n" "$as_me: WARNING: Your OpenSSL headers do not match your
library. Check config.log for details.
Also see contrib/findssl.sh for help identifying header/library mismatches." >&2;}
fi
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if programs using OpenSSL functions will link" >&5
-$as_echo_n "checking if programs using OpenSSL functions will link... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if programs using OpenSSL functions will link" >&5
+printf %s "checking if programs using OpenSSL functions will link... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <openssl/err.h>
int
-main ()
+main (void)
{
ERR_load_crypto_strings();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- saved_LIBS="$LIBS"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
LIBS="$LIBS -ldl"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if programs using OpenSSL need -ldl" >&5
-$as_echo_n "checking if programs using OpenSSL need -ldl... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if programs using OpenSSL need -ldl" >&5
+printf %s "checking if programs using OpenSSL need -ldl... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <openssl/err.h>
int
-main ()
+main (void)
{
ERR_load_crypto_strings();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ CHANNELLIBS="$CHANNELLIBS -ldl"
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- LIBS="$saved_LIBS"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
- for ac_func in \
- BN_is_prime_ex \
- DSA_generate_parameters_ex \
- EVP_CIPHER_CTX_ctrl \
- EVP_DigestFinal_ex \
- EVP_DigestInit_ex \
- EVP_MD_CTX_cleanup \
- EVP_MD_CTX_copy_ex \
- EVP_MD_CTX_init \
- HMAC_CTX_init \
- RSA_generate_key_ex \
- RSA_get_default_method \
+ ac_fn_c_check_func "$LINENO" "BN_is_prime_ex" "ac_cv_func_BN_is_prime_ex"
+if test "x$ac_cv_func_BN_is_prime_ex" = xyes
+then :
+ printf "%s\n" "#define HAVE_BN_IS_PRIME_EX 1" >>confdefs.h
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+fi
+ac_fn_c_check_func "$LINENO" "DES_crypt" "ac_cv_func_DES_crypt"
+if test "x$ac_cv_func_DES_crypt" = xyes
+then :
+ printf "%s\n" "#define HAVE_DES_CRYPT 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "DSA_generate_parameters_ex" "ac_cv_func_DSA_generate_parameters_ex"
+if test "x$ac_cv_func_DSA_generate_parameters_ex" = xyes
+then :
+ printf "%s\n" "#define HAVE_DSA_GENERATE_PARAMETERS_EX 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "EVP_DigestFinal_ex" "ac_cv_func_EVP_DigestFinal_ex"
+if test "x$ac_cv_func_EVP_DigestFinal_ex" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_DIGESTFINAL_EX 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "EVP_DigestInit_ex" "ac_cv_func_EVP_DigestInit_ex"
+if test "x$ac_cv_func_EVP_DigestInit_ex" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_DIGESTINIT_EX 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "EVP_MD_CTX_cleanup" "ac_cv_func_EVP_MD_CTX_cleanup"
+if test "x$ac_cv_func_EVP_MD_CTX_cleanup" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_MD_CTX_CLEANUP 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "EVP_MD_CTX_copy_ex" "ac_cv_func_EVP_MD_CTX_copy_ex"
+if test "x$ac_cv_func_EVP_MD_CTX_copy_ex" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_MD_CTX_COPY_EX 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "EVP_MD_CTX_init" "ac_cv_func_EVP_MD_CTX_init"
+if test "x$ac_cv_func_EVP_MD_CTX_init" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_MD_CTX_INIT 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "HMAC_CTX_init" "ac_cv_func_HMAC_CTX_init"
+if test "x$ac_cv_func_HMAC_CTX_init" = xyes
+then :
+ printf "%s\n" "#define HAVE_HMAC_CTX_INIT 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "RSA_generate_key_ex" "ac_cv_func_RSA_generate_key_ex"
+if test "x$ac_cv_func_RSA_generate_key_ex" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_GENERATE_KEY_EX 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "RSA_get_default_method" "ac_cv_func_RSA_get_default_method"
+if test "x$ac_cv_func_RSA_get_default_method" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_GET_DEFAULT_METHOD 1" >>confdefs.h
+
+fi
+
+
+ # OpenSSL_add_all_algorithms may be a macro.
+ ac_fn_c_check_func "$LINENO" "OpenSSL_add_all_algorithms" "ac_cv_func_OpenSSL_add_all_algorithms"
+if test "x$ac_cv_func_OpenSSL_add_all_algorithms" = xyes
+then :
+
+printf "%s\n" "#define HAVE_OPENSSL_ADD_ALL_ALGORITHMS 1" >>confdefs.h
+
+else $as_nop
+ ac_fn_check_decl "$LINENO" "OpenSSL_add_all_algorithms" "ac_cv_have_decl_OpenSSL_add_all_algorithms" "#include <openssl/evp.h>
+
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_OpenSSL_add_all_algorithms" = xyes
+then :
+
+printf "%s\n" "#define HAVE_OPENSSL_ADD_ALL_ALGORITHMS 1" >>confdefs.h
+
+fi
+
+fi
+
+
+ # LibreSSL/OpenSSL 1.1x API
+ ac_fn_c_check_func "$LINENO" "OPENSSL_init_crypto" "ac_cv_func_OPENSSL_init_crypto"
+if test "x$ac_cv_func_OPENSSL_init_crypto" = xyes
+then :
+ printf "%s\n" "#define HAVE_OPENSSL_INIT_CRYPTO 1" >>confdefs.h
fi
-done
+ac_fn_c_check_func "$LINENO" "DH_get0_key" "ac_cv_func_DH_get0_key"
+if test "x$ac_cv_func_DH_get0_key" = xyes
+then :
+ printf "%s\n" "#define HAVE_DH_GET0_KEY 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "DH_get0_pqg" "ac_cv_func_DH_get0_pqg"
+if test "x$ac_cv_func_DH_get0_pqg" = xyes
+then :
+ printf "%s\n" "#define HAVE_DH_GET0_PQG 1" >>confdefs.h
- # OpenSSL_add_all_algorithms may be a macro.
- ac_fn_c_check_func "$LINENO" "OpenSSL_add_all_algorithms" "ac_cv_func_OpenSSL_add_all_algorithms"
-if test "x$ac_cv_func_OpenSSL_add_all_algorithms" = xyes; then :
+fi
+ac_fn_c_check_func "$LINENO" "DH_set0_key" "ac_cv_func_DH_set0_key"
+if test "x$ac_cv_func_DH_set0_key" = xyes
+then :
+ printf "%s\n" "#define HAVE_DH_SET0_KEY 1" >>confdefs.h
-$as_echo "#define HAVE_OPENSSL_ADD_ALL_ALGORITHMS 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "DH_set_length" "ac_cv_func_DH_set_length"
+if test "x$ac_cv_func_DH_set_length" = xyes
+then :
+ printf "%s\n" "#define HAVE_DH_SET_LENGTH 1" >>confdefs.h
-else
- ac_fn_c_check_decl "$LINENO" "OpenSSL_add_all_algorithms" "ac_cv_have_decl_OpenSSL_add_all_algorithms" "#include <openssl/evp.h>
+fi
+ac_fn_c_check_func "$LINENO" "DH_set0_pqg" "ac_cv_func_DH_set0_pqg"
+if test "x$ac_cv_func_DH_set0_pqg" = xyes
+then :
+ printf "%s\n" "#define HAVE_DH_SET0_PQG 1" >>confdefs.h
-"
-if test "x$ac_cv_have_decl_OpenSSL_add_all_algorithms" = xyes; then :
+fi
+ac_fn_c_check_func "$LINENO" "DSA_get0_key" "ac_cv_func_DSA_get0_key"
+if test "x$ac_cv_func_DSA_get0_key" = xyes
+then :
+ printf "%s\n" "#define HAVE_DSA_GET0_KEY 1" >>confdefs.h
-$as_echo "#define HAVE_OPENSSL_ADD_ALL_ALGORITHMS 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "DSA_get0_pqg" "ac_cv_func_DSA_get0_pqg"
+if test "x$ac_cv_func_DSA_get0_pqg" = xyes
+then :
+ printf "%s\n" "#define HAVE_DSA_GET0_PQG 1" >>confdefs.h
fi
+ac_fn_c_check_func "$LINENO" "DSA_set0_key" "ac_cv_func_DSA_set0_key"
+if test "x$ac_cv_func_DSA_set0_key" = xyes
+then :
+ printf "%s\n" "#define HAVE_DSA_SET0_KEY 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "DSA_set0_pqg" "ac_cv_func_DSA_set0_pqg"
+if test "x$ac_cv_func_DSA_set0_pqg" = xyes
+then :
+ printf "%s\n" "#define HAVE_DSA_SET0_PQG 1" >>confdefs.h
fi
+ac_fn_c_check_func "$LINENO" "DSA_SIG_get0" "ac_cv_func_DSA_SIG_get0"
+if test "x$ac_cv_func_DSA_SIG_get0" = xyes
+then :
+ printf "%s\n" "#define HAVE_DSA_SIG_GET0 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "DSA_SIG_set0" "ac_cv_func_DSA_SIG_set0"
+if test "x$ac_cv_func_DSA_SIG_set0" = xyes
+then :
+ printf "%s\n" "#define HAVE_DSA_SIG_SET0 1" >>confdefs.h
- # LibreSSL/OpenSSL 1.1x API
- for ac_func in \
- OPENSSL_init_crypto \
- DH_get0_key \
- DH_get0_pqg \
- DH_set0_key \
- DH_set_length \
- DH_set0_pqg \
- DSA_get0_key \
- DSA_get0_pqg \
- DSA_set0_key \
- DSA_set0_pqg \
- DSA_SIG_get0 \
- DSA_SIG_set0 \
- ECDSA_SIG_get0 \
- ECDSA_SIG_set0 \
- EVP_CIPHER_CTX_iv \
- EVP_CIPHER_CTX_iv_noconst \
- EVP_CIPHER_CTX_get_iv \
- EVP_CIPHER_CTX_get_updated_iv \
- EVP_CIPHER_CTX_set_iv \
- RSA_get0_crt_params \
- RSA_get0_factors \
- RSA_get0_key \
- RSA_set0_crt_params \
- RSA_set0_factors \
- RSA_set0_key \
- RSA_meth_free \
- RSA_meth_dup \
- RSA_meth_set1_name \
- RSA_meth_get_finish \
- RSA_meth_set_priv_enc \
- RSA_meth_set_priv_dec \
- RSA_meth_set_finish \
- EVP_PKEY_get0_RSA \
- EVP_MD_CTX_new \
- EVP_MD_CTX_free \
- EVP_chacha20 \
+fi
+ac_fn_c_check_func "$LINENO" "ECDSA_SIG_get0" "ac_cv_func_ECDSA_SIG_get0"
+if test "x$ac_cv_func_ECDSA_SIG_get0" = xyes
+then :
+ printf "%s\n" "#define HAVE_ECDSA_SIG_GET0 1" >>confdefs.h
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+fi
+ac_fn_c_check_func "$LINENO" "ECDSA_SIG_set0" "ac_cv_func_ECDSA_SIG_set0"
+if test "x$ac_cv_func_ECDSA_SIG_set0" = xyes
+then :
+ printf "%s\n" "#define HAVE_ECDSA_SIG_SET0 1" >>confdefs.h
fi
-done
+ac_fn_c_check_func "$LINENO" "EVP_CIPHER_CTX_iv" "ac_cv_func_EVP_CIPHER_CTX_iv"
+if test "x$ac_cv_func_EVP_CIPHER_CTX_iv" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_CIPHER_CTX_IV 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "EVP_CIPHER_CTX_iv_noconst" "ac_cv_func_EVP_CIPHER_CTX_iv_noconst"
+if test "x$ac_cv_func_EVP_CIPHER_CTX_iv_noconst" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_CIPHER_CTX_IV_NOCONST 1" >>confdefs.h
- if test "x$openssl_engine" = "xyes" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL ENGINE support" >&5
-$as_echo_n "checking for OpenSSL ENGINE support... " >&6; }
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+fi
+ac_fn_c_check_func "$LINENO" "EVP_CIPHER_CTX_get_iv" "ac_cv_func_EVP_CIPHER_CTX_get_iv"
+if test "x$ac_cv_func_EVP_CIPHER_CTX_get_iv" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_CIPHER_CTX_GET_IV 1" >>confdefs.h
- #include <openssl/engine.h>
+fi
+ac_fn_c_check_func "$LINENO" "EVP_CIPHER_CTX_get_updated_iv" "ac_cv_func_EVP_CIPHER_CTX_get_updated_iv"
+if test "x$ac_cv_func_EVP_CIPHER_CTX_get_updated_iv" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_CIPHER_CTX_GET_UPDATED_IV 1" >>confdefs.h
-int
-main ()
-{
+fi
+ac_fn_c_check_func "$LINENO" "EVP_CIPHER_CTX_set_iv" "ac_cv_func_EVP_CIPHER_CTX_set_iv"
+if test "x$ac_cv_func_EVP_CIPHER_CTX_set_iv" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_CIPHER_CTX_SET_IV 1" >>confdefs.h
- ENGINE_load_builtin_engines();
- ENGINE_register_all_complete();
+fi
+ac_fn_c_check_func "$LINENO" "RSA_get0_crt_params" "ac_cv_func_RSA_get0_crt_params"
+if test "x$ac_cv_func_RSA_get0_crt_params" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_GET0_CRT_PARAMS 1" >>confdefs.h
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+fi
+ac_fn_c_check_func "$LINENO" "RSA_get0_factors" "ac_cv_func_RSA_get0_factors"
+if test "x$ac_cv_func_RSA_get0_factors" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_GET0_FACTORS 1" >>confdefs.h
-$as_echo "#define USE_OPENSSL_ENGINE 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "RSA_get0_key" "ac_cv_func_RSA_get0_key"
+if test "x$ac_cv_func_RSA_get0_key" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_GET0_KEY 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "RSA_set0_crt_params" "ac_cv_func_RSA_set0_crt_params"
+if test "x$ac_cv_func_RSA_set0_crt_params" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_SET0_CRT_PARAMS 1" >>confdefs.h
-else
- as_fn_error $? "OpenSSL ENGINE support not found" "$LINENO" 5
+fi
+ac_fn_c_check_func "$LINENO" "RSA_set0_factors" "ac_cv_func_RSA_set0_factors"
+if test "x$ac_cv_func_RSA_set0_factors" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_SET0_FACTORS 1" >>confdefs.h
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- fi
+ac_fn_c_check_func "$LINENO" "RSA_set0_key" "ac_cv_func_RSA_set0_key"
+if test "x$ac_cv_func_RSA_set0_key" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_SET0_KEY 1" >>confdefs.h
- # Check for OpenSSL without EVP_aes_{192,256}_cbc
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL has crippled AES support" >&5
-$as_echo_n "checking whether OpenSSL has crippled AES support... " >&6; }
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+fi
+ac_fn_c_check_func "$LINENO" "RSA_meth_free" "ac_cv_func_RSA_meth_free"
+if test "x$ac_cv_func_RSA_meth_free" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_METH_FREE 1" >>confdefs.h
- #include <stdlib.h>
- #include <string.h>
- #include <openssl/evp.h>
+fi
+ac_fn_c_check_func "$LINENO" "RSA_meth_dup" "ac_cv_func_RSA_meth_dup"
+if test "x$ac_cv_func_RSA_meth_dup" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_METH_DUP 1" >>confdefs.h
-int
-main ()
-{
+fi
+ac_fn_c_check_func "$LINENO" "RSA_meth_set1_name" "ac_cv_func_RSA_meth_set1_name"
+if test "x$ac_cv_func_RSA_meth_set1_name" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_METH_SET1_NAME 1" >>confdefs.h
- exit(EVP_aes_192_cbc() == NULL || EVP_aes_256_cbc() == NULL);
+fi
+ac_fn_c_check_func "$LINENO" "RSA_meth_get_finish" "ac_cv_func_RSA_meth_get_finish"
+if test "x$ac_cv_func_RSA_meth_get_finish" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_METH_GET_FINISH 1" >>confdefs.h
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+fi
+ac_fn_c_check_func "$LINENO" "RSA_meth_set_priv_enc" "ac_cv_func_RSA_meth_set_priv_enc"
+if test "x$ac_cv_func_RSA_meth_set_priv_enc" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_METH_SET_PRIV_ENC 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+fi
+ac_fn_c_check_func "$LINENO" "RSA_meth_set_priv_dec" "ac_cv_func_RSA_meth_set_priv_dec"
+if test "x$ac_cv_func_RSA_meth_set_priv_dec" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_METH_SET_PRIV_DEC 1" >>confdefs.h
-else
+fi
+ac_fn_c_check_func "$LINENO" "RSA_meth_set_finish" "ac_cv_func_RSA_meth_set_finish"
+if test "x$ac_cv_func_RSA_meth_set_finish" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_METH_SET_FINISH 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+fi
+ac_fn_c_check_func "$LINENO" "EVP_PKEY_get0_RSA" "ac_cv_func_EVP_PKEY_get0_RSA"
+if test "x$ac_cv_func_EVP_PKEY_get0_RSA" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_PKEY_GET0_RSA 1" >>confdefs.h
-$as_echo "#define OPENSSL_LOBOTOMISED_AES 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "EVP_MD_CTX_new" "ac_cv_func_EVP_MD_CTX_new"
+if test "x$ac_cv_func_EVP_MD_CTX_new" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_MD_CTX_NEW 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "EVP_MD_CTX_free" "ac_cv_func_EVP_MD_CTX_free"
+if test "x$ac_cv_func_EVP_MD_CTX_free" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_MD_CTX_FREE 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "EVP_chacha20" "ac_cv_func_EVP_chacha20"
+if test "x$ac_cv_func_EVP_chacha20" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_CHACHA20 1" >>confdefs.h
fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
- # Check for OpenSSL with EVP_aes_*ctr
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL has AES CTR via EVP" >&5
-$as_echo_n "checking whether OpenSSL has AES CTR via EVP... " >&6; }
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+
+ if test "x$openssl_engine" = "xyes" ; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OpenSSL ENGINE support" >&5
+printf %s "checking for OpenSSL ENGINE support... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
- #include <stdlib.h>
- #include <string.h>
- #include <openssl/evp.h>
+ #include <openssl/engine.h>
int
-main ()
+main (void)
{
- exit(EVP_aes_128_ctr() == NULL ||
- EVP_aes_192_cbc() == NULL ||
- EVP_aes_256_cbc() == NULL);
+ ENGINE_load_builtin_engines();
+ ENGINE_register_all_complete();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+printf "%s\n" "#define USE_OPENSSL_ENGINE 1" >>confdefs.h
-$as_echo "#define OPENSSL_HAVE_EVPCTR 1" >>confdefs.h
-
-
-else
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ as_fn_error $? "OpenSSL ENGINE support not found" "$LINENO" 5
fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ fi
- # Check for OpenSSL with EVP_aes_*gcm
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL has AES GCM via EVP" >&5
-$as_echo_n "checking whether OpenSSL has AES GCM via EVP... " >&6; }
+ # Check for OpenSSL without EVP_aes_{192,256}_cbc
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL has crippled AES support" >&5
+printf %s "checking whether OpenSSL has crippled AES support... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
int
-main ()
+main (void)
{
- exit(EVP_aes_128_gcm() == NULL ||
- EVP_aes_256_gcm() == NULL ||
- EVP_CTRL_GCM_SET_IV_FIXED == 0 ||
- EVP_CTRL_GCM_IV_GEN == 0 ||
- EVP_CTRL_GCM_SET_TAG == 0 ||
- EVP_CTRL_GCM_GET_TAG == 0 ||
- EVP_CIPHER_CTX_ctrl(NULL, 0, 0, NULL) == 0);
+ exit(EVP_aes_192_cbc() == NULL || EVP_aes_256_cbc() == NULL);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
-$as_echo "#define OPENSSL_HAVE_EVPGCM 1" >>confdefs.h
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
+printf "%s\n" "#define OPENSSL_LOBOTOMISED_AES 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- unsupported_algorithms="$unsupported_cipers \
- aes128-gcm@openssh.com \
- aes256-gcm@openssh.com"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if EVP_DigestUpdate returns an int" >&5
-$as_echo_n "checking if EVP_DigestUpdate returns an int... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if EVP_DigestUpdate returns an int" >&5
+printf %s "checking if EVP_DigestUpdate returns an int... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
int
-main ()
+main (void)
{
if(EVP_DigestUpdate(NULL, NULL,0))
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-else
+if ac_fn_c_try_link "$LINENO"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define OPENSSL_EVP_DIGESTUPDATE_VOID 1" >>confdefs.h
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+printf "%s\n" "#define OPENSSL_EVP_DIGESTUPDATE_VOID 1" >>confdefs.h
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
- # Some systems want crypt() from libcrypt, *not* the version in OpenSSL,
- # because the system crypt() is more featureful.
- if test "x$check_for_libcrypt_before" = "x1"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5
-$as_echo_n "checking for crypt in -lcrypt... " >&6; }
-if ${ac_cv_lib_crypt_crypt+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lcrypt $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char crypt ();
-int
-main ()
-{
-return crypt ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_crypt_crypt=yes
-else
- ac_cv_lib_crypt_crypt=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5
-$as_echo "$ac_cv_lib_crypt_crypt" >&6; }
-if test "x$ac_cv_lib_crypt_crypt" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBCRYPT 1
-_ACEOF
- LIBS="-lcrypt $LIBS"
-
-fi
-
- fi
-
- # Some Linux systems (Slackware) need crypt() from libcrypt, *not* the
- # version in OpenSSL.
- if test "x$check_for_libcrypt_later" = "x1"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5
-$as_echo_n "checking for crypt in -lcrypt... " >&6; }
-if ${ac_cv_lib_crypt_crypt+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lcrypt $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ # Check for SHA256, SHA384 and SHA512 support in OpenSSL
+ ac_fn_c_check_func "$LINENO" "EVP_sha256" "ac_cv_func_EVP_sha256"
+if test "x$ac_cv_func_EVP_sha256" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_SHA256 1" >>confdefs.h
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char crypt ();
-int
-main ()
-{
-return crypt ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_crypt_crypt=yes
-else
- ac_cv_lib_crypt_crypt=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5
-$as_echo "$ac_cv_lib_crypt_crypt" >&6; }
-if test "x$ac_cv_lib_crypt_crypt" = xyes; then :
- LIBS="$LIBS -lcrypt"
fi
-
- fi
- for ac_func in crypt DES_crypt
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ac_fn_c_check_func "$LINENO" "EVP_sha384" "ac_cv_func_EVP_sha384"
+if test "x$ac_cv_func_EVP_sha384" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_SHA384 1" >>confdefs.h
fi
-done
-
-
- # Check for SHA256, SHA384 and SHA512 support in OpenSSL
- for ac_func in EVP_sha256 EVP_sha384 EVP_sha512
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ac_fn_c_check_func "$LINENO" "EVP_sha512" "ac_cv_func_EVP_sha512"
+if test "x$ac_cv_func_EVP_sha512" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_SHA512 1" >>confdefs.h
fi
-done
# Check complete ECC support in OpenSSL
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL has NID_X9_62_prime256v1" >&5
-$as_echo_n "checking whether OpenSSL has NID_X9_62_prime256v1... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL has NID_X9_62_prime256v1" >&5
+printf %s "checking whether OpenSSL has NID_X9_62_prime256v1... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/opensslv.h>
int
-main ()
+main (void)
{
EC_KEY *e = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
const EVP_MD *m = EVP_sha256(); /* We need this too */
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_link "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
enable_nistp256=1
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL has NID_secp384r1" >&5
-$as_echo_n "checking whether OpenSSL has NID_secp384r1... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL has NID_secp384r1" >&5
+printf %s "checking whether OpenSSL has NID_secp384r1... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/opensslv.h>
int
-main ()
+main (void)
{
EC_KEY *e = EC_KEY_new_by_curve_name(NID_secp384r1);
const EVP_MD *m = EVP_sha384(); /* We need this too */
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_link "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
enable_nistp384=1
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL has NID_secp521r1" >&5
-$as_echo_n "checking whether OpenSSL has NID_secp521r1... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL has NID_secp521r1" >&5
+printf %s "checking whether OpenSSL has NID_secp521r1... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/opensslv.h>
int
-main ()
+main (void)
{
EC_KEY *e = EC_KEY_new_by_curve_name(NID_secp521r1);
const EVP_MD *m = EVP_sha512(); /* We need this too */
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if OpenSSL's NID_secp521r1 is functional" >&5
-$as_echo_n "checking if OpenSSL's NID_secp521r1 is functional... " >&6; }
- if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross-compiling: assuming yes" >&5
-$as_echo "$as_me: WARNING: cross-compiling: assuming yes" >&2;}
+if ac_fn_c_try_link "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if OpenSSL's NID_secp521r1 is functional" >&5
+printf %s "checking if OpenSSL's NID_secp521r1 is functional... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross-compiling: assuming yes" >&5
+printf "%s\n" "$as_me: WARNING: cross-compiling: assuming yes" >&2;}
enable_nistp521=1
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/opensslv.h>
int
-main ()
+main (void)
{
EC_KEY *e = EC_KEY_new_by_curve_name(NID_secp521r1);
const EVP_MD *m = EVP_sha512(); /* We need this too */
exit(e == NULL || m == NULL);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
enable_nistp521=1
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
if test x$enable_nistp256 = x1 || test x$enable_nistp384 = x1 || \
test x$enable_nistp521 = x1; then
-$as_echo "#define OPENSSL_HAS_ECC 1" >>confdefs.h
+printf "%s\n" "#define OPENSSL_HAS_ECC 1" >>confdefs.h
- for ac_func in EC_KEY_METHOD_new
-do :
- ac_fn_c_check_func "$LINENO" "EC_KEY_METHOD_new" "ac_cv_func_EC_KEY_METHOD_new"
-if test "x$ac_cv_func_EC_KEY_METHOD_new" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_EC_KEY_METHOD_NEW 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "EC_KEY_METHOD_new" "ac_cv_func_EC_KEY_METHOD_new"
+if test "x$ac_cv_func_EC_KEY_METHOD_new" = xyes
+then :
+ printf "%s\n" "#define HAVE_EC_KEY_METHOD_NEW 1" >>confdefs.h
fi
-done
openssl_ecc=yes
else
openssl_ecc=no
fi
if test x$enable_nistp256 = x1; then
-$as_echo "#define OPENSSL_HAS_NISTP256 1" >>confdefs.h
+printf "%s\n" "#define OPENSSL_HAS_NISTP256 1" >>confdefs.h
else
unsupported_algorithms="$unsupported_algorithms \
ecdsa-sha2-nistp256 \
ecdh-sha2-nistp256 \
ecdsa-sha2-nistp256-cert-v01@openssh.com"
fi
if test x$enable_nistp384 = x1; then
-$as_echo "#define OPENSSL_HAS_NISTP384 1" >>confdefs.h
+printf "%s\n" "#define OPENSSL_HAS_NISTP384 1" >>confdefs.h
else
unsupported_algorithms="$unsupported_algorithms \
ecdsa-sha2-nistp384 \
ecdh-sha2-nistp384 \
ecdsa-sha2-nistp384-cert-v01@openssh.com"
fi
if test x$enable_nistp521 = x1; then
-$as_echo "#define OPENSSL_HAS_NISTP521 1" >>confdefs.h
+printf "%s\n" "#define OPENSSL_HAS_NISTP521 1" >>confdefs.h
else
unsupported_algorithms="$unsupported_algorithms \
ecdh-sha2-nistp521 \
ecdsa-sha2-nistp521 \
ecdsa-sha2-nistp521-cert-v01@openssh.com"
fi
-
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5
-$as_echo_n "checking for crypt in -lcrypt... " >&6; }
-if ${ac_cv_lib_crypt_crypt+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lcrypt $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char crypt ();
-int
-main ()
-{
-return crypt ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_crypt_crypt=yes
-else
- ac_cv_lib_crypt_crypt=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5
-$as_echo "$ac_cv_lib_crypt_crypt" >&6; }
-if test "x$ac_cv_lib_crypt_crypt" = xyes; then :
- LIBS="$LIBS -lcrypt"
-fi
-
- for ac_func in crypt
-do :
- ac_fn_c_check_func "$LINENO" "crypt" "ac_cv_func_crypt"
-if test "x$ac_cv_func_crypt" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_CRYPT 1
-_ACEOF
-
-fi
-done
-
fi
# PKCS11/U2F depend on OpenSSL and dlopen().
enable_pkcs11=yes
enable_sk=yes
if test "x$openssl" != "xyes" ; then
enable_pkcs11="disabled; missing libcrypto"
fi
if test "x$ac_cv_func_dlopen" != "xyes" ; then
enable_pkcs11="disabled; missing dlopen(3)"
enable_sk="disabled; missing dlopen(3)"
fi
if test "x$ac_cv_have_decl_RTLD_NOW" != "xyes" ; then
- enable_pkcs11="disabled; missing RTLD_NOW"
- enable_sk="disabled; missing RTLD_NOW"
-fi
-if test ! -z "$disable_pkcs11" ; then
- enable_pkcs11="disabled by user"
-fi
-if test ! -z "$disable_sk" ; then
- enable_sk="disabled by user"
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable PKCS11" >&5
-$as_echo_n "checking whether to enable PKCS11... " >&6; }
-if test "x$enable_pkcs11" = "xyes" ; then
-
-$as_echo "#define ENABLE_PKCS11 /**/" >>confdefs.h
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_pkcs11" >&5
-$as_echo "$enable_pkcs11" >&6; }
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable U2F" >&5
-$as_echo_n "checking whether to enable U2F... " >&6; }
-if test "x$enable_sk" = "xyes" ; then
-
-$as_echo "#define ENABLE_SK /**/" >>confdefs.h
-
- SK_DUMMY_LIBRARY=regress/misc/sk-dummy/sk-dummy.so
-
-else
- # Do not try to build sk-dummy library.
- SK_DUMMY_LIBRARY=""
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_sk" >&5
-$as_echo "$enable_sk" >&6; }
-
-# Now check for built-in security key support.
-if test "x$enable_sk" = "xyes" -a "x$enable_sk_internal" = "xyes" ; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
-set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PKGCONFIG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- case $PKGCONFIG in
- [\\/]* | ?:[\\/]*)
- ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path.
- ;;
- *)
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
- ;;
-esac
+ enable_pkcs11="disabled; missing RTLD_NOW"
+ enable_sk="disabled; missing RTLD_NOW"
fi
-PKGCONFIG=$ac_cv_path_PKGCONFIG
-if test -n "$PKGCONFIG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5
-$as_echo "$PKGCONFIG" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if test ! -z "$disable_pkcs11" ; then
+ enable_pkcs11="disabled by user"
+fi
+if test ! -z "$disable_sk" ; then
+ enable_sk="disabled by user"
fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable PKCS11" >&5
+printf %s "checking whether to enable PKCS11... " >&6; }
+if test "x$enable_pkcs11" = "xyes" ; then
-fi
-if test -z "$ac_cv_path_PKGCONFIG"; then
- ac_pt_PKGCONFIG=$PKGCONFIG
- # Extract the first word of "pkg-config", so it can be a program name with args.
-set dummy pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_PKGCONFIG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- case $ac_pt_PKGCONFIG in
- [\\/]* | ?:[\\/]*)
- ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path.
- ;;
- *)
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_ac_pt_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
+printf "%s\n" "#define ENABLE_PKCS11 /**/" >>confdefs.h
- ;;
-esac
-fi
-ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG
-if test -n "$ac_pt_PKGCONFIG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5
-$as_echo "$ac_pt_PKGCONFIG" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_pkcs11" >&5
+printf "%s\n" "$enable_pkcs11" >&6; }
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable U2F" >&5
+printf %s "checking whether to enable U2F... " >&6; }
+if test "x$enable_sk" = "xyes" ; then
+
+printf "%s\n" "#define ENABLE_SK /**/" >>confdefs.h
+
+ SK_DUMMY_LIBRARY=regress/misc/sk-dummy/sk-dummy.so
- if test "x$ac_pt_PKGCONFIG" = x; then
- PKGCONFIG="no"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- PKGCONFIG=$ac_pt_PKGCONFIG
- fi
else
- PKGCONFIG="$ac_cv_path_PKGCONFIG"
+ # Do not try to build sk-dummy library.
+ SK_DUMMY_LIBRARY=""
+
fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_sk" >&5
+printf "%s\n" "$enable_sk" >&6; }
+# Now check for built-in security key support.
+if test "x$enable_sk" = "xyes" -a "x$enable_sk_internal" != "xno" ; then
use_pkgconfig_for_libfido2=
if test "x$PKGCONFIG" != "xno"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $PKGCONFIG knows about libfido2" >&5
-$as_echo_n "checking if $PKGCONFIG knows about libfido2... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $PKGCONFIG knows about libfido2" >&5
+printf %s "checking if $PKGCONFIG knows about libfido2... " >&6; }
if "$PKGCONFIG" libfido2; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
use_pkgconfig_for_libfido2=yes
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
fi
if test "x$use_pkgconfig_for_libfido2" = "xyes"; then
LIBFIDO2=`$PKGCONFIG --libs libfido2`
CPPFLAGS="$CPPFLAGS `$PKGCONFIG --cflags libfido2`"
else
LIBFIDO2="-lfido2 -lcbor"
fi
OTHERLIBS=`echo $LIBFIDO2 | sed 's/-lfido2//'`
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fido_init in -lfido2" >&5
-$as_echo_n "checking for fido_init in -lfido2... " >&6; }
-if ${ac_cv_lib_fido2_fido_init+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ fido2_error=
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fido_init in -lfido2" >&5
+printf %s "checking for fido_init in -lfido2... " >&6; }
+if test ${ac_cv_lib_fido2_fido_init+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lfido2 $OTHERLIBS
$LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char fido_init ();
int
-main ()
+main (void)
{
return fido_init ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_fido2_fido_init=yes
-else
+else $as_nop
ac_cv_lib_fido2_fido_init=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_fido2_fido_init" >&5
-$as_echo "$ac_cv_lib_fido2_fido_init" >&6; }
-if test "x$ac_cv_lib_fido2_fido_init" = xyes; then :
-
-
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_fido2_fido_init" >&5
+printf "%s\n" "$ac_cv_lib_fido2_fido_init" >&6; }
+if test "x$ac_cv_lib_fido2_fido_init" = xyes
+then :
-$as_echo "#define ENABLE_SK_INTERNAL /**/" >>confdefs.h
+else $as_nop
+ fido2_error="missing/unusable libfido2"
+fi
- enable_sk="built-in"
+ ac_fn_c_check_header_compile "$LINENO" "fido.h" "ac_cv_header_fido_h" "$ac_includes_default"
+if test "x$ac_cv_header_fido_h" = xyes
+then :
-else
- as_fn_error $? "no usable libfido2 found" "$LINENO" 5
+else $as_nop
+ fido2_error="missing fido.h from libfido2"
fi
- saved_LIBS="$LIBS"
- LIBS="$LIBS $LIBFIDO2"
- for ac_func in \
- fido_assert_set_clientdata \
- fido_cred_prot \
- fido_cred_set_prot \
- fido_cred_set_clientdata \
- fido_dev_get_touch_begin \
- fido_dev_get_touch_status \
- fido_dev_supports_cred_prot \
+ ac_fn_c_check_header_compile "$LINENO" "fido/credman.h" "ac_cv_header_fido_credman_h" " #include <fido.h>
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+"
+if test "x$ac_cv_header_fido_credman_h" = xyes
+then :
+else $as_nop
+ fido2_error="missing fido/credman.h from libfido2"
fi
-done
- LIBS="$saved_LIBS"
- ac_fn_c_check_header_mongrel "$LINENO" "fido.h" "ac_cv_header_fido_h" "$ac_includes_default"
-if test "x$ac_cv_header_fido_h" = xyes; then :
-
-else
- as_fn_error $? "missing fido.h from libfido2" "$LINENO" 5
-fi
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for usable libfido2 installation" >&5
+printf %s "checking for usable libfido2 installation... " >&6; }
+ if test ! -z "$fido2_error" ; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $fido2_error" >&5
+printf "%s\n" "$fido2_error" >&6; }
+ if test "x$enable_sk_internal" = "xyes" ; then
+ as_fn_error $? "No usable libfido2 library/headers found" "$LINENO" 5
+ fi
+ LIBFIDO2=""
+ else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
- ac_fn_c_check_header_compile "$LINENO" "fido/credman.h" "ac_cv_header_fido_credman_h" "#include <fido.h>
+printf "%s\n" "#define ENABLE_SK_INTERNAL /**/" >>confdefs.h
-"
-if test "x$ac_cv_header_fido_credman_h" = xyes; then :
+ enable_sk="built-in"
+ saved_LIBS="$LIBS"
+ LIBS="$LIBS $LIBFIDO2"
+ ac_fn_c_check_func "$LINENO" "fido_assert_set_clientdata" "ac_cv_func_fido_assert_set_clientdata"
+if test "x$ac_cv_func_fido_assert_set_clientdata" = xyes
+then :
+ printf "%s\n" "#define HAVE_FIDO_ASSERT_SET_CLIENTDATA 1" >>confdefs.h
-else
- as_fn_error $? "missing fido/credman.h from libfido2" "$LINENO" 5
fi
-
+ac_fn_c_check_func "$LINENO" "fido_cred_prot" "ac_cv_func_fido_cred_prot"
+if test "x$ac_cv_func_fido_cred_prot" = xyes
+then :
+ printf "%s\n" "#define HAVE_FIDO_CRED_PROT 1" >>confdefs.h
fi
-
-for ac_func in \
- arc4random \
- arc4random_buf \
- arc4random_stir \
- arc4random_uniform \
-
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ac_fn_c_check_func "$LINENO" "fido_cred_set_prot" "ac_cv_func_fido_cred_set_prot"
+if test "x$ac_cv_func_fido_cred_set_prot" = xyes
+then :
+ printf "%s\n" "#define HAVE_FIDO_CRED_SET_PROT 1" >>confdefs.h
fi
-done
+ac_fn_c_check_func "$LINENO" "fido_cred_set_clientdata" "ac_cv_func_fido_cred_set_clientdata"
+if test "x$ac_cv_func_fido_cred_set_clientdata" = xyes
+then :
+ printf "%s\n" "#define HAVE_FIDO_CRED_SET_CLIENTDATA 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "fido_dev_get_touch_begin" "ac_cv_func_fido_dev_get_touch_begin"
+if test "x$ac_cv_func_fido_dev_get_touch_begin" = xyes
+then :
+ printf "%s\n" "#define HAVE_FIDO_DEV_GET_TOUCH_BEGIN 1" >>confdefs.h
-saved_LIBS="$LIBS"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ia_openinfo in -liaf" >&5
-$as_echo_n "checking for ia_openinfo in -liaf... " >&6; }
-if ${ac_cv_lib_iaf_ia_openinfo+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-liaf $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+fi
+ac_fn_c_check_func "$LINENO" "fido_dev_get_touch_status" "ac_cv_func_fido_dev_get_touch_status"
+if test "x$ac_cv_func_fido_dev_get_touch_status" = xyes
+then :
+ printf "%s\n" "#define HAVE_FIDO_DEV_GET_TOUCH_STATUS 1" >>confdefs.h
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char ia_openinfo ();
-int
-main ()
-{
-return ia_openinfo ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_iaf_ia_openinfo=yes
-else
- ac_cv_lib_iaf_ia_openinfo=no
fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+ac_fn_c_check_func "$LINENO" "fido_dev_supports_cred_prot" "ac_cv_func_fido_dev_supports_cred_prot"
+if test "x$ac_cv_func_fido_dev_supports_cred_prot" = xyes
+then :
+ printf "%s\n" "#define HAVE_FIDO_DEV_SUPPORTS_CRED_PROT 1" >>confdefs.h
+
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_iaf_ia_openinfo" >&5
-$as_echo "$ac_cv_lib_iaf_ia_openinfo" >&6; }
-if test "x$ac_cv_lib_iaf_ia_openinfo" = xyes; then :
+ac_fn_c_check_func "$LINENO" "fido_dev_is_winhello" "ac_cv_func_fido_dev_is_winhello"
+if test "x$ac_cv_func_fido_dev_is_winhello" = xyes
+then :
+ printf "%s\n" "#define HAVE_FIDO_DEV_IS_WINHELLO 1" >>confdefs.h
- LIBS="$LIBS -liaf"
- for ac_func in set_id
-do :
- ac_fn_c_check_func "$LINENO" "set_id" "ac_cv_func_set_id"
-if test "x$ac_cv_func_set_id" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_SET_ID 1
-_ACEOF
- SSHDLIBS="$SSHDLIBS -liaf"
+fi
-$as_echo "#define HAVE_LIBIAF 1" >>confdefs.h
+ LIBS="$saved_LIBS"
+ fi
+fi
+ac_fn_c_check_func "$LINENO" "arc4random" "ac_cv_func_arc4random"
+if test "x$ac_cv_func_arc4random" = xyes
+then :
+ printf "%s\n" "#define HAVE_ARC4RANDOM 1" >>confdefs.h
fi
-done
+ac_fn_c_check_func "$LINENO" "arc4random_buf" "ac_cv_func_arc4random_buf"
+if test "x$ac_cv_func_arc4random_buf" = xyes
+then :
+ printf "%s\n" "#define HAVE_ARC4RANDOM_BUF 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "arc4random_stir" "ac_cv_func_arc4random_stir"
+if test "x$ac_cv_func_arc4random_stir" = xyes
+then :
+ printf "%s\n" "#define HAVE_ARC4RANDOM_STIR 1" >>confdefs.h
fi
+ac_fn_c_check_func "$LINENO" "arc4random_uniform" "ac_cv_func_arc4random_uniform"
+if test "x$ac_cv_func_arc4random_uniform" = xyes
+then :
+ printf "%s\n" "#define HAVE_ARC4RANDOM_UNIFORM 1" >>confdefs.h
-LIBS="$saved_LIBS"
+fi
### Configure cryptographic random number support
# Check whether OpenSSL seeds itself
if test "x$openssl" = "xyes" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL's PRNG is internally seeded" >&5
-$as_echo_n "checking whether OpenSSL's PRNG is internally seeded... " >&6; }
- if test "$cross_compiling" = yes; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL's PRNG is internally seeded" >&5
+printf %s "checking whether OpenSSL's PRNG is internally seeded... " >&6; }
+ if test "$cross_compiling" = yes
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming yes" >&5
-$as_echo "$as_me: WARNING: cross compiling: assuming yes" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming yes" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: assuming yes" >&2;}
# This is safe, since we will fatal() at runtime if
# OpenSSL is not seeded correctly.
OPENSSL_SEEDS_ITSELF=yes
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <string.h>
#include <openssl/rand.h>
int
-main ()
+main (void)
{
exit(RAND_status() == 1 ? 0 : 1);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_run "$LINENO"
+then :
OPENSSL_SEEDS_ITSELF=yes
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
# PRNGD TCP socket
# Check whether --with-prngd-port was given.
-if test "${with_prngd_port+set}" = set; then :
+if test ${with_prngd_port+y}
+then :
withval=$with_prngd_port;
case "$withval" in
no)
withval=""
;;
[0-9]*)
;;
*)
as_fn_error $? "You must specify a numeric port number for --with-prngd-port" "$LINENO" 5
;;
esac
if test ! -z "$withval" ; then
PRNGD_PORT="$withval"
-cat >>confdefs.h <<_ACEOF
-#define PRNGD_PORT $PRNGD_PORT
-_ACEOF
+printf "%s\n" "#define PRNGD_PORT $PRNGD_PORT" >>confdefs.h
fi
fi
# PRNGD Unix domain socket
# Check whether --with-prngd-socket was given.
-if test "${with_prngd_socket+set}" = set; then :
+if test ${with_prngd_socket+y}
+then :
withval=$with_prngd_socket;
case "$withval" in
yes)
withval="/var/run/egd-pool"
;;
no)
withval=""
;;
/*)
;;
*)
as_fn_error $? "You must specify an absolute path to the entropy socket" "$LINENO" 5
;;
esac
if test ! -z "$withval" ; then
if test ! -z "$PRNGD_PORT" ; then
as_fn_error $? "You may not specify both a PRNGD/EGD port and socket" "$LINENO" 5
fi
if test ! -r "$withval" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Entropy socket is not readable" >&5
-$as_echo "$as_me: WARNING: Entropy socket is not readable" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Entropy socket is not readable" >&5
+printf "%s\n" "$as_me: WARNING: Entropy socket is not readable" >&2;}
fi
PRNGD_SOCKET="$withval"
-cat >>confdefs.h <<_ACEOF
-#define PRNGD_SOCKET "$PRNGD_SOCKET"
-_ACEOF
+printf "%s\n" "#define PRNGD_SOCKET \"$PRNGD_SOCKET\"" >>confdefs.h
fi
-else
+else $as_nop
# Check for existing socket only if we don't have a random device already
if test "x$OPENSSL_SEEDS_ITSELF" != "xyes" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PRNGD/EGD socket" >&5
-$as_echo_n "checking for PRNGD/EGD socket... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PRNGD/EGD socket" >&5
+printf %s "checking for PRNGD/EGD socket... " >&6; }
# Insert other locations here
for sock in /var/run/egd-pool /dev/egd-pool /etc/entropy; do
if test -r $sock && $TEST_MINUS_S_SH -c "test -S $sock -o -p $sock" ; then
PRNGD_SOCKET="$sock"
- cat >>confdefs.h <<_ACEOF
-#define PRNGD_SOCKET "$PRNGD_SOCKET"
-_ACEOF
+ printf "%s\n" "#define PRNGD_SOCKET \"$PRNGD_SOCKET\"" >>confdefs.h
break;
fi
done
if test ! -z "$PRNGD_SOCKET" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PRNGD_SOCKET" >&5
-$as_echo "$PRNGD_SOCKET" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PRNGD_SOCKET" >&5
+printf "%s\n" "$PRNGD_SOCKET" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
-$as_echo "not found" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+printf "%s\n" "not found" >&6; }
fi
fi
fi
# Which randomness source do we use?
if test ! -z "$PRNGD_PORT" ; then
RAND_MSG="PRNGd port $PRNGD_PORT"
elif test ! -z "$PRNGD_SOCKET" ; then
RAND_MSG="PRNGd socket $PRNGD_SOCKET"
elif test ! -z "$OPENSSL_SEEDS_ITSELF" ; then
-$as_echo "#define OPENSSL_PRNG_ONLY 1" >>confdefs.h
+printf "%s\n" "#define OPENSSL_PRNG_ONLY 1" >>confdefs.h
RAND_MSG="OpenSSL internal ONLY"
elif test "x$openssl" = "xno" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: OpenSSH will use /dev/urandom as a source of random numbers. It will fail if this device is not supported or accessible" >&5
-$as_echo "$as_me: WARNING: OpenSSH will use /dev/urandom as a source of random numbers. It will fail if this device is not supported or accessible" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: OpenSSH will use /dev/urandom as a source of random numbers. It will fail if this device is not supported or accessible" >&5
+printf "%s\n" "$as_me: WARNING: OpenSSH will use /dev/urandom as a source of random numbers. It will fail if this device is not supported or accessible" >&2;}
else
as_fn_error $? "OpenSSH has no source of random numbers. Please configure OpenSSL with an entropy source or re-run configure using one of the --with-prngd-port or --with-prngd-socket options" "$LINENO" 5
fi
+LIBS="$nocrypto_saved_LIBS"
+
+saved_LIBS="$LIBS"
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ia_openinfo in -liaf" >&5
+printf %s "checking for ia_openinfo in -liaf... " >&6; }
+if test ${ac_cv_lib_iaf_ia_openinfo+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-liaf $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+char ia_openinfo ();
+int
+main (void)
+{
+return ia_openinfo ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_iaf_ia_openinfo=yes
+else $as_nop
+ ac_cv_lib_iaf_ia_openinfo=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_iaf_ia_openinfo" >&5
+printf "%s\n" "$ac_cv_lib_iaf_ia_openinfo" >&6; }
+if test "x$ac_cv_lib_iaf_ia_openinfo" = xyes
+then :
+
+ LIBS="$LIBS -liaf"
+
+ for ac_func in set_id
+do :
+ ac_fn_c_check_func "$LINENO" "set_id" "ac_cv_func_set_id"
+if test "x$ac_cv_func_set_id" = xyes
+then :
+ printf "%s\n" "#define HAVE_SET_ID 1" >>confdefs.h
+ SSHDLIBS="$SSHDLIBS -liaf"
+
+printf "%s\n" "#define HAVE_LIBIAF 1" >>confdefs.h
+
+
+fi
+
+done
+
+fi
+
+LIBS="$saved_LIBS"
+
+# Check for crypt() in libcrypt. If we have it, we only need it for sshd.
+saved_LIBS="$LIBS"
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5
+printf %s "checking for crypt in -lcrypt... " >&6; }
+if test ${ac_cv_lib_crypt_crypt+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypt $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+char crypt ();
+int
+main (void)
+{
+return crypt ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_crypt_crypt=yes
+else $as_nop
+ ac_cv_lib_crypt_crypt=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5
+printf "%s\n" "$ac_cv_lib_crypt_crypt" >&6; }
+if test "x$ac_cv_lib_crypt_crypt" = xyes
+then :
+
+ LIBS="-lcrypt $LIBS"
+ SSHDLIBS="-lcrypt $SSHDLIBS"
+
+fi
+
+ac_fn_c_check_func "$LINENO" "crypt" "ac_cv_func_crypt"
+if test "x$ac_cv_func_crypt" = xyes
+then :
+ printf "%s\n" "#define HAVE_CRYPT 1" >>confdefs.h
+
+fi
+
+LIBS="$saved_LIBS"
# Check for PAM libs
PAM_MSG="no"
# Check whether --with-pam was given.
-if test "${with_pam+set}" = set; then :
+if test ${with_pam+y}
+then :
withval=$with_pam;
if test "x$withval" != "xno" ; then
if test "x$ac_cv_header_security_pam_appl_h" != "xyes" && \
test "x$ac_cv_header_pam_pam_appl_h" != "xyes" ; then
as_fn_error $? "PAM headers not found" "$LINENO" 5
fi
saved_LIBS="$LIBS"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
-$as_echo_n "checking for dlopen in -ldl... " >&6; }
-if ${ac_cv_lib_dl_dlopen+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+printf %s "checking for dlopen in -ldl... " >&6; }
+if test ${ac_cv_lib_dl_dlopen+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-ldl $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char dlopen ();
int
-main ()
+main (void)
{
return dlopen ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_dl_dlopen=yes
-else
+else $as_nop
ac_cv_lib_dl_dlopen=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
-$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
-if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBDL 1
-_ACEOF
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBDL 1" >>confdefs.h
LIBS="-ldl $LIBS"
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pam_set_item in -lpam" >&5
-$as_echo_n "checking for pam_set_item in -lpam... " >&6; }
-if ${ac_cv_lib_pam_pam_set_item+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pam_set_item in -lpam" >&5
+printf %s "checking for pam_set_item in -lpam... " >&6; }
+if test ${ac_cv_lib_pam_pam_set_item+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lpam $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char pam_set_item ();
int
-main ()
+main (void)
{
return pam_set_item ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_pam_pam_set_item=yes
-else
+else $as_nop
ac_cv_lib_pam_pam_set_item=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pam_pam_set_item" >&5
-$as_echo "$ac_cv_lib_pam_pam_set_item" >&6; }
-if test "x$ac_cv_lib_pam_pam_set_item" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBPAM 1
-_ACEOF
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pam_pam_set_item" >&5
+printf "%s\n" "$ac_cv_lib_pam_pam_set_item" >&6; }
+if test "x$ac_cv_lib_pam_pam_set_item" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBPAM 1" >>confdefs.h
LIBS="-lpam $LIBS"
-else
+else $as_nop
as_fn_error $? "*** libpam missing" "$LINENO" 5
fi
- for ac_func in pam_getenvlist
-do :
- ac_fn_c_check_func "$LINENO" "pam_getenvlist" "ac_cv_func_pam_getenvlist"
-if test "x$ac_cv_func_pam_getenvlist" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_PAM_GETENVLIST 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "pam_getenvlist" "ac_cv_func_pam_getenvlist"
+if test "x$ac_cv_func_pam_getenvlist" = xyes
+then :
+ printf "%s\n" "#define HAVE_PAM_GETENVLIST 1" >>confdefs.h
fi
-done
- for ac_func in pam_putenv
-do :
- ac_fn_c_check_func "$LINENO" "pam_putenv" "ac_cv_func_pam_putenv"
-if test "x$ac_cv_func_pam_putenv" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_PAM_PUTENV 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "pam_putenv" "ac_cv_func_pam_putenv"
+if test "x$ac_cv_func_pam_putenv" = xyes
+then :
+ printf "%s\n" "#define HAVE_PAM_PUTENV 1" >>confdefs.h
fi
-done
LIBS="$saved_LIBS"
PAM_MSG="yes"
SSHDLIBS="$SSHDLIBS -lpam"
-$as_echo "#define USE_PAM 1" >>confdefs.h
+printf "%s\n" "#define USE_PAM 1" >>confdefs.h
if test $ac_cv_lib_dl_dlopen = yes; then
case "$LIBS" in
*-ldl*)
# libdl already in LIBS
;;
*)
SSHDLIBS="$SSHDLIBS -ldl"
;;
esac
fi
fi
fi
# Check whether --with-pam-service was given.
-if test "${with_pam_service+set}" = set; then :
+if test ${with_pam_service+y}
+then :
withval=$with_pam_service;
if test "x$withval" != "xno" && \
test "x$withval" != "xyes" ; then
-cat >>confdefs.h <<_ACEOF
-#define SSHD_PAM_SERVICE "$withval"
-_ACEOF
+printf "%s\n" "#define SSHD_PAM_SERVICE \"$withval\"" >>confdefs.h
fi
fi
# Check for older PAM
if test "x$PAM_MSG" = "xyes" ; then
# Check PAM strerror arguments (old PAM)
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pam_strerror takes only one argument" >&5
-$as_echo_n "checking whether pam_strerror takes only one argument... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pam_strerror takes only one argument" >&5
+printf %s "checking whether pam_strerror takes only one argument... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#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
int
-main ()
+main (void)
{
(void)pam_strerror((pam_handle_t *)NULL, -1);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-else
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+else $as_nop
-$as_echo "#define HAVE_OLD_PAM 1" >>confdefs.h
+printf "%s\n" "#define HAVE_OLD_PAM 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
PAM_MSG="yes (old library)"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
case "$host" in
*-*-cygwin*)
SSH_PRIVSEP_USER=CYGWIN_SSH_PRIVSEP_USER
;;
*)
SSH_PRIVSEP_USER=sshd
;;
esac
# Check whether --with-privsep-user was given.
-if test "${with_privsep_user+set}" = set; then :
+if test ${with_privsep_user+y}
+then :
withval=$with_privsep_user;
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
SSH_PRIVSEP_USER=$withval
fi
fi
if test "x$SSH_PRIVSEP_USER" = "xCYGWIN_SSH_PRIVSEP_USER" ; then
-cat >>confdefs.h <<_ACEOF
-#define SSH_PRIVSEP_USER CYGWIN_SSH_PRIVSEP_USER
-_ACEOF
+printf "%s\n" "#define SSH_PRIVSEP_USER CYGWIN_SSH_PRIVSEP_USER" >>confdefs.h
else
-cat >>confdefs.h <<_ACEOF
-#define SSH_PRIVSEP_USER "$SSH_PRIVSEP_USER"
-_ACEOF
+printf "%s\n" "#define SSH_PRIVSEP_USER \"$SSH_PRIVSEP_USER\"" >>confdefs.h
fi
if test "x$have_linux_no_new_privs" = "x1" ; then
-ac_fn_c_check_decl "$LINENO" "SECCOMP_MODE_FILTER" "ac_cv_have_decl_SECCOMP_MODE_FILTER" "
+ac_fn_check_decl "$LINENO" "SECCOMP_MODE_FILTER" "ac_cv_have_decl_SECCOMP_MODE_FILTER" "
#include <sys/types.h>
#include <linux/seccomp.h>
-"
-if test "x$ac_cv_have_decl_SECCOMP_MODE_FILTER" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_SECCOMP_MODE_FILTER" = xyes
+then :
have_seccomp_filter=1
fi
-
fi
if test "x$have_seccomp_filter" = "x1" ; then
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking kernel for seccomp_filter support" >&5
-$as_echo_n "checking kernel for seccomp_filter support... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking kernel for seccomp_filter support" >&5
+printf %s "checking kernel for seccomp_filter support... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <errno.h>
#include <elf.h>
#include <linux/audit.h>
#include <linux/seccomp.h>
#include <stdlib.h>
#include <sys/prctl.h>
int
-main ()
+main (void)
{
int i = $seccomp_audit_arch;
errno = 0;
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, 0, 0);
exit(errno == EFAULT ? 0 : 1);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
+if ac_fn_c_try_link "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ # Disable seccomp filter as a target
+ have_seccomp_filter=0
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+ac_fn_c_check_member "$LINENO" "struct pollfd" "fd" "ac_cv_member_struct_pollfd_fd" "
+#include <sys/types.h>
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
+
+"
+if test "x$ac_cv_member_struct_pollfd_fd" = xyes
+then :
+
+printf "%s\n" "#define HAVE_STRUCT_POLLFD_FD 1" >>confdefs.h
+
+
+fi
+
+
+ac_fn_c_check_type "$LINENO" "nfds_t" "ac_cv_type_nfds_t" "
+#include <sys/types.h>
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- # Disable seccomp filter as a target
- have_seccomp_filter=0
+"
+if test "x$ac_cv_type_nfds_t" = xyes
+then :
+
+printf "%s\n" "#define HAVE_NFDS_T 1" >>confdefs.h
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
fi
+
# Decide which sandbox style to use
sandbox_arg=""
# Check whether --with-sandbox was given.
-if test "${with_sandbox+set}" = set; then :
+if test ${with_sandbox+y}
+then :
withval=$with_sandbox;
if test "x$withval" = "xyes" ; then
sandbox_arg=""
else
sandbox_arg="$withval"
fi
fi
+if test "x$sandbox_arg" != "xno"; then
# POSIX specifies that poll() "shall fail with EINVAL if the nfds argument
# is greater than OPEN_MAX". On some platforms that includes implementions
-# ofselect in userspace on top of poll() so check both work with rlimit NOFILES
-# so check that both work before enabling the rlimit sandbox.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if select and/or poll works with descriptor rlimit" >&5
-$as_echo_n "checking if select and/or poll works with descriptor rlimit... " >&6; }
-if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming no" >&5
-$as_echo "$as_me: WARNING: cross compiling: assuming no" >&2;}
+# of select in userspace on top of poll() so check both work with rlimit
+# NOFILES so check that both work before enabling the rlimit sandbox.
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if select and/or poll works with descriptor rlimit" >&5
+printf %s "checking if select and/or poll works with descriptor rlimit... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming no" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: assuming no" >&2;}
select_works_with_rlimit=no
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/resource.h>
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#ifdef HAVE_POLL_H
# include <poll.h>
#elif HAVE_SYS_POLL_H
# include <sys/poll.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
int
-main ()
+main (void)
{
struct rlimit rl_zero;
int fd, r;
fd_set fds;
struct timeval tv;
#ifdef HAVE_POLL
struct pollfd pfd;
#endif
fd = open("/dev/null", O_RDONLY);
FD_ZERO(&fds);
FD_SET(fd, &fds);
rl_zero.rlim_cur = rl_zero.rlim_max = 0;
setrlimit(RLIMIT_FSIZE, &rl_zero);
setrlimit(RLIMIT_NOFILE, &rl_zero);
tv.tv_sec = 1;
tv.tv_usec = 0;
r = select(fd+1, &fds, NULL, NULL, &tv);
if (r == -1)
exit(1);
#ifdef HAVE_POLL
pfd.fd = fd;
pfd.events = POLLIN;
r = poll(&pfd, 1, 1);
if (r == -1)
exit(2);
#endif
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
select_works_with_rlimit=yes
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
select_works_with_rlimit=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-ac_fn_c_check_member "$LINENO" "struct pollfd" "fd" "ac_cv_member_struct_pollfd_fd" "
-#include <sys/types.h>
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
-#ifdef HAVE_SYS_POLL_H
-#include <sys/poll.h>
-#endif
-
-"
-if test "x$ac_cv_member_struct_pollfd_fd" = xyes; then :
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_POLLFD_FD 1
-_ACEOF
-
-
-fi
-
-
-ac_fn_c_check_type "$LINENO" "nfds_t" "ac_cv_type_nfds_t" "
-#include <sys/types.h>
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
-#ifdef HAVE_SYS_POLL_H
-#include <sys/poll.h>
-#endif
-
-"
-if test "x$ac_cv_type_nfds_t" = xyes; then :
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_NFDS_T 1
-_ACEOF
-
-
-fi
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if setrlimit(RLIMIT_NOFILE,{0,0}) works" >&5
-$as_echo_n "checking if setrlimit(RLIMIT_NOFILE,{0,0}) works... " >&6; }
-if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming yes" >&5
-$as_echo "$as_me: WARNING: cross compiling: assuming yes" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if setrlimit(RLIMIT_NOFILE,{0,0}) works" >&5
+printf %s "checking if setrlimit(RLIMIT_NOFILE,{0,0}) works... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming yes" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: assuming yes" >&2;}
rlimit_nofile_zero_works=yes
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/resource.h>
#include <errno.h>
#include <stdlib.h>
int
-main ()
+main (void)
{
struct rlimit rl_zero;
int r;
rl_zero.rlim_cur = rl_zero.rlim_max = 0;
r = setrlimit(RLIMIT_NOFILE, &rl_zero);
exit (r == -1 ? 1 : 0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
rlimit_nofile_zero_works=yes
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
rlimit_nofile_zero_works=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if setrlimit RLIMIT_FSIZE works" >&5
-$as_echo_n "checking if setrlimit RLIMIT_FSIZE works... " >&6; }
-if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming yes" >&5
-$as_echo "$as_me: WARNING: cross compiling: assuming yes" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if setrlimit RLIMIT_FSIZE works" >&5
+printf %s "checking if setrlimit RLIMIT_FSIZE works... " >&6; }
+ if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming yes" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: assuming yes" >&2;}
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/resource.h>
#include <stdlib.h>
int
-main ()
+main (void)
{
struct rlimit rl_zero;
rl_zero.rlim_cur = rl_zero.rlim_max = 0;
exit(setrlimit(RLIMIT_FSIZE, &rl_zero) != 0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if ac_fn_c_try_run "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
-$as_echo "#define SANDBOX_SKIP_RLIMIT_FSIZE 1" >>confdefs.h
+printf "%s\n" "#define SANDBOX_SKIP_RLIMIT_FSIZE 1" >>confdefs.h
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
+fi
if test "x$sandbox_arg" = "xpledge" || \
( test -z "$sandbox_arg" && test "x$ac_cv_func_pledge" = "xyes" ) ; then
test "x$ac_cv_func_pledge" != "xyes" && \
as_fn_error $? "pledge sandbox requires pledge(2) support" "$LINENO" 5
SANDBOX_STYLE="pledge"
-$as_echo "#define SANDBOX_PLEDGE 1" >>confdefs.h
+printf "%s\n" "#define SANDBOX_PLEDGE 1" >>confdefs.h
elif test "x$sandbox_arg" = "xsystrace" || \
( test -z "$sandbox_arg" && test "x$have_systr_policy_kill" = "x1" ) ; then
test "x$have_systr_policy_kill" != "x1" && \
as_fn_error $? "systrace sandbox requires systrace headers and SYSTR_POLICY_KILL support" "$LINENO" 5
SANDBOX_STYLE="systrace"
-$as_echo "#define SANDBOX_SYSTRACE 1" >>confdefs.h
+printf "%s\n" "#define SANDBOX_SYSTRACE 1" >>confdefs.h
elif test "x$sandbox_arg" = "xdarwin" || \
( test -z "$sandbox_arg" && test "x$ac_cv_func_sandbox_init" = "xyes" && \
test "x$ac_cv_header_sandbox_h" = "xyes") ; then
test "x$ac_cv_func_sandbox_init" != "xyes" -o \
"x$ac_cv_header_sandbox_h" != "xyes" && \
as_fn_error $? "Darwin seatbelt sandbox requires sandbox.h and sandbox_init function" "$LINENO" 5
SANDBOX_STYLE="darwin"
-$as_echo "#define SANDBOX_DARWIN 1" >>confdefs.h
+printf "%s\n" "#define SANDBOX_DARWIN 1" >>confdefs.h
elif test "x$sandbox_arg" = "xseccomp_filter" || \
( test -z "$sandbox_arg" && \
test "x$have_seccomp_filter" = "x1" && \
test "x$ac_cv_header_elf_h" = "xyes" && \
test "x$ac_cv_header_linux_audit_h" = "xyes" && \
test "x$ac_cv_header_linux_filter_h" = "xyes" && \
test "x$seccomp_audit_arch" != "x" && \
test "x$have_linux_no_new_privs" = "x1" && \
test "x$ac_cv_func_prctl" = "xyes" ) ; then
test "x$seccomp_audit_arch" = "x" && \
as_fn_error $? "seccomp_filter sandbox not supported on $host" "$LINENO" 5
test "x$have_linux_no_new_privs" != "x1" && \
as_fn_error $? "seccomp_filter sandbox requires PR_SET_NO_NEW_PRIVS" "$LINENO" 5
test "x$have_seccomp_filter" != "x1" && \
as_fn_error $? "seccomp_filter sandbox requires seccomp headers" "$LINENO" 5
test "x$ac_cv_func_prctl" != "xyes" && \
as_fn_error $? "seccomp_filter sandbox requires prctl function" "$LINENO" 5
SANDBOX_STYLE="seccomp_filter"
-$as_echo "#define SANDBOX_SECCOMP_FILTER 1" >>confdefs.h
+printf "%s\n" "#define SANDBOX_SECCOMP_FILTER 1" >>confdefs.h
elif test "x$sandbox_arg" = "xcapsicum" || \
( test -z "$sandbox_arg" && \
test "x$disable_capsicum" != "xyes" && \
test "x$ac_cv_header_sys_capsicum_h" = "xyes" && \
test "x$ac_cv_func_cap_rights_limit" = "xyes") ; then
test "x$ac_cv_header_sys_capsicum_h" != "xyes" && \
as_fn_error $? "capsicum sandbox requires sys/capsicum.h header" "$LINENO" 5
test "x$ac_cv_func_cap_rights_limit" != "xyes" && \
as_fn_error $? "capsicum sandbox requires cap_rights_limit function" "$LINENO" 5
SANDBOX_STYLE="capsicum"
-$as_echo "#define SANDBOX_CAPSICUM 1" >>confdefs.h
+printf "%s\n" "#define SANDBOX_CAPSICUM 1" >>confdefs.h
elif test "x$sandbox_arg" = "xrlimit" || \
( test -z "$sandbox_arg" && test "x$ac_cv_func_setrlimit" = "xyes" && \
test "x$select_works_with_rlimit" = "xyes" && \
test "x$rlimit_nofile_zero_works" = "xyes" ) ; then
test "x$ac_cv_func_setrlimit" != "xyes" && \
as_fn_error $? "rlimit sandbox requires setrlimit function" "$LINENO" 5
test "x$select_works_with_rlimit" != "xyes" && \
as_fn_error $? "rlimit sandbox requires select to work with rlimit" "$LINENO" 5
SANDBOX_STYLE="rlimit"
-$as_echo "#define SANDBOX_RLIMIT 1" >>confdefs.h
+printf "%s\n" "#define SANDBOX_RLIMIT 1" >>confdefs.h
elif test "x$sandbox_arg" = "xsolaris" || \
( test -z "$sandbox_arg" && test "x$SOLARIS_PRIVS" = "xyes" ) ; then
SANDBOX_STYLE="solaris"
-$as_echo "#define SANDBOX_SOLARIS 1" >>confdefs.h
+printf "%s\n" "#define SANDBOX_SOLARIS 1" >>confdefs.h
elif test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \
test "x$sandbox_arg" = "xnone" || test "x$sandbox_arg" = "xnull" ; then
SANDBOX_STYLE="none"
-$as_echo "#define SANDBOX_NULL 1" >>confdefs.h
+printf "%s\n" "#define SANDBOX_NULL 1" >>confdefs.h
else
as_fn_error $? "unsupported --with-sandbox" "$LINENO" 5
fi
# Cheap hack to ensure NEWS-OS libraries are arranged right.
if test ! -z "$SONY" ; then
LIBS="$LIBS -liberty";
fi
# Check for long long datatypes
ac_fn_c_check_type "$LINENO" "long long" "ac_cv_type_long_long" "$ac_includes_default"
-if test "x$ac_cv_type_long_long" = xyes; then :
+if test "x$ac_cv_type_long_long" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_LONG_LONG 1
-_ACEOF
+printf "%s\n" "#define HAVE_LONG_LONG 1" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "unsigned long long" "ac_cv_type_unsigned_long_long" "$ac_includes_default"
-if test "x$ac_cv_type_unsigned_long_long" = xyes; then :
+if test "x$ac_cv_type_unsigned_long_long" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_UNSIGNED_LONG_LONG 1
-_ACEOF
+printf "%s\n" "#define HAVE_UNSIGNED_LONG_LONG 1" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "long double" "ac_cv_type_long_double" "$ac_includes_default"
-if test "x$ac_cv_type_long_double" = xyes; then :
+if test "x$ac_cv_type_long_double" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_LONG_DOUBLE 1
-_ACEOF
+printf "%s\n" "#define HAVE_LONG_DOUBLE 1" >>confdefs.h
fi
# Check datatype sizes
# The cast to long int works around a bug in the HP C Compiler
# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
# This bug is HP SR number 8606223364.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short int" >&5
-$as_echo_n "checking size of short int... " >&6; }
-if ${ac_cv_sizeof_short_int+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short int))" "ac_cv_sizeof_short_int" "$ac_includes_default"; then :
-
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of short int" >&5
+printf %s "checking size of short int... " >&6; }
+if test ${ac_cv_sizeof_short_int+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short int))" "ac_cv_sizeof_short_int" "$ac_includes_default"
+then :
+
+else $as_nop
if test "$ac_cv_type_short_int" = yes; then
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (short int)
See \`config.log' for more details" "$LINENO" 5; }
else
ac_cv_sizeof_short_int=0
fi
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short_int" >&5
-$as_echo "$ac_cv_sizeof_short_int" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short_int" >&5
+printf "%s\n" "$ac_cv_sizeof_short_int" >&6; }
-cat >>confdefs.h <<_ACEOF
-#define SIZEOF_SHORT_INT $ac_cv_sizeof_short_int
-_ACEOF
+printf "%s\n" "#define SIZEOF_SHORT_INT $ac_cv_sizeof_short_int" >>confdefs.h
# The cast to long int works around a bug in the HP C Compiler
# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
# This bug is HP SR number 8606223364.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5
-$as_echo_n "checking size of int... " >&6; }
-if ${ac_cv_sizeof_int+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then :
-
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of int" >&5
+printf %s "checking size of int... " >&6; }
+if test ${ac_cv_sizeof_int+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"
+then :
+
+else $as_nop
if test "$ac_cv_type_int" = yes; then
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (int)
See \`config.log' for more details" "$LINENO" 5; }
else
ac_cv_sizeof_int=0
fi
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5
-$as_echo "$ac_cv_sizeof_int" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5
+printf "%s\n" "$ac_cv_sizeof_int" >&6; }
-cat >>confdefs.h <<_ACEOF
-#define SIZEOF_INT $ac_cv_sizeof_int
-_ACEOF
+printf "%s\n" "#define SIZEOF_INT $ac_cv_sizeof_int" >>confdefs.h
# The cast to long int works around a bug in the HP C Compiler
# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
# This bug is HP SR number 8606223364.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long int" >&5
-$as_echo_n "checking size of long int... " >&6; }
-if ${ac_cv_sizeof_long_int+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long int))" "ac_cv_sizeof_long_int" "$ac_includes_default"; then :
-
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long int" >&5
+printf %s "checking size of long int... " >&6; }
+if test ${ac_cv_sizeof_long_int+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long int))" "ac_cv_sizeof_long_int" "$ac_includes_default"
+then :
+
+else $as_nop
if test "$ac_cv_type_long_int" = yes; then
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (long int)
See \`config.log' for more details" "$LINENO" 5; }
else
ac_cv_sizeof_long_int=0
fi
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_int" >&5
-$as_echo "$ac_cv_sizeof_long_int" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_int" >&5
+printf "%s\n" "$ac_cv_sizeof_long_int" >&6; }
-cat >>confdefs.h <<_ACEOF
-#define SIZEOF_LONG_INT $ac_cv_sizeof_long_int
-_ACEOF
+printf "%s\n" "#define SIZEOF_LONG_INT $ac_cv_sizeof_long_int" >>confdefs.h
# The cast to long int works around a bug in the HP C Compiler
# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
# This bug is HP SR number 8606223364.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long int" >&5
-$as_echo_n "checking size of long long int... " >&6; }
-if ${ac_cv_sizeof_long_long_int+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long int))" "ac_cv_sizeof_long_long_int" "$ac_includes_default"; then :
-
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long long int" >&5
+printf %s "checking size of long long int... " >&6; }
+if test ${ac_cv_sizeof_long_long_int+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long int))" "ac_cv_sizeof_long_long_int" "$ac_includes_default"
+then :
+
+else $as_nop
if test "$ac_cv_type_long_long_int" = yes; then
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (long long int)
See \`config.log' for more details" "$LINENO" 5; }
else
ac_cv_sizeof_long_long_int=0
fi
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long_int" >&5
-$as_echo "$ac_cv_sizeof_long_long_int" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long_int" >&5
+printf "%s\n" "$ac_cv_sizeof_long_long_int" >&6; }
-cat >>confdefs.h <<_ACEOF
-#define SIZEOF_LONG_LONG_INT $ac_cv_sizeof_long_long_int
-_ACEOF
+printf "%s\n" "#define SIZEOF_LONG_LONG_INT $ac_cv_sizeof_long_long_int" >>confdefs.h
# The cast to long int works around a bug in the HP C Compiler
# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
# This bug is HP SR number 8606223364.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5
-$as_echo_n "checking size of time_t... " >&6; }
-if ${ac_cv_sizeof_time_t+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5
+printf %s "checking size of time_t... " >&6; }
+if test ${ac_cv_sizeof_time_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" "
#include <sys/types.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_TIME_H
# include <time.h>
#endif
-"; then :
+"
+then :
-else
+else $as_nop
if test "$ac_cv_type_time_t" = yes; then
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (time_t)
See \`config.log' for more details" "$LINENO" 5; }
else
ac_cv_sizeof_time_t=0
fi
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5
-$as_echo "$ac_cv_sizeof_time_t" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5
+printf "%s\n" "$ac_cv_sizeof_time_t" >&6; }
-cat >>confdefs.h <<_ACEOF
-#define SIZEOF_TIME_T $ac_cv_sizeof_time_t
-_ACEOF
+printf "%s\n" "#define SIZEOF_TIME_T $ac_cv_sizeof_time_t" >>confdefs.h
# Sanity check long long for some platforms (AIX)
if test "x$ac_cv_sizeof_long_long_int" = "x4" ; then
ac_cv_sizeof_long_long_int=0
fi
# compute LLONG_MIN and LLONG_MAX if we don't know them.
if test -z "$have_llong_max" && test -z "$have_long_long_max"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for max value of long long" >&5
-$as_echo_n "checking for max value of long long... " >&6; }
- if test "$cross_compiling" = yes; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for max value of long long" >&5
+printf %s "checking for max value of long long... " >&6; }
+ if test "$cross_compiling" = yes
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking" >&5
-$as_echo "$as_me: WARNING: cross compiling: not checking" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: not checking" >&2;}
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
#include <stdlib.h>
/* Why is this so damn hard? */
#ifdef __GNUC__
# undef __GNUC__
#endif
#define __USE_ISOC99
#include <limits.h>
#define DATA "conftest.llminmax"
#define my_abs(a) ((a) < 0 ? ((a) * -1) : (a))
/*
* printf in libc on some platforms (eg old Tru64) does not understand %lld so
* we do this the hard way.
*/
static int
fprint_ll(FILE *f, long long n)
{
unsigned int i;
int l[sizeof(long long) * 8];
if (n < 0)
if (fprintf(f, "-") < 0)
return -1;
for (i = 0; n != 0; i++) {
l[i] = my_abs(n % 10);
n /= 10;
}
do {
if (fprintf(f, "%d", l[--i]) < 0)
return -1;
} while (i != 0);
if (fprintf(f, " ") < 0)
return -1;
return 0;
}
int
-main ()
+main (void)
{
FILE *f;
long long i, llmin, llmax = 0;
if((f = fopen(DATA,"w")) == NULL)
exit(1);
#if defined(LLONG_MIN) && defined(LLONG_MAX)
fprintf(stderr, "Using system header for LLONG_MIN and LLONG_MAX\n");
llmin = LLONG_MIN;
llmax = LLONG_MAX;
#else
fprintf(stderr, "Calculating LLONG_MIN and LLONG_MAX\n");
/* This will work on one's complement and two's complement */
for (i = 1; i > llmax; i <<= 1, i++)
llmax = i;
llmin = llmax + 1LL; /* wrap */
#endif
/* Sanity check */
if (llmin + 1 < llmin || llmin - 1 < llmin || llmax + 1 > llmax
|| llmax - 1 > llmax || llmin == llmax || llmin == 0
|| llmax == 0 || llmax < LONG_MAX || llmin > LONG_MIN) {
fprintf(f, "unknown unknown\n");
exit(2);
}
if (fprint_ll(f, llmin) < 0)
exit(3);
if (fprint_ll(f, llmax) < 0)
exit(4);
if (fclose(f) < 0)
exit(5);
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_run "$LINENO"
+then :
llong_min=`$AWK '{print $1}' conftest.llminmax`
llong_max=`$AWK '{print $2}' conftest.llminmax`
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $llong_max" >&5
-$as_echo "$llong_max" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $llong_max" >&5
+printf "%s\n" "$llong_max" >&6; }
-cat >>confdefs.h <<_ACEOF
-#define LLONG_MAX ${llong_max}LL
-_ACEOF
+printf "%s\n" "#define LLONG_MAX ${llong_max}LL" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for min value of long long" >&5
-$as_echo_n "checking for min value of long long... " >&6; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $llong_min" >&5
-$as_echo "$llong_min" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for min value of long long" >&5
+printf %s "checking for min value of long long... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $llong_min" >&5
+printf "%s\n" "$llong_min" >&6; }
-cat >>confdefs.h <<_ACEOF
-#define LLONG_MIN ${llong_min}LL
-_ACEOF
+printf "%s\n" "#define LLONG_MIN ${llong_min}LL" >>confdefs.h
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
-$as_echo "not found" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+printf "%s\n" "not found" >&6; }
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
-ac_fn_c_check_decl "$LINENO" "UINT32_MAX" "ac_cv_have_decl_UINT32_MAX" "
+ac_fn_check_decl "$LINENO" "UINT32_MAX" "ac_cv_have_decl_UINT32_MAX" "
#ifdef HAVE_SYS_LIMITS_H
# include <sys/limits.h>
#endif
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
-"
-if test "x$ac_cv_have_decl_UINT32_MAX" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_UINT32_MAX" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_UINT32_MAX $ac_have_decl
-_ACEOF
+printf "%s\n" "#define HAVE_DECL_UINT32_MAX $ac_have_decl" >>confdefs.h
# More checks for data types
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for u_int type" >&5
-$as_echo_n "checking for u_int type... " >&6; }
-if ${ac_cv_have_u_int+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for u_int type" >&5
+printf %s "checking for u_int type... " >&6; }
+if test ${ac_cv_have_u_int+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
int
-main ()
+main (void)
{
u_int a; a = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_u_int="yes"
-else
+else $as_nop
ac_cv_have_u_int="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_u_int" >&5
-$as_echo "$ac_cv_have_u_int" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_u_int" >&5
+printf "%s\n" "$ac_cv_have_u_int" >&6; }
if test "x$ac_cv_have_u_int" = "xyes" ; then
-$as_echo "#define HAVE_U_INT 1" >>confdefs.h
+printf "%s\n" "#define HAVE_U_INT 1" >>confdefs.h
have_u_int=1
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for intXX_t types" >&5
-$as_echo_n "checking for intXX_t types... " >&6; }
-if ${ac_cv_have_intxx_t+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for intXX_t types" >&5
+printf %s "checking for intXX_t types... " >&6; }
+if test ${ac_cv_have_intxx_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
int
-main ()
+main (void)
{
int8_t a; int16_t b; int32_t c; a = b = c = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_intxx_t="yes"
-else
+else $as_nop
ac_cv_have_intxx_t="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_intxx_t" >&5
-$as_echo "$ac_cv_have_intxx_t" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_intxx_t" >&5
+printf "%s\n" "$ac_cv_have_intxx_t" >&6; }
if test "x$ac_cv_have_intxx_t" = "xyes" ; then
-$as_echo "#define HAVE_INTXX_T 1" >>confdefs.h
+printf "%s\n" "#define HAVE_INTXX_T 1" >>confdefs.h
have_intxx_t=1
fi
if (test -z "$have_intxx_t" && \
test "x$ac_cv_header_stdint_h" = "xyes")
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for intXX_t types in stdint.h" >&5
-$as_echo_n "checking for intXX_t types in stdint.h... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for intXX_t types in stdint.h" >&5
+printf %s "checking for intXX_t types in stdint.h... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdint.h>
int
-main ()
+main (void)
{
int8_t a; int16_t b; int32_t c; a = b = c = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
- $as_echo "#define HAVE_INTXX_T 1" >>confdefs.h
+ printf "%s\n" "#define HAVE_INTXX_T 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for int64_t type" >&5
-$as_echo_n "checking for int64_t type... " >&6; }
-if ${ac_cv_have_int64_t+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for int64_t type" >&5
+printf %s "checking for int64_t type... " >&6; }
+if test ${ac_cv_have_int64_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#include <sys/socket.h>
#ifdef HAVE_SYS_BITYPES_H
# include <sys/bitypes.h>
#endif
int
-main ()
+main (void)
{
int64_t a; a = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_int64_t="yes"
-else
+else $as_nop
ac_cv_have_int64_t="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_int64_t" >&5
-$as_echo "$ac_cv_have_int64_t" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_int64_t" >&5
+printf "%s\n" "$ac_cv_have_int64_t" >&6; }
if test "x$ac_cv_have_int64_t" = "xyes" ; then
-$as_echo "#define HAVE_INT64_T 1" >>confdefs.h
+printf "%s\n" "#define HAVE_INT64_T 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for u_intXX_t types" >&5
-$as_echo_n "checking for u_intXX_t types... " >&6; }
-if ${ac_cv_have_u_intxx_t+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for u_intXX_t types" >&5
+printf %s "checking for u_intXX_t types... " >&6; }
+if test ${ac_cv_have_u_intxx_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
int
-main ()
+main (void)
{
u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_u_intxx_t="yes"
-else
+else $as_nop
ac_cv_have_u_intxx_t="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_u_intxx_t" >&5
-$as_echo "$ac_cv_have_u_intxx_t" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_u_intxx_t" >&5
+printf "%s\n" "$ac_cv_have_u_intxx_t" >&6; }
if test "x$ac_cv_have_u_intxx_t" = "xyes" ; then
-$as_echo "#define HAVE_U_INTXX_T 1" >>confdefs.h
+printf "%s\n" "#define HAVE_U_INTXX_T 1" >>confdefs.h
have_u_intxx_t=1
fi
if test -z "$have_u_intxx_t" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for u_intXX_t types in sys/socket.h" >&5
-$as_echo_n "checking for u_intXX_t types in sys/socket.h... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for u_intXX_t types in sys/socket.h" >&5
+printf %s "checking for u_intXX_t types in sys/socket.h... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/socket.h>
int
-main ()
+main (void)
{
u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
- $as_echo "#define HAVE_U_INTXX_T 1" >>confdefs.h
+ printf "%s\n" "#define HAVE_U_INTXX_T 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for u_int64_t types" >&5
-$as_echo_n "checking for u_int64_t types... " >&6; }
-if ${ac_cv_have_u_int64_t+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for u_int64_t types" >&5
+printf %s "checking for u_int64_t types... " >&6; }
+if test ${ac_cv_have_u_int64_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
int
-main ()
+main (void)
{
u_int64_t a; a = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_u_int64_t="yes"
-else
+else $as_nop
ac_cv_have_u_int64_t="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_u_int64_t" >&5
-$as_echo "$ac_cv_have_u_int64_t" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_u_int64_t" >&5
+printf "%s\n" "$ac_cv_have_u_int64_t" >&6; }
if test "x$ac_cv_have_u_int64_t" = "xyes" ; then
-$as_echo "#define HAVE_U_INT64_T 1" >>confdefs.h
+printf "%s\n" "#define HAVE_U_INT64_T 1" >>confdefs.h
have_u_int64_t=1
fi
if (test -z "$have_u_int64_t" && \
test "x$ac_cv_header_sys_bitypes_h" = "xyes")
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for u_int64_t type in sys/bitypes.h" >&5
-$as_echo_n "checking for u_int64_t type in sys/bitypes.h... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for u_int64_t type in sys/bitypes.h" >&5
+printf %s "checking for u_int64_t type in sys/bitypes.h... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/bitypes.h>
int
-main ()
+main (void)
{
u_int64_t a; a = 1
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
- $as_echo "#define HAVE_U_INT64_T 1" >>confdefs.h
+ printf "%s\n" "#define HAVE_U_INT64_T 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
if test -z "$have_u_intxx_t" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uintXX_t types" >&5
-$as_echo_n "checking for uintXX_t types... " >&6; }
-if ${ac_cv_have_uintxx_t+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uintXX_t types" >&5
+printf %s "checking for uintXX_t types... " >&6; }
+if test ${ac_cv_have_uintxx_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
int
-main ()
+main (void)
{
uint8_t a;
uint16_t b;
uint32_t c;
a = b = c = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_uintxx_t="yes"
-else
+else $as_nop
ac_cv_have_uintxx_t="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_uintxx_t" >&5
-$as_echo "$ac_cv_have_uintxx_t" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_uintxx_t" >&5
+printf "%s\n" "$ac_cv_have_uintxx_t" >&6; }
if test "x$ac_cv_have_uintxx_t" = "xyes" ; then
-$as_echo "#define HAVE_UINTXX_T 1" >>confdefs.h
+printf "%s\n" "#define HAVE_UINTXX_T 1" >>confdefs.h
fi
fi
if (test -z "$have_uintxx_t" && \
test "x$ac_cv_header_stdint_h" = "xyes")
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uintXX_t types in stdint.h" >&5
-$as_echo_n "checking for uintXX_t types in stdint.h... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uintXX_t types in stdint.h" >&5
+printf %s "checking for uintXX_t types in stdint.h... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdint.h>
int
-main ()
+main (void)
{
uint8_t a; uint16_t b; uint32_t c; a = b = c = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
- $as_echo "#define HAVE_UINTXX_T 1" >>confdefs.h
+ printf "%s\n" "#define HAVE_UINTXX_T 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
if (test -z "$have_uintxx_t" && \
test "x$ac_cv_header_inttypes_h" = "xyes")
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uintXX_t types in inttypes.h" >&5
-$as_echo_n "checking for uintXX_t types in inttypes.h... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uintXX_t types in inttypes.h" >&5
+printf %s "checking for uintXX_t types in inttypes.h... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <inttypes.h>
int
-main ()
+main (void)
{
uint8_t a; uint16_t b; uint32_t c; a = b = c = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
- $as_echo "#define HAVE_UINTXX_T 1" >>confdefs.h
+ printf "%s\n" "#define HAVE_UINTXX_T 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
if (test -z "$have_u_intxx_t" || test -z "$have_intxx_t" && \
test "x$ac_cv_header_sys_bitypes_h" = "xyes")
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for intXX_t and u_intXX_t types in sys/bitypes.h" >&5
-$as_echo_n "checking for intXX_t and u_intXX_t types in sys/bitypes.h... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for intXX_t and u_intXX_t types in sys/bitypes.h" >&5
+printf %s "checking for intXX_t and u_intXX_t types in sys/bitypes.h... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/bitypes.h>
int
-main ()
+main (void)
{
int8_t a; int16_t b; int32_t c;
u_int8_t e; u_int16_t f; u_int32_t g;
a = b = c = e = f = g = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
- $as_echo "#define HAVE_U_INTXX_T 1" >>confdefs.h
+ printf "%s\n" "#define HAVE_U_INTXX_T 1" >>confdefs.h
- $as_echo "#define HAVE_INTXX_T 1" >>confdefs.h
+ printf "%s\n" "#define HAVE_INTXX_T 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for u_char" >&5
-$as_echo_n "checking for u_char... " >&6; }
-if ${ac_cv_have_u_char+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for u_char" >&5
+printf %s "checking for u_char... " >&6; }
+if test ${ac_cv_have_u_char+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
int
-main ()
+main (void)
{
u_char foo; foo = 125;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_u_char="yes"
-else
+else $as_nop
ac_cv_have_u_char="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_u_char" >&5
-$as_echo "$ac_cv_have_u_char" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_u_char" >&5
+printf "%s\n" "$ac_cv_have_u_char" >&6; }
if test "x$ac_cv_have_u_char" = "xyes" ; then
-$as_echo "#define HAVE_U_CHAR 1" >>confdefs.h
+printf "%s\n" "#define HAVE_U_CHAR 1" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "intmax_t" "ac_cv_type_intmax_t" "
#include <sys/types.h>
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
"
-if test "x$ac_cv_type_intmax_t" = xyes; then :
+if test "x$ac_cv_type_intmax_t" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_INTMAX_T 1
-_ACEOF
+printf "%s\n" "#define HAVE_INTMAX_T 1" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "uintmax_t" "ac_cv_type_uintmax_t" "
#include <sys/types.h>
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
"
-if test "x$ac_cv_type_uintmax_t" = xyes; then :
+if test "x$ac_cv_type_uintmax_t" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_UINTMAX_T 1
-_ACEOF
+printf "%s\n" "#define HAVE_UINTMAX_T 1" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" "#include <sys/types.h>
#include <sys/socket.h>
"
-if test "x$ac_cv_type_socklen_t" = xyes; then :
+if test "x$ac_cv_type_socklen_t" = xyes
+then :
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t equivalent" >&5
-$as_echo_n "checking for socklen_t equivalent... " >&6; }
- if ${curl_cv_socklen_t_equiv+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for socklen_t equivalent" >&5
+printf %s "checking for socklen_t equivalent... " >&6; }
+ if test ${curl_cv_socklen_t_equiv+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
# Systems have either "struct sockaddr *" or
# "void *" as the second argument to getpeername
curl_cv_socklen_t_equiv=
for arg2 in "struct sockaddr" void; do
for t in int size_t unsigned long "unsigned long"; do
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/socket.h>
int getpeername (int, $arg2 *, $t *);
int
-main ()
+main (void)
{
$t len;
getpeername(0,0,&len);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
curl_cv_socklen_t_equiv="$t"
break
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
done
done
if test "x$curl_cv_socklen_t_equiv" = x; then
as_fn_error $? "Cannot find a type to use in place of socklen_t" "$LINENO" 5
fi
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $curl_cv_socklen_t_equiv" >&5
-$as_echo "$curl_cv_socklen_t_equiv" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $curl_cv_socklen_t_equiv" >&5
+printf "%s\n" "$curl_cv_socklen_t_equiv" >&6; }
-cat >>confdefs.h <<_ACEOF
-#define socklen_t $curl_cv_socklen_t_equiv
-_ACEOF
+printf "%s\n" "#define socklen_t $curl_cv_socklen_t_equiv" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "sig_atomic_t" "ac_cv_type_sig_atomic_t" "#include <signal.h>
"
-if test "x$ac_cv_type_sig_atomic_t" = xyes; then :
+if test "x$ac_cv_type_sig_atomic_t" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_SIG_ATOMIC_T 1
-_ACEOF
+printf "%s\n" "#define HAVE_SIG_ATOMIC_T 1" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "sighandler_t" "ac_cv_type_sighandler_t" "#include <signal.h>
"
-if test "x$ac_cv_type_sighandler_t" = xyes; then :
+if test "x$ac_cv_type_sighandler_t" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_SIGHANDLER_T 1
-_ACEOF
+printf "%s\n" "#define HAVE_SIGHANDLER_T 1" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "fsblkcnt_t" "ac_cv_type_fsblkcnt_t" "
#include <sys/types.h>
#ifdef HAVE_SYS_BITYPES_H
#include <sys/bitypes.h>
#endif
#ifdef HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#ifdef HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
"
-if test "x$ac_cv_type_fsblkcnt_t" = xyes; then :
+if test "x$ac_cv_type_fsblkcnt_t" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_FSBLKCNT_T 1
-_ACEOF
+printf "%s\n" "#define HAVE_FSBLKCNT_T 1" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "fsfilcnt_t" "ac_cv_type_fsfilcnt_t" "
#include <sys/types.h>
#ifdef HAVE_SYS_BITYPES_H
#include <sys/bitypes.h>
#endif
#ifdef HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#ifdef HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
"
-if test "x$ac_cv_type_fsfilcnt_t" = xyes; then :
+if test "x$ac_cv_type_fsfilcnt_t" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_FSFILCNT_T 1
-_ACEOF
+printf "%s\n" "#define HAVE_FSFILCNT_T 1" >>confdefs.h
fi
ac_fn_c_check_member "$LINENO" "struct statfs" "f_files" "ac_cv_member_struct_statfs_f_files" "
#include <sys/param.h>
#include <sys/types.h>
#ifdef HAVE_SYS_BITYPES_H
#include <sys/bitypes.h>
#endif
#ifdef HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#ifdef HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
"
-if test "x$ac_cv_member_struct_statfs_f_files" = xyes; then :
+if test "x$ac_cv_member_struct_statfs_f_files" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_STATFS_F_FILES 1
-_ACEOF
+printf "%s\n" "#define HAVE_STRUCT_STATFS_F_FILES 1" >>confdefs.h
fi
ac_fn_c_check_member "$LINENO" "struct statfs" "f_flags" "ac_cv_member_struct_statfs_f_flags" "
#include <sys/param.h>
#include <sys/types.h>
#ifdef HAVE_SYS_BITYPES_H
#include <sys/bitypes.h>
#endif
#ifdef HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#ifdef HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
"
-if test "x$ac_cv_member_struct_statfs_f_flags" = xyes; then :
+if test "x$ac_cv_member_struct_statfs_f_flags" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_STATFS_F_FLAGS 1
-_ACEOF
+printf "%s\n" "#define HAVE_STRUCT_STATFS_F_FLAGS 1" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "in_addr_t" "ac_cv_type_in_addr_t" "#include <sys/types.h>
#include <netinet/in.h>
"
-if test "x$ac_cv_type_in_addr_t" = xyes; then :
+if test "x$ac_cv_type_in_addr_t" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_IN_ADDR_T 1
-_ACEOF
+printf "%s\n" "#define HAVE_IN_ADDR_T 1" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "in_port_t" "ac_cv_type_in_port_t" "#include <sys/types.h>
#include <netinet/in.h>
"
-if test "x$ac_cv_type_in_port_t" = xyes; then :
+if test "x$ac_cv_type_in_port_t" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_IN_PORT_T 1
-_ACEOF
+printf "%s\n" "#define HAVE_IN_PORT_T 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for size_t" >&5
-$as_echo_n "checking for size_t... " >&6; }
-if ${ac_cv_have_size_t+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for size_t" >&5
+printf %s "checking for size_t... " >&6; }
+if test ${ac_cv_have_size_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
int
-main ()
+main (void)
{
size_t foo; foo = 1235;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_size_t="yes"
-else
+else $as_nop
ac_cv_have_size_t="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_size_t" >&5
-$as_echo "$ac_cv_have_size_t" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_size_t" >&5
+printf "%s\n" "$ac_cv_have_size_t" >&6; }
if test "x$ac_cv_have_size_t" = "xyes" ; then
-$as_echo "#define HAVE_SIZE_T 1" >>confdefs.h
+printf "%s\n" "#define HAVE_SIZE_T 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ssize_t" >&5
-$as_echo_n "checking for ssize_t... " >&6; }
-if ${ac_cv_have_ssize_t+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ssize_t" >&5
+printf %s "checking for ssize_t... " >&6; }
+if test ${ac_cv_have_ssize_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
int
-main ()
+main (void)
{
ssize_t foo; foo = 1235;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_ssize_t="yes"
-else
+else $as_nop
ac_cv_have_ssize_t="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_ssize_t" >&5
-$as_echo "$ac_cv_have_ssize_t" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_ssize_t" >&5
+printf "%s\n" "$ac_cv_have_ssize_t" >&6; }
if test "x$ac_cv_have_ssize_t" = "xyes" ; then
-$as_echo "#define HAVE_SSIZE_T 1" >>confdefs.h
+printf "%s\n" "#define HAVE_SSIZE_T 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_t" >&5
-$as_echo_n "checking for clock_t... " >&6; }
-if ${ac_cv_have_clock_t+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_t" >&5
+printf %s "checking for clock_t... " >&6; }
+if test ${ac_cv_have_clock_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <time.h>
int
-main ()
+main (void)
{
clock_t foo; foo = 1235;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_clock_t="yes"
-else
+else $as_nop
ac_cv_have_clock_t="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_clock_t" >&5
-$as_echo "$ac_cv_have_clock_t" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_clock_t" >&5
+printf "%s\n" "$ac_cv_have_clock_t" >&6; }
if test "x$ac_cv_have_clock_t" = "xyes" ; then
-$as_echo "#define HAVE_CLOCK_T 1" >>confdefs.h
+printf "%s\n" "#define HAVE_CLOCK_T 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sa_family_t" >&5
-$as_echo_n "checking for sa_family_t... " >&6; }
-if ${ac_cv_have_sa_family_t+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sa_family_t" >&5
+printf %s "checking for sa_family_t... " >&6; }
+if test ${ac_cv_have_sa_family_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/socket.h>
int
-main ()
+main (void)
{
sa_family_t foo; foo = 1235;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_sa_family_t="yes"
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int
-main ()
+main (void)
{
sa_family_t foo; foo = 1235;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_sa_family_t="yes"
-else
+else $as_nop
ac_cv_have_sa_family_t="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_sa_family_t" >&5
-$as_echo "$ac_cv_have_sa_family_t" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_sa_family_t" >&5
+printf "%s\n" "$ac_cv_have_sa_family_t" >&6; }
if test "x$ac_cv_have_sa_family_t" = "xyes" ; then
-$as_echo "#define HAVE_SA_FAMILY_T 1" >>confdefs.h
+printf "%s\n" "#define HAVE_SA_FAMILY_T 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pid_t" >&5
-$as_echo_n "checking for pid_t... " >&6; }
-if ${ac_cv_have_pid_t+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pid_t" >&5
+printf %s "checking for pid_t... " >&6; }
+if test ${ac_cv_have_pid_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
int
-main ()
+main (void)
{
pid_t foo; foo = 1235;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_pid_t="yes"
-else
+else $as_nop
ac_cv_have_pid_t="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_pid_t" >&5
-$as_echo "$ac_cv_have_pid_t" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_pid_t" >&5
+printf "%s\n" "$ac_cv_have_pid_t" >&6; }
if test "x$ac_cv_have_pid_t" = "xyes" ; then
-$as_echo "#define HAVE_PID_T 1" >>confdefs.h
+printf "%s\n" "#define HAVE_PID_T 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mode_t" >&5
-$as_echo_n "checking for mode_t... " >&6; }
-if ${ac_cv_have_mode_t+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mode_t" >&5
+printf %s "checking for mode_t... " >&6; }
+if test ${ac_cv_have_mode_t+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
int
-main ()
+main (void)
{
mode_t foo; foo = 1235;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_mode_t="yes"
-else
+else $as_nop
ac_cv_have_mode_t="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_mode_t" >&5
-$as_echo "$ac_cv_have_mode_t" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_mode_t" >&5
+printf "%s\n" "$ac_cv_have_mode_t" >&6; }
if test "x$ac_cv_have_mode_t" = "xyes" ; then
-$as_echo "#define HAVE_MODE_T 1" >>confdefs.h
+printf "%s\n" "#define HAVE_MODE_T 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct sockaddr_storage" >&5
-$as_echo_n "checking for struct sockaddr_storage... " >&6; }
-if ${ac_cv_have_struct_sockaddr_storage+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct sockaddr_storage" >&5
+printf %s "checking for struct sockaddr_storage... " >&6; }
+if test ${ac_cv_have_struct_sockaddr_storage+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/socket.h>
int
-main ()
+main (void)
{
struct sockaddr_storage s;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_struct_sockaddr_storage="yes"
-else
+else $as_nop
ac_cv_have_struct_sockaddr_storage="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_struct_sockaddr_storage" >&5
-$as_echo "$ac_cv_have_struct_sockaddr_storage" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_struct_sockaddr_storage" >&5
+printf "%s\n" "$ac_cv_have_struct_sockaddr_storage" >&6; }
if test "x$ac_cv_have_struct_sockaddr_storage" = "xyes" ; then
-$as_echo "#define HAVE_STRUCT_SOCKADDR_STORAGE 1" >>confdefs.h
+printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_STORAGE 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct sockaddr_in6" >&5
-$as_echo_n "checking for struct sockaddr_in6... " >&6; }
-if ${ac_cv_have_struct_sockaddr_in6+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct sockaddr_in6" >&5
+printf %s "checking for struct sockaddr_in6... " >&6; }
+if test ${ac_cv_have_struct_sockaddr_in6+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <netinet/in.h>
int
-main ()
+main (void)
{
struct sockaddr_in6 s; s.sin6_family = 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_struct_sockaddr_in6="yes"
-else
+else $as_nop
ac_cv_have_struct_sockaddr_in6="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_struct_sockaddr_in6" >&5
-$as_echo "$ac_cv_have_struct_sockaddr_in6" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_struct_sockaddr_in6" >&5
+printf "%s\n" "$ac_cv_have_struct_sockaddr_in6" >&6; }
if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then
-$as_echo "#define HAVE_STRUCT_SOCKADDR_IN6 1" >>confdefs.h
+printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_IN6 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct in6_addr" >&5
-$as_echo_n "checking for struct in6_addr... " >&6; }
-if ${ac_cv_have_struct_in6_addr+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct in6_addr" >&5
+printf %s "checking for struct in6_addr... " >&6; }
+if test ${ac_cv_have_struct_in6_addr+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <netinet/in.h>
int
-main ()
+main (void)
{
struct in6_addr s; s.s6_addr[0] = 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_struct_in6_addr="yes"
-else
+else $as_nop
ac_cv_have_struct_in6_addr="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_struct_in6_addr" >&5
-$as_echo "$ac_cv_have_struct_in6_addr" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_struct_in6_addr" >&5
+printf "%s\n" "$ac_cv_have_struct_in6_addr" >&6; }
if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then
-$as_echo "#define HAVE_STRUCT_IN6_ADDR 1" >>confdefs.h
+printf "%s\n" "#define HAVE_STRUCT_IN6_ADDR 1" >>confdefs.h
ac_fn_c_check_member "$LINENO" "struct sockaddr_in6" "sin6_scope_id" "ac_cv_member_struct_sockaddr_in6_sin6_scope_id" "
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <netinet/in.h>
"
-if test "x$ac_cv_member_struct_sockaddr_in6_sin6_scope_id" = xyes; then :
+if test "x$ac_cv_member_struct_sockaddr_in6_sin6_scope_id" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1
-_ACEOF
+printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1" >>confdefs.h
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct addrinfo" >&5
-$as_echo_n "checking for struct addrinfo... " >&6; }
-if ${ac_cv_have_struct_addrinfo+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct addrinfo" >&5
+printf %s "checking for struct addrinfo... " >&6; }
+if test ${ac_cv_have_struct_addrinfo+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int
-main ()
+main (void)
{
struct addrinfo s; s.ai_flags = AI_PASSIVE;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_struct_addrinfo="yes"
-else
+else $as_nop
ac_cv_have_struct_addrinfo="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_struct_addrinfo" >&5
-$as_echo "$ac_cv_have_struct_addrinfo" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_struct_addrinfo" >&5
+printf "%s\n" "$ac_cv_have_struct_addrinfo" >&6; }
if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then
-$as_echo "#define HAVE_STRUCT_ADDRINFO 1" >>confdefs.h
+printf "%s\n" "#define HAVE_STRUCT_ADDRINFO 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct timeval" >&5
-$as_echo_n "checking for struct timeval... " >&6; }
-if ${ac_cv_have_struct_timeval+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct timeval" >&5
+printf %s "checking for struct timeval... " >&6; }
+if test ${ac_cv_have_struct_timeval+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/time.h>
int
-main ()
+main (void)
{
struct timeval tv; tv.tv_sec = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_struct_timeval="yes"
-else
+else $as_nop
ac_cv_have_struct_timeval="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_struct_timeval" >&5
-$as_echo "$ac_cv_have_struct_timeval" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_struct_timeval" >&5
+printf "%s\n" "$ac_cv_have_struct_timeval" >&6; }
if test "x$ac_cv_have_struct_timeval" = "xyes" ; then
-$as_echo "#define HAVE_STRUCT_TIMEVAL 1" >>confdefs.h
+printf "%s\n" "#define HAVE_STRUCT_TIMEVAL 1" >>confdefs.h
have_struct_timeval=1
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct timespec" >&5
-$as_echo_n "checking for struct timespec... " >&6; }
-if ${ac_cv_have_struct_timespec+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct timespec" >&5
+printf %s "checking for struct timespec... " >&6; }
+if test ${ac_cv_have_struct_timespec+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_TIME_H
# include <time.h>
#endif
int
-main ()
+main (void)
{
struct timespec ts; ts.tv_sec = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_struct_timespec="yes"
-else
+else $as_nop
ac_cv_have_struct_timespec="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_struct_timespec" >&5
-$as_echo "$ac_cv_have_struct_timespec" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_struct_timespec" >&5
+printf "%s\n" "$ac_cv_have_struct_timespec" >&6; }
if test "x$ac_cv_have_struct_timespec" = "xyes" ; then
-$as_echo "#define HAVE_STRUCT_TIMESPEC 1" >>confdefs.h
+printf "%s\n" "#define HAVE_STRUCT_TIMESPEC 1" >>confdefs.h
have_struct_timespec=1
fi
# We need int64_t or else certain parts of the compile will fail.
if test "x$ac_cv_have_int64_t" = "xno" && \
test "x$ac_cv_sizeof_long_int" != "x8" && \
test "x$ac_cv_sizeof_long_long_int" = "x0" ; then
echo "OpenSSH requires int64_t support. Contact your vendor or install"
echo "an alternative compiler (I.E., GCC) before continuing."
echo ""
exit 1;
else
- if test "$cross_compiling" = yes; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: Assuming working snprintf()" >&5
-$as_echo "$as_me: WARNING: cross compiling: Assuming working snprintf()" >&2;}
+ if test "$cross_compiling" = yes
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: Assuming working snprintf()" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: Assuming working snprintf()" >&2;}
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_SNPRINTF
main()
{
char buf[50];
char expected_out[50];
int mazsize = 50 ;
#if (SIZEOF_LONG_INT == 8)
long int num = 0x7fffffffffffffff;
#else
long long num = 0x7fffffffffffffffll;
#endif
strcpy(expected_out, "9223372036854775807");
snprintf(buf, mazsize, "%lld", num);
if(strcmp(buf, expected_out) != 0)
exit(1);
exit(0);
}
#else
main() { exit(0); }
#endif
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_run "$LINENO"
+then :
true
-else
- $as_echo "#define BROKEN_SNPRINTF 1" >>confdefs.h
+else $as_nop
+ printf "%s\n" "#define BROKEN_SNPRINTF 1" >>confdefs.h
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
# look for field 'ut_host' in header 'utmp.h'
ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_host
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_host field in utmp.h" >&5
-$as_echo_n "checking for ut_host field in utmp.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_host field in utmp.h" >&5
+printf %s "checking for ut_host field in utmp.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmp.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_host" >/dev/null 2>&1; then :
+ $EGREP "ut_host" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_HOST_IN_UTMP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_HOST_IN_UTMP 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_host' in header 'utmpx.h'
ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_host
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_host field in utmpx.h" >&5
-$as_echo_n "checking for ut_host field in utmpx.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_host field in utmpx.h" >&5
+printf %s "checking for ut_host field in utmpx.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmpx.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_host" >/dev/null 2>&1; then :
+ $EGREP "ut_host" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_HOST_IN_UTMPX 1" >>confdefs.h
+printf "%s\n" "#define HAVE_HOST_IN_UTMPX 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'syslen' in header 'utmpx.h'
ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"syslen
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for syslen field in utmpx.h" >&5
-$as_echo_n "checking for syslen field in utmpx.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for syslen field in utmpx.h" >&5
+printf %s "checking for syslen field in utmpx.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmpx.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "syslen" >/dev/null 2>&1; then :
+ $EGREP "syslen" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_SYSLEN_IN_UTMPX 1" >>confdefs.h
+printf "%s\n" "#define HAVE_SYSLEN_IN_UTMPX 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_pid' in header 'utmp.h'
ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_pid
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_pid field in utmp.h" >&5
-$as_echo_n "checking for ut_pid field in utmp.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_pid field in utmp.h" >&5
+printf %s "checking for ut_pid field in utmp.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmp.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_pid" >/dev/null 2>&1; then :
+ $EGREP "ut_pid" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_PID_IN_UTMP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_PID_IN_UTMP 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_type' in header 'utmp.h'
ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_type
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_type field in utmp.h" >&5
-$as_echo_n "checking for ut_type field in utmp.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_type field in utmp.h" >&5
+printf %s "checking for ut_type field in utmp.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmp.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_type" >/dev/null 2>&1; then :
+ $EGREP "ut_type" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_TYPE_IN_UTMP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_TYPE_IN_UTMP 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_type' in header 'utmpx.h'
ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_type
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_type field in utmpx.h" >&5
-$as_echo_n "checking for ut_type field in utmpx.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_type field in utmpx.h" >&5
+printf %s "checking for ut_type field in utmpx.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmpx.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_type" >/dev/null 2>&1; then :
+ $EGREP "ut_type" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_TYPE_IN_UTMPX 1" >>confdefs.h
+printf "%s\n" "#define HAVE_TYPE_IN_UTMPX 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_tv' in header 'utmp.h'
ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_tv
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_tv field in utmp.h" >&5
-$as_echo_n "checking for ut_tv field in utmp.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_tv field in utmp.h" >&5
+printf %s "checking for ut_tv field in utmp.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmp.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_tv" >/dev/null 2>&1; then :
+ $EGREP "ut_tv" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_TV_IN_UTMP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_TV_IN_UTMP 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_id' in header 'utmp.h'
ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_id
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_id field in utmp.h" >&5
-$as_echo_n "checking for ut_id field in utmp.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_id field in utmp.h" >&5
+printf %s "checking for ut_id field in utmp.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmp.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_id" >/dev/null 2>&1; then :
+ $EGREP "ut_id" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_ID_IN_UTMP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_ID_IN_UTMP 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_id' in header 'utmpx.h'
ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_id
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_id field in utmpx.h" >&5
-$as_echo_n "checking for ut_id field in utmpx.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_id field in utmpx.h" >&5
+printf %s "checking for ut_id field in utmpx.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmpx.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_id" >/dev/null 2>&1; then :
+ $EGREP "ut_id" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_ID_IN_UTMPX 1" >>confdefs.h
+printf "%s\n" "#define HAVE_ID_IN_UTMPX 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_addr' in header 'utmp.h'
ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_addr
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_addr field in utmp.h" >&5
-$as_echo_n "checking for ut_addr field in utmp.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_addr field in utmp.h" >&5
+printf %s "checking for ut_addr field in utmp.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmp.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_addr" >/dev/null 2>&1; then :
+ $EGREP "ut_addr" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_ADDR_IN_UTMP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_ADDR_IN_UTMP 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_addr' in header 'utmpx.h'
ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_addr
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_addr field in utmpx.h" >&5
-$as_echo_n "checking for ut_addr field in utmpx.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_addr field in utmpx.h" >&5
+printf %s "checking for ut_addr field in utmpx.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmpx.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_addr" >/dev/null 2>&1; then :
+ $EGREP "ut_addr" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_ADDR_IN_UTMPX 1" >>confdefs.h
+printf "%s\n" "#define HAVE_ADDR_IN_UTMPX 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_addr_v6' in header 'utmp.h'
ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_addr_v6
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_addr_v6 field in utmp.h" >&5
-$as_echo_n "checking for ut_addr_v6 field in utmp.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_addr_v6 field in utmp.h" >&5
+printf %s "checking for ut_addr_v6 field in utmp.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmp.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_addr_v6" >/dev/null 2>&1; then :
+ $EGREP "ut_addr_v6" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_ADDR_V6_IN_UTMP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_ADDR_V6_IN_UTMP 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_addr_v6' in header 'utmpx.h'
ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_addr_v6
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_addr_v6 field in utmpx.h" >&5
-$as_echo_n "checking for ut_addr_v6 field in utmpx.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_addr_v6 field in utmpx.h" >&5
+printf %s "checking for ut_addr_v6 field in utmpx.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmpx.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_addr_v6" >/dev/null 2>&1; then :
+ $EGREP "ut_addr_v6" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_ADDR_V6_IN_UTMPX 1" >>confdefs.h
+printf "%s\n" "#define HAVE_ADDR_V6_IN_UTMPX 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_exit' in header 'utmp.h'
ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_exit
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_exit field in utmp.h" >&5
-$as_echo_n "checking for ut_exit field in utmp.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_exit field in utmp.h" >&5
+printf %s "checking for ut_exit field in utmp.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmp.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_exit" >/dev/null 2>&1; then :
+ $EGREP "ut_exit" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_EXIT_IN_UTMP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_EXIT_IN_UTMP 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_time' in header 'utmp.h'
ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_time
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_time field in utmp.h" >&5
-$as_echo_n "checking for ut_time field in utmp.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_time field in utmp.h" >&5
+printf %s "checking for ut_time field in utmp.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmp.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_time" >/dev/null 2>&1; then :
+ $EGREP "ut_time" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_TIME_IN_UTMP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_TIME_IN_UTMP 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_time' in header 'utmpx.h'
ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_time
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_time field in utmpx.h" >&5
-$as_echo_n "checking for ut_time field in utmpx.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_time field in utmpx.h" >&5
+printf %s "checking for ut_time field in utmpx.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmpx.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_time" >/dev/null 2>&1; then :
+ $EGREP "ut_time" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_TIME_IN_UTMPX 1" >>confdefs.h
+printf "%s\n" "#define HAVE_TIME_IN_UTMPX 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_tv' in header 'utmpx.h'
ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_tv
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_tv field in utmpx.h" >&5
-$as_echo_n "checking for ut_tv field in utmpx.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_tv field in utmpx.h" >&5
+printf %s "checking for ut_tv field in utmpx.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmpx.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_tv" >/dev/null 2>&1; then :
+ $EGREP "ut_tv" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_TV_IN_UTMPX 1" >>confdefs.h
+printf "%s\n" "#define HAVE_TV_IN_UTMPX 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# look for field 'ut_ss' in header 'utmpx.h'
ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
ossh_varname="ossh_cv_$ossh_safe""_has_"ut_ss
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ut_ss field in utmpx.h" >&5
-$as_echo_n "checking for ut_ss field in utmpx.h... " >&6; }
- if eval \${$ossh_varname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ut_ss field in utmpx.h" >&5
+printf %s "checking for ut_ss field in utmpx.h... " >&6; }
+ if eval test \${$ossh_varname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <utmpx.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "ut_ss" >/dev/null 2>&1; then :
+ $EGREP "ut_ss" >/dev/null 2>&1
+then :
eval "$ossh_varname=yes"
-else
+else $as_nop
eval "$ossh_varname=no"
fi
-rm -f conftest*
+rm -rf conftest*
fi
ossh_result=`eval 'echo $'"$ossh_varname"`
if test -n "`echo $ossh_varname`"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
-$as_echo "$ossh_result" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ossh_result" >&5
+printf "%s\n" "$ossh_result" >&6; }
if test "x$ossh_result" = "xyes"; then
-$as_echo "#define HAVE_SS_IN_UTMPX 1" >>confdefs.h
+printf "%s\n" "#define HAVE_SS_IN_UTMPX 1" >>confdefs.h
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
ac_fn_c_check_member "$LINENO" "struct stat" "st_blksize" "ac_cv_member_struct_stat_st_blksize" "$ac_includes_default"
-if test "x$ac_cv_member_struct_stat_st_blksize" = xyes; then :
+if test "x$ac_cv_member_struct_stat_st_blksize" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_STAT_ST_BLKSIZE 1
-_ACEOF
+printf "%s\n" "#define HAVE_STRUCT_STAT_ST_BLKSIZE 1" >>confdefs.h
fi
ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim" "ac_cv_member_struct_stat_st_mtim" "$ac_includes_default"
-if test "x$ac_cv_member_struct_stat_st_mtim" = xyes; then :
+if test "x$ac_cv_member_struct_stat_st_mtim" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_STAT_ST_MTIM 1
-_ACEOF
+printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIM 1" >>confdefs.h
fi
ac_fn_c_check_member "$LINENO" "struct stat" "st_mtime" "ac_cv_member_struct_stat_st_mtime" "$ac_includes_default"
-if test "x$ac_cv_member_struct_stat_st_mtime" = xyes; then :
+if test "x$ac_cv_member_struct_stat_st_mtime" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_STAT_ST_MTIME 1
-_ACEOF
+printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIME 1" >>confdefs.h
fi
ac_fn_c_check_member "$LINENO" "struct passwd" "pw_gecos" "ac_cv_member_struct_passwd_pw_gecos" "
#include <sys/types.h>
#include <pwd.h>
"
-if test "x$ac_cv_member_struct_passwd_pw_gecos" = xyes; then :
+if test "x$ac_cv_member_struct_passwd_pw_gecos" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_PASSWD_PW_GECOS 1
-_ACEOF
+printf "%s\n" "#define HAVE_STRUCT_PASSWD_PW_GECOS 1" >>confdefs.h
fi
ac_fn_c_check_member "$LINENO" "struct passwd" "pw_class" "ac_cv_member_struct_passwd_pw_class" "
#include <sys/types.h>
#include <pwd.h>
"
-if test "x$ac_cv_member_struct_passwd_pw_class" = xyes; then :
+if test "x$ac_cv_member_struct_passwd_pw_class" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_PASSWD_PW_CLASS 1
-_ACEOF
+printf "%s\n" "#define HAVE_STRUCT_PASSWD_PW_CLASS 1" >>confdefs.h
fi
ac_fn_c_check_member "$LINENO" "struct passwd" "pw_change" "ac_cv_member_struct_passwd_pw_change" "
#include <sys/types.h>
#include <pwd.h>
"
-if test "x$ac_cv_member_struct_passwd_pw_change" = xyes; then :
+if test "x$ac_cv_member_struct_passwd_pw_change" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_PASSWD_PW_CHANGE 1
-_ACEOF
+printf "%s\n" "#define HAVE_STRUCT_PASSWD_PW_CHANGE 1" >>confdefs.h
fi
ac_fn_c_check_member "$LINENO" "struct passwd" "pw_expire" "ac_cv_member_struct_passwd_pw_expire" "
#include <sys/types.h>
#include <pwd.h>
"
-if test "x$ac_cv_member_struct_passwd_pw_expire" = xyes; then :
+if test "x$ac_cv_member_struct_passwd_pw_expire" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_PASSWD_PW_EXPIRE 1
-_ACEOF
+printf "%s\n" "#define HAVE_STRUCT_PASSWD_PW_EXPIRE 1" >>confdefs.h
fi
ac_fn_c_check_member "$LINENO" "struct __res_state" "retrans" "ac_cv_member_struct___res_state_retrans" "
#include <stdio.h>
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
"
-if test "x$ac_cv_member_struct___res_state_retrans" = xyes; then :
+if test "x$ac_cv_member_struct___res_state_retrans" = xyes
+then :
-else
+else $as_nop
-$as_echo "#define __res_state state" >>confdefs.h
+printf "%s\n" "#define __res_state state" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ss_family field in struct sockaddr_storage" >&5
-$as_echo_n "checking for ss_family field in struct sockaddr_storage... " >&6; }
-if ${ac_cv_have_ss_family_in_struct_ss+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ss_family field in struct sockaddr_storage" >&5
+printf %s "checking for ss_family field in struct sockaddr_storage... " >&6; }
+if test ${ac_cv_have_ss_family_in_struct_ss+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/socket.h>
int
-main ()
+main (void)
{
struct sockaddr_storage s; s.ss_family = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_ss_family_in_struct_ss="yes"
-else
+else $as_nop
ac_cv_have_ss_family_in_struct_ss="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_ss_family_in_struct_ss" >&5
-$as_echo "$ac_cv_have_ss_family_in_struct_ss" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_ss_family_in_struct_ss" >&5
+printf "%s\n" "$ac_cv_have_ss_family_in_struct_ss" >&6; }
if test "x$ac_cv_have_ss_family_in_struct_ss" = "xyes" ; then
-$as_echo "#define HAVE_SS_FAMILY_IN_SS 1" >>confdefs.h
+printf "%s\n" "#define HAVE_SS_FAMILY_IN_SS 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __ss_family field in struct sockaddr_storage" >&5
-$as_echo_n "checking for __ss_family field in struct sockaddr_storage... " >&6; }
-if ${ac_cv_have___ss_family_in_struct_ss+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __ss_family field in struct sockaddr_storage" >&5
+printf %s "checking for __ss_family field in struct sockaddr_storage... " >&6; }
+if test ${ac_cv_have___ss_family_in_struct_ss+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/socket.h>
int
-main ()
+main (void)
{
struct sockaddr_storage s; s.__ss_family = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have___ss_family_in_struct_ss="yes"
-else
+else $as_nop
ac_cv_have___ss_family_in_struct_ss="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have___ss_family_in_struct_ss" >&5
-$as_echo "$ac_cv_have___ss_family_in_struct_ss" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have___ss_family_in_struct_ss" >&5
+printf "%s\n" "$ac_cv_have___ss_family_in_struct_ss" >&6; }
if test "x$ac_cv_have___ss_family_in_struct_ss" = "xyes" ; then
-$as_echo "#define HAVE___SS_FAMILY_IN_SS 1" >>confdefs.h
+printf "%s\n" "#define HAVE___SS_FAMILY_IN_SS 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for msg_accrights field in struct msghdr" >&5
-$as_echo_n "checking for msg_accrights field in struct msghdr... " >&6; }
-if ${ac_cv_have_accrights_in_msghdr+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for msg_accrights field in struct msghdr" >&5
+printf %s "checking for msg_accrights field in struct msghdr... " >&6; }
+if test ${ac_cv_have_accrights_in_msghdr+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <stdlib.h>
int
-main ()
+main (void)
{
#ifdef msg_accrights
#error "msg_accrights is a macro"
exit(1);
#endif
struct msghdr m;
m.msg_accrights = 0;
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_accrights_in_msghdr="yes"
-else
+else $as_nop
ac_cv_have_accrights_in_msghdr="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_accrights_in_msghdr" >&5
-$as_echo "$ac_cv_have_accrights_in_msghdr" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_accrights_in_msghdr" >&5
+printf "%s\n" "$ac_cv_have_accrights_in_msghdr" >&6; }
if test "x$ac_cv_have_accrights_in_msghdr" = "xyes" ; then
-$as_echo "#define HAVE_ACCRIGHTS_IN_MSGHDR 1" >>confdefs.h
+printf "%s\n" "#define HAVE_ACCRIGHTS_IN_MSGHDR 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if struct statvfs.f_fsid is integral type" >&5
-$as_echo_n "checking if struct statvfs.f_fsid is integral type... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if struct statvfs.f_fsid is integral type" >&5
+printf %s "checking if struct statvfs.f_fsid is integral type... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/param.h>
#include <sys/stat.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
int
-main ()
+main (void)
{
struct statvfs s; s.f_fsid = 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if fsid_t has member val" >&5
-$as_echo_n "checking if fsid_t has member val... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if fsid_t has member val" >&5
+printf %s "checking if fsid_t has member val... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/statvfs.h>
int
-main ()
+main (void)
{
fsid_t t; t.val[0] = 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define FSID_HAS_VAL 1" >>confdefs.h
+printf "%s\n" "#define FSID_HAS_VAL 1" >>confdefs.h
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if f_fsid has member __val" >&5
-$as_echo_n "checking if f_fsid has member __val... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if f_fsid has member __val" >&5
+printf %s "checking if f_fsid has member __val... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/statvfs.h>
int
-main ()
+main (void)
{
fsid_t t; t.__val[0] = 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define FSID_HAS___VAL 1" >>confdefs.h
+printf "%s\n" "#define FSID_HAS___VAL 1" >>confdefs.h
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for msg_control field in struct msghdr" >&5
-$as_echo_n "checking for msg_control field in struct msghdr... " >&6; }
-if ${ac_cv_have_control_in_msghdr+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for msg_control field in struct msghdr" >&5
+printf %s "checking for msg_control field in struct msghdr... " >&6; }
+if test ${ac_cv_have_control_in_msghdr+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <stdlib.h>
int
-main ()
+main (void)
{
#ifdef msg_control
#error "msg_control is a macro"
exit(1);
#endif
struct msghdr m;
m.msg_control = 0;
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_have_control_in_msghdr="yes"
-else
+else $as_nop
ac_cv_have_control_in_msghdr="no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_control_in_msghdr" >&5
-$as_echo "$ac_cv_have_control_in_msghdr" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_control_in_msghdr" >&5
+printf "%s\n" "$ac_cv_have_control_in_msghdr" >&6; }
if test "x$ac_cv_have_control_in_msghdr" = "xyes" ; then
-$as_echo "#define HAVE_CONTROL_IN_MSGHDR 1" >>confdefs.h
+printf "%s\n" "#define HAVE_CONTROL_IN_MSGHDR 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if libc defines __progname" >&5
-$as_echo_n "checking if libc defines __progname... " >&6; }
-if ${ac_cv_libc_defines___progname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libc defines __progname" >&5
+printf %s "checking if libc defines __progname... " >&6; }
+if test ${ac_cv_libc_defines___progname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
int
-main ()
+main (void)
{
extern char *__progname; printf("%s", __progname);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_libc_defines___progname="yes"
-else
+else $as_nop
ac_cv_libc_defines___progname="no"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libc_defines___progname" >&5
-$as_echo "$ac_cv_libc_defines___progname" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libc_defines___progname" >&5
+printf "%s\n" "$ac_cv_libc_defines___progname" >&6; }
if test "x$ac_cv_libc_defines___progname" = "xyes" ; then
-$as_echo "#define HAVE___PROGNAME 1" >>confdefs.h
+printf "%s\n" "#define HAVE___PROGNAME 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC implements __FUNCTION__" >&5
-$as_echo_n "checking whether $CC implements __FUNCTION__... " >&6; }
-if ${ac_cv_cc_implements___FUNCTION__+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC implements __FUNCTION__" >&5
+printf %s "checking whether $CC implements __FUNCTION__... " >&6; }
+if test ${ac_cv_cc_implements___FUNCTION__+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
int
-main ()
+main (void)
{
printf("%s", __FUNCTION__);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_cc_implements___FUNCTION__="yes"
-else
+else $as_nop
ac_cv_cc_implements___FUNCTION__="no"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_implements___FUNCTION__" >&5
-$as_echo "$ac_cv_cc_implements___FUNCTION__" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_implements___FUNCTION__" >&5
+printf "%s\n" "$ac_cv_cc_implements___FUNCTION__" >&6; }
if test "x$ac_cv_cc_implements___FUNCTION__" = "xyes" ; then
-$as_echo "#define HAVE___FUNCTION__ 1" >>confdefs.h
+printf "%s\n" "#define HAVE___FUNCTION__ 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC implements __func__" >&5
-$as_echo_n "checking whether $CC implements __func__... " >&6; }
-if ${ac_cv_cc_implements___func__+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC implements __func__" >&5
+printf %s "checking whether $CC implements __func__... " >&6; }
+if test ${ac_cv_cc_implements___func__+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
int
-main ()
+main (void)
{
printf("%s", __func__);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_cc_implements___func__="yes"
-else
+else $as_nop
ac_cv_cc_implements___func__="no"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_implements___func__" >&5
-$as_echo "$ac_cv_cc_implements___func__" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_implements___func__" >&5
+printf "%s\n" "$ac_cv_cc_implements___func__" >&6; }
if test "x$ac_cv_cc_implements___func__" = "xyes" ; then
-$as_echo "#define HAVE___func__ 1" >>confdefs.h
+printf "%s\n" "#define HAVE___func__ 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether va_copy exists" >&5
-$as_echo_n "checking whether va_copy exists... " >&6; }
-if ${ac_cv_have_va_copy+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether va_copy exists" >&5
+printf %s "checking whether va_copy exists... " >&6; }
+if test ${ac_cv_have_va_copy+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdarg.h>
va_list x,y;
int
-main ()
+main (void)
{
va_copy(x,y);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_have_va_copy="yes"
-else
+else $as_nop
ac_cv_have_va_copy="no"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_va_copy" >&5
-$as_echo "$ac_cv_have_va_copy" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_va_copy" >&5
+printf "%s\n" "$ac_cv_have_va_copy" >&6; }
if test "x$ac_cv_have_va_copy" = "xyes" ; then
-$as_echo "#define HAVE_VA_COPY 1" >>confdefs.h
+printf "%s\n" "#define HAVE_VA_COPY 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether __va_copy exists" >&5
-$as_echo_n "checking whether __va_copy exists... " >&6; }
-if ${ac_cv_have___va_copy+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether __va_copy exists" >&5
+printf %s "checking whether __va_copy exists... " >&6; }
+if test ${ac_cv_have___va_copy+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdarg.h>
va_list x,y;
int
-main ()
+main (void)
{
__va_copy(x,y);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_have___va_copy="yes"
-else
+else $as_nop
ac_cv_have___va_copy="no"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have___va_copy" >&5
-$as_echo "$ac_cv_have___va_copy" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have___va_copy" >&5
+printf "%s\n" "$ac_cv_have___va_copy" >&6; }
if test "x$ac_cv_have___va_copy" = "xyes" ; then
-$as_echo "#define HAVE___VA_COPY 1" >>confdefs.h
+printf "%s\n" "#define HAVE___VA_COPY 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether getopt has optreset support" >&5
-$as_echo_n "checking whether getopt has optreset support... " >&6; }
-if ${ac_cv_have_getopt_optreset+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether getopt has optreset support" >&5
+printf %s "checking whether getopt has optreset support... " >&6; }
+if test ${ac_cv_have_getopt_optreset+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <getopt.h>
int
-main ()
+main (void)
{
extern int optreset; optreset = 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_have_getopt_optreset="yes"
-else
+else $as_nop
ac_cv_have_getopt_optreset="no"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_getopt_optreset" >&5
-$as_echo "$ac_cv_have_getopt_optreset" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_getopt_optreset" >&5
+printf "%s\n" "$ac_cv_have_getopt_optreset" >&6; }
if test "x$ac_cv_have_getopt_optreset" = "xyes" ; then
-$as_echo "#define HAVE_GETOPT_OPTRESET 1" >>confdefs.h
+printf "%s\n" "#define HAVE_GETOPT_OPTRESET 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if libc defines sys_errlist" >&5
-$as_echo_n "checking if libc defines sys_errlist... " >&6; }
-if ${ac_cv_libc_defines_sys_errlist+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libc defines sys_errlist" >&5
+printf %s "checking if libc defines sys_errlist... " >&6; }
+if test ${ac_cv_libc_defines_sys_errlist+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
int
-main ()
+main (void)
{
extern const char *const sys_errlist[]; printf("%s", sys_errlist[0]);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_libc_defines_sys_errlist="yes"
-else
+else $as_nop
ac_cv_libc_defines_sys_errlist="no"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libc_defines_sys_errlist" >&5
-$as_echo "$ac_cv_libc_defines_sys_errlist" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libc_defines_sys_errlist" >&5
+printf "%s\n" "$ac_cv_libc_defines_sys_errlist" >&6; }
if test "x$ac_cv_libc_defines_sys_errlist" = "xyes" ; then
-$as_echo "#define HAVE_SYS_ERRLIST 1" >>confdefs.h
+printf "%s\n" "#define HAVE_SYS_ERRLIST 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if libc defines sys_nerr" >&5
-$as_echo_n "checking if libc defines sys_nerr... " >&6; }
-if ${ac_cv_libc_defines_sys_nerr+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libc defines sys_nerr" >&5
+printf %s "checking if libc defines sys_nerr... " >&6; }
+if test ${ac_cv_libc_defines_sys_nerr+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
int
-main ()
+main (void)
{
extern int sys_nerr; printf("%i", sys_nerr);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_libc_defines_sys_nerr="yes"
-else
+else $as_nop
ac_cv_libc_defines_sys_nerr="no"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libc_defines_sys_nerr" >&5
-$as_echo "$ac_cv_libc_defines_sys_nerr" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libc_defines_sys_nerr" >&5
+printf "%s\n" "$ac_cv_libc_defines_sys_nerr" >&6; }
if test "x$ac_cv_libc_defines_sys_nerr" = "xyes" ; then
-$as_echo "#define HAVE_SYS_NERR 1" >>confdefs.h
+printf "%s\n" "#define HAVE_SYS_NERR 1" >>confdefs.h
fi
# Check libraries needed by DNS fingerprint support
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing getrrsetbyname" >&5
-$as_echo_n "checking for library containing getrrsetbyname... " >&6; }
-if ${ac_cv_search_getrrsetbyname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing getrrsetbyname" >&5
+printf %s "checking for library containing getrrsetbyname... " >&6; }
+if test ${ac_cv_search_getrrsetbyname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char getrrsetbyname ();
int
-main ()
+main (void)
{
return getrrsetbyname ();
;
return 0;
}
_ACEOF
-for ac_lib in '' resolv; do
+for ac_lib in '' resolv
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
+ if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_search_getrrsetbyname=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_getrrsetbyname+:} false; then :
+ if test ${ac_cv_search_getrrsetbyname+y}
+then :
break
fi
done
-if ${ac_cv_search_getrrsetbyname+:} false; then :
+if test ${ac_cv_search_getrrsetbyname+y}
+then :
-else
+else $as_nop
ac_cv_search_getrrsetbyname=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_getrrsetbyname" >&5
-$as_echo "$ac_cv_search_getrrsetbyname" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_getrrsetbyname" >&5
+printf "%s\n" "$ac_cv_search_getrrsetbyname" >&6; }
ac_res=$ac_cv_search_getrrsetbyname
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-$as_echo "#define HAVE_GETRRSETBYNAME 1" >>confdefs.h
+printf "%s\n" "#define HAVE_GETRRSETBYNAME 1" >>confdefs.h
-else
+else $as_nop
# Needed by our getrrsetbyname()
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing res_query" >&5
-$as_echo_n "checking for library containing res_query... " >&6; }
-if ${ac_cv_search_res_query+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing res_query" >&5
+printf %s "checking for library containing res_query... " >&6; }
+if test ${ac_cv_search_res_query+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char res_query ();
int
-main ()
+main (void)
{
return res_query ();
;
return 0;
}
_ACEOF
-for ac_lib in '' resolv; do
+for ac_lib in '' resolv
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
+ if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_search_res_query=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_res_query+:} false; then :
+ if test ${ac_cv_search_res_query+y}
+then :
break
fi
done
-if ${ac_cv_search_res_query+:} false; then :
+if test ${ac_cv_search_res_query+y}
+then :
-else
+else $as_nop
ac_cv_search_res_query=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_res_query" >&5
-$as_echo "$ac_cv_search_res_query" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_res_query" >&5
+printf "%s\n" "$ac_cv_search_res_query" >&6; }
ac_res=$ac_cv_search_res_query
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dn_expand" >&5
-$as_echo_n "checking for library containing dn_expand... " >&6; }
-if ${ac_cv_search_dn_expand+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing dn_expand" >&5
+printf %s "checking for library containing dn_expand... " >&6; }
+if test ${ac_cv_search_dn_expand+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char dn_expand ();
int
-main ()
+main (void)
{
return dn_expand ();
;
return 0;
}
_ACEOF
-for ac_lib in '' resolv; do
+for ac_lib in '' resolv
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
+ if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_search_dn_expand=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_dn_expand+:} false; then :
+ if test ${ac_cv_search_dn_expand+y}
+then :
break
fi
done
-if ${ac_cv_search_dn_expand+:} false; then :
+if test ${ac_cv_search_dn_expand+y}
+then :
-else
+else $as_nop
ac_cv_search_dn_expand=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dn_expand" >&5
-$as_echo "$ac_cv_search_dn_expand" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dn_expand" >&5
+printf "%s\n" "$ac_cv_search_dn_expand" >&6; }
ac_res=$ac_cv_search_dn_expand
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if res_query will link" >&5
-$as_echo_n "checking if res_query will link... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if res_query will link" >&5
+printf %s "checking if res_query will link... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
int
-main ()
+main (void)
{
res_query (0, 0, 0, 0, 0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if ac_fn_c_try_link "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
saved_LIBS="$LIBS"
LIBS="$LIBS -lresolv"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for res_query in -lresolv" >&5
-$as_echo_n "checking for res_query in -lresolv... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for res_query in -lresolv" >&5
+printf %s "checking for res_query in -lresolv... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
int
-main ()
+main (void)
{
res_query (0, 0, 0, 0, 0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
+if ac_fn_c_try_link "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
LIBS="$saved_LIBS"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
- for ac_func in _getshort _getlong
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "_getshort" "ac_cv_func__getshort"
+if test "x$ac_cv_func__getshort" = xyes
+then :
+ printf "%s\n" "#define HAVE__GETSHORT 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "_getlong" "ac_cv_func__getlong"
+if test "x$ac_cv_func__getlong" = xyes
+then :
+ printf "%s\n" "#define HAVE__GETLONG 1" >>confdefs.h
fi
-done
- ac_fn_c_check_decl "$LINENO" "_getshort" "ac_cv_have_decl__getshort" "#include <sys/types.h>
+ ac_fn_check_decl "$LINENO" "_getshort" "ac_cv_have_decl__getshort" "#include <sys/types.h>
#include <arpa/nameser.h>
-"
-if test "x$ac_cv_have_decl__getshort" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl__getshort" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL__GETSHORT $ac_have_decl
-_ACEOF
-ac_fn_c_check_decl "$LINENO" "_getlong" "ac_cv_have_decl__getlong" "#include <sys/types.h>
+printf "%s\n" "#define HAVE_DECL__GETSHORT $ac_have_decl" >>confdefs.h
+ac_fn_check_decl "$LINENO" "_getlong" "ac_cv_have_decl__getlong" "#include <sys/types.h>
#include <arpa/nameser.h>
-"
-if test "x$ac_cv_have_decl__getlong" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl__getlong" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL__GETLONG $ac_have_decl
-_ACEOF
+printf "%s\n" "#define HAVE_DECL__GETLONG $ac_have_decl" >>confdefs.h
ac_fn_c_check_member "$LINENO" "HEADER" "ad" "ac_cv_member_HEADER_ad" "#include <arpa/nameser.h>
"
-if test "x$ac_cv_member_HEADER_ad" = xyes; then :
+if test "x$ac_cv_member_HEADER_ad" = xyes
+then :
-$as_echo "#define HAVE_HEADER_AD 1" >>confdefs.h
+printf "%s\n" "#define HAVE_HEADER_AD 1" >>confdefs.h
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if struct __res_state _res is an extern" >&5
-$as_echo_n "checking if struct __res_state _res is an extern... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if struct __res_state _res is an extern" >&5
+printf %s "checking if struct __res_state _res is an extern... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
extern struct __res_state _res;
int
-main ()
+main (void)
{
struct __res_state *volatile p = &_res; /* force resolution of _res */
return 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_link "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE__RES_EXTERN 1" >>confdefs.h
+printf "%s\n" "#define HAVE__RES_EXTERN 1" >>confdefs.h
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
# Check whether user wants SELinux support
SELINUX_MSG="no"
LIBSELINUX=""
# Check whether --with-selinux was given.
-if test "${with_selinux+set}" = set; then :
+if test ${with_selinux+y}
+then :
withval=$with_selinux; if test "x$withval" != "xno" ; then
save_LIBS="$LIBS"
-$as_echo "#define WITH_SELINUX 1" >>confdefs.h
+printf "%s\n" "#define WITH_SELINUX 1" >>confdefs.h
SELINUX_MSG="yes"
- ac_fn_c_check_header_mongrel "$LINENO" "selinux/selinux.h" "ac_cv_header_selinux_selinux_h" "$ac_includes_default"
-if test "x$ac_cv_header_selinux_selinux_h" = xyes; then :
+ ac_fn_c_check_header_compile "$LINENO" "selinux/selinux.h" "ac_cv_header_selinux_selinux_h" "$ac_includes_default"
+if test "x$ac_cv_header_selinux_selinux_h" = xyes
+then :
-else
+else $as_nop
as_fn_error $? "SELinux support requires selinux.h header" "$LINENO" 5
fi
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setexeccon in -lselinux" >&5
-$as_echo_n "checking for setexeccon in -lselinux... " >&6; }
-if ${ac_cv_lib_selinux_setexeccon+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for setexeccon in -lselinux" >&5
+printf %s "checking for setexeccon in -lselinux... " >&6; }
+if test ${ac_cv_lib_selinux_setexeccon+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lselinux $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char setexeccon ();
int
-main ()
+main (void)
{
return setexeccon ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_selinux_setexeccon=yes
-else
+else $as_nop
ac_cv_lib_selinux_setexeccon=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_selinux_setexeccon" >&5
-$as_echo "$ac_cv_lib_selinux_setexeccon" >&6; }
-if test "x$ac_cv_lib_selinux_setexeccon" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_selinux_setexeccon" >&5
+printf "%s\n" "$ac_cv_lib_selinux_setexeccon" >&6; }
+if test "x$ac_cv_lib_selinux_setexeccon" = xyes
+then :
LIBSELINUX="-lselinux"
LIBS="$LIBS -lselinux"
-else
+else $as_nop
as_fn_error $? "SELinux support requires libselinux library" "$LINENO" 5
fi
- for ac_func in getseuserbyname get_default_context_with_level
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "getseuserbyname" "ac_cv_func_getseuserbyname"
+if test "x$ac_cv_func_getseuserbyname" = xyes
+then :
+ printf "%s\n" "#define HAVE_GETSEUSERBYNAME 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "get_default_context_with_level" "ac_cv_func_get_default_context_with_level"
+if test "x$ac_cv_func_get_default_context_with_level" = xyes
+then :
+ printf "%s\n" "#define HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL 1" >>confdefs.h
fi
-done
LIBS="$save_LIBS $LIBSELINUX"
fi
fi
# Check whether user wants Kerberos 5 support
KRB5_MSG="no"
# Check whether --with-kerberos5 was given.
-if test "${with_kerberos5+set}" = set; then :
+if test ${with_kerberos5+y}
+then :
withval=$with_kerberos5; if test "x$withval" != "xno" ; then
if test "x$withval" = "xyes" ; then
KRB5ROOT="/usr/local"
else
KRB5ROOT=${withval}
fi
-$as_echo "#define KRB5 1" >>confdefs.h
+printf "%s\n" "#define KRB5 1" >>confdefs.h
KRB5_MSG="yes"
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
-set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PKGCONFIG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- case $PKGCONFIG in
- [\\/]* | ?:[\\/]*)
- ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path.
- ;;
- *)
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
- ;;
-esac
-fi
-PKGCONFIG=$ac_cv_path_PKGCONFIG
-if test -n "$PKGCONFIG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5
-$as_echo "$PKGCONFIG" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_path_PKGCONFIG"; then
- ac_pt_PKGCONFIG=$PKGCONFIG
- # Extract the first word of "pkg-config", so it can be a program name with args.
-set dummy pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_PKGCONFIG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- case $ac_pt_PKGCONFIG in
- [\\/]* | ?:[\\/]*)
- ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path.
- ;;
- *)
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_ac_pt_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
- ;;
-esac
-fi
-ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG
-if test -n "$ac_pt_PKGCONFIG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5
-$as_echo "$ac_pt_PKGCONFIG" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
- if test "x$ac_pt_PKGCONFIG" = x; then
- PKGCONFIG="no"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- PKGCONFIG=$ac_pt_PKGCONFIG
- fi
-else
- PKGCONFIG="$ac_cv_path_PKGCONFIG"
-fi
-
use_pkgconfig_for_krb5=
if test "x$PKGCONFIG" != "xno"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $PKGCONFIG knows about kerberos5" >&5
-$as_echo_n "checking if $PKGCONFIG knows about kerberos5... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $PKGCONFIG knows about kerberos5" >&5
+printf %s "checking if $PKGCONFIG knows about kerberos5... " >&6; }
if "$PKGCONFIG" krb5; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
use_pkgconfig_for_krb5=yes
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
fi
if test "x$use_pkgconfig_for_krb5" = "xyes"; then
K5CFLAGS=`$PKGCONFIG --cflags krb5`
K5LIBS=`$PKGCONFIG --libs krb5`
CPPFLAGS="$CPPFLAGS $K5CFLAGS"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gssapi support" >&5
-$as_echo_n "checking for gssapi support... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gssapi support" >&5
+printf %s "checking for gssapi support... " >&6; }
if "$PKGCONFIG" krb5-gssapi; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define GSSAPI 1" >>confdefs.h
+printf "%s\n" "#define GSSAPI 1" >>confdefs.h
GSSCFLAGS="`$PKGCONFIG --cflags krb5-gssapi`"
GSSLIBS="`$PKGCONFIG --libs krb5-gssapi`"
CPPFLAGS="$CPPFLAGS $GSSCFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using Heimdal" >&5
-$as_echo_n "checking whether we are using Heimdal... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are using Heimdal" >&5
+printf %s "checking whether we are using Heimdal... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <krb5.h>
int
-main ()
+main (void)
{
char *tmp = heimdal_version;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HEIMDAL 1" >>confdefs.h
+printf "%s\n" "#define HEIMDAL 1" >>confdefs.h
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
else
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}krb5-config", so it can be a program name with args.
set dummy ${ac_tool_prefix}krb5-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_KRB5CONF+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_KRB5CONF+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $KRB5CONF in
[\\/]* | ?:[\\/]*)
ac_cv_path_KRB5CONF="$KRB5CONF" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
as_dummy="$KRB5ROOT/bin:$PATH"
for as_dir in $as_dummy
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_KRB5CONF="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_KRB5CONF="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
KRB5CONF=$ac_cv_path_KRB5CONF
if test -n "$KRB5CONF"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $KRB5CONF" >&5
-$as_echo "$KRB5CONF" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $KRB5CONF" >&5
+printf "%s\n" "$KRB5CONF" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
fi
if test -z "$ac_cv_path_KRB5CONF"; then
ac_pt_KRB5CONF=$KRB5CONF
# Extract the first word of "krb5-config", so it can be a program name with args.
set dummy krb5-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_KRB5CONF+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_ac_pt_KRB5CONF+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $ac_pt_KRB5CONF in
[\\/]* | ?:[\\/]*)
ac_cv_path_ac_pt_KRB5CONF="$ac_pt_KRB5CONF" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
as_dummy="$KRB5ROOT/bin:$PATH"
for as_dir in $as_dummy
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_ac_pt_KRB5CONF="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_ac_pt_KRB5CONF="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
ac_pt_KRB5CONF=$ac_cv_path_ac_pt_KRB5CONF
if test -n "$ac_pt_KRB5CONF"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_KRB5CONF" >&5
-$as_echo "$ac_pt_KRB5CONF" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_KRB5CONF" >&5
+printf "%s\n" "$ac_pt_KRB5CONF" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_pt_KRB5CONF" = x; then
KRB5CONF="$KRB5ROOT/bin/krb5-config"
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
KRB5CONF=$ac_pt_KRB5CONF
fi
else
KRB5CONF="$ac_cv_path_KRB5CONF"
fi
if test -x $KRB5CONF ; then
K5CFLAGS="`$KRB5CONF --cflags`"
K5LIBS="`$KRB5CONF --libs`"
CPPFLAGS="$CPPFLAGS $K5CFLAGS"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gssapi support" >&5
-$as_echo_n "checking for gssapi support... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gssapi support" >&5
+printf %s "checking for gssapi support... " >&6; }
if $KRB5CONF | grep gssapi >/dev/null ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define GSSAPI 1" >>confdefs.h
+printf "%s\n" "#define GSSAPI 1" >>confdefs.h
GSSCFLAGS="`$KRB5CONF --cflags gssapi`"
GSSLIBS="`$KRB5CONF --libs gssapi`"
CPPFLAGS="$CPPFLAGS $GSSCFLAGS"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using Heimdal" >&5
-$as_echo_n "checking whether we are using Heimdal... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are using Heimdal" >&5
+printf %s "checking whether we are using Heimdal... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <krb5.h>
int
-main ()
+main (void)
{
char *tmp = heimdal_version;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HEIMDAL 1" >>confdefs.h
+printf "%s\n" "#define HEIMDAL 1" >>confdefs.h
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
else
CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include"
LDFLAGS="$LDFLAGS -L${KRB5ROOT}/lib"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using Heimdal" >&5
-$as_echo_n "checking whether we are using Heimdal... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are using Heimdal" >&5
+printf %s "checking whether we are using Heimdal... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <krb5.h>
int
-main ()
+main (void)
{
char *tmp = heimdal_version;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- $as_echo "#define HEIMDAL 1" >>confdefs.h
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ printf "%s\n" "#define HEIMDAL 1" >>confdefs.h
K5LIBS="-lkrb5"
K5LIBS="$K5LIBS -lcom_err -lasn1"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for net_write in -lroken" >&5
-$as_echo_n "checking for net_write in -lroken... " >&6; }
-if ${ac_cv_lib_roken_net_write+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for net_write in -lroken" >&5
+printf %s "checking for net_write in -lroken... " >&6; }
+if test ${ac_cv_lib_roken_net_write+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lroken $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char net_write ();
int
-main ()
+main (void)
{
return net_write ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_roken_net_write=yes
-else
+else $as_nop
ac_cv_lib_roken_net_write=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_roken_net_write" >&5
-$as_echo "$ac_cv_lib_roken_net_write" >&6; }
-if test "x$ac_cv_lib_roken_net_write" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_roken_net_write" >&5
+printf "%s\n" "$ac_cv_lib_roken_net_write" >&6; }
+if test "x$ac_cv_lib_roken_net_write" = xyes
+then :
K5LIBS="$K5LIBS -lroken"
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for des_cbc_encrypt in -ldes" >&5
-$as_echo_n "checking for des_cbc_encrypt in -ldes... " >&6; }
-if ${ac_cv_lib_des_des_cbc_encrypt+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for des_cbc_encrypt in -ldes" >&5
+printf %s "checking for des_cbc_encrypt in -ldes... " >&6; }
+if test ${ac_cv_lib_des_des_cbc_encrypt+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-ldes $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char des_cbc_encrypt ();
int
-main ()
+main (void)
{
return des_cbc_encrypt ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_des_des_cbc_encrypt=yes
-else
+else $as_nop
ac_cv_lib_des_des_cbc_encrypt=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_des_des_cbc_encrypt" >&5
-$as_echo "$ac_cv_lib_des_des_cbc_encrypt" >&6; }
-if test "x$ac_cv_lib_des_des_cbc_encrypt" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_des_des_cbc_encrypt" >&5
+printf "%s\n" "$ac_cv_lib_des_des_cbc_encrypt" >&6; }
+if test "x$ac_cv_lib_des_des_cbc_encrypt" = xyes
+then :
K5LIBS="$K5LIBS -ldes"
fi
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
K5LIBS="-lkrb5 -lk5crypto -lcom_err"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dn_expand" >&5
-$as_echo_n "checking for library containing dn_expand... " >&6; }
-if ${ac_cv_search_dn_expand+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing dn_expand" >&5
+printf %s "checking for library containing dn_expand... " >&6; }
+if test ${ac_cv_search_dn_expand+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char dn_expand ();
int
-main ()
+main (void)
{
return dn_expand ();
;
return 0;
}
_ACEOF
-for ac_lib in '' resolv; do
+for ac_lib in '' resolv
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
+ if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_search_dn_expand=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_dn_expand+:} false; then :
+ if test ${ac_cv_search_dn_expand+y}
+then :
break
fi
done
-if ${ac_cv_search_dn_expand+:} false; then :
+if test ${ac_cv_search_dn_expand+y}
+then :
-else
+else $as_nop
ac_cv_search_dn_expand=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dn_expand" >&5
-$as_echo "$ac_cv_search_dn_expand" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dn_expand" >&5
+printf "%s\n" "$ac_cv_search_dn_expand" >&6; }
ac_res=$ac_cv_search_dn_expand
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gss_init_sec_context in -lgssapi_krb5" >&5
-$as_echo_n "checking for gss_init_sec_context in -lgssapi_krb5... " >&6; }
-if ${ac_cv_lib_gssapi_krb5_gss_init_sec_context+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gss_init_sec_context in -lgssapi_krb5" >&5
+printf %s "checking for gss_init_sec_context in -lgssapi_krb5... " >&6; }
+if test ${ac_cv_lib_gssapi_krb5_gss_init_sec_context+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lgssapi_krb5 $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char gss_init_sec_context ();
int
-main ()
+main (void)
{
return gss_init_sec_context ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_gssapi_krb5_gss_init_sec_context=yes
-else
+else $as_nop
ac_cv_lib_gssapi_krb5_gss_init_sec_context=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gssapi_krb5_gss_init_sec_context" >&5
-$as_echo "$ac_cv_lib_gssapi_krb5_gss_init_sec_context" >&6; }
-if test "x$ac_cv_lib_gssapi_krb5_gss_init_sec_context" = xyes; then :
- $as_echo "#define GSSAPI 1" >>confdefs.h
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gssapi_krb5_gss_init_sec_context" >&5
+printf "%s\n" "$ac_cv_lib_gssapi_krb5_gss_init_sec_context" >&6; }
+if test "x$ac_cv_lib_gssapi_krb5_gss_init_sec_context" = xyes
+then :
+ printf "%s\n" "#define GSSAPI 1" >>confdefs.h
GSSLIBS="-lgssapi_krb5"
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gss_init_sec_context in -lgssapi" >&5
-$as_echo_n "checking for gss_init_sec_context in -lgssapi... " >&6; }
-if ${ac_cv_lib_gssapi_gss_init_sec_context+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gss_init_sec_context in -lgssapi" >&5
+printf %s "checking for gss_init_sec_context in -lgssapi... " >&6; }
+if test ${ac_cv_lib_gssapi_gss_init_sec_context+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lgssapi $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char gss_init_sec_context ();
int
-main ()
+main (void)
{
return gss_init_sec_context ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_gssapi_gss_init_sec_context=yes
-else
+else $as_nop
ac_cv_lib_gssapi_gss_init_sec_context=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gssapi_gss_init_sec_context" >&5
-$as_echo "$ac_cv_lib_gssapi_gss_init_sec_context" >&6; }
-if test "x$ac_cv_lib_gssapi_gss_init_sec_context" = xyes; then :
- $as_echo "#define GSSAPI 1" >>confdefs.h
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gssapi_gss_init_sec_context" >&5
+printf "%s\n" "$ac_cv_lib_gssapi_gss_init_sec_context" >&6; }
+if test "x$ac_cv_lib_gssapi_gss_init_sec_context" = xyes
+then :
+ printf "%s\n" "#define GSSAPI 1" >>confdefs.h
GSSLIBS="-lgssapi"
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gss_init_sec_context in -lgss" >&5
-$as_echo_n "checking for gss_init_sec_context in -lgss... " >&6; }
-if ${ac_cv_lib_gss_gss_init_sec_context+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gss_init_sec_context in -lgss" >&5
+printf %s "checking for gss_init_sec_context in -lgss... " >&6; }
+if test ${ac_cv_lib_gss_gss_init_sec_context+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lgss $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char gss_init_sec_context ();
int
-main ()
+main (void)
{
return gss_init_sec_context ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_gss_gss_init_sec_context=yes
-else
+else $as_nop
ac_cv_lib_gss_gss_init_sec_context=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gss_gss_init_sec_context" >&5
-$as_echo "$ac_cv_lib_gss_gss_init_sec_context" >&6; }
-if test "x$ac_cv_lib_gss_gss_init_sec_context" = xyes; then :
- $as_echo "#define GSSAPI 1" >>confdefs.h
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gss_gss_init_sec_context" >&5
+printf "%s\n" "$ac_cv_lib_gss_gss_init_sec_context" >&6; }
+if test "x$ac_cv_lib_gss_gss_init_sec_context" = xyes
+then :
+ printf "%s\n" "#define GSSAPI 1" >>confdefs.h
GSSLIBS="-lgss"
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find any suitable gss-api library - build may fail" >&5
-$as_echo "$as_me: WARNING: Cannot find any suitable gss-api library - build may fail" >&2;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find any suitable gss-api library - build may fail" >&5
+printf "%s\n" "$as_me: WARNING: Cannot find any suitable gss-api library - build may fail" >&2;}
fi
fi
fi
- ac_fn_c_check_header_mongrel "$LINENO" "gssapi.h" "ac_cv_header_gssapi_h" "$ac_includes_default"
-if test "x$ac_cv_header_gssapi_h" = xyes; then :
+ ac_fn_c_check_header_compile "$LINENO" "gssapi.h" "ac_cv_header_gssapi_h" "$ac_includes_default"
+if test "x$ac_cv_header_gssapi_h" = xyes
+then :
-else
+else $as_nop
unset ac_cv_header_gssapi_h
CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi"
- for ac_header in gssapi.h
+ for ac_header in gssapi.h
do :
- ac_fn_c_check_header_mongrel "$LINENO" "gssapi.h" "ac_cv_header_gssapi_h" "$ac_includes_default"
-if test "x$ac_cv_header_gssapi_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_GSSAPI_H 1
-_ACEOF
+ ac_fn_c_check_header_compile "$LINENO" "gssapi.h" "ac_cv_header_gssapi_h" "$ac_includes_default"
+if test "x$ac_cv_header_gssapi_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_GSSAPI_H 1" >>confdefs.h
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find any suitable gss-api header - build may fail" >&5
-$as_echo "$as_me: WARNING: Cannot find any suitable gss-api header - build may fail" >&2;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find any suitable gss-api header - build may fail" >&5
+printf "%s\n" "$as_me: WARNING: Cannot find any suitable gss-api header - build may fail" >&2;}
fi
done
-
fi
-
oldCPP="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi"
- ac_fn_c_check_header_mongrel "$LINENO" "gssapi_krb5.h" "ac_cv_header_gssapi_krb5_h" "$ac_includes_default"
-if test "x$ac_cv_header_gssapi_krb5_h" = xyes; then :
+ ac_fn_c_check_header_compile "$LINENO" "gssapi_krb5.h" "ac_cv_header_gssapi_krb5_h" "$ac_includes_default"
+if test "x$ac_cv_header_gssapi_krb5_h" = xyes
+then :
-else
+else $as_nop
CPPFLAGS="$oldCPP"
fi
-
fi
fi
if test -n "${rpath_opt}" ; then
LDFLAGS="$LDFLAGS ${rpath_opt}${KRB5ROOT}/lib"
fi
if test ! -z "$blibpath" ; then
blibpath="$blibpath:${KRB5ROOT}/lib"
fi
- for ac_header in gssapi.h gssapi/gssapi.h
-do :
- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
+ ac_fn_c_check_header_compile "$LINENO" "gssapi.h" "ac_cv_header_gssapi_h" "$ac_includes_default"
+if test "x$ac_cv_header_gssapi_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_GSSAPI_H 1" >>confdefs.h
fi
+ac_fn_c_check_header_compile "$LINENO" "gssapi/gssapi.h" "ac_cv_header_gssapi_gssapi_h" "$ac_includes_default"
+if test "x$ac_cv_header_gssapi_gssapi_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_GSSAPI_GSSAPI_H 1" >>confdefs.h
-done
+fi
- for ac_header in gssapi_krb5.h gssapi/gssapi_krb5.h
-do :
- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
+ ac_fn_c_check_header_compile "$LINENO" "gssapi_krb5.h" "ac_cv_header_gssapi_krb5_h" "$ac_includes_default"
+if test "x$ac_cv_header_gssapi_krb5_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_GSSAPI_KRB5_H 1" >>confdefs.h
fi
+ac_fn_c_check_header_compile "$LINENO" "gssapi/gssapi_krb5.h" "ac_cv_header_gssapi_gssapi_krb5_h" "$ac_includes_default"
+if test "x$ac_cv_header_gssapi_gssapi_krb5_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_GSSAPI_GSSAPI_KRB5_H 1" >>confdefs.h
-done
+fi
- for ac_header in gssapi_generic.h gssapi/gssapi_generic.h
-do :
- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
+ ac_fn_c_check_header_compile "$LINENO" "gssapi_generic.h" "ac_cv_header_gssapi_generic_h" "$ac_includes_default"
+if test "x$ac_cv_header_gssapi_generic_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_GSSAPI_GENERIC_H 1" >>confdefs.h
fi
+ac_fn_c_check_header_compile "$LINENO" "gssapi/gssapi_generic.h" "ac_cv_header_gssapi_gssapi_generic_h" "$ac_includes_default"
+if test "x$ac_cv_header_gssapi_gssapi_generic_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_GSSAPI_GSSAPI_GENERIC_H 1" >>confdefs.h
-done
+fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing k_hasafs" >&5
-$as_echo_n "checking for library containing k_hasafs... " >&6; }
-if ${ac_cv_search_k_hasafs+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing k_hasafs" >&5
+printf %s "checking for library containing k_hasafs... " >&6; }
+if test ${ac_cv_search_k_hasafs+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char k_hasafs ();
int
-main ()
+main (void)
{
return k_hasafs ();
;
return 0;
}
_ACEOF
-for ac_lib in '' kafs; do
+for ac_lib in '' kafs
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
+ if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_search_k_hasafs=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_k_hasafs+:} false; then :
+ if test ${ac_cv_search_k_hasafs+y}
+then :
break
fi
done
-if ${ac_cv_search_k_hasafs+:} false; then :
+if test ${ac_cv_search_k_hasafs+y}
+then :
-else
+else $as_nop
ac_cv_search_k_hasafs=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_k_hasafs" >&5
-$as_echo "$ac_cv_search_k_hasafs" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_k_hasafs" >&5
+printf "%s\n" "$ac_cv_search_k_hasafs" >&6; }
ac_res=$ac_cv_search_k_hasafs
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-$as_echo "#define USE_AFS 1" >>confdefs.h
+printf "%s\n" "#define USE_AFS 1" >>confdefs.h
fi
- ac_fn_c_check_decl "$LINENO" "GSS_C_NT_HOSTBASED_SERVICE" "ac_cv_have_decl_GSS_C_NT_HOSTBASED_SERVICE" "
+ ac_fn_check_decl "$LINENO" "GSS_C_NT_HOSTBASED_SERVICE" "ac_cv_have_decl_GSS_C_NT_HOSTBASED_SERVICE" "
#ifdef HAVE_GSSAPI_H
# include <gssapi.h>
#elif defined(HAVE_GSSAPI_GSSAPI_H)
# include <gssapi/gssapi.h>
#endif
#ifdef HAVE_GSSAPI_GENERIC_H
# include <gssapi_generic.h>
#elif defined(HAVE_GSSAPI_GSSAPI_GENERIC_H)
# include <gssapi/gssapi_generic.h>
#endif
-"
-if test "x$ac_cv_have_decl_GSS_C_NT_HOSTBASED_SERVICE" = xyes; then :
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_GSS_C_NT_HOSTBASED_SERVICE" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_GSS_C_NT_HOSTBASED_SERVICE $ac_have_decl
-_ACEOF
+printf "%s\n" "#define HAVE_DECL_GSS_C_NT_HOSTBASED_SERVICE $ac_have_decl" >>confdefs.h
saved_LIBS="$LIBS"
LIBS="$LIBS $K5LIBS"
- for ac_func in krb5_cc_new_unique krb5_get_error_message krb5_free_error_message
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ ac_fn_c_check_func "$LINENO" "krb5_cc_new_unique" "ac_cv_func_krb5_cc_new_unique"
+if test "x$ac_cv_func_krb5_cc_new_unique" = xyes
+then :
+ printf "%s\n" "#define HAVE_KRB5_CC_NEW_UNIQUE 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "krb5_get_error_message" "ac_cv_func_krb5_get_error_message"
+if test "x$ac_cv_func_krb5_get_error_message" = xyes
+then :
+ printf "%s\n" "#define HAVE_KRB5_GET_ERROR_MESSAGE 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "krb5_free_error_message" "ac_cv_func_krb5_free_error_message"
+if test "x$ac_cv_func_krb5_free_error_message" = xyes
+then :
+ printf "%s\n" "#define HAVE_KRB5_FREE_ERROR_MESSAGE 1" >>confdefs.h
fi
-done
LIBS="$saved_LIBS"
fi
fi
+
# Looking for programs, paths and files
PRIVSEP_PATH=/var/empty
# Check whether --with-privsep-path was given.
-if test "${with_privsep_path+set}" = set; then :
+if test ${with_privsep_path+y}
+then :
withval=$with_privsep_path;
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
PRIVSEP_PATH=$withval
fi
fi
# Check whether --with-xauth was given.
-if test "${with_xauth+set}" = set; then :
+if test ${with_xauth+y}
+then :
withval=$with_xauth;
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
xauth_path=$withval
fi
-else
+else $as_nop
TestPath="$PATH"
TestPath="${TestPath}${PATH_SEPARATOR}/usr/X/bin"
TestPath="${TestPath}${PATH_SEPARATOR}/usr/bin/X11"
TestPath="${TestPath}${PATH_SEPARATOR}/usr/X11R6/bin"
TestPath="${TestPath}${PATH_SEPARATOR}/usr/openwin/bin"
# Extract the first word of "xauth", so it can be a program name with args.
set dummy xauth; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_xauth_path+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_xauth_path+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $xauth_path in
[\\/]* | ?:[\\/]*)
ac_cv_path_xauth_path="$xauth_path" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $TestPath
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_xauth_path="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_xauth_path="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
xauth_path=$ac_cv_path_xauth_path
if test -n "$xauth_path"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xauth_path" >&5
-$as_echo "$xauth_path" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $xauth_path" >&5
+printf "%s\n" "$xauth_path" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if (test ! -z "$xauth_path" && test -x "/usr/openwin/bin/xauth") ; then
xauth_path="/usr/openwin/bin/xauth"
fi
fi
STRIP_OPT=-s
# Check whether --enable-strip was given.
-if test "${enable_strip+set}" = set; then :
+if test ${enable_strip+y}
+then :
enableval=$enable_strip;
if test "x$enableval" = "xno" ; then
STRIP_OPT=
fi
fi
if test -z "$xauth_path" ; then
XAUTH_PATH="undefined"
else
-cat >>confdefs.h <<_ACEOF
-#define XAUTH_PATH "$xauth_path"
-_ACEOF
+printf "%s\n" "#define XAUTH_PATH \"$xauth_path\"" >>confdefs.h
XAUTH_PATH=$xauth_path
fi
# Check for mail directory
# Check whether --with-maildir was given.
-if test "${with_maildir+set}" = set; then :
+if test ${with_maildir+y}
+then :
withval=$with_maildir;
if test "X$withval" != X && test "x$withval" != xno && \
test "x${withval}" != xyes; then
-cat >>confdefs.h <<_ACEOF
-#define MAIL_DIRECTORY "$withval"
-_ACEOF
+printf "%s\n" "#define MAIL_DIRECTORY \"$withval\"" >>confdefs.h
fi
-else
+else $as_nop
if test "X$maildir" != "X"; then
- cat >>confdefs.h <<_ACEOF
-#define MAIL_DIRECTORY "$maildir"
-_ACEOF
+ printf "%s\n" "#define MAIL_DIRECTORY \"$maildir\"" >>confdefs.h
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking Discovering system mail directory" >&5
-$as_echo_n "checking Discovering system mail directory... " >&6; }
- if test "$cross_compiling" = yes; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking Discovering system mail directory" >&5
+printf %s "checking Discovering system mail directory... " >&6; }
+ if test "$cross_compiling" = yes
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: use --with-maildir=/path/to/mail" >&5
-$as_echo "$as_me: WARNING: cross compiling: use --with-maildir=/path/to/mail" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: use --with-maildir=/path/to/mail" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: use --with-maildir=/path/to/mail" >&2;}
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#ifdef HAVE_MAILLOCK_H
#include <maillock.h>
#endif
#define DATA "conftest.maildir"
int
-main ()
+main (void)
{
FILE *fd;
int rc;
fd = fopen(DATA,"w");
if(fd == NULL)
exit(1);
#if defined (_PATH_MAILDIR)
if ((rc = fprintf(fd ,"_PATH_MAILDIR:%s\n", _PATH_MAILDIR)) <0)
exit(1);
#elif defined (MAILDIR)
if ((rc = fprintf(fd ,"MAILDIR:%s\n", MAILDIR)) <0)
exit(1);
#elif defined (_PATH_MAIL)
if ((rc = fprintf(fd ,"_PATH_MAIL:%s\n", _PATH_MAIL)) <0)
exit(1);
#else
exit (2);
#endif
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_run "$LINENO"
+then :
maildir_what=`awk -F: '{print $1}' conftest.maildir`
maildir=`awk -F: '{print $2}' conftest.maildir \
| sed 's|/$||'`
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using: $maildir from $maildir_what" >&5
-$as_echo "Using: $maildir from $maildir_what" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using: $maildir from $maildir_what" >&5
+printf "%s\n" "Using: $maildir from $maildir_what" >&6; }
if test "x$maildir_what" != "x_PATH_MAILDIR"; then
- cat >>confdefs.h <<_ACEOF
-#define MAIL_DIRECTORY "$maildir"
-_ACEOF
+ printf "%s\n" "#define MAIL_DIRECTORY \"$maildir\"" >>confdefs.h
fi
-else
+else $as_nop
if test "X$ac_status" = "X2";then
# our test program didn't find it. Default to /var/spool/mail
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using: default value of /var/spool/mail" >&5
-$as_echo "Using: default value of /var/spool/mail" >&6; }
- cat >>confdefs.h <<_ACEOF
-#define MAIL_DIRECTORY "/var/spool/mail"
-_ACEOF
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using: default value of /var/spool/mail" >&5
+printf "%s\n" "Using: default value of /var/spool/mail" >&6; }
+ printf "%s\n" "#define MAIL_DIRECTORY \"/var/spool/mail\"" >>confdefs.h
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: *** not found ***" >&5
-$as_echo "*** not found ***" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: *** not found ***" >&5
+printf "%s\n" "*** not found ***" >&6; }
fi
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
fi
# maildir
if test ! -z "$cross_compiling" && test "x$cross_compiling" = "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: Disabling /dev/ptmx test" >&5
-$as_echo "$as_me: WARNING: cross compiling: Disabling /dev/ptmx test" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: Disabling /dev/ptmx test" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: Disabling /dev/ptmx test" >&2;}
disable_ptmx_check=yes
fi
if test -z "$no_dev_ptmx" ; then
if test "x$disable_ptmx_check" != "xyes" ; then
- as_ac_File=`$as_echo "ac_cv_file_"/dev/ptmx"" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for \"/dev/ptmx\"" >&5
-$as_echo_n "checking for \"/dev/ptmx\"... " >&6; }
-if eval \${$as_ac_File+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ as_ac_File=`printf "%s\n" "ac_cv_file_"/dev/ptmx"" | $as_tr_sh`
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for \"/dev/ptmx\"" >&5
+printf %s "checking for \"/dev/ptmx\"... " >&6; }
+if eval test \${$as_ac_File+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
test "$cross_compiling" = yes &&
as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
if test -r ""/dev/ptmx""; then
eval "$as_ac_File=yes"
else
eval "$as_ac_File=no"
fi
fi
eval ac_res=\$$as_ac_File
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_File"\" = x"yes"; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_File"\" = x"yes"
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DEV_PTMX 1
-_ACEOF
+printf "%s\n" "#define HAVE_DEV_PTMX 1" >>confdefs.h
have_dev_ptmx=1
fi
fi
fi
if test ! -z "$cross_compiling" && test "x$cross_compiling" != "xyes"; then
- as_ac_File=`$as_echo "ac_cv_file_"/dev/ptc"" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for \"/dev/ptc\"" >&5
-$as_echo_n "checking for \"/dev/ptc\"... " >&6; }
-if eval \${$as_ac_File+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ as_ac_File=`printf "%s\n" "ac_cv_file_"/dev/ptc"" | $as_tr_sh`
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for \"/dev/ptc\"" >&5
+printf %s "checking for \"/dev/ptc\"... " >&6; }
+if eval test \${$as_ac_File+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
test "$cross_compiling" = yes &&
as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
if test -r ""/dev/ptc""; then
eval "$as_ac_File=yes"
else
eval "$as_ac_File=no"
fi
fi
eval ac_res=\$$as_ac_File
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_File"\" = x"yes"; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_File"\" = x"yes"
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DEV_PTS_AND_PTC 1
-_ACEOF
+printf "%s\n" "#define HAVE_DEV_PTS_AND_PTC 1" >>confdefs.h
have_dev_ptc=1
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: Disabling /dev/ptc test" >&5
-$as_echo "$as_me: WARNING: cross compiling: Disabling /dev/ptc test" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: Disabling /dev/ptc test" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: Disabling /dev/ptc test" >&2;}
fi
# Options from here on. Some of these are preset by platform above
# Check whether --with-mantype was given.
-if test "${with_mantype+set}" = set; then :
+if test ${with_mantype+y}
+then :
withval=$with_mantype;
case "$withval" in
man|cat|doc)
MANTYPE=$withval
;;
*)
as_fn_error $? "invalid man type: $withval" "$LINENO" 5
;;
esac
fi
if test -z "$MANTYPE"; then
if ${MANDOC} ${srcdir}/ssh.1 >/dev/null 2>&1; then
MANTYPE=doc
elif ${NROFF} -mdoc ${srcdir}/ssh.1 >/dev/null 2>&1; then
MANTYPE=doc
elif ${NROFF} -man ${srcdir}/ssh.1 >/dev/null 2>&1; then
MANTYPE=man
else
MANTYPE=cat
fi
fi
if test "$MANTYPE" = "doc"; then
mansubdir=man;
else
mansubdir=$MANTYPE;
fi
# Whether to disable shadow password support
# Check whether --with-shadow was given.
-if test "${with_shadow+set}" = set; then :
+if test ${with_shadow+y}
+then :
withval=$with_shadow;
if test "x$withval" = "xno" ; then
- $as_echo "#define DISABLE_SHADOW 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_SHADOW 1" >>confdefs.h
disable_shadow=yes
fi
fi
if test -z "$disable_shadow" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the systems has expire shadow information" >&5
-$as_echo_n "checking if the systems has expire shadow information... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the systems has expire shadow information" >&5
+printf %s "checking if the systems has expire shadow information... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <shadow.h>
struct spwd sp;
int
-main ()
+main (void)
{
sp.sp_expire = sp.sp_lstchg = sp.sp_inact = 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
sp_expire_available=yes
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
if test "x$sp_expire_available" = "xyes" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAS_SHADOW_EXPIRE 1" >>confdefs.h
+printf "%s\n" "#define HAS_SHADOW_EXPIRE 1" >>confdefs.h
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
fi
# Use ip address instead of hostname in $DISPLAY
if test ! -z "$IPADDR_IN_DISPLAY" ; then
DISPLAY_HACK_MSG="yes"
-$as_echo "#define IPADDR_IN_DISPLAY 1" >>confdefs.h
+printf "%s\n" "#define IPADDR_IN_DISPLAY 1" >>confdefs.h
else
DISPLAY_HACK_MSG="no"
# Check whether --with-ipaddr-display was given.
-if test "${with_ipaddr_display+set}" = set; then :
+if test ${with_ipaddr_display+y}
+then :
withval=$with_ipaddr_display;
if test "x$withval" != "xno" ; then
- $as_echo "#define IPADDR_IN_DISPLAY 1" >>confdefs.h
+ printf "%s\n" "#define IPADDR_IN_DISPLAY 1" >>confdefs.h
DISPLAY_HACK_MSG="yes"
fi
fi
fi
# check for /etc/default/login and use it if present.
# Check whether --enable-etc-default-login was given.
-if test "${enable_etc_default_login+set}" = set; then :
+if test ${enable_etc_default_login+y}
+then :
enableval=$enable_etc_default_login; if test "x$enableval" = "xno"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: /etc/default/login handling disabled" >&5
-$as_echo "$as_me: /etc/default/login handling disabled" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: /etc/default/login handling disabled" >&5
+printf "%s\n" "$as_me: /etc/default/login handling disabled" >&6;}
etc_default_login=no
else
etc_default_login=yes
fi
-else
+else $as_nop
if test ! -z "$cross_compiling" && test "x$cross_compiling" = "xyes";
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking /etc/default/login" >&5
-$as_echo "$as_me: WARNING: cross compiling: not checking /etc/default/login" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: not checking /etc/default/login" >&5
+printf "%s\n" "$as_me: WARNING: cross compiling: not checking /etc/default/login" >&2;}
etc_default_login=no
else
etc_default_login=yes
fi
fi
if test "x$etc_default_login" != "xno"; then
- as_ac_File=`$as_echo "ac_cv_file_"/etc/default/login"" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for \"/etc/default/login\"" >&5
-$as_echo_n "checking for \"/etc/default/login\"... " >&6; }
-if eval \${$as_ac_File+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ as_ac_File=`printf "%s\n" "ac_cv_file_"/etc/default/login"" | $as_tr_sh`
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for \"/etc/default/login\"" >&5
+printf %s "checking for \"/etc/default/login\"... " >&6; }
+if eval test \${$as_ac_File+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
test "$cross_compiling" = yes &&
as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
if test -r ""/etc/default/login""; then
eval "$as_ac_File=yes"
else
eval "$as_ac_File=no"
fi
fi
eval ac_res=\$$as_ac_File
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_File"\" = x"yes"; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_File"\" = x"yes"
+then :
external_path_file=/etc/default/login
fi
if test "x$external_path_file" = "x/etc/default/login"; then
-$as_echo "#define HAVE_ETC_DEFAULT_LOGIN 1" >>confdefs.h
+printf "%s\n" "#define HAVE_ETC_DEFAULT_LOGIN 1" >>confdefs.h
fi
fi
if test $ac_cv_func_login_getcapbool = "yes" && \
test $ac_cv_header_login_cap_h = "yes" ; then
external_path_file=/etc/login.conf
fi
# Whether to mess with the default path
SERVER_PATH_MSG="(default)"
# Check whether --with-default-path was given.
-if test "${with_default_path+set}" = set; then :
+if test ${with_default_path+y}
+then :
withval=$with_default_path;
if test "x$external_path_file" = "x/etc/login.conf" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING:
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING:
--with-default-path=PATH has no effect on this system.
Edit /etc/login.conf instead." >&5
-$as_echo "$as_me: WARNING:
+printf "%s\n" "$as_me: WARNING:
--with-default-path=PATH has no effect on this system.
Edit /etc/login.conf instead." >&2;}
elif test "x$withval" != "xno" ; then
if test ! -z "$external_path_file" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING:
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING:
--with-default-path=PATH will only be used if PATH is not defined in
$external_path_file ." >&5
-$as_echo "$as_me: WARNING:
+printf "%s\n" "$as_me: WARNING:
--with-default-path=PATH will only be used if PATH is not defined in
$external_path_file ." >&2;}
fi
user_path="$withval"
SERVER_PATH_MSG="$withval"
fi
-else
+else $as_nop
if test "x$external_path_file" = "x/etc/login.conf" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Make sure the path to scp is in /etc/login.conf" >&5
-$as_echo "$as_me: WARNING: Make sure the path to scp is in /etc/login.conf" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Make sure the path to scp is in /etc/login.conf" >&5
+printf "%s\n" "$as_me: WARNING: Make sure the path to scp is in /etc/login.conf" >&2;}
else
if test ! -z "$external_path_file" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING:
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING:
If PATH is defined in $external_path_file, ensure the path to scp is included,
otherwise scp will not work." >&5
-$as_echo "$as_me: WARNING:
+printf "%s\n" "$as_me: WARNING:
If PATH is defined in $external_path_file, ensure the path to scp is included,
otherwise scp will not work." >&2;}
fi
- if test "$cross_compiling" = yes; then :
+ if test "$cross_compiling" = yes
+then :
user_path="/usr/bin:/bin:/usr/sbin:/sbin"
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* find out what STDPATH is */
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#ifndef _PATH_STDPATH
# ifdef _PATH_USERPATH /* Irix */
# define _PATH_STDPATH _PATH_USERPATH
# else
# define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin"
# endif
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define DATA "conftest.stdpath"
int
-main ()
+main (void)
{
FILE *fd;
int rc;
fd = fopen(DATA,"w");
if(fd == NULL)
exit(1);
if ((rc = fprintf(fd,"%s", _PATH_STDPATH)) < 0)
exit(1);
exit(0);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_run "$LINENO"
+then :
user_path=`cat conftest.stdpath`
-else
+else $as_nop
user_path="/usr/bin:/bin:/usr/sbin:/sbin"
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
# make sure $bindir is in USER_PATH so scp will work
t_bindir="${bindir}"
while echo "${t_bindir}" | egrep '\$\{|NONE/' >/dev/null 2>&1; do
t_bindir=`eval echo ${t_bindir}`
case $t_bindir in
NONE/*) t_bindir=`echo $t_bindir | sed "s~NONE~$prefix~"` ;;
esac
case $t_bindir in
NONE/*) t_bindir=`echo $t_bindir | sed "s~NONE~$ac_default_prefix~"` ;;
esac
done
echo $user_path | grep ":$t_bindir" > /dev/null 2>&1
if test $? -ne 0 ; then
echo $user_path | grep "^$t_bindir" > /dev/null 2>&1
if test $? -ne 0 ; then
user_path=$user_path:$t_bindir
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Adding $t_bindir to USER_PATH so scp will work" >&5
-$as_echo "Adding $t_bindir to USER_PATH so scp will work" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Adding $t_bindir to USER_PATH so scp will work" >&5
+printf "%s\n" "Adding $t_bindir to USER_PATH so scp will work" >&6; }
fi
fi
fi
fi
if test "x$external_path_file" != "x/etc/login.conf" ; then
-cat >>confdefs.h <<_ACEOF
-#define USER_PATH "$user_path"
-_ACEOF
+printf "%s\n" "#define USER_PATH \"$user_path\"" >>confdefs.h
fi
# Set superuser path separately to user path
# Check whether --with-superuser-path was given.
-if test "${with_superuser_path+set}" = set; then :
+if test ${with_superuser_path+y}
+then :
withval=$with_superuser_path;
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
-cat >>confdefs.h <<_ACEOF
-#define SUPERUSER_PATH "$withval"
-_ACEOF
+printf "%s\n" "#define SUPERUSER_PATH \"$withval\"" >>confdefs.h
superuser_path=$withval
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we need to convert IPv4 in IPv6-mapped addresses" >&5
-$as_echo_n "checking if we need to convert IPv4 in IPv6-mapped addresses... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we need to convert IPv4 in IPv6-mapped addresses" >&5
+printf %s "checking if we need to convert IPv4 in IPv6-mapped addresses... " >&6; }
IPV4_IN6_HACK_MSG="no"
# Check whether --with-4in6 was given.
-if test "${with_4in6+set}" = set; then :
+if test ${with_4in6+y}
+then :
withval=$with_4in6;
if test "x$withval" != "xno" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define IPV4_IN_IPV6 1" >>confdefs.h
+printf "%s\n" "#define IPV4_IN_IPV6 1" >>confdefs.h
IPV4_IN6_HACK_MSG="yes"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-else
+else $as_nop
if test "x$inet6_default_4in6" = "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (default)" >&5
-$as_echo "yes (default)" >&6; }
- $as_echo "#define IPV4_IN_IPV6 1" >>confdefs.h
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (default)" >&5
+printf "%s\n" "yes (default)" >&6; }
+ printf "%s\n" "#define IPV4_IN_IPV6 1" >>confdefs.h
IPV4_IN6_HACK_MSG="yes"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no (default)" >&5
-$as_echo "no (default)" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no (default)" >&5
+printf "%s\n" "no (default)" >&6; }
fi
fi
# Whether to enable BSD auth support
BSD_AUTH_MSG=no
# Check whether --with-bsd-auth was given.
-if test "${with_bsd_auth+set}" = set; then :
+if test ${with_bsd_auth+y}
+then :
withval=$with_bsd_auth;
if test "x$withval" != "xno" ; then
-$as_echo "#define BSD_AUTH 1" >>confdefs.h
+printf "%s\n" "#define BSD_AUTH 1" >>confdefs.h
BSD_AUTH_MSG=yes
fi
fi
# Where to place sshd.pid
piddir=/var/run
# make sure the directory exists
if test ! -d $piddir ; then
piddir=`eval echo ${sysconfdir}`
case $piddir in
NONE/*) piddir=`echo $piddir | sed "s~NONE~$ac_default_prefix~"` ;;
esac
fi
# Check whether --with-pid-dir was given.
-if test "${with_pid_dir+set}" = set; then :
+if test ${with_pid_dir+y}
+then :
withval=$with_pid_dir;
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
piddir=$withval
if test ! -d $piddir ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ** no $piddir directory on this system **" >&5
-$as_echo "$as_me: WARNING: ** no $piddir directory on this system **" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: ** no $piddir directory on this system **" >&5
+printf "%s\n" "$as_me: WARNING: ** no $piddir directory on this system **" >&2;}
fi
fi
fi
-cat >>confdefs.h <<_ACEOF
-#define _PATH_SSH_PIDDIR "$piddir"
-_ACEOF
+printf "%s\n" "#define _PATH_SSH_PIDDIR \"$piddir\"" >>confdefs.h
# Check whether --enable-lastlog was given.
-if test "${enable_lastlog+set}" = set; then :
+if test ${enable_lastlog+y}
+then :
enableval=$enable_lastlog;
if test "x$enableval" = "xno" ; then
- $as_echo "#define DISABLE_LASTLOG 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_LASTLOG 1" >>confdefs.h
fi
fi
# Check whether --enable-utmp was given.
-if test "${enable_utmp+set}" = set; then :
+if test ${enable_utmp+y}
+then :
enableval=$enable_utmp;
if test "x$enableval" = "xno" ; then
- $as_echo "#define DISABLE_UTMP 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_UTMP 1" >>confdefs.h
fi
fi
# Check whether --enable-utmpx was given.
-if test "${enable_utmpx+set}" = set; then :
+if test ${enable_utmpx+y}
+then :
enableval=$enable_utmpx;
if test "x$enableval" = "xno" ; then
-$as_echo "#define DISABLE_UTMPX 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_UTMPX 1" >>confdefs.h
fi
fi
# Check whether --enable-wtmp was given.
-if test "${enable_wtmp+set}" = set; then :
+if test ${enable_wtmp+y}
+then :
enableval=$enable_wtmp;
if test "x$enableval" = "xno" ; then
- $as_echo "#define DISABLE_WTMP 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_WTMP 1" >>confdefs.h
fi
fi
# Check whether --enable-wtmpx was given.
-if test "${enable_wtmpx+set}" = set; then :
+if test ${enable_wtmpx+y}
+then :
enableval=$enable_wtmpx;
if test "x$enableval" = "xno" ; then
-$as_echo "#define DISABLE_WTMPX 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_WTMPX 1" >>confdefs.h
fi
fi
# Check whether --enable-libutil was given.
-if test "${enable_libutil+set}" = set; then :
+if test ${enable_libutil+y}
+then :
enableval=$enable_libutil;
if test "x$enableval" = "xno" ; then
- $as_echo "#define DISABLE_LOGIN 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_LOGIN 1" >>confdefs.h
fi
fi
# Check whether --enable-pututline was given.
-if test "${enable_pututline+set}" = set; then :
+if test ${enable_pututline+y}
+then :
enableval=$enable_pututline;
if test "x$enableval" = "xno" ; then
-$as_echo "#define DISABLE_PUTUTLINE 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_PUTUTLINE 1" >>confdefs.h
fi
fi
# Check whether --enable-pututxline was given.
-if test "${enable_pututxline+set}" = set; then :
+if test ${enable_pututxline+y}
+then :
enableval=$enable_pututxline;
if test "x$enableval" = "xno" ; then
-$as_echo "#define DISABLE_PUTUTXLINE 1" >>confdefs.h
+printf "%s\n" "#define DISABLE_PUTUTXLINE 1" >>confdefs.h
fi
fi
# Check whether --with-lastlog was given.
-if test "${with_lastlog+set}" = set; then :
+if test ${with_lastlog+y}
+then :
withval=$with_lastlog;
if test "x$withval" = "xno" ; then
- $as_echo "#define DISABLE_LASTLOG 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_LASTLOG 1" >>confdefs.h
elif test -n "$withval" && test "x${withval}" != "xyes"; then
conf_lastlog_location=$withval
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if your system defines LASTLOG_FILE" >&5
-$as_echo_n "checking if your system defines LASTLOG_FILE... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if your system defines LASTLOG_FILE" >&5
+printf %s "checking if your system defines LASTLOG_FILE... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_LASTLOG_H
# include <lastlog.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#ifdef HAVE_LOGIN_H
# include <login.h>
#endif
int
-main ()
+main (void)
{
char *lastlog = LASTLOG_FILE;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if your system defines _PATH_LASTLOG" >&5
-$as_echo_n "checking if your system defines _PATH_LASTLOG... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if your system defines _PATH_LASTLOG" >&5
+printf %s "checking if your system defines _PATH_LASTLOG... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_LASTLOG_H
# include <lastlog.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
int
-main ()
+main (void)
{
char *lastlog = _PATH_LASTLOG;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
system_lastlog_path=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
if test -z "$conf_lastlog_location"; then
if test x"$system_lastlog_path" = x"no" ; then
for f in /var/log/lastlog /usr/adm/lastlog /var/adm/lastlog /etc/security/lastlog ; do
if (test -d "$f" || test -f "$f") ; then
conf_lastlog_location=$f
fi
done
if test -z "$conf_lastlog_location"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ** Cannot find lastlog **" >&5
-$as_echo "$as_me: WARNING: ** Cannot find lastlog **" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: ** Cannot find lastlog **" >&5
+printf "%s\n" "$as_me: WARNING: ** Cannot find lastlog **" >&2;}
fi
fi
fi
if test -n "$conf_lastlog_location"; then
-cat >>confdefs.h <<_ACEOF
-#define CONF_LASTLOG_FILE "$conf_lastlog_location"
-_ACEOF
+printf "%s\n" "#define CONF_LASTLOG_FILE \"$conf_lastlog_location\"" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if your system defines UTMP_FILE" >&5
-$as_echo_n "checking if your system defines UTMP_FILE... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if your system defines UTMP_FILE" >&5
+printf %s "checking if your system defines UTMP_FILE... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
int
-main ()
+main (void)
{
char *utmp = UTMP_FILE;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
system_utmp_path=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
if test -z "$conf_utmp_location"; then
if test x"$system_utmp_path" = x"no" ; then
for f in /etc/utmp /usr/adm/utmp /var/run/utmp; do
if test -f $f ; then
conf_utmp_location=$f
fi
done
if test -z "$conf_utmp_location"; then
- $as_echo "#define DISABLE_UTMP 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_UTMP 1" >>confdefs.h
fi
fi
fi
if test -n "$conf_utmp_location"; then
-cat >>confdefs.h <<_ACEOF
-#define CONF_UTMP_FILE "$conf_utmp_location"
-_ACEOF
+printf "%s\n" "#define CONF_UTMP_FILE \"$conf_utmp_location\"" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if your system defines WTMP_FILE" >&5
-$as_echo_n "checking if your system defines WTMP_FILE... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if your system defines WTMP_FILE" >&5
+printf %s "checking if your system defines WTMP_FILE... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
int
-main ()
+main (void)
{
char *wtmp = WTMP_FILE;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
system_wtmp_path=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
if test -z "$conf_wtmp_location"; then
if test x"$system_wtmp_path" = x"no" ; then
for f in /usr/adm/wtmp /var/log/wtmp; do
if test -f $f ; then
conf_wtmp_location=$f
fi
done
if test -z "$conf_wtmp_location"; then
- $as_echo "#define DISABLE_WTMP 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_WTMP 1" >>confdefs.h
fi
fi
fi
if test -n "$conf_wtmp_location"; then
-cat >>confdefs.h <<_ACEOF
-#define CONF_WTMP_FILE "$conf_wtmp_location"
-_ACEOF
+printf "%s\n" "#define CONF_WTMP_FILE \"$conf_wtmp_location\"" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if your system defines WTMPX_FILE" >&5
-$as_echo_n "checking if your system defines WTMPX_FILE... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if your system defines WTMPX_FILE" >&5
+printf %s "checking if your system defines WTMPX_FILE... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_UTMPX_H
#include <utmpx.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
int
-main ()
+main (void)
{
char *wtmpx = WTMPX_FILE;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if ac_fn_c_try_compile "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
system_wtmpx_path=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
if test -z "$conf_wtmpx_location"; then
if test x"$system_wtmpx_path" = x"no" ; then
- $as_echo "#define DISABLE_WTMPX 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_WTMPX 1" >>confdefs.h
fi
else
-cat >>confdefs.h <<_ACEOF
-#define CONF_WTMPX_FILE "$conf_wtmpx_location"
-_ACEOF
+printf "%s\n" "#define CONF_WTMPX_FILE \"$conf_wtmpx_location\"" >>confdefs.h
fi
if test ! -z "$blibpath" ; then
LDFLAGS="$LDFLAGS $blibflags$blibpath"
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Please check and edit blibpath in LDFLAGS in Makefile" >&5
-$as_echo "$as_me: WARNING: Please check and edit blibpath in LDFLAGS in Makefile" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Please check and edit blibpath in LDFLAGS in Makefile" >&5
+printf "%s\n" "$as_me: WARNING: Please check and edit blibpath in LDFLAGS in Makefile" >&2;}
fi
ac_fn_c_check_member "$LINENO" "struct lastlog" "ll_line" "ac_cv_member_struct_lastlog_ll_line" "
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_UTMP_H
#include <utmp.h>
#endif
#ifdef HAVE_UTMPX_H
#include <utmpx.h>
#endif
#ifdef HAVE_LASTLOG_H
#include <lastlog.h>
#endif
"
-if test "x$ac_cv_member_struct_lastlog_ll_line" = xyes; then :
+if test "x$ac_cv_member_struct_lastlog_ll_line" = xyes
+then :
-else
+else $as_nop
if test x$SKIP_DISABLE_LASTLOG_DEFINE != "xyes" ; then
- $as_echo "#define DISABLE_LASTLOG 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_LASTLOG 1" >>confdefs.h
fi
fi
ac_fn_c_check_member "$LINENO" "struct utmp" "ut_line" "ac_cv_member_struct_utmp_ut_line" "
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_UTMP_H
#include <utmp.h>
#endif
#ifdef HAVE_UTMPX_H
#include <utmpx.h>
#endif
#ifdef HAVE_LASTLOG_H
#include <lastlog.h>
#endif
"
-if test "x$ac_cv_member_struct_utmp_ut_line" = xyes; then :
+if test "x$ac_cv_member_struct_utmp_ut_line" = xyes
+then :
-else
+else $as_nop
- $as_echo "#define DISABLE_UTMP 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_UTMP 1" >>confdefs.h
- $as_echo "#define DISABLE_WTMP 1" >>confdefs.h
+ printf "%s\n" "#define DISABLE_WTMP 1" >>confdefs.h
fi
CFLAGS="$CFLAGS $werror_flags"
if test "x$ac_cv_func_getaddrinfo" != "xyes" ; then
TEST_SSH_IPV6=no
else
TEST_SSH_IPV6=yes
fi
-ac_fn_c_check_decl "$LINENO" "BROKEN_GETADDRINFO" "ac_cv_have_decl_BROKEN_GETADDRINFO" "$ac_includes_default"
-if test "x$ac_cv_have_decl_BROKEN_GETADDRINFO" = xyes; then :
+ac_fn_check_decl "$LINENO" "BROKEN_GETADDRINFO" "ac_cv_have_decl_BROKEN_GETADDRINFO" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_BROKEN_GETADDRINFO" = xyes
+then :
TEST_SSH_IPV6=no
fi
-
TEST_SSH_IPV6=$TEST_SSH_IPV6
TEST_SSH_UTF8=$TEST_SSH_UTF8
TEST_MALLOC_OPTIONS=$TEST_MALLOC_OPTIONS
UNSUPPORTED_ALGORITHMS=$unsupported_algorithms
DEPEND=$(cat $srcdir/.depend)
CFLAGS="${CFLAGS} ${CFLAGS_AFTER}"
LDFLAGS="${LDFLAGS} ${LDFLAGS_AFTER}"
# Make a copy of CFLAGS/LDFLAGS without PIE options.
LDFLAGS_NOPIE=`echo "$LDFLAGS" | sed 's/ -pie//'`
CFLAGS_NOPIE=`echo "$CFLAGS" | sed 's/ -fPIE//'`
ac_config_files="$ac_config_files Makefile buildpkg.sh opensshd.init openssh.xml openbsd-compat/Makefile openbsd-compat/regress/Makefile survey.sh"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
# scripts and configure runs, see configure's option --config-cache.
# It is not useful on other systems. If it contains results you don't
# want to keep, you may remove or edit it.
#
# config.status only pays attention to the cache file if you give it
# the --recheck option to rerun configure.
#
# `ac_cv_env_foo' variables (set or unset) will be overridden when
# loading this file, other *unset* `ac_cv_foo' will be assigned the
# following values.
_ACEOF
# The following way of writing the cache mishandles newlines in values,
# but we know of no workaround that is simple, portable, and efficient.
# So, we kill variables containing newlines.
# Ultrix sh set writes to stderr and can't be redirected directly,
# and sets the high bit in the cache file unless we assign to the vars.
(
for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
eval ac_val=\$$ac_var
case $ac_val in #(
*${as_nl}*)
case $ac_var in #(
- *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
esac
case $ac_var in #(
_ | IFS | as_nl) ;; #(
BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
*) { eval $ac_var=; unset $ac_var;} ;;
esac ;;
esac
done
(set) 2>&1 |
case $as_nl`(ac_space=' '; set) 2>&1` in #(
*${as_nl}ac_space=\ *)
# `set' does not quote correctly, so add quotes: double-quote
# substitution turns \\\\ into \\, and sed turns \\ into \.
sed -n \
"s/'/'\\\\''/g;
s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
;; #(
*)
# `set' quotes correctly as required by POSIX, so do not add quotes.
sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
;;
esac |
sort
) |
sed '
/^ac_cv_env_/b end
t clear
:clear
- s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/
t end
s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
:end' >>confcache
if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
if test -w "$cache_file"; then
if test "x$cache_file" != "x/dev/null"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
-$as_echo "$as_me: updating cache $cache_file" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+printf "%s\n" "$as_me: updating cache $cache_file" >&6;}
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
case $cache_file in #(
*/* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
*)
mv -f confcache "$cache_file" ;;
esac
fi
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
-$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;}
fi
fi
rm -f confcache
test "x$prefix" = xNONE && prefix=$ac_default_prefix
# Let make expand exec_prefix.
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
DEFS=-DHAVE_CONFIG_H
ac_libobjs=
ac_ltlibobjs=
U=
for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
# 1. Remove the extension, and $U if already installed.
ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
- ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"`
# 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
# will be set to the directory where LIBOBJS objects are built.
as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
done
LIBOBJS=$ac_libobjs
LTLIBOBJS=$ac_ltlibobjs
: "${CONFIG_STATUS=./config.status}"
ac_write_fail=0
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files $CONFIG_STATUS"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
-$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;}
as_write_fail=0
cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
#! $SHELL
# Generated by $as_me.
# Run this file to recreate the current configuration.
# Compiler output produced by configure, useful for debugging
# configure, is in config.log if it exists.
debug=false
ac_cs_recheck=false
ac_cs_silent=false
SHELL=\${CONFIG_SHELL-$SHELL}
export SHELL
_ASEOF
cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
## -------------------- ##
## M4sh Initialization. ##
## -------------------- ##
# Be more Bourne compatible
DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+as_nop=:
+if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
+then :
emulate sh
NULLCMD=:
# Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
# is contrary to our usage. Disable this feature.
alias -g '${1+"$@"}'='"$@"'
setopt NO_GLOB_SUBST
-else
+else $as_nop
case `(set -o) 2>/dev/null` in #(
*posix*) :
set -o posix ;; #(
*) :
;;
esac
fi
+
+# Reset variables that may have inherited troublesome values from
+# the environment.
+
+# IFS needs to be set, to space, tab, and newline, in precisely that order.
+# (If _AS_PATH_WALK were called with IFS unset, it would have the
+# side effect of setting IFS to empty, thus disabling word splitting.)
+# Quoting is to prevent editors from complaining about space-tab.
as_nl='
'
export as_nl
-# Printing a long string crashes Solaris 7 /usr/bin/printf.
-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-# Prefer a ksh shell builtin over an external printf program on Solaris,
-# but without wasting forks for bash or zsh.
-if test -z "$BASH_VERSION$ZSH_VERSION" \
- && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
- as_echo='print -r --'
- as_echo_n='print -rn --'
-elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
- as_echo='printf %s\n'
- as_echo_n='printf %s'
-else
- if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
- as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
- as_echo_n='/usr/ucb/echo -n'
- else
- as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
- as_echo_n_body='eval
- arg=$1;
- case $arg in #(
- *"$as_nl"*)
- expr "X$arg" : "X\\(.*\\)$as_nl";
- arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
- esac;
- expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
- '
- export as_echo_n_body
- as_echo_n='sh -c $as_echo_n_body as_echo'
- fi
- export as_echo_body
- as_echo='sh -c $as_echo_body as_echo'
-fi
+IFS=" "" $as_nl"
+
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# Ensure predictable behavior from utilities with locale-dependent output.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# We cannot yet rely on "unset" to work, but we need these variables
+# to be unset--not just set to an empty or harmless value--now, to
+# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
+# also avoids known problems related to "unset" and subshell syntax
+# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
+for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
+do eval test \${$as_var+y} \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+
+# Ensure that fds 0, 1, and 2 are open.
+if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
+if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
+if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
+if ${PATH_SEPARATOR+false} :; then
PATH_SEPARATOR=:
(PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
(PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
PATH_SEPARATOR=';'
}
fi
-# IFS
-# We need space, tab and new line, in precisely that order. Quoting is
-# there to prevent editors from complaining about space-tab.
-# (If _AS_PATH_WALK were called with IFS unset, it would disable word
-# splitting by setting IFS to empty value.)
-IFS=" "" $as_nl"
-
# Find who we are. Look in the path if we contain no directory separator.
as_myself=
case $0 in #((
*[\\/]* ) as_myself=$0 ;;
*) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ test -r "$as_dir$0" && as_myself=$as_dir$0 && break
done
IFS=$as_save_IFS
;;
esac
# We did not find ourselves, most probably we were run as `sh COMMAND'
# in which case we are not to be found in the path.
if test "x$as_myself" = x; then
as_myself=$0
fi
if test ! -f "$as_myself"; then
- $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
exit 1
fi
-# Unset variables that we do not need and which cause bugs (e.g. in
-# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
-# suppresses any "Segmentation fault" message there. '((' could
-# trigger a bug in pdksh 5.2.14.
-for as_var in BASH_ENV ENV MAIL MAILPATH
-do eval test x\${$as_var+set} = xset \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# NLS nuisances.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# CDPATH.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
# as_fn_error STATUS ERROR [LINENO LOG_FD]
# ----------------------------------------
# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
# script with STATUS, using 1 if that was 0.
as_fn_error ()
{
as_status=$1; test $as_status -eq 0 && as_status=1
if test "$4"; then
as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
fi
- $as_echo "$as_me: error: $2" >&2
+ printf "%s\n" "$as_me: error: $2" >&2
as_fn_exit $as_status
} # as_fn_error
+
# as_fn_set_status STATUS
# -----------------------
# Set $? to STATUS, without forking.
as_fn_set_status ()
{
return $1
} # as_fn_set_status
# as_fn_exit STATUS
# -----------------
# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
as_fn_exit ()
{
set +e
as_fn_set_status $1
exit $1
} # as_fn_exit
# as_fn_unset VAR
# ---------------
# Portably unset VAR.
as_fn_unset ()
{
{ eval $1=; unset $1;}
}
as_unset=as_fn_unset
+
# as_fn_append VAR VALUE
# ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take
# advantage of any shell optimizations that allow amortized linear growth over
# repeated appends, instead of the typical quadratic growth present in naive
# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null
+then :
eval 'as_fn_append ()
{
eval $1+=\$2
}'
-else
+else $as_nop
as_fn_append ()
{
eval $1=\$$1\$2
}
fi # as_fn_append
# as_fn_arith ARG...
# ------------------
# Perform arithmetic evaluation on the ARGs, and store the result in the
# global $as_val. Take advantage of shells that can avoid forks. The arguments
# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null
+then :
eval 'as_fn_arith ()
{
as_val=$(( $* ))
}'
-else
+else $as_nop
as_fn_arith ()
{
as_val=`expr "$@" || test $? -eq 1`
}
fi # as_fn_arith
if expr a : '\(a\)' >/dev/null 2>&1 &&
test "X`expr 00001 : '.*\(...\)'`" = X001; then
as_expr=expr
else
as_expr=false
fi
if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
as_basename=basename
else
as_basename=false
fi
if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
as_dirname=dirname
else
as_dirname=false
fi
as_me=`$as_basename -- "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
X"$0" : 'X\(//\)$' \| \
X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X/"$0" |
+printf "%s\n" X/"$0" |
sed '/^.*\/\([^/][^/]*\)\/*$/{
s//\1/
q
}
/^X\/\(\/\/\)$/{
s//\1/
q
}
/^X\/\(\/\).*/{
s//\1/
q
}
s/.*/./; q'`
# Avoid depending upon Character Ranges.
as_cr_letters='abcdefghijklmnopqrstuvwxyz'
as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
as_cr_Letters=$as_cr_letters$as_cr_LETTERS
as_cr_digits='0123456789'
as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# Determine whether it's possible to make 'echo' print without a newline.
+# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
+# for compatibility with existing Makefiles.
ECHO_C= ECHO_N= ECHO_T=
case `echo -n x` in #(((((
-n*)
case `echo 'xy\c'` in
*c*) ECHO_T=' ';; # ECHO_T is single tab character.
xy) ECHO_C='\c';;
*) echo `echo ksh88 bug on AIX 6.1` > /dev/null
ECHO_T=' ';;
esac;;
*)
ECHO_N='-n';;
esac
+# For backward compatibility with old third-party macros, we provide
+# the shell variables $as_echo and $as_echo_n. New code should use
+# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
+as_echo='printf %s\n'
+as_echo_n='printf %s'
+
rm -f conf$$ conf$$.exe conf$$.file
if test -d conf$$.dir; then
rm -f conf$$.dir/conf$$.file
else
rm -f conf$$.dir
mkdir conf$$.dir 2>/dev/null
fi
if (echo >conf$$.file) 2>/dev/null; then
if ln -s conf$$.file conf$$ 2>/dev/null; then
as_ln_s='ln -s'
# ... but there are two gotchas:
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
# In both cases, we have to default to `cp -pR'.
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
as_ln_s='cp -pR'
elif ln conf$$.file conf$$ 2>/dev/null; then
as_ln_s=ln
else
as_ln_s='cp -pR'
fi
else
as_ln_s='cp -pR'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null
# as_fn_mkdir_p
# -------------
# Create "$as_dir" as a directory, including parents if necessary.
as_fn_mkdir_p ()
{
case $as_dir in #(
-*) as_dir=./$as_dir;;
esac
test -d "$as_dir" || eval $as_mkdir_p || {
as_dirs=
while :; do
case $as_dir in #(
- *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
*) as_qdir=$as_dir;;
esac
as_dirs="'$as_qdir' $as_dirs"
as_dir=`$as_dirname -- "$as_dir" ||
$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$as_dir" : 'X\(//\)[^/]' \| \
X"$as_dir" : 'X\(//\)$' \| \
X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_dir" |
+printf "%s\n" X"$as_dir" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'`
test -d "$as_dir" && break
done
test -z "$as_dirs" || eval "mkdir $as_dirs"
} || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
} # as_fn_mkdir_p
if mkdir -p . 2>/dev/null; then
as_mkdir_p='mkdir -p "$as_dir"'
else
test -d ./-p && rmdir ./-p
as_mkdir_p=false
fi
# as_fn_executable_p FILE
# -----------------------
# Test if FILE is an executable regular file.
as_fn_executable_p ()
{
test -f "$1" && test -x "$1"
} # as_fn_executable_p
as_test_x='test -x'
as_executable_p=as_fn_executable_p
# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
# Sed expression to map a string onto a valid variable name.
as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
exec 6>&1
## ----------------------------------- ##
## Main body of $CONFIG_STATUS script. ##
## ----------------------------------- ##
_ASEOF
test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# Save the log message, to keep $0 and so on meaningful, and to
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by OpenSSH $as_me Portable, which was
-generated by GNU Autoconf 2.69. Invocation command line was
+generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
CONFIG_LINKS = $CONFIG_LINKS
CONFIG_COMMANDS = $CONFIG_COMMANDS
$ $0 $@
on `(hostname || uname -n) 2>/dev/null | sed 1q`
"
_ACEOF
case $ac_config_files in *"
"*) set x $ac_config_files; shift; ac_config_files=$*;;
esac
case $ac_config_headers in *"
"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
esac
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
# Files that config.status was made for.
config_files="$ac_config_files"
config_headers="$ac_config_headers"
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
ac_cs_usage="\
\`$as_me' instantiates files and other configuration actions
from templates according to the current configuration. Unless the files
and actions are specified as TAGs, all are instantiated by default.
Usage: $0 [OPTION]... [TAG]...
-h, --help print this help, then exit
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
instantiate the configuration file FILE
--header=FILE[:TEMPLATE]
instantiate the configuration header FILE
Configuration files:
$config_files
Configuration headers:
$config_headers
Report bugs to <openssh-unix-dev@mindrot.org>."
_ACEOF
+ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"`
+ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"`
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
OpenSSH config.status Portable
-configured by $0, generated by GNU Autoconf 2.69,
+configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2021 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."
ac_pwd='$ac_pwd'
srcdir='$srcdir'
INSTALL='$INSTALL'
MKDIR_P='$MKDIR_P'
AWK='$AWK'
test -n "\$AWK" || AWK=awk
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# The default lists apply if the user does not specify any file.
ac_need_defaults=:
while test $# != 0
do
case $1 in
--*=?*)
ac_option=`expr "X$1" : 'X\([^=]*\)='`
ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
ac_shift=:
;;
--*=)
ac_option=`expr "X$1" : 'X\([^=]*\)='`
ac_optarg=
ac_shift=:
;;
*)
ac_option=$1
ac_optarg=$2
ac_shift=shift
;;
esac
case $ac_option in
# Handling of the options.
-recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
ac_cs_recheck=: ;;
--version | --versio | --versi | --vers | --ver | --ve | --v | -V )
- $as_echo "$ac_cs_version"; exit ;;
+ printf "%s\n" "$ac_cs_version"; exit ;;
--config | --confi | --conf | --con | --co | --c )
- $as_echo "$ac_cs_config"; exit ;;
+ printf "%s\n" "$ac_cs_config"; exit ;;
--debug | --debu | --deb | --de | --d | -d )
debug=: ;;
--file | --fil | --fi | --f )
$ac_shift
case $ac_optarg in
- *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
'') as_fn_error $? "missing file argument" ;;
esac
as_fn_append CONFIG_FILES " '$ac_optarg'"
ac_need_defaults=false;;
--header | --heade | --head | --hea )
$ac_shift
case $ac_optarg in
- *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
esac
as_fn_append CONFIG_HEADERS " '$ac_optarg'"
ac_need_defaults=false;;
--he | --h)
# Conflict between --help and --header
as_fn_error $? "ambiguous option: \`$1'
Try \`$0 --help' for more information.";;
--help | --hel | -h )
- $as_echo "$ac_cs_usage"; exit ;;
+ printf "%s\n" "$ac_cs_usage"; exit ;;
-q | -quiet | --quiet | --quie | --qui | --qu | --q \
| -silent | --silent | --silen | --sile | --sil | --si | --s)
ac_cs_silent=: ;;
# This is an error.
-*) as_fn_error $? "unrecognized option: \`$1'
Try \`$0 --help' for more information." ;;
*) as_fn_append ac_config_targets " $1"
ac_need_defaults=false ;;
esac
shift
done
ac_configure_extra_args=
if $ac_cs_silent; then
exec 6>/dev/null
ac_configure_extra_args="$ac_configure_extra_args --silent"
fi
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
if \$ac_cs_recheck; then
set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
shift
- \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6
CONFIG_SHELL='$SHELL'
export CONFIG_SHELL
exec "\$@"
fi
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
exec 5>>config.log
{
echo
sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
## Running $as_me. ##
_ASBOX
- $as_echo "$ac_log"
+ printf "%s\n" "$ac_log"
} >&5
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# Handling of arguments.
for ac_config_target in $ac_config_targets
do
case $ac_config_target in
"config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
"buildpkg.sh") CONFIG_FILES="$CONFIG_FILES buildpkg.sh" ;;
"opensshd.init") CONFIG_FILES="$CONFIG_FILES opensshd.init" ;;
"openssh.xml") CONFIG_FILES="$CONFIG_FILES openssh.xml" ;;
"openbsd-compat/Makefile") CONFIG_FILES="$CONFIG_FILES openbsd-compat/Makefile" ;;
"openbsd-compat/regress/Makefile") CONFIG_FILES="$CONFIG_FILES openbsd-compat/regress/Makefile" ;;
"survey.sh") CONFIG_FILES="$CONFIG_FILES survey.sh" ;;
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
esac
done
# If the user did not use the arguments to specify the items to instantiate,
# then the envvar interface is used. Set only those that are not.
# We use the long form for the default assignment because of an extremely
# bizarre bug on SunOS 4.1.3.
if $ac_need_defaults; then
- test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
- test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files
+ test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers
fi
# Have a temporary directory for convenience. Make it in the build tree
# simply because there is no reason against having it here, and in addition,
# creating and moving files from /tmp can sometimes cause problems.
# Hook for its removal unless debugging.
# Note that there is a small window in which the directory will not be cleaned:
# after its creation but before its name has been assigned to `$tmp'.
$debug ||
{
tmp= ac_tmp=
trap 'exit_status=$?
: "${ac_tmp:=$tmp}"
{ test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
' 0
trap 'as_fn_exit 1' 1 2 13 15
}
# Create a (secure) tmp directory for tmp files.
{
tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
test -d "$tmp"
} ||
{
tmp=./conf$$-$RANDOM
(umask 077 && mkdir "$tmp")
} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
ac_tmp=$tmp
# Set up the scripts for CONFIG_FILES section.
# No need to generate them if there are no CONFIG_FILES.
# This happens for instance with `./config.status config.h'.
if test -n "$CONFIG_FILES"; then
ac_cr=`echo X | tr X '\015'`
# On cygwin, bash can eat \r inside `` if the user requested igncr.
# But we know of no other shell where ac_cr would be empty at this
# point, so we can use a bashism as a fallback.
if test "x$ac_cr" = x; then
eval ac_cr=\$\'\\r\'
fi
ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
ac_cs_awk_cr='\\r'
else
ac_cs_awk_cr=$ac_cr
fi
echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
_ACEOF
{
echo "cat >conf$$subs.awk <<_ACEOF" &&
echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
echo "_ACEOF"
} >conf$$subs.sh ||
as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
ac_delim='%!_!# '
for ac_last_try in false false false false false :; do
. ./conf$$subs.sh ||
as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
if test $ac_delim_n = $ac_delim_num; then
break
elif $ac_last_try; then
as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
else
ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
fi
done
rm -f conf$$subs.sh
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
_ACEOF
sed -n '
h
s/^/S["/; s/!.*/"]=/
p
g
s/^[^!]*!//
:repl
t repl
s/'"$ac_delim"'$//
t delim
:nl
h
s/\(.\{148\}\)..*/\1/
t more1
s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
p
n
b repl
:more1
s/["\\]/\\&/g; s/^/"/; s/$/"\\/
p
g
s/.\{148\}//
t nl
:delim
h
s/\(.\{148\}\)..*/\1/
t more2
s/["\\]/\\&/g; s/^/"/; s/$/"/
p
b
:more2
s/["\\]/\\&/g; s/^/"/; s/$/"\\/
p
g
s/.\{148\}//
t delim
' <conf$$subs.awk | sed '
/^[^""]/{
N
s/\n//
}
' >>$CONFIG_STATUS || ac_write_fail=1
rm -f conf$$subs.awk
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
_ACAWK
cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
for (key in S) S_is_set[key] = 1
FS = ""
}
{
line = $ 0
nfields = split(line, field, "@")
substed = 0
len = length(field[1])
for (i = 2; i < nfields; i++) {
key = field[i]
keylen = length(key)
if (S_is_set[key]) {
value = S[key]
line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
len += length(value) + length(field[++i])
substed = 1
} else
len += 1 + keylen
}
print line
}
_ACAWK
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
else
cat
fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
|| as_fn_error $? "could not setup config files machinery" "$LINENO" 5
_ACEOF
# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
# trailing colons and then remove the whole line if VPATH becomes empty
# (actually we leave an empty line to preserve line numbers).
if test "x$srcdir" = x.; then
ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
h
s///
s/^/:/
s/[ ]*$/:/
s/:\$(srcdir):/:/g
s/:\${srcdir}:/:/g
s/:@srcdir@:/:/g
s/^:*//
s/:*$//
x
s/\(=[ ]*\).*/\1/
G
s/\n//
s/^[^=]*=[ ]*$//
}'
fi
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
fi # test -n "$CONFIG_FILES"
# Set up the scripts for CONFIG_HEADERS section.
# No need to generate them if there are no CONFIG_HEADERS.
# This happens for instance with `./config.status Makefile'.
if test -n "$CONFIG_HEADERS"; then
cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
BEGIN {
_ACEOF
# Transform confdefs.h into an awk script `defines.awk', embedded as
# here-document in config.status, that substitutes the proper values into
# config.h.in to produce config.h.
# Create a delimiter string that does not exist in confdefs.h, to ease
# handling of long lines.
ac_delim='%!_!# '
for ac_last_try in false false :; do
ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
if test -z "$ac_tt"; then
break
elif $ac_last_try; then
as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
else
ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
fi
done
# For the awk script, D is an array of macro values keyed by name,
# likewise P contains macro parameters if any. Preserve backslash
# newline sequences.
ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
sed -n '
s/.\{148\}/&'"$ac_delim"'/g
t rset
:rset
s/^[ ]*#[ ]*define[ ][ ]*/ /
t def
d
:def
s/\\$//
t bsnl
s/["\\]/\\&/g
s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
D["\1"]=" \3"/p
s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
d
:bsnl
s/["\\]/\\&/g
s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
D["\1"]=" \3\\\\\\n"\\/p
t cont
s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
t cont
d
:cont
n
s/.\{148\}/&'"$ac_delim"'/g
t clear
:clear
s/\\$//
t bsnlc
s/["\\]/\\&/g; s/^/"/; s/$/"/p
d
:bsnlc
s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
b cont
' <confdefs.h | sed '
s/'"$ac_delim"'/"\\\
"/g' >>$CONFIG_STATUS || ac_write_fail=1
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
for (key in D) D_is_set[key] = 1
FS = ""
}
/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
line = \$ 0
split(line, arg, " ")
if (arg[1] == "#") {
defundef = arg[2]
mac1 = arg[3]
} else {
defundef = substr(arg[1], 2)
mac1 = arg[2]
}
split(mac1, mac2, "(") #)
macro = mac2[1]
prefix = substr(line, 1, index(line, defundef) - 1)
if (D_is_set[macro]) {
# Preserve the white space surrounding the "#".
print prefix "define", macro P[macro] D[macro]
next
} else {
# Replace #undef with comments. This is necessary, for example,
# in the case of _POSIX_SOURCE, which is predefined and required
# on some systems where configure will not decide to define it.
if (defundef == "undef") {
print "/*", prefix defundef, macro, "*/"
next
}
}
}
{ print }
_ACAWK
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
fi # test -n "$CONFIG_HEADERS"
eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS "
shift
for ac_tag
do
case $ac_tag in
:[FHLC]) ac_mode=$ac_tag; continue;;
esac
case $ac_mode$ac_tag in
:[FHL]*:*);;
:L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
:[FH]-) ac_tag=-:-;;
:[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
esac
ac_save_IFS=$IFS
IFS=:
set x $ac_tag
IFS=$ac_save_IFS
shift
ac_file=$1
shift
case $ac_mode in
:L) ac_source=$1;;
:[FH])
ac_file_inputs=
for ac_f
do
case $ac_f in
-) ac_f="$ac_tmp/stdin";;
*) # Look for the file first in the build tree, then in the source tree
# (if the path is not absolute). The absolute path cannot be DOS-style,
# because $ac_f cannot contain `:'.
test -f "$ac_f" ||
case $ac_f in
[\\/$]*) false;;
*) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
esac ||
as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
esac
- case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
as_fn_append ac_file_inputs " '$ac_f'"
done
# Let's still pretend it is `configure' which instantiates (i.e., don't
# use $as_me), people would be surprised to read:
# /* config.h. Generated by config.status. */
configure_input='Generated from '`
- $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
`' by configure.'
if test x"$ac_file" != x-; then
configure_input="$ac_file. $configure_input"
- { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
-$as_echo "$as_me: creating $ac_file" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+printf "%s\n" "$as_me: creating $ac_file" >&6;}
fi
# Neutralize special characters interpreted by sed in replacement strings.
case $configure_input in #(
*\&* | *\|* | *\\* )
- ac_sed_conf_input=`$as_echo "$configure_input" |
+ ac_sed_conf_input=`printf "%s\n" "$configure_input" |
sed 's/[\\\\&|]/\\\\&/g'`;; #(
*) ac_sed_conf_input=$configure_input;;
esac
case $ac_tag in
*:-:* | *:-) cat >"$ac_tmp/stdin" \
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
esac
;;
esac
ac_dir=`$as_dirname -- "$ac_file" ||
$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$ac_file" : 'X\(//\)[^/]' \| \
X"$ac_file" : 'X\(//\)$' \| \
X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$ac_file" |
+printf "%s\n" X"$ac_file" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'`
as_dir="$ac_dir"; as_fn_mkdir_p
ac_builddir=.
case "$ac_dir" in
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
*)
- ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
# A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
case $ac_top_builddir_sub in
"") ac_top_builddir_sub=. ac_top_build_prefix= ;;
*) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
esac ;;
esac
ac_abs_top_builddir=$ac_pwd
ac_abs_builddir=$ac_pwd$ac_dir_suffix
# for backward compatibility:
ac_top_builddir=$ac_top_build_prefix
case $srcdir in
.) # We are building in place.
ac_srcdir=.
ac_top_srcdir=$ac_top_builddir_sub
ac_abs_top_srcdir=$ac_pwd ;;
[\\/]* | ?:[\\/]* ) # Absolute name.
ac_srcdir=$srcdir$ac_dir_suffix;
ac_top_srcdir=$srcdir
ac_abs_top_srcdir=$srcdir ;;
*) # Relative name.
ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
ac_top_srcdir=$ac_top_build_prefix$srcdir
ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
esac
ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
case $ac_mode in
:F)
#
# CONFIG_FILE
#
case $INSTALL in
[\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
*) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
esac
ac_MKDIR_P=$MKDIR_P
case $MKDIR_P in
[\\/$]* | ?:[\\/]* ) ;;
*/*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
esac
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# If the template does not know about datarootdir, expand it.
# FIXME: This hack should be removed a few years after 2.60.
ac_datarootdir_hack=; ac_datarootdir_seen=
ac_sed_dataroot='
/datarootdir/ {
p
q
}
/@datadir@/p
/@docdir@/p
/@infodir@/p
/@localedir@/p
/@mandir@/p'
case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
*datarootdir*) ac_datarootdir_seen=yes;;
*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
-$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_datarootdir_hack='
s&@datadir@&$datadir&g
s&@docdir@&$docdir&g
s&@infodir@&$infodir&g
s&@localedir@&$localedir&g
s&@mandir@&$mandir&g
s&\\\${datarootdir}&$datarootdir&g' ;;
esac
_ACEOF
# Neutralize VPATH when `$srcdir' = `.'.
# Shell code in configure.ac might set extrasub.
# FIXME: do we really want to maintain this feature?
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_sed_extra="$ac_vpsub
$extrasub
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
:t
/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
s|@configure_input@|$ac_sed_conf_input|;t t
s&@top_builddir@&$ac_top_builddir_sub&;t t
s&@top_build_prefix@&$ac_top_build_prefix&;t t
s&@srcdir@&$ac_srcdir&;t t
s&@abs_srcdir@&$ac_abs_srcdir&;t t
s&@top_srcdir@&$ac_top_srcdir&;t t
s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
s&@builddir@&$ac_builddir&;t t
s&@abs_builddir@&$ac_abs_builddir&;t t
s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
s&@INSTALL@&$ac_INSTALL&;t t
s&@MKDIR_P@&$ac_MKDIR_P&;t t
$ac_datarootdir_hack
"
eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
>$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
{ ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
{ ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
"$ac_tmp/out"`; test -z "$ac_out"; } &&
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
which seems to be undefined. Please make sure it is defined" >&5
-$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
which seems to be undefined. Please make sure it is defined" >&2;}
rm -f "$ac_tmp/stdin"
case $ac_file in
-) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
*) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
esac \
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
;;
:H)
#
# CONFIG_HEADER
#
if test x"$ac_file" != x-; then
{
- $as_echo "/* $configure_input */" \
+ printf "%s\n" "/* $configure_input */" >&1 \
&& eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
} >"$ac_tmp/config.h" \
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
-$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+printf "%s\n" "$as_me: $ac_file is unchanged" >&6;}
else
rm -f "$ac_file"
mv "$ac_tmp/config.h" "$ac_file" \
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
fi
else
- $as_echo "/* $configure_input */" \
+ printf "%s\n" "/* $configure_input */" >&1 \
&& eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
|| as_fn_error $? "could not create -" "$LINENO" 5
fi
;;
esac
done # for ac_tag
as_fn_exit 0
_ACEOF
ac_clean_files=$ac_clean_files_save
test $ac_write_fail = 0 ||
as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
# configure is writing to config.log, and then calls config.status.
# config.status does its own redirection, appending to config.log.
# Unfortunately, on DOS this fails, as config.log is still kept open
# by configure, so config.status won't be able to write to it; its
# output is simply discarded. So we exec the FD to /dev/null,
# effectively closing config.log, so it can be properly (re)opened and
# appended to by config.status. When coming back to configure, we
# need to make the FD available again.
if test "$no_create" != yes; then
ac_cs_success=:
ac_config_status_args=
test "$silent" = yes &&
ac_config_status_args="$ac_config_status_args --quiet"
exec 5>/dev/null
$SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
exec 5>>config.log
# Use ||, not &&, to avoid exiting from the if with $? = 1, which
# would make configure fail if this is the last instruction.
$ac_cs_success || as_fn_exit 1
fi
if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
-$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
fi
# Print summary of options
# Someone please show me a better way :)
A=`eval echo ${prefix}` ; A=`eval echo ${A}`
B=`eval echo ${bindir}` ; B=`eval echo ${B}`
C=`eval echo ${sbindir}` ; C=`eval echo ${C}`
D=`eval echo ${sysconfdir}` ; D=`eval echo ${D}`
E=`eval echo ${libexecdir}/ssh-askpass` ; E=`eval echo ${E}`
F=`eval echo ${mandir}/${mansubdir}X` ; F=`eval echo ${F}`
G=`eval echo ${piddir}` ; G=`eval echo ${G}`
H=`eval echo ${PRIVSEP_PATH}` ; H=`eval echo ${H}`
I=`eval echo ${user_path}` ; I=`eval echo ${I}`
J=`eval echo ${superuser_path}` ; J=`eval echo ${J}`
echo ""
echo "OpenSSH has been configured with the following options:"
echo " User binaries: $B"
echo " System binaries: $C"
echo " Configuration files: $D"
echo " Askpass program: $E"
echo " Manual pages: $F"
echo " PID file: $G"
echo " Privilege separation chroot path: $H"
if test "x$external_path_file" = "x/etc/login.conf" ; then
echo " At runtime, sshd will use the path defined in $external_path_file"
echo " Make sure the path to scp is present, otherwise scp will not work"
else
echo " sshd default user PATH: $I"
if test ! -z "$external_path_file"; then
echo " (If PATH is set in $external_path_file it will be used instead. If"
echo " used, ensure the path to scp is present, otherwise scp will not work.)"
fi
fi
if test ! -z "$superuser_path" ; then
echo " sshd superuser user PATH: $J"
fi
echo " Manpage format: $MANTYPE"
echo " PAM support: $PAM_MSG"
echo " OSF SIA support: $SIA_MSG"
echo " KerberosV support: $KRB5_MSG"
echo " SELinux support: $SELINUX_MSG"
echo " libedit support: $LIBEDIT_MSG"
echo " libldns support: $LDNS_MSG"
echo " Solaris process contract support: $SPC_MSG"
echo " Solaris project support: $SP_MSG"
echo " Solaris privilege support: $SPP_MSG"
echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
echo " BSD Auth support: $BSD_AUTH_MSG"
echo " Random number source: $RAND_MSG"
echo " Privsep sandbox style: $SANDBOX_STYLE"
echo " PKCS#11 support: $enable_pkcs11"
echo " U2F/FIDO support: $enable_sk"
echo ""
echo " Host: ${host}"
echo " Compiler: ${CC}"
echo " Compiler flags: ${CFLAGS}"
echo "Preprocessor flags: ${CPPFLAGS}"
echo " Linker flags: ${LDFLAGS}"
echo " Libraries: ${LIBS}"
+if test ! -z "${CHANNELLIBS}"; then
+echo " +for channels: ${CHANNELLIBS}"
+fi
+if test ! -z "${LIBFIDO2}"; then
+echo " +for FIDO2: ${LIBFIDO2}"
+fi
if test ! -z "${SSHDLIBS}"; then
echo " +for sshd: ${SSHDLIBS}"
fi
echo ""
if test "x$MAKE_PACKAGE_SUPPORTED" = "xyes" ; then
echo "SVR4 style packages are supported with \"make package\""
echo ""
fi
if test "x$PAM_MSG" = "xyes" ; then
echo "PAM is enabled. You may need to install a PAM control file "
echo "for sshd, otherwise password authentication may fail. "
echo "Example PAM control files can be found in the contrib/ "
echo "subdirectory"
echo ""
fi
if test ! -z "$NO_PEERCHECK" ; then
echo "WARNING: the operating system that you are using does not"
echo "appear to support getpeereid(), getpeerucred() or the"
echo "SO_PEERCRED getsockopt() option. These facilities are used to"
echo "enforce security checks to prevent unauthorised connections to"
echo "ssh-agent. Their absence increases the risk that a malicious"
echo "user can connect to your agent."
echo ""
fi
if test "$AUDIT_MODULE" = "bsm" ; then
echo "WARNING: BSM audit support is currently considered EXPERIMENTAL."
echo "See the Solaris section in README.platform for details."
fi
diff --git a/configure.ac b/configure.ac
index c285ea32b13d..de60a1b1fe80 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5658 +1,5651 @@
#
# Copyright (c) 1999-2004 Damien Miller
#
# 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.
AC_INIT([OpenSSH], [Portable], [openssh-unix-dev@mindrot.org])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR([ssh.c])
+
+# Check for stale configure as early as possible.
+for i in $srcdir/configure.ac $srcdir/m4/*.m4; do
+ if test "$i" -nt "$srcdir/configure"; then
+ AC_MSG_ERROR([$i newer than configure, run autoreconf])
+ fi
+done
+
AC_LANG([C])
AC_CONFIG_HEADERS([config.h])
AC_PROG_CC([cc gcc clang])
# XXX relax this after reimplementing logit() etc.
AC_MSG_CHECKING([if $CC supports C99-style variadic macros])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
int f(int a, int b, int c) { return a + b + c; }
#define F(a, ...) f(a, __VA_ARGS__)
]], [[return F(1, 2, -3);]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_ERROR([*** OpenSSH requires support for C99-style variadic macros]) ]
)
AC_CANONICAL_HOST
AC_C_BIGENDIAN
# Checks for programs.
AC_PROG_AWK
AC_PROG_CPP
AC_PROG_RANLIB
AC_PROG_INSTALL
AC_PROG_EGREP
AC_PROG_MKDIR_P
AC_CHECK_TOOLS([AR], [ar])
AC_PATH_PROG([CAT], [cat])
AC_PATH_PROG([KILL], [kill])
AC_PATH_PROG([SED], [sed])
AC_PATH_PROG([TEST_MINUS_S_SH], [bash])
AC_PATH_PROG([TEST_MINUS_S_SH], [ksh])
AC_PATH_PROG([TEST_MINUS_S_SH], [sh])
AC_PATH_PROG([SH], [bash])
AC_PATH_PROG([SH], [ksh])
AC_PATH_PROG([SH], [sh])
AC_PATH_PROG([GROFF], [groff])
AC_PATH_PROG([NROFF], [nroff awf])
AC_PATH_PROG([MANDOC], [mandoc])
+AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no])
AC_SUBST([TEST_SHELL], [sh])
dnl select manpage formatter to be used to build "cat" format pages.
if test "x$MANDOC" != "x" ; then
MANFMT="$MANDOC"
elif test "x$NROFF" != "x" ; then
MANFMT="$NROFF -mandoc"
elif test "x$GROFF" != "x" ; then
MANFMT="$GROFF -mandoc -Tascii"
else
AC_MSG_WARN([no manpage formatter found])
MANFMT="false"
fi
AC_SUBST([MANFMT])
dnl for buildpkg.sh
AC_PATH_PROG([PATH_GROUPADD_PROG], [groupadd], [groupadd],
[/usr/sbin${PATH_SEPARATOR}/etc])
AC_PATH_PROG([PATH_USERADD_PROG], [useradd], [useradd],
[/usr/sbin${PATH_SEPARATOR}/etc])
AC_CHECK_PROG([MAKE_PACKAGE_SUPPORTED], [pkgmk], [yes], [no])
if test -x /sbin/sh; then
AC_SUBST([STARTUP_SCRIPT_SHELL], [/sbin/sh])
else
AC_SUBST([STARTUP_SCRIPT_SHELL], [/bin/sh])
fi
# System features
AC_SYS_LARGEFILE
if test -z "$AR" ; then
AC_MSG_ERROR([*** 'ar' missing, please install or fix your \$PATH ***])
fi
AC_PATH_PROG([PATH_PASSWD_PROG], [passwd])
if test ! -z "$PATH_PASSWD_PROG" ; then
AC_DEFINE_UNQUOTED([_PATH_PASSWD_PROG], ["$PATH_PASSWD_PROG"],
[Full path of your "passwd" program])
fi
dnl Since autoconf doesn't support it very well, we no longer allow users to
dnl override LD, however keeping the hook here for now in case there's a use
dnl use case we overlooked and someone needs to re-enable it. Unless a good
dnl reason is found we'll be removing this in future.
LD="$CC"
AC_SUBST([LD])
AC_C_INLINE
AC_CHECK_DECL([LLONG_MAX], [have_llong_max=1], , [#include <limits.h>])
AC_CHECK_DECL([LONG_LONG_MAX], [have_long_long_max=1], , [#include <limits.h>])
AC_CHECK_DECL([SYSTR_POLICY_KILL], [have_systr_policy_kill=1], , [
#include <sys/types.h>
#include <sys/param.h>
#include <dev/systrace.h>
])
AC_CHECK_DECL([RLIMIT_NPROC],
[AC_DEFINE([HAVE_RLIMIT_NPROC], [], [sys/resource.h has RLIMIT_NPROC])], , [
#include <sys/types.h>
#include <sys/resource.h>
])
AC_CHECK_DECL([PR_SET_NO_NEW_PRIVS], [have_linux_no_new_privs=1], , [
#include <sys/types.h>
#include <linux/prctl.h>
])
openssl=yes
AC_ARG_WITH([openssl],
[ --without-openssl Disable use of OpenSSL; use only limited internal crypto **EXPERIMENTAL** ],
[ if test "x$withval" = "xno" ; then
openssl=no
fi
]
)
AC_MSG_CHECKING([whether OpenSSL will be used for cryptography])
if test "x$openssl" = "xyes" ; then
AC_MSG_RESULT([yes])
AC_DEFINE_UNQUOTED([WITH_OPENSSL], [1], [use libcrypto for cryptography])
else
AC_MSG_RESULT([no])
fi
use_stack_protector=1
use_toolchain_hardening=1
AC_ARG_WITH([stackprotect],
[ --without-stackprotect Don't use compiler's stack protection], [
if test "x$withval" = "xno"; then
use_stack_protector=0
fi ])
AC_ARG_WITH([hardening],
[ --without-hardening Don't use toolchain hardening flags], [
if test "x$withval" = "xno"; then
use_toolchain_hardening=0
fi ])
# We use -Werror for the tests only so that we catch warnings like "this is
# on by default" for things like -fPIE.
AC_MSG_CHECKING([if $CC supports -Werror])
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Werror"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int main(void) { return 0; }]])],
[ AC_MSG_RESULT([yes])
WERROR="-Werror"],
[ AC_MSG_RESULT([no])
WERROR="" ]
)
CFLAGS="$saved_CFLAGS"
if test "$GCC" = "yes" || test "$GCC" = "egcs"; then
OSSH_CHECK_CFLAG_COMPILE([-pipe])
OSSH_CHECK_CFLAG_COMPILE([-Wunknown-warning-option])
OSSH_CHECK_CFLAG_COMPILE([-Wno-error=format-truncation])
OSSH_CHECK_CFLAG_COMPILE([-Qunused-arguments])
OSSH_CHECK_CFLAG_COMPILE([-Wall])
OSSH_CHECK_CFLAG_COMPILE([-Wextra])
OSSH_CHECK_CFLAG_COMPILE([-Wpointer-arith])
OSSH_CHECK_CFLAG_COMPILE([-Wuninitialized])
OSSH_CHECK_CFLAG_COMPILE([-Wsign-compare])
OSSH_CHECK_CFLAG_COMPILE([-Wformat-security])
OSSH_CHECK_CFLAG_COMPILE([-Wsizeof-pointer-memaccess])
OSSH_CHECK_CFLAG_COMPILE([-Wpointer-sign], [-Wno-pointer-sign])
OSSH_CHECK_CFLAG_COMPILE([-Wunused-parameter], [-Wno-unused-parameter])
OSSH_CHECK_CFLAG_COMPILE([-Wunused-result], [-Wno-unused-result])
OSSH_CHECK_CFLAG_COMPILE([-Wimplicit-fallthrough])
OSSH_CHECK_CFLAG_COMPILE([-Wmisleading-indentation])
OSSH_CHECK_CFLAG_COMPILE([-Wbitwise-instead-of-logical])
OSSH_CHECK_CFLAG_COMPILE([-fno-strict-aliasing])
if test "x$use_toolchain_hardening" = "x1"; then
OSSH_CHECK_CFLAG_COMPILE([-mretpoline]) # clang
OSSH_CHECK_LDFLAG_LINK([-Wl,-z,retpolineplt])
OSSH_CHECK_CFLAG_COMPILE([-D_FORTIFY_SOURCE=2])
OSSH_CHECK_LDFLAG_LINK([-Wl,-z,relro])
OSSH_CHECK_LDFLAG_LINK([-Wl,-z,now])
OSSH_CHECK_LDFLAG_LINK([-Wl,-z,noexecstack])
# NB. -ftrapv expects certain support functions to be present in
# the compiler library (libgcc or similar) to detect integer operations
# that can overflow. We must check that the result of enabling it
# actually links. The test program compiled/linked includes a number
# of integer operations that should exercise this.
OSSH_CHECK_CFLAG_LINK([-ftrapv])
OSSH_CHECK_CFLAG_COMPILE([-fzero-call-used-regs=all])
OSSH_CHECK_CFLAG_COMPILE([-ftrivial-auto-var-init=zero])
fi
AC_MSG_CHECKING([gcc version])
GCC_VER=`$CC -v 2>&1 | $AWK '/gcc version /{print $3}'`
case $GCC_VER in
1.*) no_attrib_nonnull=1 ;;
2.8* | 2.9*)
no_attrib_nonnull=1
;;
2.*) no_attrib_nonnull=1 ;;
*) ;;
esac
AC_MSG_RESULT([$GCC_VER])
AC_MSG_CHECKING([if $CC accepts -fno-builtin-memset])
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -fno-builtin-memset"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <string.h> ]],
[[ char b[10]; memset(b, 0, sizeof(b)); ]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
CFLAGS="$saved_CFLAGS" ]
)
# -fstack-protector-all doesn't always work for some GCC versions
# and/or platforms, so we test if we can. If it's not supported
# on a given platform gcc will emit a warning so we use -Werror.
if test "x$use_stack_protector" = "x1"; then
for t in -fstack-protector-strong -fstack-protector-all \
-fstack-protector; do
AC_MSG_CHECKING([if $CC supports $t])
saved_CFLAGS="$CFLAGS"
saved_LDFLAGS="$LDFLAGS"
CFLAGS="$CFLAGS $t -Werror"
LDFLAGS="$LDFLAGS $t -Werror"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdio.h>
int func (int t) {char b[100]; snprintf(b,sizeof b,"%d",t); return t;}
]],
[[
char x[256];
snprintf(x, sizeof(x), "XXX%d", func(1));
]])],
[ AC_MSG_RESULT([yes])
CFLAGS="$saved_CFLAGS $t"
LDFLAGS="$saved_LDFLAGS $t"
AC_MSG_CHECKING([if $t works])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdio.h>
int func (int t) {char b[100]; snprintf(b,sizeof b,"%d",t); return t;}
]],
[[
char x[256];
snprintf(x, sizeof(x), "XXX%d", func(1));
]])],
[ AC_MSG_RESULT([yes])
break ],
[ AC_MSG_RESULT([no]) ],
[ AC_MSG_WARN([cross compiling: cannot test])
break ]
)
],
[ AC_MSG_RESULT([no]) ]
)
CFLAGS="$saved_CFLAGS"
LDFLAGS="$saved_LDFLAGS"
done
fi
if test -z "$have_llong_max"; then
# retry LLONG_MAX with -std=gnu99, needed on some Linuxes
unset ac_cv_have_decl_LLONG_MAX
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -std=gnu99"
AC_CHECK_DECL([LLONG_MAX],
[have_llong_max=1],
[CFLAGS="$saved_CFLAGS"],
[#include <limits.h>]
)
fi
fi
AC_MSG_CHECKING([if compiler allows __attribute__ on return types])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdlib.h>
__attribute__((__unused__)) static void foo(void){return;}]],
[[ exit(0); ]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
AC_DEFINE(NO_ATTRIBUTE_ON_RETURN_TYPE, 1,
[compiler does not accept __attribute__ on return types]) ]
)
AC_MSG_CHECKING([if compiler allows __attribute__ prototype args])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdlib.h>
typedef void foo(const char *, ...) __attribute__((format(printf, 1, 2)));]],
[[ exit(0); ]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
AC_DEFINE(NO_ATTRIBUTE_ON_PROTOTYPE_ARGS, 1,
[compiler does not accept __attribute__ on prototype args]) ]
)
AC_MSG_CHECKING([if compiler supports variable length arrays])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[#include <stdlib.h>]],
[[ int i; for (i=0; i<3; i++){int a[i]; a[i-1]=0;} exit(0); ]])],
[ AC_MSG_RESULT([yes])
AC_DEFINE(VARIABLE_LENGTH_ARRAYS, [1],
[compiler supports variable length arrays]) ],
[ AC_MSG_RESULT([no]) ]
)
AC_MSG_CHECKING([if compiler accepts variable declarations after code])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[#include <stdlib.h>]],
[[ int a; a = 1; int b = 1; exit(a-b); ]])],
[ AC_MSG_RESULT([yes])
AC_DEFINE(VARIABLE_DECLARATION_AFTER_CODE, [1],
[compiler variable declarations after code]) ],
[ AC_MSG_RESULT([no]) ]
)
if test "x$no_attrib_nonnull" != "x1" ; then
AC_DEFINE([HAVE_ATTRIBUTE__NONNULL__], [1], [Have attribute nonnull])
fi
AC_ARG_WITH([rpath],
[ --without-rpath Disable auto-added -R linker paths],
[
if test "x$withval" = "xno" ; then
rpath_opt=""
elif test "x$withval" = "xyes" ; then
rpath_opt="-R"
else
rpath_opt="$withval"
fi
]
)
# Allow user to specify flags
AC_ARG_WITH([cflags],
[ --with-cflags Specify additional flags to pass to compiler],
[
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
CFLAGS="$CFLAGS $withval"
fi
]
)
AC_ARG_WITH([cflags-after],
[ --with-cflags-after Specify additional flags to pass to compiler after configure],
[
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
CFLAGS_AFTER="$withval"
fi
]
)
AC_ARG_WITH([cppflags],
[ --with-cppflags Specify additional flags to pass to preprocessor] ,
[
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
CPPFLAGS="$CPPFLAGS $withval"
fi
]
)
AC_ARG_WITH([ldflags],
[ --with-ldflags Specify additional flags to pass to linker],
[
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
LDFLAGS="$LDFLAGS $withval"
fi
]
)
AC_ARG_WITH([ldflags-after],
[ --with-ldflags-after Specify additional flags to pass to linker after configure],
[
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
LDFLAGS_AFTER="$withval"
fi
]
)
AC_ARG_WITH([libs],
[ --with-libs Specify additional libraries to link with],
[
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
LIBS="$LIBS $withval"
fi
]
)
AC_ARG_WITH([Werror],
[ --with-Werror Build main code with -Werror],
[
if test -n "$withval" && test "x$withval" != "xno"; then
werror_flags="-Werror"
if test "x${withval}" != "xyes"; then
werror_flags="$withval"
fi
fi
]
)
AC_CHECK_HEADERS([ \
blf.h \
bstring.h \
crypt.h \
crypto/sha2.h \
dirent.h \
endian.h \
elf.h \
err.h \
features.h \
fcntl.h \
floatingpoint.h \
fnmatch.h \
getopt.h \
glob.h \
ia.h \
iaf.h \
ifaddrs.h \
inttypes.h \
langinfo.h \
limits.h \
locale.h \
login.h \
maillock.h \
ndir.h \
net/if_tun.h \
netdb.h \
netgroup.h \
pam/pam_appl.h \
paths.h \
poll.h \
pty.h \
readpassphrase.h \
rpc/types.h \
security/pam_appl.h \
sha2.h \
shadow.h \
stddef.h \
stdint.h \
string.h \
strings.h \
sys/bitypes.h \
sys/byteorder.h \
sys/bsdtty.h \
sys/cdefs.h \
sys/dir.h \
sys/file.h \
sys/mman.h \
sys/label.h \
sys/ndir.h \
sys/param.h \
sys/poll.h \
sys/prctl.h \
sys/procctl.h \
sys/pstat.h \
sys/ptrace.h \
sys/random.h \
sys/select.h \
sys/stat.h \
sys/stream.h \
sys/stropts.h \
sys/strtio.h \
sys/statvfs.h \
sys/sysmacros.h \
sys/time.h \
sys/timers.h \
sys/vfs.h \
time.h \
tmpdir.h \
ttyent.h \
ucred.h \
unistd.h \
usersec.h \
util.h \
utime.h \
utmp.h \
utmpx.h \
vis.h \
wchar.h \
])
# On some platforms (eg SunOS4) sys/audit.h requires sys/[time|types|label.h]
# to be included first.
AC_CHECK_HEADERS([sys/audit.h], [], [], [
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_LABEL_H
# include <sys/label.h>
#endif
])
# sys/capsicum.h requires sys/types.h
-AC_CHECK_HEADERS([sys/capsicum.h], [], [], [
+AC_CHECK_HEADERS([sys/capsicum.h capsicum_helpers.h], [], [], [
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
])
+AC_MSG_CHECKING([for caph_cache_tzdata])
+AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([[ #include <capsicum_helpers.h> ]],
+ [[caph_cache_tzdata();]])],
+ [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([HAVE_CAPH_CACHE_TZDATA], [1],
+ [Define if you have caph_cache_tzdata])
+ ],
+ [ AC_MSG_RESULT([no]) ]
+)
+
# net/route.h requires sys/socket.h and sys/types.h.
# sys/sysctl.h also requires sys/param.h
AC_CHECK_HEADERS([net/route.h sys/sysctl.h], [], [], [
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <sys/param.h>
#include <sys/socket.h>
])
# lastlog.h requires sys/time.h to be included first on Solaris
AC_CHECK_HEADERS([lastlog.h], [], [], [
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
])
# sys/ptms.h requires sys/stream.h to be included first on Solaris
AC_CHECK_HEADERS([sys/ptms.h], [], [], [
#ifdef HAVE_SYS_STREAM_H
# include <sys/stream.h>
#endif
])
# login_cap.h requires sys/types.h on NetBSD
AC_CHECK_HEADERS([login_cap.h], [], [], [
#include <sys/types.h>
])
# older BSDs need sys/param.h before sys/mount.h
AC_CHECK_HEADERS([sys/mount.h], [], [], [
#include <sys/param.h>
])
# Android requires sys/socket.h to be included before sys/un.h
AC_CHECK_HEADERS([sys/un.h], [], [], [
#include <sys/types.h>
#include <sys/socket.h>
])
# Messages for features tested for in target-specific section
SIA_MSG="no"
SPC_MSG="no"
SP_MSG="no"
SPP_MSG="no"
# Support for Solaris/Illumos privileges (this test is used by both
# the --with-solaris-privs option and --with-sandbox=solaris).
SOLARIS_PRIVS="no"
# Check for some target-specific stuff
case "$host" in
*-*-aix*)
# Some versions of VAC won't allow macro redefinitions at
# -qlanglevel=ansi, and autoconf 2.60 sometimes insists on using that
# particularly with older versions of vac or xlc.
# It also throws errors about null macro arguments, but these are
# not fatal.
AC_MSG_CHECKING([if compiler allows macro redefinitions])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[
#define testmacro foo
#define testmacro bar]],
[[ exit(0); ]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
CC="`echo $CC | sed 's/-qlanglvl\=ansi//g'`"
CFLAGS="`echo $CFLAGS | sed 's/-qlanglvl\=ansi//g'`"
CPPFLAGS="`echo $CPPFLAGS | sed 's/-qlanglvl\=ansi//g'`"
]
)
AC_MSG_CHECKING([how to specify blibpath for linker ($LD)])
if (test -z "$blibpath"); then
blibpath="/usr/lib:/lib"
fi
saved_LDFLAGS="$LDFLAGS"
if test "$GCC" = "yes"; then
flags="-Wl,-blibpath: -Wl,-rpath, -blibpath:"
else
flags="-blibpath: -Wl,-blibpath: -Wl,-rpath,"
fi
for tryflags in $flags ;do
if (test -z "$blibflags"); then
LDFLAGS="$saved_LDFLAGS $tryflags$blibpath"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
[blibflags=$tryflags], [])
fi
done
if (test -z "$blibflags"); then
AC_MSG_RESULT([not found])
AC_MSG_ERROR([*** must be able to specify blibpath on AIX - check config.log])
else
AC_MSG_RESULT([$blibflags])
fi
LDFLAGS="$saved_LDFLAGS"
dnl Check for authenticate. Might be in libs.a on older AIXes
AC_CHECK_FUNC([authenticate], [AC_DEFINE([WITH_AIXAUTHENTICATE], [1],
[Define if you want to enable AIX4's authenticate function])],
[AC_CHECK_LIB([s], [authenticate],
[ AC_DEFINE([WITH_AIXAUTHENTICATE])
LIBS="$LIBS -ls"
])
])
dnl Check for various auth function declarations in headers.
AC_CHECK_DECLS([authenticate, loginrestrictions, loginsuccess,
passwdexpired, setauthdb], , , [#include <usersec.h>])
dnl Check if loginfailed is declared and takes 4 arguments (AIX >= 5.2)
AC_CHECK_DECLS([loginfailed],
[AC_MSG_CHECKING([if loginfailed takes 4 arguments])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <usersec.h> ]],
[[ (void)loginfailed("user","host","tty",0); ]])],
[AC_MSG_RESULT([yes])
AC_DEFINE([AIX_LOGINFAILED_4ARG], [1],
[Define if your AIX loginfailed() function
takes 4 arguments (AIX >= 5.2)])], [AC_MSG_RESULT([no])
])],
[],
[#include <usersec.h>]
)
AC_CHECK_FUNCS([getgrset setauthdb])
AC_CHECK_DECL([F_CLOSEM],
AC_DEFINE([HAVE_FCNTL_CLOSEM], [1], [Use F_CLOSEM fcntl for closefrom]),
[],
[ #include <limits.h>
#include <fcntl.h> ]
)
check_for_aix_broken_getaddrinfo=1
AC_DEFINE([SETEUID_BREAKS_SETUID], [1],
[Define if your platform breaks doing a seteuid before a setuid])
AC_DEFINE([BROKEN_SETREUID], [1], [Define if your setreuid() is broken])
AC_DEFINE([BROKEN_SETREGID], [1], [Define if your setregid() is broken])
dnl AIX handles lastlog as part of its login message
AC_DEFINE([DISABLE_LASTLOG], [1], [Define if you don't want to use lastlog])
AC_DEFINE([LOGIN_NEEDS_UTMPX], [1],
[Some systems need a utmpx entry for /bin/login to work])
AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV],
[Define to a Set Process Title type if your system is
supported by bsd-setproctitle.c])
AC_DEFINE([SSHPAM_CHAUTHTOK_NEEDS_RUID], [1],
[AIX 5.2 and 5.3 (and presumably newer) require this])
AC_DEFINE([PTY_ZEROREAD], [1], [read(1) can return 0 for a non-closed fd])
AC_DEFINE([PLATFORM_SYS_DIR_UID], 2, [System dirs owned by bin (uid 2)])
AC_DEFINE([BROKEN_STRNDUP], 1, [strndup broken, see APAR IY61211])
AC_DEFINE([BROKEN_STRNLEN], 1, [strnlen broken, see APAR IY62551])
;;
*-*-android*)
AC_DEFINE([DISABLE_UTMP], [1], [Define if you don't want to use utmp])
AC_DEFINE([DISABLE_WTMP], [1], [Define if you don't want to use wtmp])
;;
*-*-cygwin*)
- check_for_libcrypt_later=1
LIBS="$LIBS /usr/lib/textreadmode.o"
AC_DEFINE([HAVE_CYGWIN], [1], [Define if you are on Cygwin])
AC_DEFINE([USE_PIPES], [1], [Use PIPES instead of a socketpair()])
AC_DEFINE([NO_UID_RESTORATION_TEST], [1],
[Define to disable UID restoration test])
AC_DEFINE([DISABLE_SHADOW], [1],
[Define if you want to disable shadow passwords])
AC_DEFINE([NO_X11_UNIX_SOCKETS], [1],
[Define if X11 doesn't support AF_UNIX sockets on that system])
AC_DEFINE([DISABLE_FD_PASSING], [1],
[Define if your platform needs to skip post auth
file descriptor passing])
AC_DEFINE([SSH_IOBUFSZ], [65535], [Windows is sensitive to read buffer size])
AC_DEFINE([FILESYSTEM_NO_BACKSLASH], [1], [File names may not contain backslash characters])
# Cygwin defines optargs, optargs as declspec(dllimport) for historical
# reasons which cause compile warnings, so we disable those warnings.
OSSH_CHECK_CFLAG_COMPILE([-Wno-attributes])
;;
*-*-dgux*)
AC_DEFINE([IP_TOS_IS_BROKEN], [1],
[Define if your system choked on IP TOS setting])
AC_DEFINE([SETEUID_BREAKS_SETUID])
AC_DEFINE([BROKEN_SETREUID])
AC_DEFINE([BROKEN_SETREGID])
;;
*-*-darwin*)
use_pie=auto
AC_MSG_CHECKING([if we have working getaddrinfo])
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <mach-o/dyld.h>
#include <stdlib.h>
main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
exit(0);
else
exit(1);
}
]])],
[AC_MSG_RESULT([working])],
[AC_MSG_RESULT([buggy])
AC_DEFINE([BROKEN_GETADDRINFO], [1],
[getaddrinfo is broken (if present)])
],
[AC_MSG_RESULT([assume it is working])])
AC_DEFINE([SETEUID_BREAKS_SETUID])
AC_DEFINE([BROKEN_SETREUID])
AC_DEFINE([BROKEN_SETREGID])
AC_DEFINE([BROKEN_GLOB], [1], [OS X glob does not do what we expect])
AC_DEFINE_UNQUOTED([BIND_8_COMPAT], [1],
[Define if your resolver libs need this for getrrsetbyname])
AC_DEFINE([SSH_TUN_FREEBSD], [1], [Open tunnel devices the FreeBSD way])
AC_DEFINE([SSH_TUN_COMPAT_AF], [1],
[Use tunnel device compatibility to OpenBSD])
AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
[Prepend the address family to IP tunnel traffic])
m4_pattern_allow([AU_IPv])
AC_CHECK_DECL([AU_IPv4], [],
AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records])
[#include <bsm/audit.h>]
AC_DEFINE([LASTLOG_WRITE_PUTUTXLINE], [1],
[Define if pututxline updates lastlog too])
)
AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV],
[Define to a Set Process Title type if your system is
supported by bsd-setproctitle.c])
AC_CHECK_FUNCS([sandbox_init])
AC_CHECK_HEADERS([sandbox.h])
AC_CHECK_LIB([sandbox], [sandbox_apply], [
SSHDLIBS="$SSHDLIBS -lsandbox"
])
# proc_pidinfo()-based closefrom() replacement.
AC_CHECK_HEADERS([libproc.h])
AC_CHECK_FUNCS([proc_pidinfo])
# poll(2) is broken for character-special devices (at least).
# cf. Apple bug 3710161 (not public, but searchable)
AC_DEFINE([BROKEN_POLL], [1],
[System poll(2) implementation is broken])
;;
*-*-dragonfly*)
- SSHDLIBS="$SSHDLIBS -lcrypt"
+ SSHDLIBS="$SSHDLIBS"
TEST_MALLOC_OPTIONS="AFGJPRX"
;;
*-*-haiku*)
LIBS="$LIBS -lbsd "
CFLAGS="$CFLAGS -D_BSD_SOURCE"
AC_CHECK_LIB([network], [socket])
AC_DEFINE([HAVE_U_INT64_T])
AC_DEFINE([DISABLE_UTMPX], [1], [no utmpx])
MANTYPE=man
;;
*-*-hpux*)
# first we define all of the options common to all HP-UX releases
CPPFLAGS="$CPPFLAGS -D_HPUX_SOURCE -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1"
IPADDR_IN_DISPLAY=yes
AC_DEFINE([USE_PIPES])
AC_DEFINE([LOGIN_NEEDS_UTMPX])
AC_DEFINE([LOCKED_PASSWD_STRING], ["*"],
[String used in /etc/passwd to denote locked account])
AC_DEFINE([SPT_TYPE], [SPT_PSTAT])
AC_DEFINE([PLATFORM_SYS_DIR_UID], 2, [System dirs owned by bin (uid 2)])
maildir="/var/mail"
LIBS="$LIBS -lsec"
AC_CHECK_LIB([xnet], [t_error], ,
[AC_MSG_ERROR([*** -lxnet needed on HP-UX - check config.log ***])])
# next, we define all of the options specific to major releases
case "$host" in
*-*-hpux10*)
if test -z "$GCC"; then
CFLAGS="$CFLAGS -Ae"
fi
AC_DEFINE([BROKEN_GETLINE], [1], [getline is not what we expect])
;;
*-*-hpux11*)
AC_DEFINE([PAM_SUN_CODEBASE], [1],
[Define if you are using Solaris-derived PAM which
passes pam_messages to the conversation function
with an extra level of indirection])
AC_DEFINE([DISABLE_UTMP], [1],
[Define if you don't want to use utmp])
AC_DEFINE([USE_BTMP], [1], [Use btmp to log bad logins])
check_for_hpux_broken_getaddrinfo=1
check_for_conflicting_getspnam=1
;;
esac
# lastly, we define options specific to minor releases
case "$host" in
*-*-hpux10.26)
AC_DEFINE([HAVE_SECUREWARE], [1],
[Define if you have SecureWare-based
protected password database])
disable_ptmx_check=yes
LIBS="$LIBS -lsecpw"
;;
esac
;;
*-*-irix5*)
PATH="$PATH:/usr/etc"
AC_DEFINE([BROKEN_INET_NTOA], [1],
[Define if you system's inet_ntoa is busted
(e.g. Irix gcc issue)])
AC_DEFINE([SETEUID_BREAKS_SETUID])
AC_DEFINE([BROKEN_SETREUID])
AC_DEFINE([BROKEN_SETREGID])
AC_DEFINE([WITH_ABBREV_NO_TTY], [1],
[Define if you shouldn't strip 'tty' from your
ttyname in [uw]tmp])
AC_DEFINE([LOCKED_PASSWD_STRING], ["*LK*"])
;;
*-*-irix6*)
PATH="$PATH:/usr/etc"
AC_DEFINE([WITH_IRIX_ARRAY], [1],
[Define if you have/want arrays
(cluster-wide session management, not C arrays)])
AC_DEFINE([WITH_IRIX_PROJECT], [1],
[Define if you want IRIX project management])
AC_DEFINE([WITH_IRIX_AUDIT], [1],
[Define if you want IRIX audit trails])
AC_CHECK_FUNC([jlimit_startjob], [AC_DEFINE([WITH_IRIX_JOBS], [1],
[Define if you want IRIX kernel jobs])])
AC_DEFINE([BROKEN_INET_NTOA])
AC_DEFINE([SETEUID_BREAKS_SETUID])
AC_DEFINE([BROKEN_SETREUID])
AC_DEFINE([BROKEN_SETREGID])
AC_DEFINE([BROKEN_UPDWTMPX], [1], [updwtmpx is broken (if present)])
AC_DEFINE([WITH_ABBREV_NO_TTY])
AC_DEFINE([LOCKED_PASSWD_STRING], ["*LK*"])
;;
*-*-k*bsd*-gnu | *-*-kopensolaris*-gnu)
- check_for_libcrypt_later=1
AC_DEFINE([PAM_TTY_KLUDGE])
AC_DEFINE([LOCKED_PASSWD_PREFIX], ["!"])
AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV])
AC_DEFINE([_PATH_BTMP], ["/var/log/btmp"], [log for bad login attempts])
AC_DEFINE([USE_BTMP], [1], [Use btmp to log bad logins])
;;
*-*-linux*)
no_dev_ptmx=1
use_pie=auto
- check_for_libcrypt_later=1
check_for_openpty_ctty_bug=1
dnl Target SUSv3/POSIX.1-2001 plus BSD specifics.
dnl _DEFAULT_SOURCE is the new name for _BSD_SOURCE
CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_DEFAULT_SOURCE"
AC_DEFINE([BROKEN_CLOSEFROM], [1], [broken in chroots on older kernels])
AC_DEFINE([PAM_TTY_KLUDGE], [1],
[Work around problematic Linux PAM modules handling of PAM_TTY])
AC_DEFINE([LOCKED_PASSWD_PREFIX], ["!"],
[String used in /etc/passwd to denote locked account])
AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV])
AC_DEFINE([LINK_OPNOTSUPP_ERRNO], [EPERM],
[Define to whatever link() returns for "not supported"
if it doesn't return EOPNOTSUPP.])
AC_DEFINE([_PATH_BTMP], ["/var/log/btmp"], [log for bad login attempts])
AC_DEFINE([USE_BTMP])
AC_DEFINE([LINUX_OOM_ADJUST], [1], [Adjust Linux out-of-memory killer])
inet6_default_4in6=yes
case `uname -r` in
1.*|2.0.*)
AC_DEFINE([BROKEN_CMSG_TYPE], [1],
[Define if cmsg_type is not passed correctly])
;;
esac
# tun(4) forwarding compat code
AC_CHECK_HEADERS([linux/if_tun.h])
if test "x$ac_cv_header_linux_if_tun_h" = "xyes" ; then
AC_DEFINE([SSH_TUN_LINUX], [1],
[Open tunnel devices the Linux tun/tap way])
AC_DEFINE([SSH_TUN_COMPAT_AF], [1],
[Use tunnel device compatibility to OpenBSD])
AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
[Prepend the address family to IP tunnel traffic])
fi
AC_CHECK_HEADER([linux/if.h],
AC_DEFINE([SYS_RDOMAIN_LINUX], [1],
[Support routing domains using Linux VRF]), [], [
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
])
AC_CHECK_HEADERS([linux/seccomp.h linux/filter.h linux/audit.h], [],
[], [#include <linux/types.h>])
# Obtain MIPS ABI
case "$host" in
mips*)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#if _MIPS_SIM != _ABIO32
#error
#endif
]])],[mips_abi="o32"],[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#if _MIPS_SIM != _ABIN32
#error
#endif
]])],[mips_abi="n32"],[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#if _MIPS_SIM != _ABI64
#error
#endif
]])],[mips_abi="n64"],[AC_MSG_ERROR([unknown MIPS ABI])
])
])
])
;;
esac
AC_MSG_CHECKING([for seccomp architecture])
seccomp_audit_arch=
case "$host" in
x86_64-*)
seccomp_audit_arch=AUDIT_ARCH_X86_64
;;
i*86-*)
seccomp_audit_arch=AUDIT_ARCH_I386
;;
arm*-*)
seccomp_audit_arch=AUDIT_ARCH_ARM
;;
aarch64*-*)
seccomp_audit_arch=AUDIT_ARCH_AARCH64
;;
s390x-*)
seccomp_audit_arch=AUDIT_ARCH_S390X
;;
s390-*)
seccomp_audit_arch=AUDIT_ARCH_S390
;;
+ powerpc-*)
+ seccomp_audit_arch=AUDIT_ARCH_PPC
+ ;;
powerpc64-*)
seccomp_audit_arch=AUDIT_ARCH_PPC64
;;
powerpc64le-*)
seccomp_audit_arch=AUDIT_ARCH_PPC64LE
;;
mips-*)
seccomp_audit_arch=AUDIT_ARCH_MIPS
;;
mipsel-*)
seccomp_audit_arch=AUDIT_ARCH_MIPSEL
;;
mips64-*)
case "$mips_abi" in
"n32")
seccomp_audit_arch=AUDIT_ARCH_MIPS64N32
;;
"n64")
seccomp_audit_arch=AUDIT_ARCH_MIPS64
;;
esac
;;
mips64el-*)
case "$mips_abi" in
"n32")
seccomp_audit_arch=AUDIT_ARCH_MIPSEL64N32
;;
"n64")
seccomp_audit_arch=AUDIT_ARCH_MIPSEL64
;;
esac
;;
riscv64-*)
seccomp_audit_arch=AUDIT_ARCH_RISCV64
;;
esac
if test "x$seccomp_audit_arch" != "x" ; then
AC_MSG_RESULT(["$seccomp_audit_arch"])
AC_DEFINE_UNQUOTED([SECCOMP_AUDIT_ARCH], [$seccomp_audit_arch],
[Specify the system call convention in use])
else
AC_MSG_RESULT([architecture not supported])
fi
;;
*-*-minix)
AC_DEFINE([SETEUID_BREAKS_SETUID])
# poll(2) seems to choke on /dev/null; "Bad file descriptor"
AC_DEFINE([BROKEN_POLL], [1],
[System poll(2) implementation is broken])
;;
mips-sony-bsd|mips-sony-newsos4)
AC_DEFINE([NEED_SETPGRP], [1], [Need setpgrp to acquire controlling tty])
SONY=1
;;
*-*-netbsd*)
- check_for_libcrypt_before=1
if test "x$withval" != "xno" ; then
rpath_opt="-R"
fi
CPPFLAGS="$CPPFLAGS -D_OPENBSD_SOURCE"
AC_DEFINE([SSH_TUN_FREEBSD], [1], [Open tunnel devices the FreeBSD way])
AC_CHECK_HEADER([net/if_tap.h], ,
AC_DEFINE([SSH_TUN_NO_L2], [1], [No layer 2 tunnel support]))
AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
[Prepend the address family to IP tunnel traffic])
TEST_MALLOC_OPTIONS="AJRX"
AC_DEFINE([BROKEN_READ_COMPARISON], [1],
[NetBSD read function is sometimes redirected, breaking atomicio comparisons against it])
;;
*-*-freebsd*)
- check_for_libcrypt_later=1
AC_DEFINE([LOCKED_PASSWD_PREFIX], ["*LOCKED*"], [Account locked with pw(1)])
AC_DEFINE([SSH_TUN_FREEBSD], [1], [Open tunnel devices the FreeBSD way])
AC_CHECK_HEADER([net/if_tap.h], ,
AC_DEFINE([SSH_TUN_NO_L2], [1], [No layer 2 tunnel support]))
AC_DEFINE([BROKEN_GLOB], [1], [FreeBSD glob does not do what we need])
TEST_MALLOC_OPTIONS="AJRX"
# Preauth crypto occasionally uses file descriptors for crypto offload
# and will crash if they cannot be opened.
AC_DEFINE([SANDBOX_SKIP_RLIMIT_NOFILE], [1],
[define if setrlimit RLIMIT_NOFILE breaks things])
case "$host" in
*-*-freebsd9.*|*-*-freebsd10.*)
# Capsicum on 9 and 10 do not allow ppoll() so don't auto-enable.
disable_capsicum=yes
esac
;;
*-*-bsdi*)
AC_DEFINE([SETEUID_BREAKS_SETUID])
AC_DEFINE([BROKEN_SETREUID])
AC_DEFINE([BROKEN_SETREGID])
;;
*-next-*)
conf_lastlog_location="/usr/adm/lastlog"
conf_utmp_location=/etc/utmp
conf_wtmp_location=/usr/adm/wtmp
maildir=/usr/spool/mail
AC_DEFINE([HAVE_NEXT], [1], [Define if you are on NeXT])
AC_DEFINE([USE_PIPES])
AC_DEFINE([BROKEN_SAVED_UIDS], [1], [Needed for NeXT])
;;
*-*-openbsd*)
use_pie=auto
AC_DEFINE([HAVE_ATTRIBUTE__SENTINEL__], [1], [OpenBSD's gcc has sentinel])
AC_DEFINE([HAVE_ATTRIBUTE__BOUNDED__], [1], [OpenBSD's gcc has bounded])
AC_DEFINE([SSH_TUN_OPENBSD], [1], [Open tunnel devices the OpenBSD way])
AC_DEFINE([SYSLOG_R_SAFE_IN_SIGHAND], [1],
[syslog_r function is safe to use in in a signal handler])
TEST_MALLOC_OPTIONS="AFGJPRX"
;;
*-*-solaris*)
if test "x$withval" != "xno" ; then
rpath_opt="-R"
fi
AC_DEFINE([PAM_SUN_CODEBASE])
AC_DEFINE([LOGIN_NEEDS_UTMPX])
AC_DEFINE([PAM_TTY_KLUDGE])
AC_DEFINE([SSHPAM_CHAUTHTOK_NEEDS_RUID], [1],
[Define if pam_chauthtok wants real uid set
to the unpriv'ed user])
AC_DEFINE([LOCKED_PASSWD_STRING], ["*LK*"])
# Pushing STREAMS modules will cause sshd to acquire a controlling tty.
AC_DEFINE([SSHD_ACQUIRES_CTTY], [1],
[Define if sshd somehow reacquires a controlling TTY
after setsid()])
AC_DEFINE([PASSWD_NEEDS_USERNAME], [1], [must supply username to passwd
in case the name is longer than 8 chars])
AC_DEFINE([BROKEN_TCGETATTR_ICANON], [1], [tcgetattr with ICANON may hang])
external_path_file=/etc/default/login
# hardwire lastlog location (can't detect it on some versions)
conf_lastlog_location="/var/adm/lastlog"
AC_MSG_CHECKING([for obsolete utmp and wtmp in solaris2.x])
sol2ver=`echo "$host"| sed -e 's/.*[[0-9]]\.//'`
if test "$sol2ver" -ge 8; then
AC_MSG_RESULT([yes])
AC_DEFINE([DISABLE_UTMP])
AC_DEFINE([DISABLE_WTMP], [1],
[Define if you don't want to use wtmp])
else
AC_MSG_RESULT([no])
fi
AC_CHECK_FUNCS([setpflags])
AC_CHECK_FUNCS([setppriv])
AC_CHECK_FUNCS([priv_basicset])
AC_CHECK_HEADERS([priv.h])
AC_ARG_WITH([solaris-contracts],
[ --with-solaris-contracts Enable Solaris process contracts (experimental)],
[
AC_CHECK_LIB([contract], [ct_tmpl_activate],
[ AC_DEFINE([USE_SOLARIS_PROCESS_CONTRACTS], [1],
[Define if you have Solaris process contracts])
LIBS="$LIBS -lcontract"
SPC_MSG="yes" ], )
],
)
AC_ARG_WITH([solaris-projects],
[ --with-solaris-projects Enable Solaris projects (experimental)],
[
AC_CHECK_LIB([project], [setproject],
[ AC_DEFINE([USE_SOLARIS_PROJECTS], [1],
[Define if you have Solaris projects])
LIBS="$LIBS -lproject"
SP_MSG="yes" ], )
],
)
AC_ARG_WITH([solaris-privs],
[ --with-solaris-privs Enable Solaris/Illumos privileges (experimental)],
[
AC_MSG_CHECKING([for Solaris/Illumos privilege support])
if test "x$ac_cv_func_setppriv" = "xyes" -a \
"x$ac_cv_header_priv_h" = "xyes" ; then
SOLARIS_PRIVS=yes
AC_MSG_RESULT([found])
AC_DEFINE([NO_UID_RESTORATION_TEST], [1],
[Define to disable UID restoration test])
AC_DEFINE([USE_SOLARIS_PRIVS], [1],
[Define if you have Solaris privileges])
SPP_MSG="yes"
else
AC_MSG_RESULT([not found])
AC_MSG_ERROR([*** must have support for Solaris privileges to use --with-solaris-privs])
fi
],
)
TEST_SHELL=$SHELL # let configure find us a capable shell
;;
*-*-sunos4*)
CPPFLAGS="$CPPFLAGS -DSUNOS4"
AC_CHECK_FUNCS([getpwanam])
AC_DEFINE([PAM_SUN_CODEBASE])
conf_utmp_location=/etc/utmp
conf_wtmp_location=/var/adm/wtmp
conf_lastlog_location=/var/adm/lastlog
AC_DEFINE([USE_PIPES])
AC_DEFINE([DISABLE_UTMPX], [1], [no utmpx])
;;
*-ncr-sysv*)
LIBS="$LIBS -lc89"
AC_DEFINE([USE_PIPES])
AC_DEFINE([SSHD_ACQUIRES_CTTY])
AC_DEFINE([SETEUID_BREAKS_SETUID])
AC_DEFINE([BROKEN_SETREUID])
AC_DEFINE([BROKEN_SETREGID])
;;
*-sni-sysv*)
# /usr/ucblib MUST NOT be searched on ReliantUNIX
AC_CHECK_LIB([dl], [dlsym], ,)
# -lresolv needs to be at the end of LIBS or DNS lookups break
AC_CHECK_LIB([resolv], [res_query], [ LIBS="$LIBS -lresolv" ])
IPADDR_IN_DISPLAY=yes
AC_DEFINE([USE_PIPES])
AC_DEFINE([IP_TOS_IS_BROKEN])
AC_DEFINE([SETEUID_BREAKS_SETUID])
AC_DEFINE([BROKEN_SETREUID])
AC_DEFINE([BROKEN_SETREGID])
AC_DEFINE([SSHD_ACQUIRES_CTTY])
external_path_file=/etc/default/login
# /usr/ucblib/libucb.a no longer needed on ReliantUNIX
# Attention: always take care to bind libsocket and libnsl before libc,
# otherwise you will find lots of "SIOCGPGRP errno 22" on syslog
;;
# UnixWare 1.x, UnixWare 2.x, and others based on code from Univel.
*-*-sysv4.2*)
AC_DEFINE([USE_PIPES])
AC_DEFINE([SETEUID_BREAKS_SETUID])
AC_DEFINE([BROKEN_SETREUID])
AC_DEFINE([BROKEN_SETREGID])
AC_DEFINE([PASSWD_NEEDS_USERNAME], [1], [must supply username to passwd])
AC_DEFINE([LOCKED_PASSWD_STRING], ["*LK*"])
TEST_SHELL=$SHELL # let configure find us a capable shell
;;
# UnixWare 7.x, OpenUNIX 8
*-*-sysv5*)
CPPFLAGS="$CPPFLAGS -Dvsnprintf=_xvsnprintf -Dsnprintf=_xsnprintf"
AC_DEFINE([UNIXWARE_LONG_PASSWORDS], [1], [Support passwords > 8 chars])
AC_DEFINE([USE_PIPES])
AC_DEFINE([SETEUID_BREAKS_SETUID])
AC_DEFINE([BROKEN_GETADDRINFO])
AC_DEFINE([BROKEN_SETREUID])
AC_DEFINE([BROKEN_SETREGID])
AC_DEFINE([PASSWD_NEEDS_USERNAME])
AC_DEFINE([BROKEN_TCGETATTR_ICANON])
TEST_SHELL=$SHELL # let configure find us a capable shell
- check_for_libcrypt_later=1
case "$host" in
*-*-sysv5SCO_SV*) # SCO OpenServer 6.x
maildir=/var/spool/mail
AC_DEFINE([BROKEN_UPDWTMPX])
AC_CHECK_LIB([prot], [getluid], [ LIBS="$LIBS -lprot"
AC_CHECK_FUNCS([getluid setluid], , , [-lprot])
], , )
;;
*) AC_DEFINE([LOCKED_PASSWD_STRING], ["*LK*"])
;;
esac
;;
*-*-sysv*)
;;
# SCO UNIX and OEM versions of SCO UNIX
*-*-sco3.2v4*)
AC_MSG_ERROR("This Platform is no longer supported.")
;;
# SCO OpenServer 5.x
*-*-sco3.2v5*)
if test -z "$GCC"; then
CFLAGS="$CFLAGS -belf"
fi
LIBS="$LIBS -lprot -lx -ltinfo -lm"
no_dev_ptmx=1
AC_DEFINE([USE_PIPES])
AC_DEFINE([HAVE_SECUREWARE])
AC_DEFINE([DISABLE_SHADOW])
AC_DEFINE([DISABLE_FD_PASSING])
AC_DEFINE([SETEUID_BREAKS_SETUID])
AC_DEFINE([BROKEN_GETADDRINFO])
AC_DEFINE([BROKEN_SETREUID])
AC_DEFINE([BROKEN_SETREGID])
AC_DEFINE([WITH_ABBREV_NO_TTY])
AC_DEFINE([BROKEN_UPDWTMPX])
AC_DEFINE([PASSWD_NEEDS_USERNAME])
AC_CHECK_FUNCS([getluid setluid])
MANTYPE=man
TEST_SHELL=$SHELL # let configure find us a capable shell
SKIP_DISABLE_LASTLOG_DEFINE=yes
;;
*-dec-osf*)
AC_MSG_CHECKING([for Digital Unix SIA])
no_osfsia=""
AC_ARG_WITH([osfsia],
[ --with-osfsia Enable Digital Unix SIA],
[
if test "x$withval" = "xno" ; then
AC_MSG_RESULT([disabled])
no_osfsia=1
fi
],
)
if test -z "$no_osfsia" ; then
if test -f /etc/sia/matrix.conf; then
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_OSF_SIA], [1],
[Define if you have Digital Unix Security
Integration Architecture])
AC_DEFINE([DISABLE_LOGIN], [1],
[Define if you don't want to use your
system's login() call])
AC_DEFINE([DISABLE_FD_PASSING])
LIBS="$LIBS -lsecurity -ldb -lm -laud"
SIA_MSG="yes"
else
AC_MSG_RESULT([no])
AC_DEFINE([LOCKED_PASSWD_SUBSTR], ["Nologin"],
[String used in /etc/passwd to denote locked account])
fi
fi
AC_DEFINE([BROKEN_GETADDRINFO])
AC_DEFINE([SETEUID_BREAKS_SETUID])
AC_DEFINE([BROKEN_SETREUID])
AC_DEFINE([BROKEN_SETREGID])
AC_DEFINE([BROKEN_READV_COMPARISON], [1], [Can't do comparisons on readv])
;;
*-*-nto-qnx*)
AC_DEFINE([USE_PIPES])
AC_DEFINE([NO_X11_UNIX_SOCKETS])
AC_DEFINE([DISABLE_LASTLOG])
AC_DEFINE([SSHD_ACQUIRES_CTTY])
AC_DEFINE([BROKEN_SHADOW_EXPIRE], [1], [QNX shadow support is broken])
enable_etc_default_login=no # has incompatible /etc/default/login
case "$host" in
*-*-nto-qnx6*)
AC_DEFINE([DISABLE_FD_PASSING])
;;
esac
;;
*-*-ultrix*)
AC_DEFINE([BROKEN_GETGROUPS], [1], [getgroups(0,NULL) will return -1])
AC_DEFINE([NEED_SETPGRP], [1], [Need setpgrp to for controlling tty])
AC_DEFINE([HAVE_SYS_SYSLOG_H], [1], [Force use of sys/syslog.h on Ultrix])
AC_DEFINE([DISABLE_UTMPX], [1], [Disable utmpx])
# DISABLE_FD_PASSING so that we call setpgrp as root, otherwise we
# don't get a controlling tty.
AC_DEFINE([DISABLE_FD_PASSING], [1], [Need to call setpgrp as root])
# On Ultrix some headers are not protected against multiple includes,
# so we create wrappers and put it where the compiler will find it.
AC_MSG_WARN([creating compat wrappers for headers])
mkdir -p netinet
for header in netinet/ip.h netdb.h resolv.h; do
name=`echo $header | tr 'a-z/.' 'A-Z__'`
cat >$header <<EOD
#ifndef _SSH_COMPAT_${name}
#define _SSH_COMPAT_${name}
#include "/usr/include/${header}"
#endif
EOD
done
;;
*-*-lynxos)
CFLAGS="$CFLAGS -D__NO_INCLUDE_WARN__"
AC_DEFINE([BROKEN_SETVBUF], [1],
[LynxOS has broken setvbuf() implementation])
;;
esac
AC_MSG_CHECKING([compiler and flags for sanity])
AC_RUN_IFELSE([AC_LANG_PROGRAM([[ #include <stdlib.h> ]], [[ exit(0); ]])],
[ AC_MSG_RESULT([yes]) ],
[
AC_MSG_RESULT([no])
AC_MSG_ERROR([*** compiler cannot create working executables, check config.log ***])
],
[ AC_MSG_WARN([cross compiling: not checking compiler sanity]) ]
)
dnl Checks for header files.
# Checks for libraries.
AC_CHECK_FUNC([setsockopt], , [AC_CHECK_LIB([socket], [setsockopt])])
dnl IRIX and Solaris 2.5.1 have dirname() in libgen
AC_CHECK_FUNCS([dirname], [AC_CHECK_HEADERS([libgen.h])] , [
AC_CHECK_LIB([gen], [dirname], [
AC_CACHE_CHECK([for broken dirname],
ac_cv_have_broken_dirname, [
save_LIBS="$LIBS"
LIBS="$LIBS -lgen"
AC_RUN_IFELSE(
[AC_LANG_SOURCE([[
#include <libgen.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv) {
char *s, buf[32];
strncpy(buf,"/etc", 32);
s = dirname(buf);
if (!s || strncmp(s, "/", 32) != 0) {
exit(1);
} else {
exit(0);
}
}
]])],
[ ac_cv_have_broken_dirname="no" ],
[ ac_cv_have_broken_dirname="yes" ],
[ ac_cv_have_broken_dirname="no" ],
)
LIBS="$save_LIBS"
])
if test "x$ac_cv_have_broken_dirname" = "xno" ; then
LIBS="$LIBS -lgen"
AC_DEFINE([HAVE_DIRNAME])
AC_CHECK_HEADERS([libgen.h])
fi
])
])
AC_CHECK_FUNC([getspnam], ,
[AC_CHECK_LIB([gen], [getspnam], [LIBS="$LIBS -lgen"])])
AC_SEARCH_LIBS([basename], [gen], [AC_DEFINE([HAVE_BASENAME], [1],
[Define if you have the basename function.])])
dnl zlib defaults to enabled
zlib=yes
AC_ARG_WITH([zlib],
[ --with-zlib=PATH Use zlib in PATH],
[ if test "x$withval" = "xno" ; then
zlib=no
elif test "x$withval" != "xyes"; then
if test -d "$withval/lib"; then
if test -n "${rpath_opt}"; then
LDFLAGS="-L${withval}/lib ${rpath_opt}${withval}/lib ${LDFLAGS}"
else
LDFLAGS="-L${withval}/lib ${LDFLAGS}"
fi
else
if test -n "${rpath_opt}"; then
LDFLAGS="-L${withval} ${rpath_opt}${withval} ${LDFLAGS}"
else
LDFLAGS="-L${withval} ${LDFLAGS}"
fi
fi
if test -d "$withval/include"; then
CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
else
CPPFLAGS="-I${withval} ${CPPFLAGS}"
fi
fi ]
)
+# These libraries are needed for anything that links in the channel code.
+CHANNELLIBS=""
AC_MSG_CHECKING([for zlib])
if test "x${zlib}" = "xno"; then
AC_MSG_RESULT([no])
else
- AC_MSG_RESULT([yes])
- AC_DEFINE([WITH_ZLIB], [1], [Enable zlib])
+ saved_LIBS="$LIBS"
+ CHANNELLIBS="$CHANNELLIBS -lz"
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([WITH_ZLIB], [1], [Enable zlib])
AC_CHECK_HEADER([zlib.h], ,[AC_MSG_ERROR([*** zlib.h missing - please install first or check config.log ***])])
- AC_CHECK_LIB([z], [deflate], ,
+ AC_CHECK_LIB([z], [deflate], [],
[
saved_CPPFLAGS="$CPPFLAGS"
saved_LDFLAGS="$LDFLAGS"
- save_LIBS="$LIBS"
dnl Check default zlib install dir
if test -n "${rpath_opt}"; then
LDFLAGS="-L/usr/local/lib ${rpath_opt}/usr/local/lib ${saved_LDFLAGS}"
else
LDFLAGS="-L/usr/local/lib ${saved_LDFLAGS}"
fi
CPPFLAGS="-I/usr/local/include ${saved_CPPFLAGS}"
- LIBS="$LIBS -lz"
AC_TRY_LINK_FUNC([deflate], [AC_DEFINE([HAVE_LIBZ])],
[
AC_MSG_ERROR([*** zlib missing - please install first or check config.log ***])
]
)
]
)
AC_ARG_WITH([zlib-version-check],
[ --without-zlib-version-check Disable zlib version check],
[ if test "x$withval" = "xno" ; then
zlib_check_nonfatal=1
fi
]
)
AC_MSG_CHECKING([for possibly buggy zlib])
AC_RUN_IFELSE([AC_LANG_PROGRAM([[
#include <stdio.h>
#include <stdlib.h>
#include <zlib.h>
]],
[[
int a=0, b=0, c=0, d=0, n, v;
n = sscanf(ZLIB_VERSION, "%d.%d.%d.%d", &a, &b, &c, &d);
if (n != 3 && n != 4)
exit(1);
v = a*1000000 + b*10000 + c*100 + d;
fprintf(stderr, "found zlib version %s (%d)\n", ZLIB_VERSION, v);
/* 1.1.4 is OK */
if (a == 1 && b == 1 && c >= 4)
exit(0);
/* 1.2.3 and up are OK */
if (v >= 1020300)
exit(0);
exit(2);
]])],
AC_MSG_RESULT([no]),
[ AC_MSG_RESULT([yes])
if test -z "$zlib_check_nonfatal" ; then
AC_MSG_ERROR([*** zlib too old - check config.log ***
Your reported zlib version has known security problems. It's possible your
vendor has fixed these problems without changing the version number. If you
are sure this is the case, you can disable the check by running
"./configure --without-zlib-version-check".
If you are in doubt, upgrade zlib to version 1.2.3 or greater.
See http://www.gzip.org/zlib/ for details.])
else
AC_MSG_WARN([zlib version may have security problems])
fi
],
[ AC_MSG_WARN([cross compiling: not checking zlib version]) ]
)
+ LIBS="$saved_LIBS"
fi
dnl UnixWare 2.x
AC_CHECK_FUNC([strcasecmp],
[], [ AC_CHECK_LIB([resolv], [strcasecmp], [LIBS="$LIBS -lresolv"]) ]
)
AC_CHECK_FUNCS([utimes],
[], [ AC_CHECK_LIB([c89], [utimes], [AC_DEFINE([HAVE_UTIMES])
LIBS="$LIBS -lc89"]) ]
)
dnl Checks for libutil functions
AC_CHECK_HEADERS([bsd/libutil.h libutil.h])
AC_SEARCH_LIBS([fmt_scaled], [util bsd])
AC_SEARCH_LIBS([scan_scaled], [util bsd])
AC_SEARCH_LIBS([login], [util bsd])
AC_SEARCH_LIBS([logout], [util bsd])
AC_SEARCH_LIBS([logwtmp], [util bsd])
AC_SEARCH_LIBS([openpty], [util bsd])
AC_SEARCH_LIBS([updwtmp], [util bsd])
AC_CHECK_FUNCS([fmt_scaled scan_scaled login logout openpty updwtmp logwtmp])
# On some platforms, inet_ntop and gethostbyname may be found in libresolv
# or libnsl.
AC_SEARCH_LIBS([inet_ntop], [resolv nsl])
AC_SEARCH_LIBS([gethostbyname], [resolv nsl])
# Some Linux distribtions ship the BSD libc hashing functions in
# separate libraries.
AC_SEARCH_LIBS([SHA256Update], [md bsd])
# "Particular Function Checks"
# see https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Particular-Functions.html
AC_FUNC_STRFTIME
AC_FUNC_MALLOC
AC_FUNC_REALLOC
# autoconf doesn't have AC_FUNC_CALLOC so fake it if malloc returns NULL;
AC_MSG_CHECKING([if calloc(0, N) returns non-null])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM(
[[ #include <stdlib.h> ]],
[[ void *p = calloc(0, 1); exit(p == NULL); ]]
)],
[ func_calloc_0_nonnull=yes ],
[ func_calloc_0_nonnull=no ],
[ AC_MSG_WARN([cross compiling: assuming same as malloc])
func_calloc_0_nonnull="$ac_cv_func_malloc_0_nonnull"]
)
AC_MSG_RESULT([$func_calloc_0_nonnull])
if test "x$func_calloc_0_nonnull" = "xyes"; then
AC_DEFINE(HAVE_CALLOC, 1, [calloc(0, x) returns non-null])
else
AC_DEFINE(HAVE_CALLOC, 0, [calloc(0, x) returns NULL])
AC_DEFINE(calloc, rpl_calloc,
[Define to rpl_calloc if the replacement function should be used.])
fi
# Check for ALTDIRFUNC glob() extension
AC_MSG_CHECKING([for GLOB_ALTDIRFUNC support])
AC_EGREP_CPP([FOUNDIT],
[
#include <glob.h>
#ifdef GLOB_ALTDIRFUNC
FOUNDIT
#endif
],
[
AC_DEFINE([GLOB_HAS_ALTDIRFUNC], [1],
[Define if your system glob() function has
the GLOB_ALTDIRFUNC extension])
AC_MSG_RESULT([yes])
],
[
AC_MSG_RESULT([no])
]
)
# Check for g.gl_matchc glob() extension
AC_MSG_CHECKING([for gl_matchc field in glob_t])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <glob.h> ]],
[[ glob_t g; g.gl_matchc = 1; ]])],
[
AC_DEFINE([GLOB_HAS_GL_MATCHC], [1],
[Define if your system glob() function has
gl_matchc options in glob_t])
AC_MSG_RESULT([yes])
], [
AC_MSG_RESULT([no])
])
# Check for g.gl_statv glob() extension
AC_MSG_CHECKING([for gl_statv and GLOB_KEEPSTAT extensions for glob])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <glob.h> ]], [[
#ifndef GLOB_KEEPSTAT
#error "glob does not support GLOB_KEEPSTAT extension"
#endif
glob_t g;
g.gl_statv = NULL;
]])],
[
AC_DEFINE([GLOB_HAS_GL_STATV], [1],
[Define if your system glob() function has
gl_statv options in glob_t])
AC_MSG_RESULT([yes])
], [
AC_MSG_RESULT([no])
])
AC_CHECK_DECLS([GLOB_NOMATCH], , , [#include <glob.h>])
AC_CHECK_DECL([VIS_ALL], ,
AC_DEFINE(BROKEN_STRNVIS, 1, [missing VIS_ALL]), [#include <vis.h>])
AC_MSG_CHECKING([whether struct dirent allocates space for d_name])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
]],
[[
struct dirent d;
exit(sizeof(d.d_name)<=sizeof(char));
]])],
[AC_MSG_RESULT([yes])],
[
AC_MSG_RESULT([no])
AC_DEFINE([BROKEN_ONE_BYTE_DIRENT_D_NAME], [1],
[Define if your struct dirent expects you to
allocate extra space for d_name])
],
[
AC_MSG_WARN([cross compiling: assuming BROKEN_ONE_BYTE_DIRENT_D_NAME])
AC_DEFINE([BROKEN_ONE_BYTE_DIRENT_D_NAME])
]
)
AC_MSG_CHECKING([for /proc/pid/fd directory])
if test -d "/proc/$$/fd" ; then
AC_DEFINE([HAVE_PROC_PID], [1], [Define if you have /proc/$pid/fd])
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
# Check whether user wants to use ldns
LDNS_MSG="no"
AC_ARG_WITH(ldns,
[ --with-ldns[[=PATH]] Use ldns for DNSSEC support (optionally in PATH)],
[
ldns=""
if test "x$withval" = "xyes" ; then
AC_PATH_TOOL([LDNSCONFIG], [ldns-config], [no])
if test "x$LDNSCONFIG" = "xno"; then
LIBS="-lldns $LIBS"
ldns=yes
else
LIBS="$LIBS `$LDNSCONFIG --libs`"
CPPFLAGS="$CPPFLAGS `$LDNSCONFIG --cflags`"
ldns=yes
fi
elif test "x$withval" != "xno" ; then
CPPFLAGS="$CPPFLAGS -I${withval}/include"
LDFLAGS="$LDFLAGS -L${withval}/lib"
LIBS="-lldns $LIBS"
ldns=yes
fi
# Verify that it works.
if test "x$ldns" = "xyes" ; then
AC_DEFINE(HAVE_LDNS, 1, [Define if you want ldns support])
LDNS_MSG="yes"
AC_MSG_CHECKING([for ldns support])
AC_LINK_IFELSE(
[AC_LANG_SOURCE([[
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#include <ldns/ldns.h>
int main() { ldns_status status = ldns_verify_trusted(NULL, NULL, NULL, NULL); status=LDNS_STATUS_OK; exit(0); }
]])
],
[AC_MSG_RESULT(yes)],
[
AC_MSG_RESULT(no)
AC_MSG_ERROR([** Incomplete or missing ldns libraries.])
])
fi
])
# Check whether user wants libedit support
LIBEDIT_MSG="no"
AC_ARG_WITH([libedit],
[ --with-libedit[[=PATH]] Enable libedit support for sftp],
[ if test "x$withval" != "xno" ; then
if test "x$withval" = "xyes" ; then
- AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no])
if test "x$PKGCONFIG" != "xno"; then
AC_MSG_CHECKING([if $PKGCONFIG knows about libedit])
if "$PKGCONFIG" libedit; then
AC_MSG_RESULT([yes])
use_pkgconfig_for_libedit=yes
else
AC_MSG_RESULT([no])
fi
fi
else
CPPFLAGS="$CPPFLAGS -I${withval}/include"
if test -n "${rpath_opt}"; then
LDFLAGS="-L${withval}/lib ${rpath_opt}${withval}/lib ${LDFLAGS}"
else
LDFLAGS="-L${withval}/lib ${LDFLAGS}"
fi
fi
if test "x$use_pkgconfig_for_libedit" = "xyes"; then
LIBEDIT=`$PKGCONFIG --libs libedit`
CPPFLAGS="$CPPFLAGS `$PKGCONFIG --cflags libedit`"
else
LIBEDIT="-ledit -lcurses"
fi
OTHERLIBS=`echo $LIBEDIT | sed 's/-ledit//'`
AC_CHECK_LIB([edit], [el_init],
[ AC_DEFINE([USE_LIBEDIT], [1], [Use libedit for sftp])
LIBEDIT_MSG="yes"
AC_SUBST([LIBEDIT])
],
[ AC_MSG_ERROR([libedit not found]) ],
[ $OTHERLIBS ]
)
AC_MSG_CHECKING([if libedit version is compatible])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[
#include <histedit.h>
#include <stdlib.h>
]],
[[
int i = H_SETSIZE;
el_init("", NULL, NULL, NULL);
exit(0);
]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
AC_MSG_ERROR([libedit version is not compatible]) ]
)
fi ]
)
AUDIT_MODULE=none
AC_ARG_WITH([audit],
[ --with-audit=module Enable audit support (modules=debug,bsm,linux)],
[
AC_MSG_CHECKING([for supported audit module])
case "$withval" in
bsm)
AC_MSG_RESULT([bsm])
AUDIT_MODULE=bsm
dnl Checks for headers, libs and functions
AC_CHECK_HEADERS([bsm/audit.h], [],
[AC_MSG_ERROR([BSM enabled and bsm/audit.h not found])],
[
#ifdef HAVE_TIME_H
# include <time.h>
#endif
]
)
AC_CHECK_LIB([bsm], [getaudit], [],
[AC_MSG_ERROR([BSM enabled and required library not found])])
AC_CHECK_FUNCS([getaudit], [],
[AC_MSG_ERROR([BSM enabled and required function not found])])
# These are optional
AC_CHECK_FUNCS([getaudit_addr aug_get_machine])
AC_DEFINE([USE_BSM_AUDIT], [1], [Use BSM audit module])
if test "$sol2ver" -ge 11; then
SSHDLIBS="$SSHDLIBS -lscf"
AC_DEFINE([BROKEN_BSM_API], [1],
[The system has incomplete BSM API])
fi
;;
linux)
AC_MSG_RESULT([linux])
AUDIT_MODULE=linux
dnl Checks for headers, libs and functions
AC_CHECK_HEADERS([libaudit.h])
SSHDLIBS="$SSHDLIBS -laudit"
AC_DEFINE([USE_LINUX_AUDIT], [1], [Use Linux audit module])
;;
debug)
AUDIT_MODULE=debug
AC_MSG_RESULT([debug])
AC_DEFINE([SSH_AUDIT_EVENTS], [1], [Use audit debugging module])
;;
no)
AC_MSG_RESULT([no])
;;
*)
AC_MSG_ERROR([Unknown audit module $withval])
;;
esac ]
)
AC_ARG_WITH([pie],
[ --with-pie Build Position Independent Executables if possible], [
if test "x$withval" = "xno"; then
use_pie=no
fi
if test "x$withval" = "xyes"; then
use_pie=yes
fi
]
)
if test "x$use_pie" = "x"; then
use_pie=no
fi
if test "x$use_toolchain_hardening" != "x1" && test "x$use_pie" = "xauto"; then
# Turn off automatic PIE when toolchain hardening is off.
use_pie=no
fi
if test "x$use_pie" = "xauto"; then
# Automatic PIE requires gcc >= 4.x
AC_MSG_CHECKING([for gcc >= 4.x])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
#if !defined(__GNUC__) || __GNUC__ < 4
#error gcc is too old
#endif
]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
use_pie=no ]
)
fi
if test "x$use_pie" != "xno"; then
SAVED_CFLAGS="$CFLAGS"
SAVED_LDFLAGS="$LDFLAGS"
OSSH_CHECK_CFLAG_COMPILE([-fPIE])
OSSH_CHECK_LDFLAG_LINK([-pie])
# We use both -fPIE and -pie or neither.
AC_MSG_CHECKING([whether both -fPIE and -pie are supported])
if echo "x $CFLAGS" | grep ' -fPIE' >/dev/null 2>&1 && \
echo "x $LDFLAGS" | grep ' -pie' >/dev/null 2>&1 ; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
CFLAGS="$SAVED_CFLAGS"
LDFLAGS="$SAVED_LDFLAGS"
fi
fi
AC_MSG_CHECKING([whether -fPIC is accepted])
SAVED_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -fPIC"
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM( [[ #include <stdlib.h> ]], [[ exit(0); ]] )],
[AC_MSG_RESULT([yes])
PICFLAG="-fPIC"; ],
[AC_MSG_RESULT([no])
PICFLAG=""; ])
CFLAGS="$SAVED_CFLAGS"
AC_SUBST([PICFLAG])
dnl Checks for library functions. Please keep in alphabetical order
AC_CHECK_FUNCS([ \
Blowfish_initstate \
Blowfish_expandstate \
Blowfish_expand0state \
Blowfish_stream2word \
SHA256Update \
SHA384Update \
SHA512Update \
asprintf \
b64_ntop \
__b64_ntop \
b64_pton \
__b64_pton \
bcopy \
bcrypt_pbkdf \
bindresvport_sa \
blf_enc \
bzero \
cap_rights_limit \
clock \
closefrom \
close_range \
dirfd \
endgrent \
err \
errx \
explicit_bzero \
explicit_memset \
fchmod \
fchmodat \
fchown \
fchownat \
flock \
fnmatch \
freeaddrinfo \
freezero \
fstatfs \
fstatvfs \
futimes \
getaddrinfo \
getcwd \
+ getentropy \
getgrouplist \
getline \
getnameinfo \
getopt \
getpagesize \
getpeereid \
getpeerucred \
getpgid \
_getpty \
getrlimit \
getrandom \
getsid \
getttyent \
glob \
group_from_gid \
inet_aton \
inet_ntoa \
inet_ntop \
innetgr \
killpg \
llabs \
localtime_r \
login_getcapbool \
login_getpwclass \
memmem \
memmove \
memset_s \
mkdtemp \
ngetaddrinfo \
nsleep \
ogetaddrinfo \
openlog_r \
pledge \
poll \
ppoll \
prctl \
procctl \
pselect \
pstat \
raise \
readpassphrase \
reallocarray \
realpath \
recvmsg \
recallocarray \
rresvport_af \
sendmsg \
setdtablesize \
setegid \
setenv \
seteuid \
setgroupent \
setgroups \
setlinebuf \
setlogin \
setpassent\
setpcred \
setproctitle \
setregid \
setreuid \
setrlimit \
setsid \
setvbuf \
sigaction \
sigvec \
snprintf \
socketpair \
statfs \
statvfs \
strcasestr \
strdup \
strerror \
strlcat \
strlcpy \
strmode \
strndup \
strnlen \
strnvis \
strptime \
strsignal \
strtonum \
strtoll \
strtoul \
strtoull \
swap32 \
sysconf \
tcgetpgrp \
+ timegm \
timingsafe_bcmp \
truncate \
unsetenv \
updwtmpx \
utimensat \
user_from_uid \
usleep \
vasprintf \
vsnprintf \
waitpid \
warn \
])
AC_CHECK_DECLS([bzero, memmem])
dnl Wide character support.
AC_CHECK_FUNCS([mblen mbtowc nl_langinfo wcwidth])
TEST_SSH_UTF8=${TEST_SSH_UTF8:=yes}
AC_MSG_CHECKING([for utf8 locale support])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <locale.h>
#include <stdlib.h>
]], [[
char *loc = setlocale(LC_CTYPE, "en_US.UTF-8");
if (loc != NULL)
exit(0);
exit(1);
]])],
AC_MSG_RESULT(yes),
[AC_MSG_RESULT(no)
TEST_SSH_UTF8=no],
AC_MSG_WARN([cross compiling: assuming yes])
)
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[ #include <ctype.h> ]],
[[ return (isblank('a')); ]])],
[AC_DEFINE([HAVE_ISBLANK], [1], [Define if you have isblank(3C).])
])
disable_pkcs11=
AC_ARG_ENABLE([pkcs11],
[ --disable-pkcs11 disable PKCS#11 support code [no]],
[
if test "x$enableval" = "xno" ; then
disable_pkcs11=1
fi
]
)
disable_sk=
AC_ARG_ENABLE([security-key],
[ --disable-security-key disable U2F/FIDO support code [no]],
[
if test "x$enableval" = "xno" ; then
disable_sk=1
fi
]
)
enable_sk_internal=
AC_ARG_WITH([security-key-builtin],
[ --with-security-key-builtin include builtin U2F/FIDO support],
- [
- if test "x$withval" != "xno" ; then
- enable_sk_internal=yes
- fi
- ]
+ [ enable_sk_internal=$withval ]
)
-test "x$disable_sk" != "x" && enable_sk_internal=""
AC_SEARCH_LIBS([dlopen], [dl])
AC_CHECK_FUNCS([dlopen])
AC_CHECK_DECL([RTLD_NOW], [], [], [#include <dlfcn.h>])
# IRIX has a const char return value for gai_strerror()
AC_CHECK_FUNCS([gai_strerror], [
AC_DEFINE([HAVE_GAI_STRERROR])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
const char *gai_strerror(int);
]], [[
char *str;
str = gai_strerror(0);
]])], [
AC_DEFINE([HAVE_CONST_GAI_STRERROR_PROTO], [1],
[Define if gai_strerror() returns const char *])], [])])
AC_SEARCH_LIBS([nanosleep], [rt posix4], [AC_DEFINE([HAVE_NANOSLEEP], [1],
[Some systems put nanosleep outside of libc])])
AC_SEARCH_LIBS([clock_gettime], [rt],
[AC_DEFINE([HAVE_CLOCK_GETTIME], [1], [Have clock_gettime])])
dnl check if we need -D_REENTRANT for localtime_r declaration.
AC_CHECK_DECL([localtime_r], [],
[ saved_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS -D_REENTRANT"
unset ac_cv_have_decl_localtime_r
AC_CHECK_DECL([localtime_r], [],
[ CPPFLAGS="$saved_CPPFLAGS" ],
[ #include <time.h> ]
)
],
[ #include <time.h> ]
)
dnl Make sure prototypes are defined for these before using them.
AC_CHECK_DECL([strsep],
[AC_CHECK_FUNCS([strsep])],
[],
[
#ifdef HAVE_STRING_H
# include <string.h>
#endif
])
dnl tcsendbreak might be a macro
AC_CHECK_DECL([tcsendbreak],
[AC_DEFINE([HAVE_TCSENDBREAK])],
[AC_CHECK_FUNCS([tcsendbreak])],
[#include <termios.h>]
)
AC_CHECK_DECLS([h_errno], , ,[#include <netdb.h>])
AC_CHECK_DECLS([SHUT_RD, getpeereid], , ,
[
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
])
AC_CHECK_DECLS([O_NONBLOCK], , ,
[
#include <sys/types.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
])
-AC_CHECK_DECLS([ftruncate], , ,
+AC_CHECK_DECLS([ftruncate, getentropy], , ,
[
#include <sys/types.h>
#include <unistd.h>
])
AC_CHECK_DECLS([readv, writev], , , [
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
])
AC_CHECK_DECLS([MAXSYMLINKS], , , [
#include <sys/param.h>
])
AC_CHECK_DECLS([offsetof], , , [
#include <stddef.h>
])
# extra bits for select(2)
AC_CHECK_DECLS([howmany, NFDBITS], [], [], [[
#include <sys/param.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
]])
AC_CHECK_TYPES([fd_mask], [], [], [[
#include <sys/param.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
]])
AC_CHECK_FUNCS([setresuid], [
dnl Some platorms have setresuid that isn't implemented, test for this
AC_MSG_CHECKING([if setresuid seems to work])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdlib.h>
#include <errno.h>
]], [[
errno=0;
setresuid(0,0,0);
if (errno==ENOSYS)
exit(1);
else
exit(0);
]])],
[AC_MSG_RESULT([yes])],
[AC_DEFINE([BROKEN_SETRESUID], [1],
[Define if your setresuid() is broken])
AC_MSG_RESULT([not implemented])],
[AC_MSG_WARN([cross compiling: not checking setresuid])]
)
])
AC_CHECK_FUNCS([setresgid], [
dnl Some platorms have setresgid that isn't implemented, test for this
AC_MSG_CHECKING([if setresgid seems to work])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdlib.h>
#include <errno.h>
]], [[
errno=0;
setresgid(0,0,0);
if (errno==ENOSYS)
exit(1);
else
exit(0);
]])],
[AC_MSG_RESULT([yes])],
[AC_DEFINE([BROKEN_SETRESGID], [1],
[Define if your setresgid() is broken])
AC_MSG_RESULT([not implemented])],
[AC_MSG_WARN([cross compiling: not checking setresuid])]
)
])
AC_MSG_CHECKING([for working fflush(NULL)])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdio.h>
#include <stdlib.h>
]],
[[fflush(NULL); exit(0);]])],
AC_MSG_RESULT([yes]),
[AC_MSG_RESULT([no])
AC_DEFINE([FFLUSH_NULL_BUG], [1],
[define if fflush(NULL) does not work])],
AC_MSG_WARN([cross compiling: assuming working])
)
dnl Checks for time functions
AC_CHECK_FUNCS([gettimeofday time])
dnl Checks for utmp functions
AC_CHECK_FUNCS([endutent getutent getutid getutline pututline setutent])
AC_CHECK_FUNCS([utmpname])
dnl Checks for utmpx functions
AC_CHECK_FUNCS([endutxent getutxent getutxid getutxline getutxuser pututxline])
AC_CHECK_FUNCS([setutxdb setutxent utmpxname])
dnl Checks for lastlog functions
AC_CHECK_FUNCS([getlastlogxbyname])
AC_CHECK_FUNC([daemon],
[AC_DEFINE([HAVE_DAEMON], [1], [Define if your libraries define daemon()])],
[AC_CHECK_LIB([bsd], [daemon],
[LIBS="$LIBS -lbsd"; AC_DEFINE([HAVE_DAEMON])])]
)
AC_CHECK_FUNC([getpagesize],
[AC_DEFINE([HAVE_GETPAGESIZE], [1],
[Define if your libraries define getpagesize()])],
[AC_CHECK_LIB([ucb], [getpagesize],
[LIBS="$LIBS -lucb"; AC_DEFINE([HAVE_GETPAGESIZE])])]
)
# Check for broken snprintf
if test "x$ac_cv_func_snprintf" = "xyes" ; then
AC_MSG_CHECKING([whether snprintf correctly terminates long strings])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdio.h>
#include <stdlib.h>
]],
[[
char b[5];
snprintf(b,5,"123456789");
exit(b[4]!='\0');
]])],
[AC_MSG_RESULT([yes])],
[
AC_MSG_RESULT([no])
AC_DEFINE([BROKEN_SNPRINTF], [1],
[Define if your snprintf is busted])
AC_MSG_WARN([****** Your snprintf() function is broken, complain to your vendor])
],
[ AC_MSG_WARN([cross compiling: Assuming working snprintf()]) ]
)
fi
if test "x$ac_cv_func_snprintf" = "xyes" ; then
AC_MSG_CHECKING([whether snprintf understands %zu])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
]],
[[
size_t a = 1, b = 2;
char z[128];
snprintf(z, sizeof z, "%zu%zu", a, b);
exit(strcmp(z, "12"));
]])],
[AC_MSG_RESULT([yes])],
[
AC_MSG_RESULT([no])
AC_DEFINE([BROKEN_SNPRINTF], [1],
[snprintf does not understand %zu])
],
[ AC_MSG_WARN([cross compiling: Assuming working snprintf()]) ]
)
fi
# We depend on vsnprintf returning the right thing on overflow: the
# number of characters it tried to create (as per SUSv3)
if test "x$ac_cv_func_vsnprintf" = "xyes" ; then
AC_MSG_CHECKING([whether vsnprintf returns correct values on overflow])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <stdio.h>
#include <stdarg.h>
int x_snprintf(char *str, size_t count, const char *fmt, ...)
{
size_t ret;
va_list ap;
va_start(ap, fmt);
ret = vsnprintf(str, count, fmt, ap);
va_end(ap);
return ret;
}
]], [[
char x[1];
if (x_snprintf(x, 1, "%s %d", "hello", 12345) != 11)
return 1;
if (x_snprintf(NULL, 0, "%s %d", "hello", 12345) != 11)
return 1;
return 0;
]])],
[AC_MSG_RESULT([yes])],
[
AC_MSG_RESULT([no])
AC_DEFINE([BROKEN_SNPRINTF], [1],
[Define if your snprintf is busted])
AC_MSG_WARN([****** Your vsnprintf() function is broken, complain to your vendor])
],
[ AC_MSG_WARN([cross compiling: Assuming working vsnprintf()]) ]
)
fi
# On systems where [v]snprintf is broken, but is declared in stdio,
# check that the fmt argument is const char * or just char *.
# This is only useful for when BROKEN_SNPRINTF
AC_MSG_CHECKING([whether snprintf can declare const char *fmt])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <stdio.h>
int snprintf(char *a, size_t b, const char *c, ...) { return 0; }
]], [[
snprintf(0, 0, 0);
]])],
[AC_MSG_RESULT([yes])
AC_DEFINE([SNPRINTF_CONST], [const],
[Define as const if snprintf() can declare const char *fmt])],
[AC_MSG_RESULT([no])
AC_DEFINE([SNPRINTF_CONST], [/* not const */])])
# Check for missing getpeereid (or equiv) support
NO_PEERCHECK=""
if test "x$ac_cv_func_getpeereid" != "xyes" -a "x$ac_cv_func_getpeerucred" != "xyes"; then
AC_MSG_CHECKING([whether system supports SO_PEERCRED getsockopt])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>]], [[int i = SO_PEERCRED;]])],
[ AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_SO_PEERCRED], [1], [Have PEERCRED socket option])
], [AC_MSG_RESULT([no])
NO_PEERCHECK=1
])
fi
dnl make sure that openpty does not reacquire controlling terminal
if test ! -z "$check_for_openpty_ctty_bug"; then
AC_MSG_CHECKING([if openpty correctly handles controlling tty])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
]], [[
pid_t pid;
int fd, ptyfd, ttyfd, status;
pid = fork();
if (pid < 0) { /* failed */
exit(1);
} else if (pid > 0) { /* parent */
waitpid(pid, &status, 0);
if (WIFEXITED(status))
exit(WEXITSTATUS(status));
else
exit(2);
} else { /* child */
close(0); close(1); close(2);
setsid();
openpty(&ptyfd, &ttyfd, NULL, NULL, NULL);
fd = open("/dev/tty", O_RDWR | O_NOCTTY);
if (fd >= 0)
exit(3); /* Acquired ctty: broken */
else
exit(0); /* Did not acquire ctty: OK */
}
]])],
[
AC_MSG_RESULT([yes])
],
[
AC_MSG_RESULT([no])
AC_DEFINE([SSHD_ACQUIRES_CTTY])
],
[
AC_MSG_RESULT([cross-compiling, assuming yes])
]
)
fi
if test "x$ac_cv_func_getaddrinfo" = "xyes" && \
test "x$check_for_hpux_broken_getaddrinfo" = "x1"; then
AC_MSG_CHECKING([if getaddrinfo seems to work])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <netinet/in.h>
#define TEST_PORT "2222"
]], [[
int err, sock;
struct addrinfo *gai_ai, *ai, hints;
char ntop[NI_MAXHOST], strport[NI_MAXSERV], *name = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
err = getaddrinfo(name, TEST_PORT, &hints, &gai_ai);
if (err != 0) {
fprintf(stderr, "getaddrinfo failed (%s)", gai_strerror(err));
exit(1);
}
for (ai = gai_ai; ai != NULL; ai = ai->ai_next) {
if (ai->ai_family != AF_INET6)
continue;
err = getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop,
sizeof(ntop), strport, sizeof(strport),
NI_NUMERICHOST|NI_NUMERICSERV);
if (err != 0) {
if (err == EAI_SYSTEM)
perror("getnameinfo EAI_SYSTEM");
else
fprintf(stderr, "getnameinfo failed: %s\n",
gai_strerror(err));
exit(2);
}
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sock < 0)
perror("socket");
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
if (errno == EBADF)
exit(3);
}
}
exit(0);
]])],
[
AC_MSG_RESULT([yes])
],
[
AC_MSG_RESULT([no])
AC_DEFINE([BROKEN_GETADDRINFO])
],
[
AC_MSG_RESULT([cross-compiling, assuming yes])
]
)
fi
if test "x$ac_cv_func_getaddrinfo" = "xyes" && \
test "x$check_for_aix_broken_getaddrinfo" = "x1"; then
AC_MSG_CHECKING([if getaddrinfo seems to work])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <netinet/in.h>
#define TEST_PORT "2222"
]], [[
int err, sock;
struct addrinfo *gai_ai, *ai, hints;
char ntop[NI_MAXHOST], strport[NI_MAXSERV], *name = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
err = getaddrinfo(name, TEST_PORT, &hints, &gai_ai);
if (err != 0) {
fprintf(stderr, "getaddrinfo failed (%s)", gai_strerror(err));
exit(1);
}
for (ai = gai_ai; ai != NULL; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
continue;
err = getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop,
sizeof(ntop), strport, sizeof(strport),
NI_NUMERICHOST|NI_NUMERICSERV);
if (ai->ai_family == AF_INET && err != 0) {
perror("getnameinfo");
exit(2);
}
}
exit(0);
]])],
[
AC_MSG_RESULT([yes])
AC_DEFINE([AIX_GETNAMEINFO_HACK], [1],
[Define if you have a getaddrinfo that fails
for the all-zeros IPv6 address])
],
[
AC_MSG_RESULT([no])
AC_DEFINE([BROKEN_GETADDRINFO])
],
[
AC_MSG_RESULT([cross-compiling, assuming no])
]
)
fi
if test "x$ac_cv_func_getaddrinfo" = "xyes"; then
AC_CHECK_DECLS(AI_NUMERICSERV, , ,
[#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>])
fi
if test "x$check_for_conflicting_getspnam" = "x1"; then
AC_MSG_CHECKING([for conflicting getspnam in shadow.h])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <shadow.h>
#include <stdlib.h>
]],
[[ exit(0); ]])],
[
AC_MSG_RESULT([no])
],
[
AC_MSG_RESULT([yes])
AC_DEFINE([GETSPNAM_CONFLICTING_DEFS], [1],
[Conflicting defs for getspnam])
]
)
fi
dnl NetBSD added an strnvis and unfortunately made it incompatible with the
dnl existing one in OpenBSD and Linux's libbsd (the former having existed
dnl for over ten years). Despite this incompatibility being reported during
dnl development (see http://gnats.netbsd.org/44977) they still shipped it.
dnl Even more unfortunately FreeBSD and later MacOS picked up this incompatible
dnl implementation. Try to detect this mess, and assume the only safe option
dnl if we're cross compiling.
dnl
dnl OpenBSD, 2001: strnvis(char *dst, const char *src, size_t dlen, int flag);
dnl NetBSD: 2012, strnvis(char *dst, size_t dlen, const char *src, int flag);
if test "x$ac_cv_func_strnvis" = "xyes"; then
AC_MSG_CHECKING([for working strnvis])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <vis.h>
static void sighandler(int sig) { _exit(1); }
]], [[
char dst[16];
signal(SIGSEGV, sighandler);
if (strnvis(dst, "src", 4, 0) && strcmp(dst, "src") == 0)
exit(0);
exit(1)
]])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_DEFINE([BROKEN_STRNVIS], [1], [strnvis detected broken])],
[AC_MSG_WARN([cross compiling: assuming broken])
AC_DEFINE([BROKEN_STRNVIS], [1], [strnvis assumed broken])]
)
fi
AC_MSG_CHECKING([if SA_RESTARTed signals interrupt select()])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#ifdef HAVE_SYS_SELECT
# include <sys/select.h>
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
static void sighandler(int sig) { }
]], [[
int r;
pid_t pid;
struct sigaction sa;
sa.sa_handler = sighandler;
sa.sa_flags = SA_RESTART;
(void)sigaction(SIGTERM, &sa, NULL);
if ((pid = fork()) == 0) { /* child */
pid = getppid();
sleep(1);
kill(pid, SIGTERM);
sleep(1);
if (getppid() == pid) /* if parent did not exit, shoot it */
kill(pid, SIGKILL);
exit(0);
} else { /* parent */
r = select(0, NULL, NULL, NULL, NULL);
}
exit(r == -1 ? 0 : 1);
]])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_DEFINE([NO_SA_RESTART], [1],
[SA_RESTARTed signals do no interrupt select])],
[AC_MSG_WARN([cross compiling: assuming yes])]
)
AC_CHECK_FUNCS([getpgrp],[
AC_MSG_CHECKING([if getpgrp accepts zero args])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[$ac_includes_default]], [[ getpgrp(); ]])],
[ AC_MSG_RESULT([yes])
AC_DEFINE([GETPGRP_VOID], [1], [getpgrp takes zero args])],
[ AC_MSG_RESULT([no])
AC_DEFINE([GETPGRP_VOID], [0], [getpgrp takes one arg])]
)
])
# Search for OpenSSL
saved_CPPFLAGS="$CPPFLAGS"
saved_LDFLAGS="$LDFLAGS"
AC_ARG_WITH([ssl-dir],
[ --with-ssl-dir=PATH Specify path to OpenSSL installation ],
[
if test "x$openssl" = "xno" ; then
AC_MSG_ERROR([cannot use --with-ssl-dir when OpenSSL disabled])
fi
if test "x$withval" != "xno" ; then
case "$withval" in
# Relative paths
./*|../*) withval="`pwd`/$withval"
esac
if test -d "$withval/lib"; then
libcrypto_path="${withval}/lib"
elif test -d "$withval/lib64"; then
libcrypto_path="$withval/lib64"
else
# Built but not installed
libcrypto_path="${withval}"
fi
if test -n "${rpath_opt}"; then
LDFLAGS="-L${libcrypto_path} ${rpath_opt}${libcrypto_path} ${LDFLAGS}"
else
LDFLAGS="-L${libcrypto_path} ${LDFLAGS}"
fi
if test -d "$withval/include"; then
CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
else
CPPFLAGS="-I${withval} ${CPPFLAGS}"
fi
fi
]
)
AC_ARG_WITH([openssl-header-check],
[ --without-openssl-header-check Disable OpenSSL version consistency check],
[
if test "x$withval" = "xno" ; then
openssl_check_nonfatal=1
fi
]
)
openssl_engine=no
AC_ARG_WITH([ssl-engine],
[ --with-ssl-engine Enable OpenSSL (hardware) ENGINE support ],
[
if test "x$withval" != "xno" ; then
if test "x$openssl" = "xno" ; then
AC_MSG_ERROR([cannot use --with-ssl-engine when OpenSSL disabled])
fi
openssl_engine=yes
fi
]
)
+nocrypto_saved_LIBS="$LIBS"
if test "x$openssl" = "xyes" ; then
LIBS="-lcrypto $LIBS"
+ CHANNELLIBS="-lcrypto $CHANNELLIBS"
AC_TRY_LINK_FUNC([RAND_add], ,
[AC_MSG_ERROR([*** working libcrypto not found, check config.log])])
AC_CHECK_HEADER([openssl/opensslv.h], ,
[AC_MSG_ERROR([*** OpenSSL headers missing - please install first or check config.log ***])])
# Determine OpenSSL header version
AC_MSG_CHECKING([OpenSSL header version])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <openssl/opensslv.h>
#define DATA "conftest.sslincver"
]], [[
FILE *fd;
int rc;
fd = fopen(DATA,"w");
if(fd == NULL)
exit(1);
if ((rc = fprintf(fd, "%08lx (%s)\n",
(unsigned long)OPENSSL_VERSION_NUMBER,
OPENSSL_VERSION_TEXT)) < 0)
exit(1);
exit(0);
]])],
[
ssl_header_ver=`cat conftest.sslincver`
AC_MSG_RESULT([$ssl_header_ver])
],
[
AC_MSG_RESULT([not found])
AC_MSG_ERROR([OpenSSL version header not found.])
],
[
AC_MSG_WARN([cross compiling: not checking])
]
)
# Determining OpenSSL library version is version dependent.
AC_CHECK_FUNCS([OpenSSL_version OpenSSL_version_num])
# Determine OpenSSL library version
AC_MSG_CHECKING([OpenSSL library version])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
#define DATA "conftest.ssllibver"
]], [[
FILE *fd;
int rc;
fd = fopen(DATA,"w");
if(fd == NULL)
exit(1);
#ifndef OPENSSL_VERSION
# define OPENSSL_VERSION SSLEAY_VERSION
#endif
#ifndef HAVE_OPENSSL_VERSION
# define OpenSSL_version SSLeay_version
#endif
#ifndef HAVE_OPENSSL_VERSION_NUM
# define OpenSSL_version_num SSLeay
#endif
if ((rc = fprintf(fd, "%08lx (%s)\n",
(unsigned long)OpenSSL_version_num(),
OpenSSL_version(OPENSSL_VERSION))) < 0)
exit(1);
exit(0);
]])],
[
ssl_library_ver=`cat conftest.ssllibver`
# Check version is supported.
case "$ssl_library_ver" in
10000*|0*)
AC_MSG_ERROR([OpenSSL >= 1.0.1 required (have "$ssl_library_ver")])
;;
100*) ;; # 1.0.x
101000[[0123456]]*)
# https://github.com/openssl/openssl/pull/4613
AC_MSG_ERROR([OpenSSL 1.1.x versions prior to 1.1.0g have a bug that breaks their use with OpenSSH (have "$ssl_library_ver")])
;;
101*) ;; # 1.1.x
200*) ;; # LibreSSL
- 300*) ;; # OpenSSL 3
- 301*) ;; # OpenSSL development branch.
+ 300*)
+ # OpenSSL 3; we use the 1.1x API
+ CPPFLAGS="$CPPFLAGS -DOPENSSL_API_COMPAT=0x10100000L"
+ ;;
+ 301*)
+ # OpenSSL development branch; request 1.1x API
+ CPPFLAGS="$CPPFLAGS -DOPENSSL_API_COMPAT=0x10100000L"
+ ;;
*)
AC_MSG_ERROR([Unknown/unsupported OpenSSL version ("$ssl_library_ver")])
;;
esac
AC_MSG_RESULT([$ssl_library_ver])
],
[
AC_MSG_RESULT([not found])
AC_MSG_ERROR([OpenSSL library not found.])
],
[
AC_MSG_WARN([cross compiling: not checking])
]
)
+ case "$host" in
+ x86_64-*)
+ case "$ssl_library_ver" in
+ 3000004*)
+ AC_MSG_ERROR([OpenSSL 3.0.4 has a potential RCE in its RSA implementation (CVE-2022-2274)])
+ ;;
+ esac
+ esac
+
# Sanity check OpenSSL headers
AC_MSG_CHECKING([whether OpenSSL's headers match the library])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdlib.h>
#include <string.h>
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
]], [[
#ifndef HAVE_OPENSSL_VERSION_NUM
# define OpenSSL_version_num SSLeay
#endif
exit(OpenSSL_version_num() == OPENSSL_VERSION_NUMBER ? 0 : 1);
]])],
[
AC_MSG_RESULT([yes])
],
[
AC_MSG_RESULT([no])
if test "x$openssl_check_nonfatal" = "x"; then
AC_MSG_ERROR([Your OpenSSL headers do not match your
library. Check config.log for details.
If you are sure your installation is consistent, you can disable the check
by running "./configure --without-openssl-header-check".
Also see contrib/findssl.sh for help identifying header/library mismatches.
])
else
AC_MSG_WARN([Your OpenSSL headers do not match your
library. Check config.log for details.
Also see contrib/findssl.sh for help identifying header/library mismatches.])
fi
],
[
AC_MSG_WARN([cross compiling: not checking])
]
)
AC_MSG_CHECKING([if programs using OpenSSL functions will link])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[ #include <openssl/err.h> ]],
[[ ERR_load_crypto_strings(); ]])],
[
AC_MSG_RESULT([yes])
],
[
AC_MSG_RESULT([no])
- saved_LIBS="$LIBS"
LIBS="$LIBS -ldl"
AC_MSG_CHECKING([if programs using OpenSSL need -ldl])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[ #include <openssl/err.h> ]],
[[ ERR_load_crypto_strings(); ]])],
[
AC_MSG_RESULT([yes])
+ CHANNELLIBS="$CHANNELLIBS -ldl"
],
[
AC_MSG_RESULT([no])
- LIBS="$saved_LIBS"
]
)
]
)
AC_CHECK_FUNCS([ \
BN_is_prime_ex \
+ DES_crypt \
DSA_generate_parameters_ex \
- EVP_CIPHER_CTX_ctrl \
EVP_DigestFinal_ex \
EVP_DigestInit_ex \
EVP_MD_CTX_cleanup \
EVP_MD_CTX_copy_ex \
EVP_MD_CTX_init \
HMAC_CTX_init \
RSA_generate_key_ex \
RSA_get_default_method \
])
# OpenSSL_add_all_algorithms may be a macro.
AC_CHECK_FUNC(OpenSSL_add_all_algorithms,
AC_DEFINE(HAVE_OPENSSL_ADD_ALL_ALGORITHMS, 1, [as a function]),
AC_CHECK_DECL(OpenSSL_add_all_algorithms,
AC_DEFINE(HAVE_OPENSSL_ADD_ALL_ALGORITHMS, 1, [as a macro]), ,
[[#include <openssl/evp.h>]]
)
)
# LibreSSL/OpenSSL 1.1x API
AC_CHECK_FUNCS([ \
OPENSSL_init_crypto \
DH_get0_key \
DH_get0_pqg \
DH_set0_key \
DH_set_length \
DH_set0_pqg \
DSA_get0_key \
DSA_get0_pqg \
DSA_set0_key \
DSA_set0_pqg \
DSA_SIG_get0 \
DSA_SIG_set0 \
ECDSA_SIG_get0 \
ECDSA_SIG_set0 \
EVP_CIPHER_CTX_iv \
EVP_CIPHER_CTX_iv_noconst \
EVP_CIPHER_CTX_get_iv \
EVP_CIPHER_CTX_get_updated_iv \
EVP_CIPHER_CTX_set_iv \
RSA_get0_crt_params \
RSA_get0_factors \
RSA_get0_key \
RSA_set0_crt_params \
RSA_set0_factors \
RSA_set0_key \
RSA_meth_free \
RSA_meth_dup \
RSA_meth_set1_name \
RSA_meth_get_finish \
RSA_meth_set_priv_enc \
RSA_meth_set_priv_dec \
RSA_meth_set_finish \
EVP_PKEY_get0_RSA \
EVP_MD_CTX_new \
EVP_MD_CTX_free \
EVP_chacha20 \
])
if test "x$openssl_engine" = "xyes" ; then
AC_MSG_CHECKING([for OpenSSL ENGINE support])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <openssl/engine.h>
]], [[
ENGINE_load_builtin_engines();
ENGINE_register_all_complete();
]])],
[ AC_MSG_RESULT([yes])
AC_DEFINE([USE_OPENSSL_ENGINE], [1],
[Enable OpenSSL engine support])
], [ AC_MSG_ERROR([OpenSSL ENGINE support not found])
])
fi
# Check for OpenSSL without EVP_aes_{192,256}_cbc
AC_MSG_CHECKING([whether OpenSSL has crippled AES support])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
]], [[
exit(EVP_aes_192_cbc() == NULL || EVP_aes_256_cbc() == NULL);
]])],
[
AC_MSG_RESULT([no])
],
[
AC_MSG_RESULT([yes])
AC_DEFINE([OPENSSL_LOBOTOMISED_AES], [1],
[libcrypto is missing AES 192 and 256 bit functions])
]
)
- # Check for OpenSSL with EVP_aes_*ctr
- AC_MSG_CHECKING([whether OpenSSL has AES CTR via EVP])
- AC_LINK_IFELSE(
- [AC_LANG_PROGRAM([[
- #include <stdlib.h>
- #include <string.h>
- #include <openssl/evp.h>
- ]], [[
- exit(EVP_aes_128_ctr() == NULL ||
- EVP_aes_192_cbc() == NULL ||
- EVP_aes_256_cbc() == NULL);
- ]])],
- [
- AC_MSG_RESULT([yes])
- AC_DEFINE([OPENSSL_HAVE_EVPCTR], [1],
- [libcrypto has EVP AES CTR])
- ],
- [
- AC_MSG_RESULT([no])
- ]
- )
-
- # Check for OpenSSL with EVP_aes_*gcm
- AC_MSG_CHECKING([whether OpenSSL has AES GCM via EVP])
- AC_LINK_IFELSE(
- [AC_LANG_PROGRAM([[
- #include <stdlib.h>
- #include <string.h>
- #include <openssl/evp.h>
- ]], [[
- exit(EVP_aes_128_gcm() == NULL ||
- EVP_aes_256_gcm() == NULL ||
- EVP_CTRL_GCM_SET_IV_FIXED == 0 ||
- EVP_CTRL_GCM_IV_GEN == 0 ||
- EVP_CTRL_GCM_SET_TAG == 0 ||
- EVP_CTRL_GCM_GET_TAG == 0 ||
- EVP_CIPHER_CTX_ctrl(NULL, 0, 0, NULL) == 0);
- ]])],
- [
- AC_MSG_RESULT([yes])
- AC_DEFINE([OPENSSL_HAVE_EVPGCM], [1],
- [libcrypto has EVP AES GCM])
- ],
- [
- AC_MSG_RESULT([no])
- unsupported_algorithms="$unsupported_cipers \
- aes128-gcm@openssh.com \
- aes256-gcm@openssh.com"
- ]
- )
-
AC_MSG_CHECKING([if EVP_DigestUpdate returns an int])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
]], [[
if(EVP_DigestUpdate(NULL, NULL,0))
exit(0);
]])],
[
AC_MSG_RESULT([yes])
],
[
AC_MSG_RESULT([no])
AC_DEFINE([OPENSSL_EVP_DIGESTUPDATE_VOID], [1],
[Define if EVP_DigestUpdate returns void])
]
)
- # Some systems want crypt() from libcrypt, *not* the version in OpenSSL,
- # because the system crypt() is more featureful.
- if test "x$check_for_libcrypt_before" = "x1"; then
- AC_CHECK_LIB([crypt], [crypt])
- fi
-
- # Some Linux systems (Slackware) need crypt() from libcrypt, *not* the
- # version in OpenSSL.
- if test "x$check_for_libcrypt_later" = "x1"; then
- AC_CHECK_LIB([crypt], [crypt], [LIBS="$LIBS -lcrypt"])
- fi
- AC_CHECK_FUNCS([crypt DES_crypt])
-
# Check for SHA256, SHA384 and SHA512 support in OpenSSL
AC_CHECK_FUNCS([EVP_sha256 EVP_sha384 EVP_sha512])
# Check complete ECC support in OpenSSL
AC_MSG_CHECKING([whether OpenSSL has NID_X9_62_prime256v1])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/opensslv.h>
]], [[
EC_KEY *e = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
const EVP_MD *m = EVP_sha256(); /* We need this too */
]])],
[ AC_MSG_RESULT([yes])
enable_nistp256=1 ],
[ AC_MSG_RESULT([no]) ]
)
AC_MSG_CHECKING([whether OpenSSL has NID_secp384r1])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/opensslv.h>
]], [[
EC_KEY *e = EC_KEY_new_by_curve_name(NID_secp384r1);
const EVP_MD *m = EVP_sha384(); /* We need this too */
]])],
[ AC_MSG_RESULT([yes])
enable_nistp384=1 ],
[ AC_MSG_RESULT([no]) ]
)
AC_MSG_CHECKING([whether OpenSSL has NID_secp521r1])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/opensslv.h>
]], [[
EC_KEY *e = EC_KEY_new_by_curve_name(NID_secp521r1);
const EVP_MD *m = EVP_sha512(); /* We need this too */
]])],
[ AC_MSG_RESULT([yes])
AC_MSG_CHECKING([if OpenSSL's NID_secp521r1 is functional])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/opensslv.h>
]],[[
EC_KEY *e = EC_KEY_new_by_curve_name(NID_secp521r1);
const EVP_MD *m = EVP_sha512(); /* We need this too */
exit(e == NULL || m == NULL);
]])],
[ AC_MSG_RESULT([yes])
enable_nistp521=1 ],
[ AC_MSG_RESULT([no]) ],
[ AC_MSG_WARN([cross-compiling: assuming yes])
enable_nistp521=1 ]
)],
AC_MSG_RESULT([no])
)
if test x$enable_nistp256 = x1 || test x$enable_nistp384 = x1 || \
test x$enable_nistp521 = x1; then
AC_DEFINE(OPENSSL_HAS_ECC, [1], [OpenSSL has ECC])
AC_CHECK_FUNCS([EC_KEY_METHOD_new])
openssl_ecc=yes
else
openssl_ecc=no
fi
if test x$enable_nistp256 = x1; then
AC_DEFINE([OPENSSL_HAS_NISTP256], [1],
[libcrypto has NID_X9_62_prime256v1])
else
unsupported_algorithms="$unsupported_algorithms \
ecdsa-sha2-nistp256 \
ecdh-sha2-nistp256 \
ecdsa-sha2-nistp256-cert-v01@openssh.com"
fi
if test x$enable_nistp384 = x1; then
AC_DEFINE([OPENSSL_HAS_NISTP384], [1], [libcrypto has NID_secp384r1])
else
unsupported_algorithms="$unsupported_algorithms \
ecdsa-sha2-nistp384 \
ecdh-sha2-nistp384 \
ecdsa-sha2-nistp384-cert-v01@openssh.com"
fi
if test x$enable_nistp521 = x1; then
AC_DEFINE([OPENSSL_HAS_NISTP521], [1], [libcrypto has NID_secp521r1])
else
unsupported_algorithms="$unsupported_algorithms \
ecdh-sha2-nistp521 \
ecdsa-sha2-nistp521 \
ecdsa-sha2-nistp521-cert-v01@openssh.com"
fi
-
-else
- AC_CHECK_LIB([crypt], [crypt], [LIBS="$LIBS -lcrypt"])
- AC_CHECK_FUNCS([crypt])
fi
# PKCS11/U2F depend on OpenSSL and dlopen().
enable_pkcs11=yes
enable_sk=yes
if test "x$openssl" != "xyes" ; then
enable_pkcs11="disabled; missing libcrypto"
fi
if test "x$ac_cv_func_dlopen" != "xyes" ; then
enable_pkcs11="disabled; missing dlopen(3)"
enable_sk="disabled; missing dlopen(3)"
fi
if test "x$ac_cv_have_decl_RTLD_NOW" != "xyes" ; then
enable_pkcs11="disabled; missing RTLD_NOW"
enable_sk="disabled; missing RTLD_NOW"
fi
if test ! -z "$disable_pkcs11" ; then
enable_pkcs11="disabled by user"
fi
if test ! -z "$disable_sk" ; then
enable_sk="disabled by user"
fi
AC_MSG_CHECKING([whether to enable PKCS11])
if test "x$enable_pkcs11" = "xyes" ; then
AC_DEFINE([ENABLE_PKCS11], [], [Enable for PKCS#11 support])
fi
AC_MSG_RESULT([$enable_pkcs11])
AC_MSG_CHECKING([whether to enable U2F])
if test "x$enable_sk" = "xyes" ; then
AC_DEFINE([ENABLE_SK], [], [Enable for U2F/FIDO support])
AC_SUBST(SK_DUMMY_LIBRARY, [regress/misc/sk-dummy/sk-dummy.so])
else
# Do not try to build sk-dummy library.
AC_SUBST(SK_DUMMY_LIBRARY, [""])
fi
AC_MSG_RESULT([$enable_sk])
# Now check for built-in security key support.
-if test "x$enable_sk" = "xyes" -a "x$enable_sk_internal" = "xyes" ; then
- AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no])
+if test "x$enable_sk" = "xyes" -a "x$enable_sk_internal" != "xno" ; then
use_pkgconfig_for_libfido2=
if test "x$PKGCONFIG" != "xno"; then
AC_MSG_CHECKING([if $PKGCONFIG knows about libfido2])
if "$PKGCONFIG" libfido2; then
AC_MSG_RESULT([yes])
use_pkgconfig_for_libfido2=yes
else
AC_MSG_RESULT([no])
fi
fi
if test "x$use_pkgconfig_for_libfido2" = "xyes"; then
LIBFIDO2=`$PKGCONFIG --libs libfido2`
CPPFLAGS="$CPPFLAGS `$PKGCONFIG --cflags libfido2`"
else
LIBFIDO2="-lfido2 -lcbor"
fi
OTHERLIBS=`echo $LIBFIDO2 | sed 's/-lfido2//'`
+ fido2_error=
AC_CHECK_LIB([fido2], [fido_init],
- [
- AC_SUBST([LIBFIDO2])
- AC_DEFINE([ENABLE_SK_INTERNAL], [],
- [Enable for built-in U2F/FIDO support])
- enable_sk="built-in"
- ], [ AC_MSG_ERROR([no usable libfido2 found]) ],
+ [ ],
+ [ fido2_error="missing/unusable libfido2" ],
[ $OTHERLIBS ]
)
- saved_LIBS="$LIBS"
- LIBS="$LIBS $LIBFIDO2"
- AC_CHECK_FUNCS([ \
- fido_assert_set_clientdata \
- fido_cred_prot \
- fido_cred_set_prot \
- fido_cred_set_clientdata \
- fido_dev_get_touch_begin \
- fido_dev_get_touch_status \
- fido_dev_supports_cred_prot \
- ])
- LIBS="$saved_LIBS"
AC_CHECK_HEADER([fido.h], [],
- AC_MSG_ERROR([missing fido.h from libfido2]))
+ [ fido2_error="missing fido.h from libfido2" ])
AC_CHECK_HEADER([fido/credman.h], [],
- AC_MSG_ERROR([missing fido/credman.h from libfido2]),
- [#include <fido.h>]
+ [ fido2_error="missing fido/credman.h from libfido2" ],
+ [ #include <fido.h> ]
)
+ AC_MSG_CHECKING([for usable libfido2 installation])
+ if test ! -z "$fido2_error" ; then
+ AC_MSG_RESULT([$fido2_error])
+ if test "x$enable_sk_internal" = "xyes" ; then
+ AC_MSG_ERROR([No usable libfido2 library/headers found])
+ fi
+ LIBFIDO2=""
+ else
+ AC_MSG_RESULT([yes])
+ AC_SUBST([LIBFIDO2])
+ AC_DEFINE([ENABLE_SK_INTERNAL], [],
+ [Enable for built-in U2F/FIDO support])
+ enable_sk="built-in"
+ saved_LIBS="$LIBS"
+ LIBS="$LIBS $LIBFIDO2"
+ AC_CHECK_FUNCS([ \
+ fido_assert_set_clientdata \
+ fido_cred_prot \
+ fido_cred_set_prot \
+ fido_cred_set_clientdata \
+ fido_dev_get_touch_begin \
+ fido_dev_get_touch_status \
+ fido_dev_supports_cred_prot \
+ fido_dev_is_winhello \
+ ])
+ LIBS="$saved_LIBS"
+ fi
fi
AC_CHECK_FUNCS([ \
arc4random \
arc4random_buf \
arc4random_stir \
arc4random_uniform \
])
-
-saved_LIBS="$LIBS"
-AC_CHECK_LIB([iaf], [ia_openinfo], [
- LIBS="$LIBS -liaf"
- AC_CHECK_FUNCS([set_id], [SSHDLIBS="$SSHDLIBS -liaf"
- AC_DEFINE([HAVE_LIBIAF], [1],
- [Define if system has libiaf that supports set_id])
- ])
-])
-LIBS="$saved_LIBS"
-
### Configure cryptographic random number support
# Check whether OpenSSL seeds itself
if test "x$openssl" = "xyes" ; then
AC_MSG_CHECKING([whether OpenSSL's PRNG is internally seeded])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdlib.h>
#include <string.h>
#include <openssl/rand.h>
]], [[
exit(RAND_status() == 1 ? 0 : 1);
]])],
[
OPENSSL_SEEDS_ITSELF=yes
AC_MSG_RESULT([yes])
],
[
AC_MSG_RESULT([no])
],
[
AC_MSG_WARN([cross compiling: assuming yes])
# This is safe, since we will fatal() at runtime if
# OpenSSL is not seeded correctly.
OPENSSL_SEEDS_ITSELF=yes
]
)
fi
# PRNGD TCP socket
AC_ARG_WITH([prngd-port],
[ --with-prngd-port=PORT read entropy from PRNGD/EGD TCP localhost:PORT],
[
case "$withval" in
no)
withval=""
;;
[[0-9]]*)
;;
*)
AC_MSG_ERROR([You must specify a numeric port number for --with-prngd-port])
;;
esac
if test ! -z "$withval" ; then
PRNGD_PORT="$withval"
AC_DEFINE_UNQUOTED([PRNGD_PORT], [$PRNGD_PORT],
[Port number of PRNGD/EGD random number socket])
fi
]
)
# PRNGD Unix domain socket
AC_ARG_WITH([prngd-socket],
[ --with-prngd-socket=FILE read entropy from PRNGD/EGD socket FILE (default=/var/run/egd-pool)],
[
case "$withval" in
yes)
withval="/var/run/egd-pool"
;;
no)
withval=""
;;
/*)
;;
*)
AC_MSG_ERROR([You must specify an absolute path to the entropy socket])
;;
esac
if test ! -z "$withval" ; then
if test ! -z "$PRNGD_PORT" ; then
AC_MSG_ERROR([You may not specify both a PRNGD/EGD port and socket])
fi
if test ! -r "$withval" ; then
AC_MSG_WARN([Entropy socket is not readable])
fi
PRNGD_SOCKET="$withval"
AC_DEFINE_UNQUOTED([PRNGD_SOCKET], ["$PRNGD_SOCKET"],
[Location of PRNGD/EGD random number socket])
fi
],
[
# Check for existing socket only if we don't have a random device already
if test "x$OPENSSL_SEEDS_ITSELF" != "xyes" ; then
AC_MSG_CHECKING([for PRNGD/EGD socket])
# Insert other locations here
for sock in /var/run/egd-pool /dev/egd-pool /etc/entropy; do
if test -r $sock && $TEST_MINUS_S_SH -c "test -S $sock -o -p $sock" ; then
PRNGD_SOCKET="$sock"
AC_DEFINE_UNQUOTED([PRNGD_SOCKET], ["$PRNGD_SOCKET"])
break;
fi
done
if test ! -z "$PRNGD_SOCKET" ; then
AC_MSG_RESULT([$PRNGD_SOCKET])
else
AC_MSG_RESULT([not found])
fi
fi
]
)
# Which randomness source do we use?
if test ! -z "$PRNGD_PORT" ; then
RAND_MSG="PRNGd port $PRNGD_PORT"
elif test ! -z "$PRNGD_SOCKET" ; then
RAND_MSG="PRNGd socket $PRNGD_SOCKET"
elif test ! -z "$OPENSSL_SEEDS_ITSELF" ; then
AC_DEFINE([OPENSSL_PRNG_ONLY], [1],
[Define if you want the OpenSSL internally seeded PRNG only])
RAND_MSG="OpenSSL internal ONLY"
elif test "x$openssl" = "xno" ; then
AC_MSG_WARN([OpenSSH will use /dev/urandom as a source of random numbers. It will fail if this device is not supported or accessible])
else
AC_MSG_ERROR([OpenSSH has no source of random numbers. Please configure OpenSSL with an entropy source or re-run configure using one of the --with-prngd-port or --with-prngd-socket options])
fi
+LIBS="$nocrypto_saved_LIBS"
+
+saved_LIBS="$LIBS"
+AC_CHECK_LIB([iaf], [ia_openinfo], [
+ LIBS="$LIBS -liaf"
+ AC_CHECK_FUNCS([set_id], [SSHDLIBS="$SSHDLIBS -liaf"
+ AC_DEFINE([HAVE_LIBIAF], [1],
+ [Define if system has libiaf that supports set_id])
+ ])
+])
+LIBS="$saved_LIBS"
+
+# Check for crypt() in libcrypt. If we have it, we only need it for sshd.
+saved_LIBS="$LIBS"
+AC_CHECK_LIB([crypt], [crypt], [
+ LIBS="-lcrypt $LIBS"
+ SSHDLIBS="-lcrypt $SSHDLIBS"
+])
+AC_CHECK_FUNCS([crypt])
+LIBS="$saved_LIBS"
# Check for PAM libs
PAM_MSG="no"
AC_ARG_WITH([pam],
[ --with-pam Enable PAM support ],
[
if test "x$withval" != "xno" ; then
if test "x$ac_cv_header_security_pam_appl_h" != "xyes" && \
test "x$ac_cv_header_pam_pam_appl_h" != "xyes" ; then
AC_MSG_ERROR([PAM headers not found])
fi
saved_LIBS="$LIBS"
AC_CHECK_LIB([dl], [dlopen], , )
AC_CHECK_LIB([pam], [pam_set_item], , [AC_MSG_ERROR([*** libpam missing])])
AC_CHECK_FUNCS([pam_getenvlist])
AC_CHECK_FUNCS([pam_putenv])
LIBS="$saved_LIBS"
PAM_MSG="yes"
SSHDLIBS="$SSHDLIBS -lpam"
AC_DEFINE([USE_PAM], [1],
[Define if you want to enable PAM support])
if test $ac_cv_lib_dl_dlopen = yes; then
case "$LIBS" in
*-ldl*)
# libdl already in LIBS
;;
*)
SSHDLIBS="$SSHDLIBS -ldl"
;;
esac
fi
fi
]
)
AC_ARG_WITH([pam-service],
[ --with-pam-service=name Specify PAM service name ],
[
if test "x$withval" != "xno" && \
test "x$withval" != "xyes" ; then
AC_DEFINE_UNQUOTED([SSHD_PAM_SERVICE],
["$withval"], [sshd PAM service name])
fi
]
)
# Check for older PAM
if test "x$PAM_MSG" = "xyes" ; then
# Check PAM strerror arguments (old PAM)
AC_MSG_CHECKING([whether pam_strerror takes only one argument])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <stdlib.h>
#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
]], [[
(void)pam_strerror((pam_handle_t *)NULL, -1);
]])], [AC_MSG_RESULT([no])], [
AC_DEFINE([HAVE_OLD_PAM], [1],
[Define if you have an old version of PAM
which takes only one argument to pam_strerror])
AC_MSG_RESULT([yes])
PAM_MSG="yes (old library)"
])
fi
case "$host" in
*-*-cygwin*)
SSH_PRIVSEP_USER=CYGWIN_SSH_PRIVSEP_USER
;;
*)
SSH_PRIVSEP_USER=sshd
;;
esac
AC_ARG_WITH([privsep-user],
[ --with-privsep-user=user Specify non-privileged user for privilege separation],
[
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
SSH_PRIVSEP_USER=$withval
fi
]
)
if test "x$SSH_PRIVSEP_USER" = "xCYGWIN_SSH_PRIVSEP_USER" ; then
AC_DEFINE_UNQUOTED([SSH_PRIVSEP_USER], [CYGWIN_SSH_PRIVSEP_USER],
[Cygwin function to fetch non-privileged user for privilege separation])
else
AC_DEFINE_UNQUOTED([SSH_PRIVSEP_USER], ["$SSH_PRIVSEP_USER"],
[non-privileged user for privilege separation])
fi
AC_SUBST([SSH_PRIVSEP_USER])
if test "x$have_linux_no_new_privs" = "x1" ; then
AC_CHECK_DECL([SECCOMP_MODE_FILTER], [have_seccomp_filter=1], , [
#include <sys/types.h>
#include <linux/seccomp.h>
])
fi
if test "x$have_seccomp_filter" = "x1" ; then
AC_MSG_CHECKING([kernel for seccomp_filter support])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <errno.h>
#include <elf.h>
#include <linux/audit.h>
#include <linux/seccomp.h>
#include <stdlib.h>
#include <sys/prctl.h>
]],
[[ int i = $seccomp_audit_arch;
errno = 0;
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, 0, 0);
exit(errno == EFAULT ? 0 : 1); ]])],
[ AC_MSG_RESULT([yes]) ], [
AC_MSG_RESULT([no])
# Disable seccomp filter as a target
have_seccomp_filter=0
]
)
fi
+AC_CHECK_MEMBERS([struct pollfd.fd], [], [], [[
+#include <sys/types.h>
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
+]])
+
+AC_CHECK_TYPES([nfds_t], , , [
+#include <sys/types.h>
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
+])
+
# Decide which sandbox style to use
sandbox_arg=""
AC_ARG_WITH([sandbox],
[ --with-sandbox=style Specify privilege separation sandbox (no, capsicum, darwin, rlimit, seccomp_filter, systrace, pledge)],
[
if test "x$withval" = "xyes" ; then
sandbox_arg=""
else
sandbox_arg="$withval"
fi
]
)
+if test "x$sandbox_arg" != "xno"; then
# POSIX specifies that poll() "shall fail with EINVAL if the nfds argument
# is greater than OPEN_MAX". On some platforms that includes implementions
-# ofselect in userspace on top of poll() so check both work with rlimit NOFILES
-# so check that both work before enabling the rlimit sandbox.
-AC_MSG_CHECKING([if select and/or poll works with descriptor rlimit])
-AC_RUN_IFELSE(
+# of select in userspace on top of poll() so check both work with rlimit
+# NOFILES so check that both work before enabling the rlimit sandbox.
+ AC_MSG_CHECKING([if select and/or poll works with descriptor rlimit])
+ AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <sys/types.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/resource.h>
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#ifdef HAVE_POLL_H
# include <poll.h>
#elif HAVE_SYS_POLL_H
# include <sys/poll.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
]],[[
struct rlimit rl_zero;
int fd, r;
fd_set fds;
struct timeval tv;
#ifdef HAVE_POLL
struct pollfd pfd;
#endif
fd = open("/dev/null", O_RDONLY);
FD_ZERO(&fds);
FD_SET(fd, &fds);
rl_zero.rlim_cur = rl_zero.rlim_max = 0;
setrlimit(RLIMIT_FSIZE, &rl_zero);
setrlimit(RLIMIT_NOFILE, &rl_zero);
tv.tv_sec = 1;
tv.tv_usec = 0;
r = select(fd+1, &fds, NULL, NULL, &tv);
if (r == -1)
exit(1);
#ifdef HAVE_POLL
pfd.fd = fd;
pfd.events = POLLIN;
r = poll(&pfd, 1, 1);
if (r == -1)
exit(2);
#endif
exit(0);
]])],
[AC_MSG_RESULT([yes])
select_works_with_rlimit=yes],
[AC_MSG_RESULT([no])
select_works_with_rlimit=no],
[AC_MSG_WARN([cross compiling: assuming no])
select_works_with_rlimit=no]
-)
-
-AC_CHECK_MEMBERS([struct pollfd.fd], [], [], [[
-#include <sys/types.h>
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
-#ifdef HAVE_SYS_POLL_H
-#include <sys/poll.h>
-#endif
-]])
-
-AC_CHECK_TYPES([nfds_t], , , [
-#include <sys/types.h>
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
-#ifdef HAVE_SYS_POLL_H
-#include <sys/poll.h>
-#endif
-])
+ )
-AC_MSG_CHECKING([if setrlimit(RLIMIT_NOFILE,{0,0}) works])
-AC_RUN_IFELSE(
+ AC_MSG_CHECKING([if setrlimit(RLIMIT_NOFILE,{0,0}) works])
+ AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <sys/types.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/resource.h>
#include <errno.h>
#include <stdlib.h>
]],[[
struct rlimit rl_zero;
int r;
rl_zero.rlim_cur = rl_zero.rlim_max = 0;
r = setrlimit(RLIMIT_NOFILE, &rl_zero);
exit (r == -1 ? 1 : 0);
]])],
[AC_MSG_RESULT([yes])
rlimit_nofile_zero_works=yes],
[AC_MSG_RESULT([no])
rlimit_nofile_zero_works=no],
[AC_MSG_WARN([cross compiling: assuming yes])
rlimit_nofile_zero_works=yes]
-)
+ )
-AC_MSG_CHECKING([if setrlimit RLIMIT_FSIZE works])
-AC_RUN_IFELSE(
+ AC_MSG_CHECKING([if setrlimit RLIMIT_FSIZE works])
+ AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/resource.h>
#include <stdlib.h>
]],[[
struct rlimit rl_zero;
rl_zero.rlim_cur = rl_zero.rlim_max = 0;
exit(setrlimit(RLIMIT_FSIZE, &rl_zero) != 0);
]])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_DEFINE(SANDBOX_SKIP_RLIMIT_FSIZE, 1,
[setrlimit RLIMIT_FSIZE works])],
[AC_MSG_WARN([cross compiling: assuming yes])]
-)
+ )
+fi
if test "x$sandbox_arg" = "xpledge" || \
( test -z "$sandbox_arg" && test "x$ac_cv_func_pledge" = "xyes" ) ; then
test "x$ac_cv_func_pledge" != "xyes" && \
AC_MSG_ERROR([pledge sandbox requires pledge(2) support])
SANDBOX_STYLE="pledge"
AC_DEFINE([SANDBOX_PLEDGE], [1], [Sandbox using pledge(2)])
elif test "x$sandbox_arg" = "xsystrace" || \
( test -z "$sandbox_arg" && test "x$have_systr_policy_kill" = "x1" ) ; then
test "x$have_systr_policy_kill" != "x1" && \
AC_MSG_ERROR([systrace sandbox requires systrace headers and SYSTR_POLICY_KILL support])
SANDBOX_STYLE="systrace"
AC_DEFINE([SANDBOX_SYSTRACE], [1], [Sandbox using systrace(4)])
elif test "x$sandbox_arg" = "xdarwin" || \
( test -z "$sandbox_arg" && test "x$ac_cv_func_sandbox_init" = "xyes" && \
test "x$ac_cv_header_sandbox_h" = "xyes") ; then
test "x$ac_cv_func_sandbox_init" != "xyes" -o \
"x$ac_cv_header_sandbox_h" != "xyes" && \
AC_MSG_ERROR([Darwin seatbelt sandbox requires sandbox.h and sandbox_init function])
SANDBOX_STYLE="darwin"
AC_DEFINE([SANDBOX_DARWIN], [1], [Sandbox using Darwin sandbox_init(3)])
elif test "x$sandbox_arg" = "xseccomp_filter" || \
( test -z "$sandbox_arg" && \
test "x$have_seccomp_filter" = "x1" && \
test "x$ac_cv_header_elf_h" = "xyes" && \
test "x$ac_cv_header_linux_audit_h" = "xyes" && \
test "x$ac_cv_header_linux_filter_h" = "xyes" && \
test "x$seccomp_audit_arch" != "x" && \
test "x$have_linux_no_new_privs" = "x1" && \
test "x$ac_cv_func_prctl" = "xyes" ) ; then
test "x$seccomp_audit_arch" = "x" && \
AC_MSG_ERROR([seccomp_filter sandbox not supported on $host])
test "x$have_linux_no_new_privs" != "x1" && \
AC_MSG_ERROR([seccomp_filter sandbox requires PR_SET_NO_NEW_PRIVS])
test "x$have_seccomp_filter" != "x1" && \
AC_MSG_ERROR([seccomp_filter sandbox requires seccomp headers])
test "x$ac_cv_func_prctl" != "xyes" && \
AC_MSG_ERROR([seccomp_filter sandbox requires prctl function])
SANDBOX_STYLE="seccomp_filter"
AC_DEFINE([SANDBOX_SECCOMP_FILTER], [1], [Sandbox using seccomp filter])
elif test "x$sandbox_arg" = "xcapsicum" || \
( test -z "$sandbox_arg" && \
test "x$disable_capsicum" != "xyes" && \
test "x$ac_cv_header_sys_capsicum_h" = "xyes" && \
test "x$ac_cv_func_cap_rights_limit" = "xyes") ; then
test "x$ac_cv_header_sys_capsicum_h" != "xyes" && \
AC_MSG_ERROR([capsicum sandbox requires sys/capsicum.h header])
test "x$ac_cv_func_cap_rights_limit" != "xyes" && \
AC_MSG_ERROR([capsicum sandbox requires cap_rights_limit function])
SANDBOX_STYLE="capsicum"
AC_DEFINE([SANDBOX_CAPSICUM], [1], [Sandbox using capsicum])
elif test "x$sandbox_arg" = "xrlimit" || \
( test -z "$sandbox_arg" && test "x$ac_cv_func_setrlimit" = "xyes" && \
test "x$select_works_with_rlimit" = "xyes" && \
test "x$rlimit_nofile_zero_works" = "xyes" ) ; then
test "x$ac_cv_func_setrlimit" != "xyes" && \
AC_MSG_ERROR([rlimit sandbox requires setrlimit function])
test "x$select_works_with_rlimit" != "xyes" && \
AC_MSG_ERROR([rlimit sandbox requires select to work with rlimit])
SANDBOX_STYLE="rlimit"
AC_DEFINE([SANDBOX_RLIMIT], [1], [Sandbox using setrlimit(2)])
elif test "x$sandbox_arg" = "xsolaris" || \
( test -z "$sandbox_arg" && test "x$SOLARIS_PRIVS" = "xyes" ) ; then
SANDBOX_STYLE="solaris"
AC_DEFINE([SANDBOX_SOLARIS], [1], [Sandbox using Solaris/Illumos privileges])
elif test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \
test "x$sandbox_arg" = "xnone" || test "x$sandbox_arg" = "xnull" ; then
SANDBOX_STYLE="none"
AC_DEFINE([SANDBOX_NULL], [1], [no privsep sandboxing])
else
AC_MSG_ERROR([unsupported --with-sandbox])
fi
# Cheap hack to ensure NEWS-OS libraries are arranged right.
if test ! -z "$SONY" ; then
LIBS="$LIBS -liberty";
fi
# Check for long long datatypes
AC_CHECK_TYPES([long long, unsigned long long, long double])
# Check datatype sizes
AC_CHECK_SIZEOF([short int])
AC_CHECK_SIZEOF([int])
AC_CHECK_SIZEOF([long int])
AC_CHECK_SIZEOF([long long int])
AC_CHECK_SIZEOF([time_t], [], [[
#include <sys/types.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_TIME_H
# include <time.h>
#endif
]]
)
# Sanity check long long for some platforms (AIX)
if test "x$ac_cv_sizeof_long_long_int" = "x4" ; then
ac_cv_sizeof_long_long_int=0
fi
# compute LLONG_MIN and LLONG_MAX if we don't know them.
if test -z "$have_llong_max" && test -z "$have_long_long_max"; then
AC_MSG_CHECKING([for max value of long long])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdio.h>
#include <stdlib.h>
/* Why is this so damn hard? */
#ifdef __GNUC__
# undef __GNUC__
#endif
#define __USE_ISOC99
#include <limits.h>
#define DATA "conftest.llminmax"
#define my_abs(a) ((a) < 0 ? ((a) * -1) : (a))
/*
* printf in libc on some platforms (eg old Tru64) does not understand %lld so
* we do this the hard way.
*/
static int
fprint_ll(FILE *f, long long n)
{
unsigned int i;
int l[sizeof(long long) * 8];
if (n < 0)
if (fprintf(f, "-") < 0)
return -1;
for (i = 0; n != 0; i++) {
l[i] = my_abs(n % 10);
n /= 10;
}
do {
if (fprintf(f, "%d", l[--i]) < 0)
return -1;
} while (i != 0);
if (fprintf(f, " ") < 0)
return -1;
return 0;
}
]], [[
FILE *f;
long long i, llmin, llmax = 0;
if((f = fopen(DATA,"w")) == NULL)
exit(1);
#if defined(LLONG_MIN) && defined(LLONG_MAX)
fprintf(stderr, "Using system header for LLONG_MIN and LLONG_MAX\n");
llmin = LLONG_MIN;
llmax = LLONG_MAX;
#else
fprintf(stderr, "Calculating LLONG_MIN and LLONG_MAX\n");
/* This will work on one's complement and two's complement */
for (i = 1; i > llmax; i <<= 1, i++)
llmax = i;
llmin = llmax + 1LL; /* wrap */
#endif
/* Sanity check */
if (llmin + 1 < llmin || llmin - 1 < llmin || llmax + 1 > llmax
|| llmax - 1 > llmax || llmin == llmax || llmin == 0
|| llmax == 0 || llmax < LONG_MAX || llmin > LONG_MIN) {
fprintf(f, "unknown unknown\n");
exit(2);
}
if (fprint_ll(f, llmin) < 0)
exit(3);
if (fprint_ll(f, llmax) < 0)
exit(4);
if (fclose(f) < 0)
exit(5);
exit(0);
]])],
[
llong_min=`$AWK '{print $1}' conftest.llminmax`
llong_max=`$AWK '{print $2}' conftest.llminmax`
AC_MSG_RESULT([$llong_max])
AC_DEFINE_UNQUOTED([LLONG_MAX], [${llong_max}LL],
[max value of long long calculated by configure])
AC_MSG_CHECKING([for min value of long long])
AC_MSG_RESULT([$llong_min])
AC_DEFINE_UNQUOTED([LLONG_MIN], [${llong_min}LL],
[min value of long long calculated by configure])
],
[
AC_MSG_RESULT([not found])
],
[
AC_MSG_WARN([cross compiling: not checking])
]
)
fi
AC_CHECK_DECLS([UINT32_MAX], , , [[
#ifdef HAVE_SYS_LIMITS_H
# include <sys/limits.h>
#endif
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
]])
# More checks for data types
AC_CACHE_CHECK([for u_int type], ac_cv_have_u_int, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
[[ u_int a; a = 1;]])],
[ ac_cv_have_u_int="yes" ], [ ac_cv_have_u_int="no"
])
])
if test "x$ac_cv_have_u_int" = "xyes" ; then
AC_DEFINE([HAVE_U_INT], [1], [define if you have u_int data type])
have_u_int=1
fi
AC_CACHE_CHECK([for intXX_t types], ac_cv_have_intxx_t, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
[[ int8_t a; int16_t b; int32_t c; a = b = c = 1;]])],
[ ac_cv_have_intxx_t="yes" ], [ ac_cv_have_intxx_t="no"
])
])
if test "x$ac_cv_have_intxx_t" = "xyes" ; then
AC_DEFINE([HAVE_INTXX_T], [1], [define if you have intxx_t data type])
have_intxx_t=1
fi
if (test -z "$have_intxx_t" && \
test "x$ac_cv_header_stdint_h" = "xyes")
then
AC_MSG_CHECKING([for intXX_t types in stdint.h])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <stdint.h> ]],
[[ int8_t a; int16_t b; int32_t c; a = b = c = 1;]])],
[
AC_DEFINE([HAVE_INTXX_T])
AC_MSG_RESULT([yes])
], [ AC_MSG_RESULT([no])
])
fi
AC_CACHE_CHECK([for int64_t type], ac_cv_have_int64_t, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#include <sys/socket.h>
#ifdef HAVE_SYS_BITYPES_H
# include <sys/bitypes.h>
#endif
]], [[
int64_t a; a = 1;
]])],
[ ac_cv_have_int64_t="yes" ], [ ac_cv_have_int64_t="no"
])
])
if test "x$ac_cv_have_int64_t" = "xyes" ; then
AC_DEFINE([HAVE_INT64_T], [1], [define if you have int64_t data type])
fi
AC_CACHE_CHECK([for u_intXX_t types], ac_cv_have_u_intxx_t, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
[[ u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;]])],
[ ac_cv_have_u_intxx_t="yes" ], [ ac_cv_have_u_intxx_t="no"
])
])
if test "x$ac_cv_have_u_intxx_t" = "xyes" ; then
AC_DEFINE([HAVE_U_INTXX_T], [1], [define if you have u_intxx_t data type])
have_u_intxx_t=1
fi
if test -z "$have_u_intxx_t" ; then
AC_MSG_CHECKING([for u_intXX_t types in sys/socket.h])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/socket.h> ]],
[[ u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;]])],
[
AC_DEFINE([HAVE_U_INTXX_T])
AC_MSG_RESULT([yes])
], [ AC_MSG_RESULT([no])
])
fi
AC_CACHE_CHECK([for u_int64_t types], ac_cv_have_u_int64_t, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
[[ u_int64_t a; a = 1;]])],
[ ac_cv_have_u_int64_t="yes" ], [ ac_cv_have_u_int64_t="no"
])
])
if test "x$ac_cv_have_u_int64_t" = "xyes" ; then
AC_DEFINE([HAVE_U_INT64_T], [1], [define if you have u_int64_t data type])
have_u_int64_t=1
fi
if (test -z "$have_u_int64_t" && \
test "x$ac_cv_header_sys_bitypes_h" = "xyes")
then
AC_MSG_CHECKING([for u_int64_t type in sys/bitypes.h])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/bitypes.h> ]],
[[ u_int64_t a; a = 1]])],
[
AC_DEFINE([HAVE_U_INT64_T])
AC_MSG_RESULT([yes])
], [ AC_MSG_RESULT([no])
])
fi
if test -z "$have_u_intxx_t" ; then
AC_CACHE_CHECK([for uintXX_t types], ac_cv_have_uintxx_t, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
]], [[
uint8_t a;
uint16_t b;
uint32_t c;
a = b = c = 1;
]])],
[ ac_cv_have_uintxx_t="yes" ], [ ac_cv_have_uintxx_t="no"
])
])
if test "x$ac_cv_have_uintxx_t" = "xyes" ; then
AC_DEFINE([HAVE_UINTXX_T], [1],
[define if you have uintxx_t data type])
fi
fi
if (test -z "$have_uintxx_t" && \
test "x$ac_cv_header_stdint_h" = "xyes")
then
AC_MSG_CHECKING([for uintXX_t types in stdint.h])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <stdint.h> ]],
[[ uint8_t a; uint16_t b; uint32_t c; a = b = c = 1;]])],
[
AC_DEFINE([HAVE_UINTXX_T])
AC_MSG_RESULT([yes])
], [ AC_MSG_RESULT([no])
])
fi
if (test -z "$have_uintxx_t" && \
test "x$ac_cv_header_inttypes_h" = "xyes")
then
AC_MSG_CHECKING([for uintXX_t types in inttypes.h])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <inttypes.h> ]],
[[ uint8_t a; uint16_t b; uint32_t c; a = b = c = 1;]])],
[
AC_DEFINE([HAVE_UINTXX_T])
AC_MSG_RESULT([yes])
], [ AC_MSG_RESULT([no])
])
fi
if (test -z "$have_u_intxx_t" || test -z "$have_intxx_t" && \
test "x$ac_cv_header_sys_bitypes_h" = "xyes")
then
AC_MSG_CHECKING([for intXX_t and u_intXX_t types in sys/bitypes.h])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/bitypes.h>
]], [[
int8_t a; int16_t b; int32_t c;
u_int8_t e; u_int16_t f; u_int32_t g;
a = b = c = e = f = g = 1;
]])],
[
AC_DEFINE([HAVE_U_INTXX_T])
AC_DEFINE([HAVE_INTXX_T])
AC_MSG_RESULT([yes])
], [AC_MSG_RESULT([no])
])
fi
AC_CACHE_CHECK([for u_char], ac_cv_have_u_char, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
[[ u_char foo; foo = 125; ]])],
[ ac_cv_have_u_char="yes" ], [ ac_cv_have_u_char="no"
])
])
if test "x$ac_cv_have_u_char" = "xyes" ; then
AC_DEFINE([HAVE_U_CHAR], [1], [define if you have u_char data type])
fi
AC_CHECK_TYPES([intmax_t, uintmax_t], , , [
#include <sys/types.h>
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
])
TYPE_SOCKLEN_T
AC_CHECK_TYPES([sig_atomic_t, sighandler_t], , , [#include <signal.h>])
AC_CHECK_TYPES([fsblkcnt_t, fsfilcnt_t], , , [
#include <sys/types.h>
#ifdef HAVE_SYS_BITYPES_H
#include <sys/bitypes.h>
#endif
#ifdef HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#ifdef HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
])
AC_CHECK_MEMBERS([struct statfs.f_files, struct statfs.f_flags], [], [], [[
#include <sys/param.h>
#include <sys/types.h>
#ifdef HAVE_SYS_BITYPES_H
#include <sys/bitypes.h>
#endif
#ifdef HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#ifdef HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
]])
AC_CHECK_TYPES([in_addr_t, in_port_t], , ,
[#include <sys/types.h>
#include <netinet/in.h>])
AC_CACHE_CHECK([for size_t], ac_cv_have_size_t, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
[[ size_t foo; foo = 1235; ]])],
[ ac_cv_have_size_t="yes" ], [ ac_cv_have_size_t="no"
])
])
if test "x$ac_cv_have_size_t" = "xyes" ; then
AC_DEFINE([HAVE_SIZE_T], [1], [define if you have size_t data type])
fi
AC_CACHE_CHECK([for ssize_t], ac_cv_have_ssize_t, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
[[ ssize_t foo; foo = 1235; ]])],
[ ac_cv_have_ssize_t="yes" ], [ ac_cv_have_ssize_t="no"
])
])
if test "x$ac_cv_have_ssize_t" = "xyes" ; then
AC_DEFINE([HAVE_SSIZE_T], [1], [define if you have ssize_t data type])
fi
AC_CACHE_CHECK([for clock_t], ac_cv_have_clock_t, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <time.h> ]],
[[ clock_t foo; foo = 1235; ]])],
[ ac_cv_have_clock_t="yes" ], [ ac_cv_have_clock_t="no"
])
])
if test "x$ac_cv_have_clock_t" = "xyes" ; then
AC_DEFINE([HAVE_CLOCK_T], [1], [define if you have clock_t data type])
fi
AC_CACHE_CHECK([for sa_family_t], ac_cv_have_sa_family_t, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
]], [[ sa_family_t foo; foo = 1235; ]])],
[ ac_cv_have_sa_family_t="yes" ],
[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
]], [[ sa_family_t foo; foo = 1235; ]])],
[ ac_cv_have_sa_family_t="yes" ],
[ ac_cv_have_sa_family_t="no" ]
)
])
])
if test "x$ac_cv_have_sa_family_t" = "xyes" ; then
AC_DEFINE([HAVE_SA_FAMILY_T], [1],
[define if you have sa_family_t data type])
fi
AC_CACHE_CHECK([for pid_t], ac_cv_have_pid_t, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
[[ pid_t foo; foo = 1235; ]])],
[ ac_cv_have_pid_t="yes" ], [ ac_cv_have_pid_t="no"
])
])
if test "x$ac_cv_have_pid_t" = "xyes" ; then
AC_DEFINE([HAVE_PID_T], [1], [define if you have pid_t data type])
fi
AC_CACHE_CHECK([for mode_t], ac_cv_have_mode_t, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
[[ mode_t foo; foo = 1235; ]])],
[ ac_cv_have_mode_t="yes" ], [ ac_cv_have_mode_t="no"
])
])
if test "x$ac_cv_have_mode_t" = "xyes" ; then
AC_DEFINE([HAVE_MODE_T], [1], [define if you have mode_t data type])
fi
AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
]], [[ struct sockaddr_storage s; ]])],
[ ac_cv_have_struct_sockaddr_storage="yes" ],
[ ac_cv_have_struct_sockaddr_storage="no"
])
])
if test "x$ac_cv_have_struct_sockaddr_storage" = "xyes" ; then
AC_DEFINE([HAVE_STRUCT_SOCKADDR_STORAGE], [1],
[define if you have struct sockaddr_storage data type])
fi
AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <netinet/in.h>
]], [[ struct sockaddr_in6 s; s.sin6_family = 0; ]])],
[ ac_cv_have_struct_sockaddr_in6="yes" ],
[ ac_cv_have_struct_sockaddr_in6="no"
])
])
if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then
AC_DEFINE([HAVE_STRUCT_SOCKADDR_IN6], [1],
[define if you have struct sockaddr_in6 data type])
fi
AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <netinet/in.h>
]], [[ struct in6_addr s; s.s6_addr[0] = 0; ]])],
[ ac_cv_have_struct_in6_addr="yes" ],
[ ac_cv_have_struct_in6_addr="no"
])
])
if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then
AC_DEFINE([HAVE_STRUCT_IN6_ADDR], [1],
[define if you have struct in6_addr data type])
dnl Now check for sin6_scope_id
AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_scope_id], , ,
[
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <netinet/in.h>
])
fi
AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
]], [[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ]])],
[ ac_cv_have_struct_addrinfo="yes" ],
[ ac_cv_have_struct_addrinfo="no"
])
])
if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then
AC_DEFINE([HAVE_STRUCT_ADDRINFO], [1],
[define if you have struct addrinfo data type])
fi
AC_CACHE_CHECK([for struct timeval], ac_cv_have_struct_timeval, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/time.h> ]],
[[ struct timeval tv; tv.tv_sec = 1;]])],
[ ac_cv_have_struct_timeval="yes" ],
[ ac_cv_have_struct_timeval="no"
])
])
if test "x$ac_cv_have_struct_timeval" = "xyes" ; then
AC_DEFINE([HAVE_STRUCT_TIMEVAL], [1], [define if you have struct timeval])
have_struct_timeval=1
fi
AC_CACHE_CHECK([for struct timespec], ac_cv_have_struct_timespec, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_TIME_H
# include <time.h>
#endif
]],
[[ struct timespec ts; ts.tv_sec = 1;]])],
[ ac_cv_have_struct_timespec="yes" ],
[ ac_cv_have_struct_timespec="no"
])
])
if test "x$ac_cv_have_struct_timespec" = "xyes" ; then
AC_DEFINE([HAVE_STRUCT_TIMESPEC], [1], [define if you have struct timespec])
have_struct_timespec=1
fi
# We need int64_t or else certain parts of the compile will fail.
if test "x$ac_cv_have_int64_t" = "xno" && \
test "x$ac_cv_sizeof_long_int" != "x8" && \
test "x$ac_cv_sizeof_long_long_int" = "x0" ; then
echo "OpenSSH requires int64_t support. Contact your vendor or install"
echo "an alternative compiler (I.E., GCC) before continuing."
echo ""
exit 1;
else
dnl test snprintf (broken on SCO w/gcc)
AC_RUN_IFELSE(
[AC_LANG_SOURCE([[
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_SNPRINTF
main()
{
char buf[50];
char expected_out[50];
int mazsize = 50 ;
#if (SIZEOF_LONG_INT == 8)
long int num = 0x7fffffffffffffff;
#else
long long num = 0x7fffffffffffffffll;
#endif
strcpy(expected_out, "9223372036854775807");
snprintf(buf, mazsize, "%lld", num);
if(strcmp(buf, expected_out) != 0)
exit(1);
exit(0);
}
#else
main() { exit(0); }
#endif
]])], [ true ], [ AC_DEFINE([BROKEN_SNPRINTF]) ],
AC_MSG_WARN([cross compiling: Assuming working snprintf()])
)
fi
dnl Checks for structure members
OSSH_CHECK_HEADER_FOR_FIELD([ut_host], [utmp.h], [HAVE_HOST_IN_UTMP])
OSSH_CHECK_HEADER_FOR_FIELD([ut_host], [utmpx.h], [HAVE_HOST_IN_UTMPX])
OSSH_CHECK_HEADER_FOR_FIELD([syslen], [utmpx.h], [HAVE_SYSLEN_IN_UTMPX])
OSSH_CHECK_HEADER_FOR_FIELD([ut_pid], [utmp.h], [HAVE_PID_IN_UTMP])
OSSH_CHECK_HEADER_FOR_FIELD([ut_type], [utmp.h], [HAVE_TYPE_IN_UTMP])
OSSH_CHECK_HEADER_FOR_FIELD([ut_type], [utmpx.h], [HAVE_TYPE_IN_UTMPX])
OSSH_CHECK_HEADER_FOR_FIELD([ut_tv], [utmp.h], [HAVE_TV_IN_UTMP])
OSSH_CHECK_HEADER_FOR_FIELD([ut_id], [utmp.h], [HAVE_ID_IN_UTMP])
OSSH_CHECK_HEADER_FOR_FIELD([ut_id], [utmpx.h], [HAVE_ID_IN_UTMPX])
OSSH_CHECK_HEADER_FOR_FIELD([ut_addr], [utmp.h], [HAVE_ADDR_IN_UTMP])
OSSH_CHECK_HEADER_FOR_FIELD([ut_addr], [utmpx.h], [HAVE_ADDR_IN_UTMPX])
OSSH_CHECK_HEADER_FOR_FIELD([ut_addr_v6], [utmp.h], [HAVE_ADDR_V6_IN_UTMP])
OSSH_CHECK_HEADER_FOR_FIELD([ut_addr_v6], [utmpx.h], [HAVE_ADDR_V6_IN_UTMPX])
OSSH_CHECK_HEADER_FOR_FIELD([ut_exit], [utmp.h], [HAVE_EXIT_IN_UTMP])
OSSH_CHECK_HEADER_FOR_FIELD([ut_time], [utmp.h], [HAVE_TIME_IN_UTMP])
OSSH_CHECK_HEADER_FOR_FIELD([ut_time], [utmpx.h], [HAVE_TIME_IN_UTMPX])
OSSH_CHECK_HEADER_FOR_FIELD([ut_tv], [utmpx.h], [HAVE_TV_IN_UTMPX])
OSSH_CHECK_HEADER_FOR_FIELD([ut_ss], [utmpx.h], [HAVE_SS_IN_UTMPX])
AC_CHECK_MEMBERS([struct stat.st_blksize])
AC_CHECK_MEMBERS([struct stat.st_mtim])
AC_CHECK_MEMBERS([struct stat.st_mtime])
AC_CHECK_MEMBERS([struct passwd.pw_gecos, struct passwd.pw_class,
struct passwd.pw_change, struct passwd.pw_expire],
[], [], [[
#include <sys/types.h>
#include <pwd.h>
]])
AC_CHECK_MEMBER([struct __res_state.retrans], [], [AC_DEFINE([__res_state], [state],
[Define if we don't have struct __res_state in resolv.h])],
[[
#include <stdio.h>
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
]])
AC_CACHE_CHECK([for ss_family field in struct sockaddr_storage],
ac_cv_have_ss_family_in_struct_ss, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
]], [[ struct sockaddr_storage s; s.ss_family = 1; ]])],
[ ac_cv_have_ss_family_in_struct_ss="yes" ],
[ ac_cv_have_ss_family_in_struct_ss="no" ])
])
if test "x$ac_cv_have_ss_family_in_struct_ss" = "xyes" ; then
AC_DEFINE([HAVE_SS_FAMILY_IN_SS], [1], [Fields in struct sockaddr_storage])
fi
AC_CACHE_CHECK([for __ss_family field in struct sockaddr_storage],
ac_cv_have___ss_family_in_struct_ss, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
]], [[ struct sockaddr_storage s; s.__ss_family = 1; ]])],
[ ac_cv_have___ss_family_in_struct_ss="yes" ],
[ ac_cv_have___ss_family_in_struct_ss="no"
])
])
if test "x$ac_cv_have___ss_family_in_struct_ss" = "xyes" ; then
AC_DEFINE([HAVE___SS_FAMILY_IN_SS], [1],
[Fields in struct sockaddr_storage])
fi
dnl make sure we're using the real structure members and not defines
AC_CACHE_CHECK([for msg_accrights field in struct msghdr],
ac_cv_have_accrights_in_msghdr, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <stdlib.h>
]], [[
#ifdef msg_accrights
#error "msg_accrights is a macro"
exit(1);
#endif
struct msghdr m;
m.msg_accrights = 0;
exit(0);
]])],
[ ac_cv_have_accrights_in_msghdr="yes" ],
[ ac_cv_have_accrights_in_msghdr="no" ]
)
])
if test "x$ac_cv_have_accrights_in_msghdr" = "xyes" ; then
AC_DEFINE([HAVE_ACCRIGHTS_IN_MSGHDR], [1],
[Define if your system uses access rights style
file descriptor passing])
fi
AC_MSG_CHECKING([if struct statvfs.f_fsid is integral type])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/param.h>
#include <sys/stat.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
]], [[ struct statvfs s; s.f_fsid = 0; ]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
AC_MSG_CHECKING([if fsid_t has member val])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/statvfs.h>
]], [[ fsid_t t; t.val[0] = 0; ]])],
[ AC_MSG_RESULT([yes])
AC_DEFINE([FSID_HAS_VAL], [1], [fsid_t has member val]) ],
[ AC_MSG_RESULT([no]) ])
AC_MSG_CHECKING([if f_fsid has member __val])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/statvfs.h>
]], [[ fsid_t t; t.__val[0] = 0; ]])],
[ AC_MSG_RESULT([yes])
AC_DEFINE([FSID_HAS___VAL], [1], [fsid_t has member __val]) ],
[ AC_MSG_RESULT([no]) ])
])
AC_CACHE_CHECK([for msg_control field in struct msghdr],
ac_cv_have_control_in_msghdr, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <stdlib.h>
]], [[
#ifdef msg_control
#error "msg_control is a macro"
exit(1);
#endif
struct msghdr m;
m.msg_control = 0;
exit(0);
]])],
[ ac_cv_have_control_in_msghdr="yes" ],
[ ac_cv_have_control_in_msghdr="no" ]
)
])
if test "x$ac_cv_have_control_in_msghdr" = "xyes" ; then
AC_DEFINE([HAVE_CONTROL_IN_MSGHDR], [1],
[Define if your system uses ancillary data style
file descriptor passing])
fi
AC_CACHE_CHECK([if libc defines __progname], ac_cv_libc_defines___progname, [
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <stdio.h> ]],
[[ extern char *__progname; printf("%s", __progname); ]])],
[ ac_cv_libc_defines___progname="yes" ],
[ ac_cv_libc_defines___progname="no"
])
])
if test "x$ac_cv_libc_defines___progname" = "xyes" ; then
AC_DEFINE([HAVE___PROGNAME], [1], [Define if libc defines __progname])
fi
AC_CACHE_CHECK([whether $CC implements __FUNCTION__], ac_cv_cc_implements___FUNCTION__, [
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <stdio.h> ]],
[[ printf("%s", __FUNCTION__); ]])],
[ ac_cv_cc_implements___FUNCTION__="yes" ],
[ ac_cv_cc_implements___FUNCTION__="no"
])
])
if test "x$ac_cv_cc_implements___FUNCTION__" = "xyes" ; then
AC_DEFINE([HAVE___FUNCTION__], [1],
[Define if compiler implements __FUNCTION__])
fi
AC_CACHE_CHECK([whether $CC implements __func__], ac_cv_cc_implements___func__, [
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <stdio.h> ]],
[[ printf("%s", __func__); ]])],
[ ac_cv_cc_implements___func__="yes" ],
[ ac_cv_cc_implements___func__="no"
])
])
if test "x$ac_cv_cc_implements___func__" = "xyes" ; then
AC_DEFINE([HAVE___func__], [1], [Define if compiler implements __func__])
fi
AC_CACHE_CHECK([whether va_copy exists], ac_cv_have_va_copy, [
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <stdarg.h>
va_list x,y;
]], [[ va_copy(x,y); ]])],
[ ac_cv_have_va_copy="yes" ],
[ ac_cv_have_va_copy="no"
])
])
if test "x$ac_cv_have_va_copy" = "xyes" ; then
AC_DEFINE([HAVE_VA_COPY], [1], [Define if va_copy exists])
fi
AC_CACHE_CHECK([whether __va_copy exists], ac_cv_have___va_copy, [
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <stdarg.h>
va_list x,y;
]], [[ __va_copy(x,y); ]])],
[ ac_cv_have___va_copy="yes" ], [ ac_cv_have___va_copy="no"
])
])
if test "x$ac_cv_have___va_copy" = "xyes" ; then
AC_DEFINE([HAVE___VA_COPY], [1], [Define if __va_copy exists])
fi
AC_CACHE_CHECK([whether getopt has optreset support],
ac_cv_have_getopt_optreset, [
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <getopt.h> ]],
[[ extern int optreset; optreset = 0; ]])],
[ ac_cv_have_getopt_optreset="yes" ],
[ ac_cv_have_getopt_optreset="no"
])
])
if test "x$ac_cv_have_getopt_optreset" = "xyes" ; then
AC_DEFINE([HAVE_GETOPT_OPTRESET], [1],
[Define if your getopt(3) defines and uses optreset])
fi
AC_CACHE_CHECK([if libc defines sys_errlist], ac_cv_libc_defines_sys_errlist, [
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <stdio.h> ]],
[[ extern const char *const sys_errlist[]; printf("%s", sys_errlist[0]);]])],
[ ac_cv_libc_defines_sys_errlist="yes" ],
[ ac_cv_libc_defines_sys_errlist="no"
])
])
if test "x$ac_cv_libc_defines_sys_errlist" = "xyes" ; then
AC_DEFINE([HAVE_SYS_ERRLIST], [1],
[Define if your system defines sys_errlist[]])
fi
AC_CACHE_CHECK([if libc defines sys_nerr], ac_cv_libc_defines_sys_nerr, [
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <stdio.h> ]],
[[ extern int sys_nerr; printf("%i", sys_nerr);]])],
[ ac_cv_libc_defines_sys_nerr="yes" ],
[ ac_cv_libc_defines_sys_nerr="no"
])
])
if test "x$ac_cv_libc_defines_sys_nerr" = "xyes" ; then
AC_DEFINE([HAVE_SYS_NERR], [1], [Define if your system defines sys_nerr])
fi
# Check libraries needed by DNS fingerprint support
AC_SEARCH_LIBS([getrrsetbyname], [resolv],
[AC_DEFINE([HAVE_GETRRSETBYNAME], [1],
[Define if getrrsetbyname() exists])],
[
# Needed by our getrrsetbyname()
AC_SEARCH_LIBS([res_query], [resolv])
AC_SEARCH_LIBS([dn_expand], [resolv])
AC_MSG_CHECKING([if res_query will link])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
]], [[
res_query (0, 0, 0, 0, 0);
]])],
AC_MSG_RESULT([yes]),
[AC_MSG_RESULT([no])
saved_LIBS="$LIBS"
LIBS="$LIBS -lresolv"
AC_MSG_CHECKING([for res_query in -lresolv])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
]], [[
res_query (0, 0, 0, 0, 0);
]])],
[AC_MSG_RESULT([yes])],
[LIBS="$saved_LIBS"
AC_MSG_RESULT([no])])
])
AC_CHECK_FUNCS([_getshort _getlong])
AC_CHECK_DECLS([_getshort, _getlong], , ,
[#include <sys/types.h>
#include <arpa/nameser.h>])
AC_CHECK_MEMBER([HEADER.ad],
[AC_DEFINE([HAVE_HEADER_AD], [1],
[Define if HEADER.ad exists in arpa/nameser.h])], ,
[#include <arpa/nameser.h>])
])
AC_MSG_CHECKING([if struct __res_state _res is an extern])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <stdio.h>
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
extern struct __res_state _res;
]], [[
struct __res_state *volatile p = &_res; /* force resolution of _res */
return 0;
]],)],
[AC_MSG_RESULT([yes])
AC_DEFINE([HAVE__RES_EXTERN], [1],
[Define if you have struct __res_state _res as an extern])
],
[ AC_MSG_RESULT([no]) ]
)
# Check whether user wants SELinux support
SELINUX_MSG="no"
LIBSELINUX=""
AC_ARG_WITH([selinux],
[ --with-selinux Enable SELinux support],
[ if test "x$withval" != "xno" ; then
save_LIBS="$LIBS"
AC_DEFINE([WITH_SELINUX], [1],
[Define if you want SELinux support.])
SELINUX_MSG="yes"
AC_CHECK_HEADER([selinux/selinux.h], ,
AC_MSG_ERROR([SELinux support requires selinux.h header]))
AC_CHECK_LIB([selinux], [setexeccon],
[ LIBSELINUX="-lselinux"
LIBS="$LIBS -lselinux"
],
AC_MSG_ERROR([SELinux support requires libselinux library]))
AC_CHECK_FUNCS([getseuserbyname get_default_context_with_level])
LIBS="$save_LIBS $LIBSELINUX"
fi ]
)
AC_SUBST([SSHDLIBS])
# Check whether user wants Kerberos 5 support
KRB5_MSG="no"
AC_ARG_WITH([kerberos5],
[ --with-kerberos5=PATH Enable Kerberos 5 support],
[ if test "x$withval" != "xno" ; then
if test "x$withval" = "xyes" ; then
KRB5ROOT="/usr/local"
else
KRB5ROOT=${withval}
fi
AC_DEFINE([KRB5], [1], [Define if you want Kerberos 5 support])
KRB5_MSG="yes"
- AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no])
use_pkgconfig_for_krb5=
if test "x$PKGCONFIG" != "xno"; then
AC_MSG_CHECKING([if $PKGCONFIG knows about kerberos5])
if "$PKGCONFIG" krb5; then
AC_MSG_RESULT([yes])
use_pkgconfig_for_krb5=yes
else
AC_MSG_RESULT([no])
fi
fi
if test "x$use_pkgconfig_for_krb5" = "xyes"; then
K5CFLAGS=`$PKGCONFIG --cflags krb5`
K5LIBS=`$PKGCONFIG --libs krb5`
CPPFLAGS="$CPPFLAGS $K5CFLAGS"
AC_MSG_CHECKING([for gssapi support])
if "$PKGCONFIG" krb5-gssapi; then
AC_MSG_RESULT([yes])
AC_DEFINE([GSSAPI], [1],
[Define this if you want GSSAPI
support in the version 2 protocol])
GSSCFLAGS="`$PKGCONFIG --cflags krb5-gssapi`"
GSSLIBS="`$PKGCONFIG --libs krb5-gssapi`"
CPPFLAGS="$CPPFLAGS $GSSCFLAGS"
else
AC_MSG_RESULT([no])
fi
AC_MSG_CHECKING([whether we are using Heimdal])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <krb5.h>
]], [[ char *tmp = heimdal_version; ]])],
[ AC_MSG_RESULT([yes])
AC_DEFINE([HEIMDAL], [1],
[Define this if you are using the Heimdal
version of Kerberos V5]) ],
[AC_MSG_RESULT([no])
])
else
AC_PATH_TOOL([KRB5CONF], [krb5-config],
[$KRB5ROOT/bin/krb5-config],
[$KRB5ROOT/bin:$PATH])
if test -x $KRB5CONF ; then
K5CFLAGS="`$KRB5CONF --cflags`"
K5LIBS="`$KRB5CONF --libs`"
CPPFLAGS="$CPPFLAGS $K5CFLAGS"
AC_MSG_CHECKING([for gssapi support])
if $KRB5CONF | grep gssapi >/dev/null ; then
AC_MSG_RESULT([yes])
AC_DEFINE([GSSAPI], [1],
[Define this if you want GSSAPI
support in the version 2 protocol])
GSSCFLAGS="`$KRB5CONF --cflags gssapi`"
GSSLIBS="`$KRB5CONF --libs gssapi`"
CPPFLAGS="$CPPFLAGS $GSSCFLAGS"
else
AC_MSG_RESULT([no])
fi
AC_MSG_CHECKING([whether we are using Heimdal])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <krb5.h>
]], [[ char *tmp = heimdal_version; ]])],
[ AC_MSG_RESULT([yes])
AC_DEFINE([HEIMDAL], [1],
[Define this if you are using the Heimdal
version of Kerberos V5]) ],
[AC_MSG_RESULT([no])
])
else
CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include"
LDFLAGS="$LDFLAGS -L${KRB5ROOT}/lib"
AC_MSG_CHECKING([whether we are using Heimdal])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <krb5.h>
]], [[ char *tmp = heimdal_version; ]])],
[ AC_MSG_RESULT([yes])
AC_DEFINE([HEIMDAL])
K5LIBS="-lkrb5"
K5LIBS="$K5LIBS -lcom_err -lasn1"
AC_CHECK_LIB([roken], [net_write],
[K5LIBS="$K5LIBS -lroken"])
AC_CHECK_LIB([des], [des_cbc_encrypt],
[K5LIBS="$K5LIBS -ldes"])
], [ AC_MSG_RESULT([no])
K5LIBS="-lkrb5 -lk5crypto -lcom_err"
])
AC_SEARCH_LIBS([dn_expand], [resolv])
AC_CHECK_LIB([gssapi_krb5], [gss_init_sec_context],
[ AC_DEFINE([GSSAPI])
GSSLIBS="-lgssapi_krb5" ],
[ AC_CHECK_LIB([gssapi], [gss_init_sec_context],
[ AC_DEFINE([GSSAPI])
GSSLIBS="-lgssapi" ],
[ AC_CHECK_LIB([gss], [gss_init_sec_context],
[ AC_DEFINE([GSSAPI])
GSSLIBS="-lgss" ],
AC_MSG_WARN([Cannot find any suitable gss-api library - build may fail]))
])
])
AC_CHECK_HEADER([gssapi.h], ,
[ unset ac_cv_header_gssapi_h
CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi"
AC_CHECK_HEADERS([gssapi.h], ,
AC_MSG_WARN([Cannot find any suitable gss-api header - build may fail])
)
]
)
oldCPP="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi"
AC_CHECK_HEADER([gssapi_krb5.h], ,
[ CPPFLAGS="$oldCPP" ])
fi
fi
if test -n "${rpath_opt}" ; then
LDFLAGS="$LDFLAGS ${rpath_opt}${KRB5ROOT}/lib"
fi
if test ! -z "$blibpath" ; then
blibpath="$blibpath:${KRB5ROOT}/lib"
fi
AC_CHECK_HEADERS([gssapi.h gssapi/gssapi.h])
AC_CHECK_HEADERS([gssapi_krb5.h gssapi/gssapi_krb5.h])
AC_CHECK_HEADERS([gssapi_generic.h gssapi/gssapi_generic.h])
AC_SEARCH_LIBS([k_hasafs], [kafs], [AC_DEFINE([USE_AFS], [1],
[Define this if you want to use libkafs' AFS support])])
AC_CHECK_DECLS([GSS_C_NT_HOSTBASED_SERVICE], [], [], [[
#ifdef HAVE_GSSAPI_H
# include <gssapi.h>
#elif defined(HAVE_GSSAPI_GSSAPI_H)
# include <gssapi/gssapi.h>
#endif
#ifdef HAVE_GSSAPI_GENERIC_H
# include <gssapi_generic.h>
#elif defined(HAVE_GSSAPI_GSSAPI_GENERIC_H)
# include <gssapi/gssapi_generic.h>
#endif
]])
saved_LIBS="$LIBS"
LIBS="$LIBS $K5LIBS"
AC_CHECK_FUNCS([krb5_cc_new_unique krb5_get_error_message krb5_free_error_message])
LIBS="$saved_LIBS"
fi
]
)
AC_SUBST([GSSLIBS])
AC_SUBST([K5LIBS])
+AC_SUBST([CHANNELLIBS])
# Looking for programs, paths and files
PRIVSEP_PATH=/var/empty
AC_ARG_WITH([privsep-path],
[ --with-privsep-path=xxx Path for privilege separation chroot (default=/var/empty)],
[
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
PRIVSEP_PATH=$withval
fi
]
)
AC_SUBST([PRIVSEP_PATH])
AC_ARG_WITH([xauth],
[ --with-xauth=PATH Specify path to xauth program ],
[
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
xauth_path=$withval
fi
],
[
TestPath="$PATH"
TestPath="${TestPath}${PATH_SEPARATOR}/usr/X/bin"
TestPath="${TestPath}${PATH_SEPARATOR}/usr/bin/X11"
TestPath="${TestPath}${PATH_SEPARATOR}/usr/X11R6/bin"
TestPath="${TestPath}${PATH_SEPARATOR}/usr/openwin/bin"
AC_PATH_PROG([xauth_path], [xauth], , [$TestPath])
if (test ! -z "$xauth_path" && test -x "/usr/openwin/bin/xauth") ; then
xauth_path="/usr/openwin/bin/xauth"
fi
]
)
STRIP_OPT=-s
AC_ARG_ENABLE([strip],
[ --disable-strip Disable calling strip(1) on install],
[
if test "x$enableval" = "xno" ; then
STRIP_OPT=
fi
]
)
AC_SUBST([STRIP_OPT])
if test -z "$xauth_path" ; then
XAUTH_PATH="undefined"
AC_SUBST([XAUTH_PATH])
else
AC_DEFINE_UNQUOTED([XAUTH_PATH], ["$xauth_path"],
[Define if xauth is found in your path])
XAUTH_PATH=$xauth_path
AC_SUBST([XAUTH_PATH])
fi
dnl # --with-maildir=/path/to/mail gets top priority.
dnl # if maildir is set in the platform case statement above we use that.
dnl # Otherwise we run a program to get the dir from system headers.
dnl # We first look for _PATH_MAILDIR then MAILDIR then _PATH_MAIL
dnl # If we find _PATH_MAILDIR we do nothing because that is what
dnl # session.c expects anyway. Otherwise we set to the value found
dnl # stripping any trailing slash. If for some strage reason our program
dnl # does not find what it needs, we default to /var/spool/mail.
# Check for mail directory
AC_ARG_WITH([maildir],
[ --with-maildir=/path/to/mail Specify your system mail directory],
[
if test "X$withval" != X && test "x$withval" != xno && \
test "x${withval}" != xyes; then
AC_DEFINE_UNQUOTED([MAIL_DIRECTORY], ["$withval"],
[Set this to your mail directory if you do not have _PATH_MAILDIR])
fi
],[
if test "X$maildir" != "X"; then
AC_DEFINE_UNQUOTED([MAIL_DIRECTORY], ["$maildir"])
else
AC_MSG_CHECKING([Discovering system mail directory])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#ifdef HAVE_MAILLOCK_H
#include <maillock.h>
#endif
#define DATA "conftest.maildir"
]], [[
FILE *fd;
int rc;
fd = fopen(DATA,"w");
if(fd == NULL)
exit(1);
#if defined (_PATH_MAILDIR)
if ((rc = fprintf(fd ,"_PATH_MAILDIR:%s\n", _PATH_MAILDIR)) <0)
exit(1);
#elif defined (MAILDIR)
if ((rc = fprintf(fd ,"MAILDIR:%s\n", MAILDIR)) <0)
exit(1);
#elif defined (_PATH_MAIL)
if ((rc = fprintf(fd ,"_PATH_MAIL:%s\n", _PATH_MAIL)) <0)
exit(1);
#else
exit (2);
#endif
exit(0);
]])],
[
maildir_what=`awk -F: '{print $1}' conftest.maildir`
maildir=`awk -F: '{print $2}' conftest.maildir \
| sed 's|/$||'`
AC_MSG_RESULT([Using: $maildir from $maildir_what])
if test "x$maildir_what" != "x_PATH_MAILDIR"; then
AC_DEFINE_UNQUOTED([MAIL_DIRECTORY], ["$maildir"])
fi
],
[
if test "X$ac_status" = "X2";then
# our test program didn't find it. Default to /var/spool/mail
AC_MSG_RESULT([Using: default value of /var/spool/mail])
AC_DEFINE_UNQUOTED([MAIL_DIRECTORY], ["/var/spool/mail"])
else
AC_MSG_RESULT([*** not found ***])
fi
],
[
AC_MSG_WARN([cross compiling: use --with-maildir=/path/to/mail])
]
)
fi
]
) # maildir
if test ! -z "$cross_compiling" && test "x$cross_compiling" = "xyes"; then
AC_MSG_WARN([cross compiling: Disabling /dev/ptmx test])
disable_ptmx_check=yes
fi
if test -z "$no_dev_ptmx" ; then
if test "x$disable_ptmx_check" != "xyes" ; then
AC_CHECK_FILE(["/dev/ptmx"],
[
AC_DEFINE_UNQUOTED([HAVE_DEV_PTMX], [1],
[Define if you have /dev/ptmx])
have_dev_ptmx=1
]
)
fi
fi
if test ! -z "$cross_compiling" && test "x$cross_compiling" != "xyes"; then
AC_CHECK_FILE(["/dev/ptc"],
[
AC_DEFINE_UNQUOTED([HAVE_DEV_PTS_AND_PTC], [1],
[Define if you have /dev/ptc])
have_dev_ptc=1
]
)
else
AC_MSG_WARN([cross compiling: Disabling /dev/ptc test])
fi
# Options from here on. Some of these are preset by platform above
AC_ARG_WITH([mantype],
[ --with-mantype=man|cat|doc Set man page type],
[
case "$withval" in
man|cat|doc)
MANTYPE=$withval
;;
*)
AC_MSG_ERROR([invalid man type: $withval])
;;
esac
]
)
if test -z "$MANTYPE"; then
if ${MANDOC} ${srcdir}/ssh.1 >/dev/null 2>&1; then
MANTYPE=doc
elif ${NROFF} -mdoc ${srcdir}/ssh.1 >/dev/null 2>&1; then
MANTYPE=doc
elif ${NROFF} -man ${srcdir}/ssh.1 >/dev/null 2>&1; then
MANTYPE=man
else
MANTYPE=cat
fi
fi
AC_SUBST([MANTYPE])
if test "$MANTYPE" = "doc"; then
mansubdir=man;
else
mansubdir=$MANTYPE;
fi
AC_SUBST([mansubdir])
# Whether to disable shadow password support
AC_ARG_WITH([shadow],
[ --without-shadow Disable shadow password support],
[
if test "x$withval" = "xno" ; then
AC_DEFINE([DISABLE_SHADOW])
disable_shadow=yes
fi
]
)
if test -z "$disable_shadow" ; then
AC_MSG_CHECKING([if the systems has expire shadow information])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <shadow.h>
struct spwd sp;
]], [[ sp.sp_expire = sp.sp_lstchg = sp.sp_inact = 0; ]])],
[ sp_expire_available=yes ], [
])
if test "x$sp_expire_available" = "xyes" ; then
AC_MSG_RESULT([yes])
AC_DEFINE([HAS_SHADOW_EXPIRE], [1],
[Define if you want to use shadow password expire field])
else
AC_MSG_RESULT([no])
fi
fi
# Use ip address instead of hostname in $DISPLAY
if test ! -z "$IPADDR_IN_DISPLAY" ; then
DISPLAY_HACK_MSG="yes"
AC_DEFINE([IPADDR_IN_DISPLAY], [1],
[Define if you need to use IP address
instead of hostname in $DISPLAY])
else
DISPLAY_HACK_MSG="no"
AC_ARG_WITH([ipaddr-display],
[ --with-ipaddr-display Use ip address instead of hostname in $DISPLAY],
[
if test "x$withval" != "xno" ; then
AC_DEFINE([IPADDR_IN_DISPLAY])
DISPLAY_HACK_MSG="yes"
fi
]
)
fi
# check for /etc/default/login and use it if present.
AC_ARG_ENABLE([etc-default-login],
[ --disable-etc-default-login Disable using PATH from /etc/default/login [no]],
[ if test "x$enableval" = "xno"; then
AC_MSG_NOTICE([/etc/default/login handling disabled])
etc_default_login=no
else
etc_default_login=yes
fi ],
[ if test ! -z "$cross_compiling" && test "x$cross_compiling" = "xyes";
then
AC_MSG_WARN([cross compiling: not checking /etc/default/login])
etc_default_login=no
else
etc_default_login=yes
fi ]
)
if test "x$etc_default_login" != "xno"; then
AC_CHECK_FILE(["/etc/default/login"],
[ external_path_file=/etc/default/login ])
if test "x$external_path_file" = "x/etc/default/login"; then
AC_DEFINE([HAVE_ETC_DEFAULT_LOGIN], [1],
[Define if your system has /etc/default/login])
fi
fi
dnl BSD systems use /etc/login.conf so --with-default-path= has no effect
if test $ac_cv_func_login_getcapbool = "yes" && \
test $ac_cv_header_login_cap_h = "yes" ; then
external_path_file=/etc/login.conf
fi
# Whether to mess with the default path
SERVER_PATH_MSG="(default)"
AC_ARG_WITH([default-path],
[ --with-default-path= Specify default $PATH environment for server],
[
if test "x$external_path_file" = "x/etc/login.conf" ; then
AC_MSG_WARN([
--with-default-path=PATH has no effect on this system.
Edit /etc/login.conf instead.])
elif test "x$withval" != "xno" ; then
if test ! -z "$external_path_file" ; then
AC_MSG_WARN([
--with-default-path=PATH will only be used if PATH is not defined in
$external_path_file .])
fi
user_path="$withval"
SERVER_PATH_MSG="$withval"
fi
],
[ if test "x$external_path_file" = "x/etc/login.conf" ; then
AC_MSG_WARN([Make sure the path to scp is in /etc/login.conf])
else
if test ! -z "$external_path_file" ; then
AC_MSG_WARN([
If PATH is defined in $external_path_file, ensure the path to scp is included,
otherwise scp will not work.])
fi
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
/* find out what STDPATH is */
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#ifndef _PATH_STDPATH
# ifdef _PATH_USERPATH /* Irix */
# define _PATH_STDPATH _PATH_USERPATH
# else
# define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin"
# endif
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define DATA "conftest.stdpath"
]], [[
FILE *fd;
int rc;
fd = fopen(DATA,"w");
if(fd == NULL)
exit(1);
if ((rc = fprintf(fd,"%s", _PATH_STDPATH)) < 0)
exit(1);
exit(0);
]])],
[ user_path=`cat conftest.stdpath` ],
[ user_path="/usr/bin:/bin:/usr/sbin:/sbin" ],
[ user_path="/usr/bin:/bin:/usr/sbin:/sbin" ]
)
# make sure $bindir is in USER_PATH so scp will work
t_bindir="${bindir}"
while echo "${t_bindir}" | egrep '\$\{|NONE/' >/dev/null 2>&1; do
t_bindir=`eval echo ${t_bindir}`
case $t_bindir in
NONE/*) t_bindir=`echo $t_bindir | sed "s~NONE~$prefix~"` ;;
esac
case $t_bindir in
NONE/*) t_bindir=`echo $t_bindir | sed "s~NONE~$ac_default_prefix~"` ;;
esac
done
echo $user_path | grep ":$t_bindir" > /dev/null 2>&1
if test $? -ne 0 ; then
echo $user_path | grep "^$t_bindir" > /dev/null 2>&1
if test $? -ne 0 ; then
user_path=$user_path:$t_bindir
AC_MSG_RESULT([Adding $t_bindir to USER_PATH so scp will work])
fi
fi
fi ]
)
if test "x$external_path_file" != "x/etc/login.conf" ; then
AC_DEFINE_UNQUOTED([USER_PATH], ["$user_path"], [Specify default $PATH])
AC_SUBST([user_path])
fi
# Set superuser path separately to user path
AC_ARG_WITH([superuser-path],
[ --with-superuser-path= Specify different path for super-user],
[
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
AC_DEFINE_UNQUOTED([SUPERUSER_PATH], ["$withval"],
[Define if you want a different $PATH
for the superuser])
superuser_path=$withval
fi
]
)
AC_MSG_CHECKING([if we need to convert IPv4 in IPv6-mapped addresses])
IPV4_IN6_HACK_MSG="no"
AC_ARG_WITH(4in6,
[ --with-4in6 Check for and convert IPv4 in IPv6 mapped addresses],
[
if test "x$withval" != "xno" ; then
AC_MSG_RESULT([yes])
AC_DEFINE([IPV4_IN_IPV6], [1],
[Detect IPv4 in IPv6 mapped addresses
and treat as IPv4])
IPV4_IN6_HACK_MSG="yes"
else
AC_MSG_RESULT([no])
fi
], [
if test "x$inet6_default_4in6" = "xyes"; then
AC_MSG_RESULT([yes (default)])
AC_DEFINE([IPV4_IN_IPV6])
IPV4_IN6_HACK_MSG="yes"
else
AC_MSG_RESULT([no (default)])
fi
]
)
# Whether to enable BSD auth support
BSD_AUTH_MSG=no
AC_ARG_WITH([bsd-auth],
[ --with-bsd-auth Enable BSD auth support],
[
if test "x$withval" != "xno" ; then
AC_DEFINE([BSD_AUTH], [1],
[Define if you have BSD auth support])
BSD_AUTH_MSG=yes
fi
]
)
# Where to place sshd.pid
piddir=/var/run
# make sure the directory exists
if test ! -d $piddir ; then
piddir=`eval echo ${sysconfdir}`
case $piddir in
NONE/*) piddir=`echo $piddir | sed "s~NONE~$ac_default_prefix~"` ;;
esac
fi
AC_ARG_WITH([pid-dir],
[ --with-pid-dir=PATH Specify location of sshd.pid file],
[
if test -n "$withval" && test "x$withval" != "xno" && \
test "x${withval}" != "xyes"; then
piddir=$withval
if test ! -d $piddir ; then
AC_MSG_WARN([** no $piddir directory on this system **])
fi
fi
]
)
AC_DEFINE_UNQUOTED([_PATH_SSH_PIDDIR], ["$piddir"],
[Specify location of ssh.pid])
AC_SUBST([piddir])
dnl allow user to disable some login recording features
AC_ARG_ENABLE([lastlog],
[ --disable-lastlog disable use of lastlog even if detected [no]],
[
if test "x$enableval" = "xno" ; then
AC_DEFINE([DISABLE_LASTLOG])
fi
]
)
AC_ARG_ENABLE([utmp],
[ --disable-utmp disable use of utmp even if detected [no]],
[
if test "x$enableval" = "xno" ; then
AC_DEFINE([DISABLE_UTMP])
fi
]
)
AC_ARG_ENABLE([utmpx],
[ --disable-utmpx disable use of utmpx even if detected [no]],
[
if test "x$enableval" = "xno" ; then
AC_DEFINE([DISABLE_UTMPX], [1],
[Define if you don't want to use utmpx])
fi
]
)
AC_ARG_ENABLE([wtmp],
[ --disable-wtmp disable use of wtmp even if detected [no]],
[
if test "x$enableval" = "xno" ; then
AC_DEFINE([DISABLE_WTMP])
fi
]
)
AC_ARG_ENABLE([wtmpx],
[ --disable-wtmpx disable use of wtmpx even if detected [no]],
[
if test "x$enableval" = "xno" ; then
AC_DEFINE([DISABLE_WTMPX], [1],
[Define if you don't want to use wtmpx])
fi
]
)
AC_ARG_ENABLE([libutil],
[ --disable-libutil disable use of libutil (login() etc.) [no]],
[
if test "x$enableval" = "xno" ; then
AC_DEFINE([DISABLE_LOGIN])
fi
]
)
AC_ARG_ENABLE([pututline],
[ --disable-pututline disable use of pututline() etc. ([uw]tmp) [no]],
[
if test "x$enableval" = "xno" ; then
AC_DEFINE([DISABLE_PUTUTLINE], [1],
[Define if you don't want to use pututline()
etc. to write [uw]tmp])
fi
]
)
AC_ARG_ENABLE([pututxline],
[ --disable-pututxline disable use of pututxline() etc. ([uw]tmpx) [no]],
[
if test "x$enableval" = "xno" ; then
AC_DEFINE([DISABLE_PUTUTXLINE], [1],
[Define if you don't want to use pututxline()
etc. to write [uw]tmpx])
fi
]
)
AC_ARG_WITH([lastlog],
[ --with-lastlog=FILE|DIR specify lastlog location [common locations]],
[
if test "x$withval" = "xno" ; then
AC_DEFINE([DISABLE_LASTLOG])
elif test -n "$withval" && test "x${withval}" != "xyes"; then
conf_lastlog_location=$withval
fi
]
)
dnl lastlog, [uw]tmpx? detection
dnl NOTE: set the paths in the platform section to avoid the
dnl need for command-line parameters
dnl lastlog and [uw]tmp are subject to a file search if all else fails
dnl lastlog detection
dnl NOTE: the code itself will detect if lastlog is a directory
AC_MSG_CHECKING([if your system defines LASTLOG_FILE])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_LASTLOG_H
# include <lastlog.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#ifdef HAVE_LOGIN_H
# include <login.h>
#endif
]], [[ char *lastlog = LASTLOG_FILE; ]])],
[ AC_MSG_RESULT([yes]) ],
[
AC_MSG_RESULT([no])
AC_MSG_CHECKING([if your system defines _PATH_LASTLOG])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_LASTLOG_H
# include <lastlog.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
]], [[ char *lastlog = _PATH_LASTLOG; ]])],
[ AC_MSG_RESULT([yes]) ],
[
AC_MSG_RESULT([no])
system_lastlog_path=no
])
])
if test -z "$conf_lastlog_location"; then
if test x"$system_lastlog_path" = x"no" ; then
for f in /var/log/lastlog /usr/adm/lastlog /var/adm/lastlog /etc/security/lastlog ; do
if (test -d "$f" || test -f "$f") ; then
conf_lastlog_location=$f
fi
done
if test -z "$conf_lastlog_location"; then
AC_MSG_WARN([** Cannot find lastlog **])
dnl Don't define DISABLE_LASTLOG - that means we don't try wtmp/wtmpx
fi
fi
fi
if test -n "$conf_lastlog_location"; then
AC_DEFINE_UNQUOTED([CONF_LASTLOG_FILE], ["$conf_lastlog_location"],
[Define if you want to specify the path to your lastlog file])
fi
dnl utmp detection
AC_MSG_CHECKING([if your system defines UTMP_FILE])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
]], [[ char *utmp = UTMP_FILE; ]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
system_utmp_path=no
])
if test -z "$conf_utmp_location"; then
if test x"$system_utmp_path" = x"no" ; then
for f in /etc/utmp /usr/adm/utmp /var/run/utmp; do
if test -f $f ; then
conf_utmp_location=$f
fi
done
if test -z "$conf_utmp_location"; then
AC_DEFINE([DISABLE_UTMP])
fi
fi
fi
if test -n "$conf_utmp_location"; then
AC_DEFINE_UNQUOTED([CONF_UTMP_FILE], ["$conf_utmp_location"],
[Define if you want to specify the path to your utmp file])
fi
dnl wtmp detection
AC_MSG_CHECKING([if your system defines WTMP_FILE])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
]], [[ char *wtmp = WTMP_FILE; ]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
system_wtmp_path=no
])
if test -z "$conf_wtmp_location"; then
if test x"$system_wtmp_path" = x"no" ; then
for f in /usr/adm/wtmp /var/log/wtmp; do
if test -f $f ; then
conf_wtmp_location=$f
fi
done
if test -z "$conf_wtmp_location"; then
AC_DEFINE([DISABLE_WTMP])
fi
fi
fi
if test -n "$conf_wtmp_location"; then
AC_DEFINE_UNQUOTED([CONF_WTMP_FILE], ["$conf_wtmp_location"],
[Define if you want to specify the path to your wtmp file])
fi
dnl wtmpx detection
AC_MSG_CHECKING([if your system defines WTMPX_FILE])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_UTMPX_H
#include <utmpx.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
]], [[ char *wtmpx = WTMPX_FILE; ]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
system_wtmpx_path=no
])
if test -z "$conf_wtmpx_location"; then
if test x"$system_wtmpx_path" = x"no" ; then
AC_DEFINE([DISABLE_WTMPX])
fi
else
AC_DEFINE_UNQUOTED([CONF_WTMPX_FILE], ["$conf_wtmpx_location"],
[Define if you want to specify the path to your wtmpx file])
fi
if test ! -z "$blibpath" ; then
LDFLAGS="$LDFLAGS $blibflags$blibpath"
AC_MSG_WARN([Please check and edit blibpath in LDFLAGS in Makefile])
fi
AC_CHECK_MEMBER([struct lastlog.ll_line], [], [
if test x$SKIP_DISABLE_LASTLOG_DEFINE != "xyes" ; then
AC_DEFINE([DISABLE_LASTLOG])
fi
], [
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_UTMP_H
#include <utmp.h>
#endif
#ifdef HAVE_UTMPX_H
#include <utmpx.h>
#endif
#ifdef HAVE_LASTLOG_H
#include <lastlog.h>
#endif
])
AC_CHECK_MEMBER([struct utmp.ut_line], [], [
AC_DEFINE([DISABLE_UTMP])
AC_DEFINE([DISABLE_WTMP])
], [
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_UTMP_H
#include <utmp.h>
#endif
#ifdef HAVE_UTMPX_H
#include <utmpx.h>
#endif
#ifdef HAVE_LASTLOG_H
#include <lastlog.h>
#endif
])
dnl Adding -Werror to CFLAGS early prevents configure tests from running.
dnl Add now.
CFLAGS="$CFLAGS $werror_flags"
if test "x$ac_cv_func_getaddrinfo" != "xyes" ; then
TEST_SSH_IPV6=no
else
TEST_SSH_IPV6=yes
fi
AC_CHECK_DECL([BROKEN_GETADDRINFO], [TEST_SSH_IPV6=no])
AC_SUBST([TEST_SSH_IPV6], [$TEST_SSH_IPV6])
AC_SUBST([TEST_SSH_UTF8], [$TEST_SSH_UTF8])
AC_SUBST([TEST_MALLOC_OPTIONS], [$TEST_MALLOC_OPTIONS])
AC_SUBST([UNSUPPORTED_ALGORITHMS], [$unsupported_algorithms])
AC_SUBST([DEPEND], [$(cat $srcdir/.depend)])
CFLAGS="${CFLAGS} ${CFLAGS_AFTER}"
LDFLAGS="${LDFLAGS} ${LDFLAGS_AFTER}"
# Make a copy of CFLAGS/LDFLAGS without PIE options.
LDFLAGS_NOPIE=`echo "$LDFLAGS" | sed 's/ -pie//'`
CFLAGS_NOPIE=`echo "$CFLAGS" | sed 's/ -fPIE//'`
AC_SUBST([LDFLAGS_NOPIE])
AC_SUBST([CFLAGS_NOPIE])
AC_EXEEXT
AC_CONFIG_FILES([Makefile buildpkg.sh opensshd.init openssh.xml \
openbsd-compat/Makefile openbsd-compat/regress/Makefile \
survey.sh])
AC_OUTPUT
# Print summary of options
# Someone please show me a better way :)
A=`eval echo ${prefix}` ; A=`eval echo ${A}`
B=`eval echo ${bindir}` ; B=`eval echo ${B}`
C=`eval echo ${sbindir}` ; C=`eval echo ${C}`
D=`eval echo ${sysconfdir}` ; D=`eval echo ${D}`
E=`eval echo ${libexecdir}/ssh-askpass` ; E=`eval echo ${E}`
F=`eval echo ${mandir}/${mansubdir}X` ; F=`eval echo ${F}`
G=`eval echo ${piddir}` ; G=`eval echo ${G}`
H=`eval echo ${PRIVSEP_PATH}` ; H=`eval echo ${H}`
I=`eval echo ${user_path}` ; I=`eval echo ${I}`
J=`eval echo ${superuser_path}` ; J=`eval echo ${J}`
echo ""
echo "OpenSSH has been configured with the following options:"
echo " User binaries: $B"
echo " System binaries: $C"
echo " Configuration files: $D"
echo " Askpass program: $E"
echo " Manual pages: $F"
echo " PID file: $G"
echo " Privilege separation chroot path: $H"
if test "x$external_path_file" = "x/etc/login.conf" ; then
echo " At runtime, sshd will use the path defined in $external_path_file"
echo " Make sure the path to scp is present, otherwise scp will not work"
else
echo " sshd default user PATH: $I"
if test ! -z "$external_path_file"; then
echo " (If PATH is set in $external_path_file it will be used instead. If"
echo " used, ensure the path to scp is present, otherwise scp will not work.)"
fi
fi
if test ! -z "$superuser_path" ; then
echo " sshd superuser user PATH: $J"
fi
echo " Manpage format: $MANTYPE"
echo " PAM support: $PAM_MSG"
echo " OSF SIA support: $SIA_MSG"
echo " KerberosV support: $KRB5_MSG"
echo " SELinux support: $SELINUX_MSG"
echo " libedit support: $LIBEDIT_MSG"
echo " libldns support: $LDNS_MSG"
echo " Solaris process contract support: $SPC_MSG"
echo " Solaris project support: $SP_MSG"
echo " Solaris privilege support: $SPP_MSG"
echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
echo " BSD Auth support: $BSD_AUTH_MSG"
echo " Random number source: $RAND_MSG"
echo " Privsep sandbox style: $SANDBOX_STYLE"
echo " PKCS#11 support: $enable_pkcs11"
echo " U2F/FIDO support: $enable_sk"
echo ""
echo " Host: ${host}"
echo " Compiler: ${CC}"
echo " Compiler flags: ${CFLAGS}"
echo "Preprocessor flags: ${CPPFLAGS}"
echo " Linker flags: ${LDFLAGS}"
echo " Libraries: ${LIBS}"
+if test ! -z "${CHANNELLIBS}"; then
+echo " +for channels: ${CHANNELLIBS}"
+fi
+if test ! -z "${LIBFIDO2}"; then
+echo " +for FIDO2: ${LIBFIDO2}"
+fi
if test ! -z "${SSHDLIBS}"; then
echo " +for sshd: ${SSHDLIBS}"
fi
echo ""
if test "x$MAKE_PACKAGE_SUPPORTED" = "xyes" ; then
echo "SVR4 style packages are supported with \"make package\""
echo ""
fi
if test "x$PAM_MSG" = "xyes" ; then
echo "PAM is enabled. You may need to install a PAM control file "
echo "for sshd, otherwise password authentication may fail. "
echo "Example PAM control files can be found in the contrib/ "
echo "subdirectory"
echo ""
fi
if test ! -z "$NO_PEERCHECK" ; then
echo "WARNING: the operating system that you are using does not"
echo "appear to support getpeereid(), getpeerucred() or the"
echo "SO_PEERCRED getsockopt() option. These facilities are used to"
echo "enforce security checks to prevent unauthorised connections to"
echo "ssh-agent. Their absence increases the risk that a malicious"
echo "user can connect to your agent."
echo ""
fi
if test "$AUDIT_MODULE" = "bsm" ; then
echo "WARNING: BSM audit support is currently considered EXPERIMENTAL."
echo "See the Solaris section in README.platform for details."
fi
diff --git a/contrib/redhat/openssh.spec b/contrib/redhat/openssh.spec
index b8ba8bae0469..124afccd1dcb 100644
--- a/contrib/redhat/openssh.spec
+++ b/contrib/redhat/openssh.spec
@@ -1,850 +1,850 @@
-%global ver 9.0p1
+%global ver 9.1p1
%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)? (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 \
--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
* Thu Oct 28 2021 Damien Miller <djm@mindrot.org>
- Remove remaining traces of --with-md5-passwords
* Mon Jul 20 2020 Damien Miller <djm@mindrot.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 28b9086f4cab..32bd8c189b87 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: 9.0p1
+Version: 9.1p1
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/int32_minmax.inc b/int32_minmax.inc
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/krl.c b/krl.c
index 17b88edde777..473a9d737953 100644
--- a/krl.c
+++ b/krl.c
@@ -1,1447 +1,1447 @@
/*
* Copyright (c) 2012 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.
*/
-/* $OpenBSD: krl.c,v 1.53 2021/06/04 06:19:07 djm Exp $ */
+/* $OpenBSD: krl.c,v 1.54 2022/04/28 02:53:31 djm Exp $ */
#include "includes.h"
#include <sys/types.h>
#include <openbsd-compat/sys-tree.h>
#include <openbsd-compat/sys-queue.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "sshbuf.h"
#include "ssherr.h"
#include "sshkey.h"
#include "authfile.h"
#include "misc.h"
#include "log.h"
#include "digest.h"
#include "bitmap.h"
#include "utf8.h"
#include "krl.h"
/* #define DEBUG_KRL */
#ifdef DEBUG_KRL
# define KRL_DBG(x) debug3_f x
#else
# define KRL_DBG(x)
#endif
/*
* Trees of revoked serial numbers, key IDs and keys. This allows
* quick searching, querying and producing lists in canonical order.
*/
/* Tree of serial numbers. XXX make smarter: really need a real sparse bitmap */
struct revoked_serial {
u_int64_t lo, hi;
RB_ENTRY(revoked_serial) tree_entry;
};
static int serial_cmp(struct revoked_serial *a, struct revoked_serial *b);
RB_HEAD(revoked_serial_tree, revoked_serial);
RB_GENERATE_STATIC(revoked_serial_tree, revoked_serial, tree_entry, serial_cmp)
/* Tree of key IDs */
struct revoked_key_id {
char *key_id;
RB_ENTRY(revoked_key_id) tree_entry;
};
static int key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b);
RB_HEAD(revoked_key_id_tree, revoked_key_id);
RB_GENERATE_STATIC(revoked_key_id_tree, revoked_key_id, tree_entry, key_id_cmp)
/* Tree of blobs (used for keys and fingerprints) */
struct revoked_blob {
u_char *blob;
size_t len;
RB_ENTRY(revoked_blob) tree_entry;
};
static int blob_cmp(struct revoked_blob *a, struct revoked_blob *b);
RB_HEAD(revoked_blob_tree, revoked_blob);
RB_GENERATE_STATIC(revoked_blob_tree, revoked_blob, tree_entry, blob_cmp)
/* Tracks revoked certs for a single CA */
struct revoked_certs {
struct sshkey *ca_key;
struct revoked_serial_tree revoked_serials;
struct revoked_key_id_tree revoked_key_ids;
TAILQ_ENTRY(revoked_certs) entry;
};
TAILQ_HEAD(revoked_certs_list, revoked_certs);
struct ssh_krl {
u_int64_t krl_version;
u_int64_t generated_date;
u_int64_t flags;
char *comment;
struct revoked_blob_tree revoked_keys;
struct revoked_blob_tree revoked_sha1s;
struct revoked_blob_tree revoked_sha256s;
struct revoked_certs_list revoked_certs;
};
/* Return equal if a and b overlap */
static int
serial_cmp(struct revoked_serial *a, struct revoked_serial *b)
{
if (a->hi >= b->lo && a->lo <= b->hi)
return 0;
return a->lo < b->lo ? -1 : 1;
}
static int
key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b)
{
return strcmp(a->key_id, b->key_id);
}
static int
blob_cmp(struct revoked_blob *a, struct revoked_blob *b)
{
int r;
if (a->len != b->len) {
if ((r = memcmp(a->blob, b->blob, MINIMUM(a->len, b->len))) != 0)
return r;
return a->len > b->len ? 1 : -1;
} else
return memcmp(a->blob, b->blob, a->len);
}
struct ssh_krl *
ssh_krl_init(void)
{
struct ssh_krl *krl;
if ((krl = calloc(1, sizeof(*krl))) == NULL)
return NULL;
RB_INIT(&krl->revoked_keys);
RB_INIT(&krl->revoked_sha1s);
RB_INIT(&krl->revoked_sha256s);
TAILQ_INIT(&krl->revoked_certs);
return krl;
}
static void
revoked_certs_free(struct revoked_certs *rc)
{
struct revoked_serial *rs, *trs;
struct revoked_key_id *rki, *trki;
RB_FOREACH_SAFE(rs, revoked_serial_tree, &rc->revoked_serials, trs) {
RB_REMOVE(revoked_serial_tree, &rc->revoked_serials, rs);
free(rs);
}
RB_FOREACH_SAFE(rki, revoked_key_id_tree, &rc->revoked_key_ids, trki) {
RB_REMOVE(revoked_key_id_tree, &rc->revoked_key_ids, rki);
free(rki->key_id);
free(rki);
}
sshkey_free(rc->ca_key);
}
void
ssh_krl_free(struct ssh_krl *krl)
{
struct revoked_blob *rb, *trb;
struct revoked_certs *rc, *trc;
if (krl == NULL)
return;
free(krl->comment);
RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_keys, trb) {
RB_REMOVE(revoked_blob_tree, &krl->revoked_keys, rb);
free(rb->blob);
free(rb);
}
RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_sha1s, trb) {
RB_REMOVE(revoked_blob_tree, &krl->revoked_sha1s, rb);
free(rb->blob);
free(rb);
}
RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_sha256s, trb) {
RB_REMOVE(revoked_blob_tree, &krl->revoked_sha256s, rb);
free(rb->blob);
free(rb);
}
TAILQ_FOREACH_SAFE(rc, &krl->revoked_certs, entry, trc) {
TAILQ_REMOVE(&krl->revoked_certs, rc, entry);
revoked_certs_free(rc);
}
}
void
ssh_krl_set_version(struct ssh_krl *krl, u_int64_t version)
{
krl->krl_version = version;
}
int
ssh_krl_set_comment(struct ssh_krl *krl, const char *comment)
{
free(krl->comment);
if ((krl->comment = strdup(comment)) == NULL)
return SSH_ERR_ALLOC_FAIL;
return 0;
}
/*
* Find the revoked_certs struct for a CA key. If allow_create is set then
* create a new one in the tree if one did not exist already.
*/
static int
revoked_certs_for_ca_key(struct ssh_krl *krl, const struct sshkey *ca_key,
struct revoked_certs **rcp, int allow_create)
{
struct revoked_certs *rc;
int r;
*rcp = NULL;
TAILQ_FOREACH(rc, &krl->revoked_certs, entry) {
if ((ca_key == NULL && rc->ca_key == NULL) ||
sshkey_equal(rc->ca_key, ca_key)) {
*rcp = rc;
return 0;
}
}
if (!allow_create)
return 0;
/* If this CA doesn't exist in the list then add it now */
if ((rc = calloc(1, sizeof(*rc))) == NULL)
return SSH_ERR_ALLOC_FAIL;
if (ca_key == NULL)
rc->ca_key = NULL;
else if ((r = sshkey_from_private(ca_key, &rc->ca_key)) != 0) {
free(rc);
return r;
}
RB_INIT(&rc->revoked_serials);
RB_INIT(&rc->revoked_key_ids);
TAILQ_INSERT_TAIL(&krl->revoked_certs, rc, entry);
KRL_DBG(("new CA %s", ca_key == NULL ? "*" : sshkey_type(ca_key)));
*rcp = rc;
return 0;
}
static int
insert_serial_range(struct revoked_serial_tree *rt, u_int64_t lo, u_int64_t hi)
{
struct revoked_serial rs, *ers, *crs, *irs;
KRL_DBG(("insert %llu:%llu", lo, hi));
memset(&rs, 0, sizeof(rs));
rs.lo = lo;
rs.hi = hi;
ers = RB_NFIND(revoked_serial_tree, rt, &rs);
if (ers == NULL || serial_cmp(ers, &rs) != 0) {
/* No entry matches. Just insert */
if ((irs = malloc(sizeof(rs))) == NULL)
return SSH_ERR_ALLOC_FAIL;
memcpy(irs, &rs, sizeof(*irs));
ers = RB_INSERT(revoked_serial_tree, rt, irs);
if (ers != NULL) {
KRL_DBG(("bad: ers != NULL"));
/* Shouldn't happen */
free(irs);
return SSH_ERR_INTERNAL_ERROR;
}
ers = irs;
} else {
KRL_DBG(("overlap found %llu:%llu", ers->lo, ers->hi));
/*
* The inserted entry overlaps an existing one. Grow the
* existing entry.
*/
if (ers->lo > lo)
ers->lo = lo;
if (ers->hi < hi)
ers->hi = hi;
}
/*
* The inserted or revised range might overlap or abut adjacent ones;
* coalesce as necessary.
*/
/* Check predecessors */
while ((crs = RB_PREV(revoked_serial_tree, rt, ers)) != NULL) {
KRL_DBG(("pred %llu:%llu", crs->lo, crs->hi));
if (ers->lo != 0 && crs->hi < ers->lo - 1)
break;
/* This entry overlaps. */
if (crs->lo < ers->lo) {
ers->lo = crs->lo;
KRL_DBG(("pred extend %llu:%llu", ers->lo, ers->hi));
}
RB_REMOVE(revoked_serial_tree, rt, crs);
free(crs);
}
/* Check successors */
while ((crs = RB_NEXT(revoked_serial_tree, rt, ers)) != NULL) {
KRL_DBG(("succ %llu:%llu", crs->lo, crs->hi));
if (ers->hi != (u_int64_t)-1 && crs->lo > ers->hi + 1)
break;
/* This entry overlaps. */
if (crs->hi > ers->hi) {
ers->hi = crs->hi;
KRL_DBG(("succ extend %llu:%llu", ers->lo, ers->hi));
}
RB_REMOVE(revoked_serial_tree, rt, crs);
free(crs);
}
KRL_DBG(("done, final %llu:%llu", ers->lo, ers->hi));
return 0;
}
int
ssh_krl_revoke_cert_by_serial(struct ssh_krl *krl, const struct sshkey *ca_key,
u_int64_t serial)
{
return ssh_krl_revoke_cert_by_serial_range(krl, ca_key, serial, serial);
}
int
ssh_krl_revoke_cert_by_serial_range(struct ssh_krl *krl,
const struct sshkey *ca_key, u_int64_t lo, u_int64_t hi)
{
struct revoked_certs *rc;
int r;
if (lo > hi || lo == 0)
return SSH_ERR_INVALID_ARGUMENT;
if ((r = revoked_certs_for_ca_key(krl, ca_key, &rc, 1)) != 0)
return r;
return insert_serial_range(&rc->revoked_serials, lo, hi);
}
int
ssh_krl_revoke_cert_by_key_id(struct ssh_krl *krl, const struct sshkey *ca_key,
const char *key_id)
{
struct revoked_key_id *rki, *erki;
struct revoked_certs *rc;
int r;
if ((r = revoked_certs_for_ca_key(krl, ca_key, &rc, 1)) != 0)
return r;
KRL_DBG(("revoke %s", key_id));
if ((rki = calloc(1, sizeof(*rki))) == NULL ||
(rki->key_id = strdup(key_id)) == NULL) {
free(rki);
return SSH_ERR_ALLOC_FAIL;
}
erki = RB_INSERT(revoked_key_id_tree, &rc->revoked_key_ids, rki);
if (erki != NULL) {
free(rki->key_id);
free(rki);
}
return 0;
}
/* Convert "key" to a public key blob without any certificate information */
static int
plain_key_blob(const struct sshkey *key, u_char **blob, size_t *blen)
{
struct sshkey *kcopy;
int r;
if ((r = sshkey_from_private(key, &kcopy)) != 0)
return r;
if (sshkey_is_cert(kcopy)) {
if ((r = sshkey_drop_cert(kcopy)) != 0) {
sshkey_free(kcopy);
return r;
}
}
r = sshkey_to_blob(kcopy, blob, blen);
sshkey_free(kcopy);
return r;
}
/* Revoke a key blob. Ownership of blob is transferred to the tree */
static int
revoke_blob(struct revoked_blob_tree *rbt, u_char *blob, size_t len)
{
struct revoked_blob *rb, *erb;
if ((rb = calloc(1, sizeof(*rb))) == NULL)
return SSH_ERR_ALLOC_FAIL;
rb->blob = blob;
rb->len = len;
erb = RB_INSERT(revoked_blob_tree, rbt, rb);
if (erb != NULL) {
free(rb->blob);
free(rb);
}
return 0;
}
int
ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const struct sshkey *key)
{
u_char *blob;
size_t len;
int r;
debug3_f("revoke type %s", sshkey_type(key));
if ((r = plain_key_blob(key, &blob, &len)) != 0)
return r;
return revoke_blob(&krl->revoked_keys, blob, len);
}
static int
revoke_by_hash(struct revoked_blob_tree *target, const u_char *p, size_t len)
{
u_char *blob;
int r;
/* need to copy hash, as revoke_blob steals ownership */
if ((blob = malloc(len)) == NULL)
return SSH_ERR_SYSTEM_ERROR;
memcpy(blob, p, len);
if ((r = revoke_blob(target, blob, len)) != 0) {
free(blob);
return r;
}
return 0;
}
int
ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const u_char *p, size_t len)
{
debug3_f("revoke by sha1");
if (len != 20)
return SSH_ERR_INVALID_FORMAT;
return revoke_by_hash(&krl->revoked_sha1s, p, len);
}
int
ssh_krl_revoke_key_sha256(struct ssh_krl *krl, const u_char *p, size_t len)
{
debug3_f("revoke by sha256");
if (len != 32)
return SSH_ERR_INVALID_FORMAT;
return revoke_by_hash(&krl->revoked_sha256s, p, len);
}
int
ssh_krl_revoke_key(struct ssh_krl *krl, const struct sshkey *key)
{
/* XXX replace with SHA256? */
if (!sshkey_is_cert(key))
return ssh_krl_revoke_key_explicit(krl, key);
if (key->cert->serial == 0) {
return ssh_krl_revoke_cert_by_key_id(krl,
key->cert->signature_key,
key->cert->key_id);
} else {
return ssh_krl_revoke_cert_by_serial(krl,
key->cert->signature_key,
key->cert->serial);
}
}
/*
* Select the most compact section type to emit next in a KRL based on
* the current section type, the run length of contiguous revoked serial
* numbers and the gaps from the last and to the next revoked serial.
* Applies a mostly-accurate bit cost model to select the section type
* that will minimise the size of the resultant KRL.
*/
static int
choose_next_state(int current_state, u_int64_t contig, int final,
u_int64_t last_gap, u_int64_t next_gap, int *force_new_section)
{
int new_state;
u_int64_t cost, cost_list, cost_range, cost_bitmap, cost_bitmap_restart;
/*
* Avoid unsigned overflows.
* The limits are high enough to avoid confusing the calculations.
*/
contig = MINIMUM(contig, 1ULL<<31);
last_gap = MINIMUM(last_gap, 1ULL<<31);
next_gap = MINIMUM(next_gap, 1ULL<<31);
/*
* Calculate the cost to switch from the current state to candidates.
* NB. range sections only ever contain a single range, so their
* switching cost is independent of the current_state.
*/
cost_list = cost_bitmap = cost_bitmap_restart = 0;
cost_range = 8;
switch (current_state) {
case KRL_SECTION_CERT_SERIAL_LIST:
cost_bitmap_restart = cost_bitmap = 8 + 64;
break;
case KRL_SECTION_CERT_SERIAL_BITMAP:
cost_list = 8;
cost_bitmap_restart = 8 + 64;
break;
case KRL_SECTION_CERT_SERIAL_RANGE:
case 0:
cost_bitmap_restart = cost_bitmap = 8 + 64;
cost_list = 8;
}
/* Estimate base cost in bits of each section type */
cost_list += 64 * contig + (final ? 0 : 8+64);
cost_range += (2 * 64) + (final ? 0 : 8+64);
cost_bitmap += last_gap + contig + (final ? 0 : MINIMUM(next_gap, 8+64));
cost_bitmap_restart += contig + (final ? 0 : MINIMUM(next_gap, 8+64));
/* Convert to byte costs for actual comparison */
cost_list = (cost_list + 7) / 8;
cost_bitmap = (cost_bitmap + 7) / 8;
cost_bitmap_restart = (cost_bitmap_restart + 7) / 8;
cost_range = (cost_range + 7) / 8;
/* Now pick the best choice */
*force_new_section = 0;
new_state = KRL_SECTION_CERT_SERIAL_BITMAP;
cost = cost_bitmap;
if (cost_range < cost) {
new_state = KRL_SECTION_CERT_SERIAL_RANGE;
cost = cost_range;
}
if (cost_list < cost) {
new_state = KRL_SECTION_CERT_SERIAL_LIST;
cost = cost_list;
}
if (cost_bitmap_restart < cost) {
new_state = KRL_SECTION_CERT_SERIAL_BITMAP;
*force_new_section = 1;
cost = cost_bitmap_restart;
}
KRL_DBG(("contig %llu last_gap %llu next_gap %llu final %d, costs:"
"list %llu range %llu bitmap %llu new bitmap %llu, "
"selected 0x%02x%s", (long long unsigned)contig,
(long long unsigned)last_gap, (long long unsigned)next_gap, final,
(long long unsigned)cost_list, (long long unsigned)cost_range,
(long long unsigned)cost_bitmap,
(long long unsigned)cost_bitmap_restart, new_state,
*force_new_section ? " restart" : ""));
return new_state;
}
static int
put_bitmap(struct sshbuf *buf, struct bitmap *bitmap)
{
size_t len;
u_char *blob;
int r;
len = bitmap_nbytes(bitmap);
if ((blob = malloc(len)) == NULL)
return SSH_ERR_ALLOC_FAIL;
if (bitmap_to_string(bitmap, blob, len) != 0) {
free(blob);
return SSH_ERR_INTERNAL_ERROR;
}
r = sshbuf_put_bignum2_bytes(buf, blob, len);
free(blob);
return r;
}
/* Generate a KRL_SECTION_CERTIFICATES KRL section */
static int
revoked_certs_generate(struct revoked_certs *rc, struct sshbuf *buf)
{
int final, force_new_sect, r = SSH_ERR_INTERNAL_ERROR;
u_int64_t i, contig, gap, last = 0, bitmap_start = 0;
struct revoked_serial *rs, *nrs;
struct revoked_key_id *rki;
int next_state, state = 0;
struct sshbuf *sect;
struct bitmap *bitmap = NULL;
if ((sect = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
/* Store the header: optional CA scope key, reserved */
if (rc->ca_key == NULL) {
if ((r = sshbuf_put_string(buf, NULL, 0)) != 0)
goto out;
} else {
if ((r = sshkey_puts(rc->ca_key, buf)) != 0)
goto out;
}
if ((r = sshbuf_put_string(buf, NULL, 0)) != 0)
goto out;
/* Store the revoked serials. */
for (rs = RB_MIN(revoked_serial_tree, &rc->revoked_serials);
rs != NULL;
rs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs)) {
KRL_DBG(("serial %llu:%llu state 0x%02x",
(long long unsigned)rs->lo, (long long unsigned)rs->hi,
state));
/* Check contiguous length and gap to next section (if any) */
nrs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs);
final = nrs == NULL;
gap = nrs == NULL ? 0 : nrs->lo - rs->hi;
contig = 1 + (rs->hi - rs->lo);
/* Choose next state based on these */
next_state = choose_next_state(state, contig, final,
state == 0 ? 0 : rs->lo - last, gap, &force_new_sect);
/*
* If the current section is a range section or has a different
* type to the next section, then finish it off now.
*/
if (state != 0 && (force_new_sect || next_state != state ||
state == KRL_SECTION_CERT_SERIAL_RANGE)) {
KRL_DBG(("finish state 0x%02x", state));
switch (state) {
case KRL_SECTION_CERT_SERIAL_LIST:
case KRL_SECTION_CERT_SERIAL_RANGE:
break;
case KRL_SECTION_CERT_SERIAL_BITMAP:
if ((r = put_bitmap(sect, bitmap)) != 0)
goto out;
bitmap_free(bitmap);
bitmap = NULL;
break;
}
if ((r = sshbuf_put_u8(buf, state)) != 0 ||
(r = sshbuf_put_stringb(buf, sect)) != 0)
goto out;
sshbuf_reset(sect);
}
/* If we are starting a new section then prepare it now */
if (next_state != state || force_new_sect) {
KRL_DBG(("start state 0x%02x",
next_state));
state = next_state;
sshbuf_reset(sect);
switch (state) {
case KRL_SECTION_CERT_SERIAL_LIST:
case KRL_SECTION_CERT_SERIAL_RANGE:
break;
case KRL_SECTION_CERT_SERIAL_BITMAP:
if ((bitmap = bitmap_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
bitmap_start = rs->lo;
if ((r = sshbuf_put_u64(sect,
bitmap_start)) != 0)
goto out;
break;
}
}
/* Perform section-specific processing */
switch (state) {
case KRL_SECTION_CERT_SERIAL_LIST:
for (i = 0; i < contig; i++) {
if ((r = sshbuf_put_u64(sect, rs->lo + i)) != 0)
goto out;
}
break;
case KRL_SECTION_CERT_SERIAL_RANGE:
if ((r = sshbuf_put_u64(sect, rs->lo)) != 0 ||
(r = sshbuf_put_u64(sect, rs->hi)) != 0)
goto out;
break;
case KRL_SECTION_CERT_SERIAL_BITMAP:
if (rs->lo - bitmap_start > INT_MAX) {
error_f("insane bitmap gap");
goto out;
}
for (i = 0; i < contig; i++) {
if (bitmap_set_bit(bitmap,
rs->lo + i - bitmap_start) != 0) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
}
break;
}
last = rs->hi;
}
/* Flush the remaining section, if any */
if (state != 0) {
KRL_DBG(("serial final flush for state 0x%02x", state));
switch (state) {
case KRL_SECTION_CERT_SERIAL_LIST:
case KRL_SECTION_CERT_SERIAL_RANGE:
break;
case KRL_SECTION_CERT_SERIAL_BITMAP:
if ((r = put_bitmap(sect, bitmap)) != 0)
goto out;
bitmap_free(bitmap);
bitmap = NULL;
break;
}
if ((r = sshbuf_put_u8(buf, state)) != 0 ||
(r = sshbuf_put_stringb(buf, sect)) != 0)
goto out;
}
KRL_DBG(("serial done "));
/* Now output a section for any revocations by key ID */
sshbuf_reset(sect);
RB_FOREACH(rki, revoked_key_id_tree, &rc->revoked_key_ids) {
KRL_DBG(("key ID %s", rki->key_id));
if ((r = sshbuf_put_cstring(sect, rki->key_id)) != 0)
goto out;
}
if (sshbuf_len(sect) != 0) {
if ((r = sshbuf_put_u8(buf, KRL_SECTION_CERT_KEY_ID)) != 0 ||
(r = sshbuf_put_stringb(buf, sect)) != 0)
goto out;
}
r = 0;
out:
bitmap_free(bitmap);
sshbuf_free(sect);
return r;
}
int
ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf,
struct sshkey **sign_keys, u_int nsign_keys)
{
int r = SSH_ERR_INTERNAL_ERROR;
struct revoked_certs *rc;
struct revoked_blob *rb;
struct sshbuf *sect;
u_char *sblob = NULL;
size_t slen, i;
if (krl->generated_date == 0)
krl->generated_date = time(NULL);
if ((sect = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
/* Store the header */
if ((r = sshbuf_put(buf, KRL_MAGIC, sizeof(KRL_MAGIC) - 1)) != 0 ||
(r = sshbuf_put_u32(buf, KRL_FORMAT_VERSION)) != 0 ||
(r = sshbuf_put_u64(buf, krl->krl_version)) != 0 ||
(r = sshbuf_put_u64(buf, krl->generated_date)) != 0 ||
(r = sshbuf_put_u64(buf, krl->flags)) != 0 ||
(r = sshbuf_put_string(buf, NULL, 0)) != 0 ||
(r = sshbuf_put_cstring(buf, krl->comment)) != 0)
goto out;
/* Store sections for revoked certificates */
TAILQ_FOREACH(rc, &krl->revoked_certs, entry) {
sshbuf_reset(sect);
if ((r = revoked_certs_generate(rc, sect)) != 0)
goto out;
if ((r = sshbuf_put_u8(buf, KRL_SECTION_CERTIFICATES)) != 0 ||
(r = sshbuf_put_stringb(buf, sect)) != 0)
goto out;
}
/* Finally, output sections for revocations by public key/hash */
sshbuf_reset(sect);
RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_keys) {
KRL_DBG(("key len %zu ", rb->len));
if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0)
goto out;
}
if (sshbuf_len(sect) != 0) {
if ((r = sshbuf_put_u8(buf, KRL_SECTION_EXPLICIT_KEY)) != 0 ||
(r = sshbuf_put_stringb(buf, sect)) != 0)
goto out;
}
sshbuf_reset(sect);
RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha1s) {
KRL_DBG(("hash len %zu ", rb->len));
if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0)
goto out;
}
if (sshbuf_len(sect) != 0) {
if ((r = sshbuf_put_u8(buf,
KRL_SECTION_FINGERPRINT_SHA1)) != 0 ||
(r = sshbuf_put_stringb(buf, sect)) != 0)
goto out;
}
sshbuf_reset(sect);
RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha256s) {
KRL_DBG(("hash len %zu ", rb->len));
if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0)
goto out;
}
if (sshbuf_len(sect) != 0) {
if ((r = sshbuf_put_u8(buf,
KRL_SECTION_FINGERPRINT_SHA256)) != 0 ||
(r = sshbuf_put_stringb(buf, sect)) != 0)
goto out;
}
for (i = 0; i < nsign_keys; i++) {
KRL_DBG(("sig key %s", sshkey_ssh_name(sign_keys[i])));
if ((r = sshbuf_put_u8(buf, KRL_SECTION_SIGNATURE)) != 0 ||
(r = sshkey_puts(sign_keys[i], buf)) != 0)
goto out;
/* XXX support sk-* keys */
if ((r = sshkey_sign(sign_keys[i], &sblob, &slen,
sshbuf_ptr(buf), sshbuf_len(buf), NULL, NULL,
NULL, 0)) != 0)
goto out;
KRL_DBG(("signature sig len %zu", slen));
if ((r = sshbuf_put_string(buf, sblob, slen)) != 0)
goto out;
}
r = 0;
out:
free(sblob);
sshbuf_free(sect);
return r;
}
static void
format_timestamp(u_int64_t timestamp, char *ts, size_t nts)
{
time_t t;
struct tm *tm;
t = timestamp;
tm = localtime(&t);
if (tm == NULL)
strlcpy(ts, "<INVALID>", nts);
else {
*ts = '\0';
strftime(ts, nts, "%Y%m%dT%H%M%S", tm);
}
}
static int
parse_revoked_certs(struct sshbuf *buf, struct ssh_krl *krl)
{
int r = SSH_ERR_INTERNAL_ERROR;
u_char type;
const u_char *blob;
size_t blen, nbits;
struct sshbuf *subsect = NULL;
u_int64_t serial, serial_lo, serial_hi;
struct bitmap *bitmap = NULL;
char *key_id = NULL;
struct sshkey *ca_key = NULL;
if ((subsect = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
/* Header: key, reserved */
if ((r = sshbuf_get_string_direct(buf, &blob, &blen)) != 0 ||
(r = sshbuf_skip_string(buf)) != 0)
goto out;
if (blen != 0 && (r = sshkey_from_blob(blob, blen, &ca_key)) != 0)
goto out;
while (sshbuf_len(buf) > 0) {
sshbuf_free(subsect);
subsect = NULL;
if ((r = sshbuf_get_u8(buf, &type)) != 0 ||
(r = sshbuf_froms(buf, &subsect)) != 0)
goto out;
KRL_DBG(("subsection type 0x%02x", type));
/* sshbuf_dump(subsect, stderr); */
switch (type) {
case KRL_SECTION_CERT_SERIAL_LIST:
while (sshbuf_len(subsect) > 0) {
if ((r = sshbuf_get_u64(subsect, &serial)) != 0)
goto out;
if ((r = ssh_krl_revoke_cert_by_serial(krl,
ca_key, serial)) != 0)
goto out;
}
break;
case KRL_SECTION_CERT_SERIAL_RANGE:
if ((r = sshbuf_get_u64(subsect, &serial_lo)) != 0 ||
(r = sshbuf_get_u64(subsect, &serial_hi)) != 0)
goto out;
if ((r = ssh_krl_revoke_cert_by_serial_range(krl,
ca_key, serial_lo, serial_hi)) != 0)
goto out;
break;
case KRL_SECTION_CERT_SERIAL_BITMAP:
if ((bitmap = bitmap_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_get_u64(subsect, &serial_lo)) != 0 ||
(r = sshbuf_get_bignum2_bytes_direct(subsect,
&blob, &blen)) != 0)
goto out;
if (bitmap_from_string(bitmap, blob, blen) != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
nbits = bitmap_nbits(bitmap);
for (serial = 0; serial < (u_int64_t)nbits; serial++) {
if (serial > 0 && serial_lo + serial == 0) {
error_f("bitmap wraps u64");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (!bitmap_test_bit(bitmap, serial))
continue;
if ((r = ssh_krl_revoke_cert_by_serial(krl,
ca_key, serial_lo + serial)) != 0)
goto out;
}
bitmap_free(bitmap);
bitmap = NULL;
break;
case KRL_SECTION_CERT_KEY_ID:
while (sshbuf_len(subsect) > 0) {
if ((r = sshbuf_get_cstring(subsect,
&key_id, NULL)) != 0)
goto out;
if ((r = ssh_krl_revoke_cert_by_key_id(krl,
ca_key, key_id)) != 0)
goto out;
free(key_id);
key_id = NULL;
}
break;
default:
error("Unsupported KRL certificate section %u", type);
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (sshbuf_len(subsect) > 0) {
error("KRL certificate section contains unparsed data");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
}
r = 0;
out:
if (bitmap != NULL)
bitmap_free(bitmap);
free(key_id);
sshkey_free(ca_key);
sshbuf_free(subsect);
return r;
}
static int
blob_section(struct sshbuf *sect, struct revoked_blob_tree *target_tree,
size_t expected_len)
{
u_char *rdata = NULL;
size_t rlen = 0;
int r;
while (sshbuf_len(sect) > 0) {
if ((r = sshbuf_get_string(sect, &rdata, &rlen)) != 0)
return r;
if (expected_len != 0 && rlen != expected_len) {
error_f("bad length");
free(rdata);
return SSH_ERR_INVALID_FORMAT;
}
if ((r = revoke_blob(target_tree, rdata, rlen)) != 0) {
free(rdata);
return r;
}
}
return 0;
}
/* Attempt to parse a KRL, checking its signature (if any) with sign_ca_keys. */
int
ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp,
const struct sshkey **sign_ca_keys, size_t nsign_ca_keys)
{
struct sshbuf *copy = NULL, *sect = NULL;
struct ssh_krl *krl = NULL;
char timestamp[64];
int r = SSH_ERR_INTERNAL_ERROR, sig_seen;
struct sshkey *key = NULL, **ca_used = NULL, **tmp_ca_used;
u_char type;
const u_char *blob;
size_t i, j, sig_off, sects_off, blen, nca_used;
u_int format_version;
nca_used = 0;
*krlp = NULL;
if (sshbuf_len(buf) < sizeof(KRL_MAGIC) - 1 ||
memcmp(sshbuf_ptr(buf), KRL_MAGIC, sizeof(KRL_MAGIC) - 1) != 0) {
debug3_f("not a KRL");
return SSH_ERR_KRL_BAD_MAGIC;
}
/* Take a copy of the KRL buffer so we can verify its signature later */
if ((copy = sshbuf_fromb(buf)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_consume(copy, sizeof(KRL_MAGIC) - 1)) != 0)
goto out;
if ((krl = ssh_krl_init()) == NULL) {
error_f("alloc failed");
goto out;
}
if ((r = sshbuf_get_u32(copy, &format_version)) != 0)
goto out;
if (format_version != KRL_FORMAT_VERSION) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((r = sshbuf_get_u64(copy, &krl->krl_version)) != 0 ||
(r = sshbuf_get_u64(copy, &krl->generated_date)) != 0 ||
(r = sshbuf_get_u64(copy, &krl->flags)) != 0 ||
(r = sshbuf_skip_string(copy)) != 0 ||
(r = sshbuf_get_cstring(copy, &krl->comment, NULL)) != 0)
goto out;
format_timestamp(krl->generated_date, timestamp, sizeof(timestamp));
debug("KRL version %llu generated at %s%s%s",
(long long unsigned)krl->krl_version, timestamp,
*krl->comment ? ": " : "", krl->comment);
/*
* 1st pass: verify signatures, if any. This is done to avoid
* detailed parsing of data whose provenance is unverified.
*/
sig_seen = 0;
if (sshbuf_len(buf) < sshbuf_len(copy)) {
/* Shouldn't happen */
r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
sects_off = sshbuf_len(buf) - sshbuf_len(copy);
while (sshbuf_len(copy) > 0) {
if ((r = sshbuf_get_u8(copy, &type)) != 0 ||
(r = sshbuf_get_string_direct(copy, &blob, &blen)) != 0)
goto out;
KRL_DBG(("first pass, section 0x%02x", type));
if (type != KRL_SECTION_SIGNATURE) {
if (sig_seen) {
error("KRL contains non-signature section "
"after signature");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* Not interested for now. */
continue;
}
sig_seen = 1;
/* First string component is the signing key */
if ((r = sshkey_from_blob(blob, blen, &key)) != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (sshbuf_len(buf) < sshbuf_len(copy)) {
/* Shouldn't happen */
r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
sig_off = sshbuf_len(buf) - sshbuf_len(copy);
/* Second string component is the signature itself */
if ((r = sshbuf_get_string_direct(copy, &blob, &blen)) != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* Check signature over entire KRL up to this point */
if ((r = sshkey_verify(key, blob, blen,
sshbuf_ptr(buf), sig_off, NULL, 0, NULL)) != 0)
goto out;
/* Check if this key has already signed this KRL */
for (i = 0; i < nca_used; i++) {
if (sshkey_equal(ca_used[i], key)) {
error("KRL signed more than once with "
"the same key");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
}
/* Record keys used to sign the KRL */
tmp_ca_used = recallocarray(ca_used, nca_used, nca_used + 1,
sizeof(*ca_used));
if (tmp_ca_used == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
ca_used = tmp_ca_used;
ca_used[nca_used++] = key;
key = NULL;
}
if (sshbuf_len(copy) != 0) {
/* Shouldn't happen */
r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
/*
* 2nd pass: parse and load the KRL, skipping the header to the point
* where the section start.
*/
sshbuf_free(copy);
if ((copy = sshbuf_fromb(buf)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_consume(copy, sects_off)) != 0)
goto out;
while (sshbuf_len(copy) > 0) {
sshbuf_free(sect);
sect = NULL;
if ((r = sshbuf_get_u8(copy, &type)) != 0 ||
(r = sshbuf_froms(copy, &sect)) != 0)
goto out;
KRL_DBG(("second pass, section 0x%02x", type));
switch (type) {
case KRL_SECTION_CERTIFICATES:
if ((r = parse_revoked_certs(sect, krl)) != 0)
goto out;
break;
case KRL_SECTION_EXPLICIT_KEY:
if ((r = blob_section(sect,
&krl->revoked_keys, 0)) != 0)
goto out;
break;
case KRL_SECTION_FINGERPRINT_SHA1:
if ((r = blob_section(sect,
&krl->revoked_sha1s, 20)) != 0)
goto out;
break;
case KRL_SECTION_FINGERPRINT_SHA256:
if ((r = blob_section(sect,
&krl->revoked_sha256s, 32)) != 0)
goto out;
break;
case KRL_SECTION_SIGNATURE:
/* Handled above, but still need to stay in synch */
sshbuf_free(sect);
sect = NULL;
if ((r = sshbuf_skip_string(copy)) != 0)
goto out;
break;
default:
error("Unsupported KRL section %u", type);
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (sect != NULL && sshbuf_len(sect) > 0) {
error("KRL section contains unparsed data");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
}
/* Check that the key(s) used to sign the KRL weren't revoked */
sig_seen = 0;
for (i = 0; i < nca_used; i++) {
if (ssh_krl_check_key(krl, ca_used[i]) == 0)
sig_seen = 1;
else {
sshkey_free(ca_used[i]);
ca_used[i] = NULL;
}
}
if (nca_used && !sig_seen) {
error("All keys used to sign KRL were revoked");
r = SSH_ERR_KEY_REVOKED;
goto out;
}
/* If we have CA keys, then verify that one was used to sign the KRL */
if (sig_seen && nsign_ca_keys != 0) {
sig_seen = 0;
for (i = 0; !sig_seen && i < nsign_ca_keys; i++) {
for (j = 0; j < nca_used; j++) {
if (ca_used[j] == NULL)
continue;
if (sshkey_equal(ca_used[j], sign_ca_keys[i])) {
sig_seen = 1;
break;
}
}
}
if (!sig_seen) {
r = SSH_ERR_SIGNATURE_INVALID;
error("KRL not signed with any trusted key");
goto out;
}
}
*krlp = krl;
r = 0;
out:
if (r != 0)
ssh_krl_free(krl);
for (i = 0; i < nca_used; i++)
sshkey_free(ca_used[i]);
free(ca_used);
sshkey_free(key);
sshbuf_free(copy);
sshbuf_free(sect);
return r;
}
/* Checks certificate serial number and key ID revocation */
static int
is_cert_revoked(const struct sshkey *key, struct revoked_certs *rc)
{
struct revoked_serial rs, *ers;
struct revoked_key_id rki, *erki;
/* Check revocation by cert key ID */
memset(&rki, 0, sizeof(rki));
rki.key_id = key->cert->key_id;
erki = RB_FIND(revoked_key_id_tree, &rc->revoked_key_ids, &rki);
if (erki != NULL) {
KRL_DBG(("revoked by key ID"));
return SSH_ERR_KEY_REVOKED;
}
/*
* Zero serials numbers are ignored (it's the default when the
* CA doesn't specify one).
*/
if (key->cert->serial == 0)
return 0;
memset(&rs, 0, sizeof(rs));
rs.lo = rs.hi = key->cert->serial;
ers = RB_FIND(revoked_serial_tree, &rc->revoked_serials, &rs);
if (ers != NULL) {
KRL_DBG(("revoked serial %llu matched %llu:%llu",
key->cert->serial, ers->lo, ers->hi));
return SSH_ERR_KEY_REVOKED;
}
return 0;
}
/* Checks whether a given key/cert is revoked. Does not check its CA */
static int
is_key_revoked(struct ssh_krl *krl, const struct sshkey *key)
{
struct revoked_blob rb, *erb;
struct revoked_certs *rc;
int r;
/* Check explicitly revoked hashes first */
memset(&rb, 0, sizeof(rb));
if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1,
&rb.blob, &rb.len)) != 0)
return r;
erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb);
free(rb.blob);
if (erb != NULL) {
KRL_DBG(("revoked by key SHA1"));
return SSH_ERR_KEY_REVOKED;
}
memset(&rb, 0, sizeof(rb));
if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA256,
&rb.blob, &rb.len)) != 0)
return r;
erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha256s, &rb);
free(rb.blob);
if (erb != NULL) {
KRL_DBG(("revoked by key SHA256"));
return SSH_ERR_KEY_REVOKED;
}
/* Next, explicit keys */
memset(&rb, 0, sizeof(rb));
if ((r = plain_key_blob(key, &rb.blob, &rb.len)) != 0)
return r;
erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb);
free(rb.blob);
if (erb != NULL) {
KRL_DBG(("revoked by explicit key"));
return SSH_ERR_KEY_REVOKED;
}
if (!sshkey_is_cert(key))
return 0;
/* Check cert revocation for the specified CA */
if ((r = revoked_certs_for_ca_key(krl, key->cert->signature_key,
&rc, 0)) != 0)
return r;
if (rc != NULL) {
if ((r = is_cert_revoked(key, rc)) != 0)
return r;
}
/* Check cert revocation for the wildcard CA */
if ((r = revoked_certs_for_ca_key(krl, NULL, &rc, 0)) != 0)
return r;
if (rc != NULL) {
if ((r = is_cert_revoked(key, rc)) != 0)
return r;
}
KRL_DBG(("%llu no match", key->cert->serial));
return 0;
}
int
ssh_krl_check_key(struct ssh_krl *krl, const struct sshkey *key)
{
int r;
KRL_DBG(("checking key"));
if ((r = is_key_revoked(krl, key)) != 0)
return r;
if (sshkey_is_cert(key)) {
debug2_f("checking CA key");
if ((r = is_key_revoked(krl, key->cert->signature_key)) != 0)
return r;
}
KRL_DBG(("key okay"));
return 0;
}
int
ssh_krl_file_contains_key(const char *path, const struct sshkey *key)
{
struct sshbuf *krlbuf = NULL;
struct ssh_krl *krl = NULL;
int oerrno = 0, r;
if (path == NULL)
return 0;
if ((r = sshbuf_load_file(path, &krlbuf)) != 0) {
oerrno = errno;
goto out;
}
if ((r = ssh_krl_from_blob(krlbuf, &krl, NULL, 0)) != 0)
goto out;
debug2_f("checking KRL %s", path);
r = ssh_krl_check_key(krl, key);
out:
sshbuf_free(krlbuf);
ssh_krl_free(krl);
if (r != 0)
errno = oerrno;
return r;
}
int
krl_dump(struct ssh_krl *krl, FILE *f)
{
struct sshkey *key = NULL;
struct revoked_blob *rb;
struct revoked_certs *rc;
struct revoked_serial *rs;
struct revoked_key_id *rki;
int r, ret = 0;
char *fp, timestamp[64];
/* Try to print in a KRL spec-compatible format */
format_timestamp(krl->generated_date, timestamp, sizeof(timestamp));
fprintf(f, "# KRL version %llu\n",
(unsigned long long)krl->krl_version);
fprintf(f, "# Generated at %s\n", timestamp);
if (krl->comment != NULL && *krl->comment != '\0') {
r = INT_MAX;
asmprintf(&fp, INT_MAX, &r, "%s", krl->comment);
fprintf(f, "# Comment: %s\n", fp);
free(fp);
}
fputc('\n', f);
RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_keys) {
if ((r = sshkey_from_blob(rb->blob, rb->len, &key)) != 0) {
ret = SSH_ERR_INVALID_FORMAT;
error_r(r, "parse KRL key");
continue;
}
if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
SSH_FP_DEFAULT)) == NULL) {
ret = SSH_ERR_INVALID_FORMAT;
error("sshkey_fingerprint failed");
continue;
}
- fprintf(f, "hash: SHA256:%s # %s\n", fp, sshkey_ssh_name(key));
+ fprintf(f, "hash: %s # %s\n", fp, sshkey_ssh_name(key));
free(fp);
free(key);
}
RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha256s) {
fp = tohex(rb->blob, rb->len);
fprintf(f, "hash: SHA256:%s\n", fp);
free(fp);
}
RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha1s) {
/*
* There is not KRL spec keyword for raw SHA1 hashes, so
* print them as comments.
*/
fp = tohex(rb->blob, rb->len);
fprintf(f, "# hash SHA1:%s\n", fp);
free(fp);
}
TAILQ_FOREACH(rc, &krl->revoked_certs, entry) {
fputc('\n', f);
if (rc->ca_key == NULL)
fprintf(f, "# Wildcard CA\n");
else {
if ((fp = sshkey_fingerprint(rc->ca_key,
SSH_FP_HASH_DEFAULT, SSH_FP_DEFAULT)) == NULL) {
ret = SSH_ERR_INVALID_FORMAT;
error("sshkey_fingerprint failed");
continue;
}
fprintf(f, "# CA key %s %s\n",
sshkey_ssh_name(rc->ca_key), fp);
free(fp);
}
RB_FOREACH(rs, revoked_serial_tree, &rc->revoked_serials) {
if (rs->lo == rs->hi) {
fprintf(f, "serial: %llu\n",
(unsigned long long)rs->lo);
} else {
fprintf(f, "serial: %llu-%llu\n",
(unsigned long long)rs->lo,
(unsigned long long)rs->hi);
}
}
RB_FOREACH(rki, revoked_key_id_tree, &rc->revoked_key_ids) {
/*
* We don't want key IDs with embedded newlines to
* mess up the display.
*/
r = INT_MAX;
asmprintf(&fp, INT_MAX, &r, "%s", rki->key_id);
fprintf(f, "id: %s\n", fp);
free(fp);
}
}
return ret;
}
diff --git a/misc.c b/misc.c
index 85d22369505d..f2135803737a 100644
--- a/misc.c
+++ b/misc.c
@@ -1,2795 +1,2828 @@
-/* $OpenBSD: misc.c,v 1.175 2022/03/20 08:51:21 djm Exp $ */
+/* $OpenBSD: misc.c,v 1.177 2022/08/11 01:56:51 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>
#include <grp.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;
}
/* remove whitespace from end of string */
void
rtrim(char *s)
{
size_t i;
if ((i = strlen(s)) == 0)
return;
for (i--; i > 0; i--) {
if (isspace((int)s[i]))
s[i] = '\0';
}
}
/* 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 == NULL ? "*" : 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;
}
/* The common case: only accept colon as delimiter. */
char *
hpdelim(char **cp)
{
char *r, delim = '\0';
r = hpdelim2(cp, &delim);
if (delim == '/')
return NULL;
return r;
}
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_f("argument too long");
nalloc = args->nalloc;
if (args->list == NULL) {
nalloc = 32;
args->num = 0;
} else if (args->num > (256 * 1024))
fatal_f("too many arguments");
else if (args->num >= args->nalloc)
fatal_f("arglist corrupt");
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_f("argument too long");
if (args->list == NULL || args->num >= args->nalloc)
fatal_f("arglist corrupt");
if (which >= args->num)
fatal_f("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 == NULL)
return;
if (args->list != NULL && args->num < args->nalloc) {
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*.
*/
int
tilde_expand(const char *filename, uid_t uid, char **retp)
{
char *ocopy = NULL, *copy, *s = NULL;
const char *path = NULL, *user = NULL;
struct passwd *pw;
size_t len;
int ret = -1, r, slash;
*retp = NULL;
if (*filename != '~') {
*retp = xstrdup(filename);
return 0;
}
ocopy = copy = xstrdup(filename + 1);
if (*copy == '\0') /* ~ */
path = NULL;
else if (*copy == '/') {
copy += strspn(copy, "/");
if (*copy == '\0')
path = NULL; /* ~/ */
else
path = copy; /* ~/path */
} else {
user = copy;
if ((path = strchr(copy, '/')) != NULL) {
copy[path - copy] = '\0';
path++;
path += strspn(path, "/");
if (*path == '\0') /* ~user/ */
path = NULL;
/* else ~user/path */
}
/* else ~user */
}
if (user != NULL) {
if ((pw = getpwnam(user)) == NULL) {
error_f("No such user %s", user);
goto out;
}
} else if ((pw = getpwuid(uid)) == NULL) {
error_f("No such uid %ld", (long)uid);
goto out;
}
/* Make sure directory has a trailing '/' */
slash = (len = strlen(pw->pw_dir)) == 0 || pw->pw_dir[len - 1] != '/';
if ((r = xasprintf(&s, "%s%s%s", pw->pw_dir,
slash ? "/" : "", path != NULL ? path : "")) <= 0) {
error_f("xasprintf failed");
goto out;
}
if (r >= PATH_MAX) {
error_f("Path too long");
goto out;
}
/* success */
ret = 0;
*retp = s;
s = NULL;
out:
free(s);
free(ocopy);
return ret;
}
char *
tilde_expand_filename(const char *filename, uid_t uid)
{
char *ret;
if (tilde_expand(filename, uid, &ret) != 0)
cleanup_exit(255);
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);
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_timespec(struct timespec *ts, int ms)
{
if (ms < 0)
ms = 0;
ts->tv_sec = ms / 1000;
ts->tv_nsec = (ms % 1000) * 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 terminate_on_comment)
{
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;
if (terminate_on_comment && s[i] == '#')
break;
/* Start of a token */
quote = 0;
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] == '\\' ||
(quote == 0 && 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)
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;
}
char *
argv_next(int *argcp, char ***argvp)
{
char *ret = (*argvp)[0];
if (*argcp > 0 && ret != NULL) {
(*argcp)--;
(*argvp)++;
}
return ret;
}
void
argv_consume(int *argcp)
{
*argcp = 0;
}
void
argv_free(char **av, int ac)
{
int i;
if (av == NULL)
return;
for (i = 0; i < ac; i++)
free(av[i]);
free(av);
}
/* 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;
+ const char *cp;
+ size_t l;
+ int is_utc = 0;
*tp = 0;
+ l = strlen(s);
+ if (l > 1 && strcasecmp(s + l - 1, "Z") == 0) {
+ is_utc = 1;
+ l--;
+ } else if (l > 3 && strcasecmp(s + l - 3, "UTC") == 0) {
+ is_utc = 1;
+ l -= 3;
+ }
/*
* 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)) {
+ switch (l) {
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)
+ if ((cp = strptime(buf, fmt, &tm)) == NULL || *cp != '\0')
return SSH_ERR_INVALID_FORMAT;
+ if (is_utc) {
+ if ((tt = timegm(&tm)) < 0)
+ return SSH_ERR_INVALID_FORMAT;
+ } else {
+ if ((tt = mktime(&tm)) < 0)
+ return SSH_ERR_INVALID_FORMAT;
+ }
/* success */
*tp = (uint64_t)tt;
return 0;
}
/* On OpenBSD time_t is int64_t which is long long. */
/* #define SSH_TIME_T_MAX LLONG_MAX */
void
format_absolute_time(uint64_t t, char *buf, size_t len)
{
time_t tt = t > SSH_TIME_T_MAX ? SSH_TIME_T_MAX : t;
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 (geteuid() == 0 &&
initgroups(pw->pw_name, pw->pw_gid) == -1) {
error("%s: initgroups(%s, %u): %s", tag,
pw->pw_name, (u_int)pw->pw_gid, strerror(errno));
_exit(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;
}
const char *
lookup_env_in_list(const char *env, char * const *envs, size_t nenvs)
{
size_t i, envlen;
envlen = strlen(env);
for (i = 0; i < nenvs; i++) {
if (strncmp(envs[i], env, envlen) == 0 &&
envs[i][envlen] == '=') {
return envs[i] + envlen + 1;
}
}
return NULL;
}
+
+const char *
+lookup_setenv_in_list(const char *env, char * const *envs, size_t nenvs)
+{
+ char *name, *cp;
+ const char *ret;
+
+ name = xstrdup(env);
+ if ((cp = strchr(name, '=')) == NULL) {
+ free(name);
+ return NULL; /* not env=val */
+ }
+ *cp = '\0';
+ ret = lookup_env_in_list(name, envs, nenvs);
+ free(name);
+ return ret;
+}
diff --git a/misc.h b/misc.h
index 2e1b5fecaa01..7ef75bd0929c 100644
--- a/misc.h
+++ b/misc.h
@@ -1,232 +1,234 @@
-/* $OpenBSD: misc.h,v 1.99 2021/11/13 21:14:13 deraadt Exp $ */
+/* $OpenBSD: misc.h,v 1.100 2022/06/03 04:30:47 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 rtrim(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);
int tilde_expand(const char *, uid_t, char **);
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_timespec(struct timespec *, 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)));
void replacearg(arglist *, u_int, char *, ...)
__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 *lookup_env_in_list(const char *env,
char * const *envs, size_t nenvs);
+const char *lookup_setenv_in_list(const char *env,
+ char * const *envs, size_t nenvs);
int argv_split(const char *, int *, char ***, int);
char *argv_assemble(int, char **argv);
char *argv_next(int *, char ***);
void argv_consume(int *);
void argv_free(char **, int);
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);
int safe_path_fd(int, const char *, struct passwd *,
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 1362f20e1bd1..c580e1773469 100644
--- a/moduli
+++ b/moduli
@@ -1,383 +1,420 @@
-# $OpenBSD: moduli,v 1.31 2021/09/28 11:10:05 dtucker Exp $
+# $OpenBSD: moduli,v 1.32 2022/04/20 01:13:47 dtucker Exp $
# Time Type Tests Tries Size Generator Modulus
-20210524220022 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F806ABBEB
-20210524220025 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F807D248B
-20210524220034 2 6 100 2047 5 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F80D9BC9F
-20210524220041 2 6 100 2047 5 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F812A0A37
-20210524220046 2 6 100 2047 5 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F8155AB97
-20210524220054 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F81B2848B
-20210524220056 2 6 100 2047 5 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F81C13007
-20210524220118 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F82930D03
-20210524220122 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F82BE877B
-20210524220127 2 6 100 2047 5 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F82EBBF97
-20210524220132 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F8320C043
-20210524220137 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F83476BCB
-20210524220154 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F83FA204B
-20210524220159 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F842A67EB
-20210524220217 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F84E7FEDB
-20210524220251 2 6 100 2047 5 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F86503997
-20210524220256 2 6 100 2047 5 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F867E7587
-20210524220301 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F86A47F7B
-20210524220302 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F86A754D3
-20210524220304 2 6 100 2047 5 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F86BFB23F
-20210524220310 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F86F871FB
-20210524220313 2 6 100 2047 5 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F87125B7F
-20210524220316 2 6 100 2047 5 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F87290AD7
-20210524220323 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F876DECFB
-20210524220330 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F87B31B33
-20210524220332 2 6 100 2047 5 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F87BD0977
-20210524220333 2 6 100 2047 5 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F87C5168F
-20210524220335 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F87D5CCB3
-20210524220337 2 6 100 2047 2 C117F4B631CA032FD2F00AC0D9A5473D8E56DA246FC44FD594BF5657D399E453728341CC920EE9127729637683D268CA3B62F5CB61C7D4F08D3F202D67DBBBD88498043861190549649D82E7793A1874FE0E8ED0B460E3442DD4DFC2301A1B6D8FA36C7CAD084B2FFEF2205E3CE46B030E4618C7B50656BF9FB60592B1FA32E91E0D536A12E601317F0562F547FF44DF33377ABAB2A2991EC99887712BFD9C78BBAA8759B09577706493F50A416F472D6F7B9532959A8899FACEB55B012E8FE8131AA45E1851FFAA3572E489FF4AAE89ECB583C98CC29ADBB1E9677AE2517D6BC1BC13C5A18A232FAD4CDC6E580FEC730D070D49E88A23C528A4985F87DBEA23
-20210524220355 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A44F8E93
-20210524220404 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A4A0C6AF
-20210524220412 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A4EF1E03
-20210524220414 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A4F93C23
-20210524220420 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A535963B
-20210524220424 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A5566833
-20210524220425 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A5599617
-20210524220426 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A55EC4A7
-20210524220436 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A5BD5EB7
-20210524220445 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A619258B
-20210524220451 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A650122B
-20210524220501 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A6B04DA7
-20210524220513 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A725B467
-20210524220528 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A7C40A4B
-20210524220537 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A825DA4F
-20210524220559 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A906849F
-20210524220603 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A92B2543
-20210524220606 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A946A62B
-20210524220611 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A96E9F73
-20210524220612 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A9741957
-20210524220613 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A977BF53
-20210524220614 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A9808FE3
-20210524220616 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A994D8CB
-20210524220618 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A99CAF0B
-20210524220624 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A9D53ABF
-20210524220627 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01A9F1F75B
-20210524220644 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01AAB771E7
-20210524220645 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01AAB8D6C3
-20210524220650 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01AAE8CD27
-20210524220652 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01AAFAE557
-20210524220656 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01AB231D03
-20210524220658 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01AB2F512F
-20210524220700 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01AB3ED6AF
-20210524220706 2 6 100 2047 5 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01AB7A3DDF
-20210524220712 2 6 100 2047 2 CDA33E2E7179C731632DFF6272815DAAC78E971B46095FA70FD7153B8FEC3061C37064D6D6961EA44D04D20222E7071AF123319EE4B70C6C6C7F5EC5BF6F4556A9636794FE249A109E9292CAE57FE40829089D99A5731AC08639F090500DAA9ECD8D56C83368EA05DEB9A1C37C82C0E84396128BF47B2222A7312DC06F7220DB671F16302E8C9ACEB9034E4955EC08E27C9E708FF81884B81CFB3DD2D662D0A60A5DAA91EBD69F564B8B2A565637663A4D444BA4BBEE7F029BB44AE1EA2182F39A1E2ABFDE297432932295FCF1DB704EFCD3A30A9EF881D6090480232D8893B9F7608037E1B5A2A09DD9E590C63ED28A82EFF89135E05E010710FC01ABB48B1B
-20210524221547 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB8505902F721263
-20210524221723 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB85059030ED9F9B
-20210524221800 2 6 100 3071 5 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB8505903179F84F
-20210524221940 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB850590331E399B
-20210524222007 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB850590338E4BEB
-20210524222013 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB850590339E72DB
-20210524222057 2 6 100 3071 5 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB8505903458ADC7
-20210524222125 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB85059034C60DC3
-20210524222149 2 6 100 3071 5 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB8505903527AD67
-20210524222206 2 6 100 3071 5 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB850590356715BF
-20210524222226 2 6 100 3071 5 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB85059035B2AF7F
-20210524222240 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB85059035E27D63
-20210524222530 2 6 100 3071 5 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB85059038AD337F
-20210524222550 2 6 100 3071 5 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB85059038FF50F7
-20210524222711 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB8505903A587DBB
-20210524222722 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB8505903A7E2593
-20210524222813 2 6 100 3071 5 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB8505903B518C67
-20210524222821 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB8505903B6BA4B3
-20210524222927 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB8505903C7ADF53
-20210524222944 2 6 100 3071 5 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB8505903CB9378F
-20210524223124 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB8505903E4E0F63
-20210524223132 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB8505903E680D03
-20210524223318 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB8505904017708B
-20210524223328 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB85059040391D6B
-20210524223340 2 6 100 3071 5 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB8505904064990F
-20210524223418 2 6 100 3071 2 C1064E3791D96D66CA94320FDDA0DD731891FE4D4E4BCB5C8C2A22E33BE0C071BDD6B55DF0A474F1123F6AA3CDBB043EE9972052E3422BAAF9CBB6C1E77E2817F0266F0018351110EE2017EDE4312F0E0ABECA6585F15630FE2228BC03E4DEC84F31650177D712CDE77D6D6D2B0B391F64CD792A6C14BF9A16011EE673183465882595613087535464AC29A1138E1FB2B1024693A368700447307B43435E1BC718CD239396943F22BBF861EA0098069CAB7976B13C60A9CDD4BEDE6DF3659D61188E161D2D5A02CADDCCB547319E02211D00445BE47F5484F673239D7796CB1E1D3FF1558DA0ACD3AB17C6B3D8C3F00DFBBBF69F3B600E98DDC1FB0C0F79FC2E2F88C891F7BACAD4023331B623DF6835B2A7E881E59F0B7CE676208717E3AA51FBEDD7E9EE62527F253762C7B6A3D987DF800D2FB66DFE4F9588BEAA938DD9FAA5916186746FBC25A357F57D0E03442EEA6D067F19ABB96865474A250C73F66FE0FC5B5847CAB8F2CE25765A52A27223BD725C7ECFCF55EAAB85059040FCE473
-20210524223453 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EB455657B
-20210524223634 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EB5FCC833
-20210524223659 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EB65DD6F3
-20210524223732 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EB6E02573
-20210524223739 2 6 100 3071 5 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EB6F4ED87
-20210524223745 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EB7068FBB
-20210524223826 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EB7A2859B
-20210524223848 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EB7EE3B1B
-20210524223936 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EB8AE2333
-20210524224015 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EB93EC75B
-20210524224018 2 6 100 3071 5 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EB944D10F
-20210524224136 2 6 100 3071 5 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EBA7C4FC7
-20210524224213 2 6 100 3071 5 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EBB023E7F
-20210524224228 2 6 100 3071 5 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EBB36560F
-20210524224236 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EBB4F6853
-20210524224323 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EBC0F75BB
-20210524224346 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EBC62CB7B
-20210524224413 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EBCC9AD0B
-20210524224441 2 6 100 3071 5 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EBD2F9967
-20210524224508 2 6 100 3071 5 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EBD92D627
-20210524224722 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EBF92432B
-20210524224733 2 6 100 3071 5 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EBFB7A837
-20210524224832 2 6 100 3071 5 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EC09EA30F
-20210524224841 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EC0B86AD3
-20210524224843 2 6 100 3071 5 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EC0B88DBF
-20210524225050 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EC2C17DEB
-20210524225054 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EC2C967DB
-20210524225112 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EC30CDA43
-20210524225123 2 6 100 3071 5 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EC3311D0F
-20210524225247 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EC4813D2B
-20210524225254 2 6 100 3071 2 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EC4923E73
-20210524225346 2 6 100 3071 5 C6D582E2863DD842704EDE65181452A2A54FD6112537B792F2AF066D30656086948D10BD502D46881AA1766656F36A4BDDCCAF0893BA661A1E7952ED0CC9FD481640C27E1513322DA51E6CF68B2659BFED70ACA5F3D45188E2DCE57C05479C7564EB1573D3A039E815105E5BED13E0810D70E388766005C2DE1ADA9855EB53BF83EFABFCB67D8BDC4156C639A547EBDCB3EB980DCD81A44255F1EFCEAE2367482CD7AC7C7B68CA9536B6548F5323C1F46C9ADB084274D82387B7005D7D964CF53F4FCD2EF3337466DEB47BF46DA8501BCDAC4579FE0512B1D6C2AFDF933E9C6B89B25CCD5066B103D59FF1CB96DD4E427520CC06DEE74325885FD48E20E6DA45009CFD337511AF8081C2BC4341306DB2F2BFEB6912F7176D07161162D1BF8B603B0500EDAE3985D29BE88F3F94E98F91A73BA3CCAD9F35EBF6F95F179DA44AD4255AE983FBF8A8BD9458ED7D3AC7E410735FF90ECB32029C5A7D562A33C295F6262E6E91AA15444B971D565A6F90CD898E700B4EE15FE1ADABD3EA6EC562D397
-20210524230435 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375A8B66EEB
-20210524230743 2 6 100 4095 5 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375AA1B04D7
-20210524231138 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375ABDA60AB
-20210524231337 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375ACBB313B
-20210524231610 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375ADDB3D53
-20210524231810 2 6 100 4095 5 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375AEB7413F
-20210524231830 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375AED5921B
-20210524231850 2 6 100 4095 5 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375AEF2A0D7
-20210524232438 2 6 100 4095 5 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375B19B5B17
-20210524232556 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375B23127DB
-20210524233441 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375B624C5D3
-20210524233915 2 6 100 4095 5 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375B81FBBEF
-20210524234022 2 6 100 4095 5 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375B89ABD27
-20210524234251 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375B9AA7603
-20210524234341 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375B9FF196B
-20210524234859 2 6 100 4095 5 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375BC541C47
-20210524234945 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375BCA418EB
-20210524235116 2 6 100 4095 5 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375BD49C877
-20210524235639 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375BFB1B0BB
-20210524235928 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375C0F703EB
-20210525000202 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375C21C5393
-20210525000215 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375C22B072B
-20210525000220 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375C22DB943
-20210525000241 2 6 100 4095 5 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375C24E57CF
-20210525000519 2 6 100 4095 5 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375C37CDA8F
-20210525000617 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375C3E42EBB
-20210525000910 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375C52F623B
-20210525000950 2 6 100 4095 2 DF313B012B87BCB41D4138171AA4A3ACBBCE90E58F3142966241384A0C0FFB78A3AAF92DFD19BAEF944D6323266A2BF7DAD5B917587B37D446A09EC84E519C10C981F1F59D7BF098A174589ACE1272D2BEDBC6703AE8F728E2EEC81F0C8F5E3E77991C632A664FAB45A584FD7A34133DB362EC04B2EFC6EC3F6C609C3ECEFB6223BA4CF06792D3A623F8FA4E1C78603B22B8AF856C8435AA6B25EEEB5C90F24572236182A79EE6A31331B4A78F1EFDE526AE53EA6C30F93DC2AEB3790E8AA728CE26D13080F84CC81ABB03E8E8E653368825D488461676BACF9BAAEDDA84A2E0E3524F407DD717A1DEC0D46C8FCF63F6F8952BCF1B19C03425F5AAB759ECD3C1E943756694A0F32CB0F765FB5EE410AFA6BAA30B0C96F4E65C76741BD067048DFF657B4C7C43336F200951448F3348AD241D9EBA14EE8CD8C023EF049835B6F6A6A4BA8B45CFF29C5252521494750C51972D2D448E357EA1B5A7230DCEFE9F2404E1D1C857E2DBFA18ABEA6369D958870D5657E3C6465748E2E10F851F9301B26F0A4AEF77F134C52A9391F7C92783FD7A2E378B5CE9F6D0ADA2B1EADC9BC9959E30E3821B2473DC1E2F3529DAE96B9E09BB0BC7806F41D7F39CEC690DB9F3DCCDFD92FA5DBF29FA26E5F55D87ED627E7788120A76ADDF2F2F28323F0950E1D9EAAC4270A6D66269978BB7382055BE7C36CE63446899C7ADF725F375C573F39B
-20210525001816 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB091FBF7D2A3
-20210525001921 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB091FC6DAC53
-20210525001926 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB091FC6F3373
-20210525002309 2 6 100 4095 5 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB091FE12C677
-20210525002320 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB091FE1E59AB
-20210525002338 2 6 100 4095 5 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB091FE3AB02F
-20210525002359 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB091FE5BF4C3
-20210525002601 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB091FF3C869B
-20210525002851 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB09200739083
-20210525003041 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0920140797B
-20210525003049 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB092014502F3
-20210525003141 2 6 100 4095 5 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB09201A2B9FF
-20210525003223 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB09201EA8A9B
-20210525003231 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB09201F326F3
-20210525003352 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB092028EFD83
-20210525003809 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0920482BA13
-20210525003923 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB09205072CA3
-20210525004024 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB09205780163
-20210525004148 2 6 100 4095 5 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0920617E947
-20210525004457 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB092077D9FDB
-20210525004558 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB09207ED990B
-20210525004731 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB092089EB6C3
-20210525004805 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB09208D77E3B
-20210525004822 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB09208EF6DA3
-20210525005103 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0920A21B82B
-20210525005232 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0920AC6072B
-20210525005335 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0920B39092B
-20210525005400 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0920B611A73
-20210525005804 2 6 100 4095 5 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0920D2EF2A7
-20210525005836 2 6 100 4095 5 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0920D66062F
-20210525010525 2 6 100 4095 5 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0921066C17F
-20210525010559 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB09210A11893
-20210525010655 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0921101CC03
-20210525010715 2 6 100 4095 5 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB092111F033F
-20210525011027 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0921284AEC3
-20210525011247 2 6 100 4095 5 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB092138697D7
-20210525011345 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB09213EAC66B
-20210525011758 2 6 100 4095 5 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB09215CA5E7F
-20210525011827 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB09215F9F6DB
-20210525011950 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB092168F25FB
-20210525012059 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB09217019A9B
-20210525012441 2 6 100 4095 5 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB092189F6357
-20210525012731 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB09219DE687B
-20210525012806 2 6 100 4095 5 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0921A19486F
-20210525012959 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0921AE8C22B
-20210525013036 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0921B277E7B
-20210525013100 2 6 100 4095 2 D26A87E5A681F2A0E0231EC9449860176D2F9282C1D6E791D912B84987AAEF8BBCDE27FCC3A31FD76A78509ACB3673A0091330E077333D6682329E65ED16DAB1DC98ED93D911BCC3B63FF1271937AE5CE43688C0322530126BCC852EBA388F6B5B9AFF6808DD0B17790AD76F462EA9F0438F1E5A622C921E50A0358335806DD4A574C8117028E6DD07A42F09C3CDE7B5B9CD8914CEE9116E2F952862EFDB94F826D826C8EF15C468E80F916E09F4C411483E2C3CBDBF1CEE282F1144D17F9F681B0B238337941C1C5DEAB7DD52F0EC84A5C8B9FEEF5AA7EEA118FDF857B8BC0190C81A8D2E446E58C5F18DE1CFDD4680E04C89D421E1DEF67BC5A6FBA6B525FB06C263624A5D668A36F2254F9ADC7366544CE3A388B31675E3886801F9DFB571BA159C7D20B6175711387D696741F64FD689DC61F775028924BCCFC0197844340F61BB7EF0370B3FA53CFEEF65B4058B4CA1B25290DEB7E9ED829154430B7008A5E4174FCCAD783F3C8D1CE61014AF4299527B81B9F4D6EA4DEDEE89DD042FBDB6F0ED861CD7073F59AE181C5922BF8B480F7C71E2EC6CB6EA922FBA8C7383AA72001AA4A0AF633CD82D423B880E4AA3B96921BA8CE3EAB0337BAF49F37576905D811D657E3420C8C41C9BC693ACA6C94B34102F54FB370D597A1F9C00ED602927871F79C396D778FA4C968D2CD48788196EFB9511315087B9AEB0921B4B1893
-20210525015106 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081BF2FBF4B
-20210525015719 2 6 100 6143 5 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081C01C9317
-20210525022943 2 6 100 6143 5 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081C51E7ABF
-20210525025621 2 6 100 6143 5 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081C92AC0FF
-20210525030139 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081C9F26EFB
-20210525030310 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081CA22ECE3
-20210525033123 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081CE69BC83
-20210525035425 2 6 100 6143 5 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081D1EA340F
-20210525042046 2 6 100 6143 5 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081D5E1F147
-20210525044151 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081D906177B
-20210525045703 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081DB34C7EB
-20210525050443 2 6 100 6143 5 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081DC53F8C7
-20210525050557 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081DC7921BB
-20210525051327 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081DD90DF33
-20210525051635 2 6 100 6143 5 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081DE04D46F
-20210525052745 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081DFAB207B
-20210525053701 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081E102FFA3
-20210525060524 2 6 100 6143 5 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081E525193F
-20210525061916 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081E723D123
-20210525062421 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081E7DAEAA3
-20210525062728 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081E8449753
-20210525064313 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081EA8CAE5B
-20210525072251 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081F04FCEC3
-20210525082731 2 6 100 6143 5 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081F9AA3067
-20210525090241 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB3081FEACB11B
-20210525093810 2 6 100 6143 2 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB308203BF9E43
-20210525094831 2 6 100 6143 5 CAED937BA3084DFE7B4C1B59AC23C7EA9F28E677B8AFA536E9079DECED93EDAAEFB2C757F9E7AE4E90C4C68C8C937CAA8A0FB92A36FBBD24F777D579E264E8750B365A59AF83C5925262981B301C94CA57CE2A4825438EE089B2E0A5A8D90B51B7DB6044383542685F2D543030403741A6337C0280866A08D15BBFF32D9326073E6F8BAE510E66CF5A5DC6C7D96EFA13984EA383224CD59C7F8A49BA170EBD0BCF896FAD0FD67AB88D4D25CC81D29FFB7062328C9BA3BCD7EB107B74FAC05412D7677C058604F544B2EE8548E9372064C0CEB79BADEF8755F86E8DC894BD043DE697ECE323D624156B731D99C12FD1F42BB2FCADF8CFFEAB8DB59F9CB5843C1A01018DB3E415B4BF00D7F3F20FAAD86938C6B3061BC2A4ED0D18FAD01B1E53D0C8D41D208189D6E341E167B4B975236701B76C72097A34AAC46F4781185A7A63E4FB4A3CDDAB793EE4DFBA3D57481AF41ACD06A45F8D59D33FEBABCD3B98675A9C3F54B0AB42CFCABCA47021C709867AB12F830C4E93AE48AE5EBDD109E3F672AAE6A2EFFEAF07648D3110EE52627D44C8EA35482502C1CDC7B655F4D4A5E7DA1A064E138D00A9CC85DA5E833221AC5FF62F7871B53A8CE279AD441A5795D092F257C9BD2A871D098B3583ED9876342351C063BC2EA9FF111D245FE68A6A087B9E0B7AB0C47F2C6BD98A5CB4DFC57B71A1CF13A83308DA1E3BEB572AFDA9B88F05CCE1DBE359A44E849CAE4AB6196262877B119EDF241326C0F523ACF04DDF90601DC0D4107B935444D5C9E019B340227A386996D071BAA64D62FA049F285F12366ACDD439FCD3D0BAF9C37519177AAC6CF3B6986BAB5F68BDC9FB6E3B82FA157BE36D452FC0EDC4CDB95F9677F97C0F98725F275EAE0FF15C53957D1EFA9CABCE7B68FC186F117C40C5D24BD982A7F21AD6FE4A9CAC6C763FB68DD0B1C725E5DBC4522B86A42B02E3F5E704595977829607FDEB0922C497A9A93F327FA921D8BFBCD9C18272506A1A9F23171787FCBA72E4670C857D089DB5A22AE801EEBD567D48D697EBF25E6183374FC4C47C1747C3F69E650333F6F7ABEB30820532247F
-20210525101346 2 6 100 6143 5 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7A84C1DCF
-20210525102328 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7A9C0F78B
-20210525102507 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7A9F844D3
-20210525105019 2 6 100 6143 5 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7ADB803E7
-20210525110206 2 6 100 6143 5 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7AF734957
-20210525110823 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7B0605EAB
-20210525113051 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7B3C762EB
-20210525114458 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7B5E9D203
-20210525120436 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7B8DCCD03
-20210525120944 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7B9A11BE3
-20210525122534 2 6 100 6143 5 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7BBFCC14F
-20210525140523 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7CAD4CEEB
-20210525141051 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7CB96ECE3
-20210525141705 2 6 100 6143 5 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7CC76C197
-20210525145447 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7D1FC10C3
-20210525152246 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7D605451B
-20210525153139 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7D73E819B
-20210525153550 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7D7D225C3
-20210525161421 2 6 100 6143 5 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7DD5B0F27
-20210525163744 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7E0BFFE7B
-20210525165044 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7E29682EB
-20210525172301 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7E730C6C3
-20210525172835 2 6 100 6143 5 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7E7F17D9F
-20210525173319 2 6 100 6143 5 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7E89CD397
-20210525174552 2 6 100 6143 2 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7EA6442E3
-20210525175415 2 6 100 6143 5 E14FDFEE7787F1C28112A16D64FE7C953E3A963B98675E5C078465D774DDD60D0689616D88E223B1D75C4D124BD32324D828137D8AF145AED00162977FA394F7D9657F5E892CDAC98461E41CCF76B3F42471E8DC112FB82F65AD55AE55ADE7F3B85C9EE6E914F2DEE618D55A9FA0F72F6C03664BCDAEDC64ACD9DAE85B0396321F79565522DE272B5D041155C8949BE08B5B09712887BE1E20C31FE5A5A90E0F9610000EF7E1BBA8C7EF3A9F7E3BD2710BCA36C5390673FC55FC47CF63A356472C491229E283A236DB444E75BCD2F43B0FF35B809E6336314945B725912A1C3423141007FFC129C65CCD772966D9E394AECC3252F9C9AD019950C188FE8922A959E19F226B33235BA30D0F3B163F21BE8964C67D0CD118EB7EDBE0DB21762006A115ECCF829452B51E533AC29A836DC6CF40135FCB31B77A287E5CD377A0A80D7F2683A9D9E760F3EA479CFCE9627AFF5BF6AEC257043D71E0CC695D2DF4589C3255DBA1A2F58FA3F673C23FEF80366042BC0DBD7AE2556E3EA38577FC0CA9D56324CB084E6EBE01ADFAD00AB41CF94822FC7680A9007A6BA804A2242E8EDE7D599A46F59886D36E6B7F4AA20D92E682AFC1BB0BD5F5AC0203185B978F438508933EE2A85666467A95051DF1EA0C6366CC28D36030242A4B51820D043190B310D5D51DCE6A6AF333629FAEE5F3A6D88DDC325321A3767CF1C97B6B5FD8E2AC2E95C54F142BD4F5A5F5609E6D4BC09C55FA03F92BA35C006662FC08BEE197777F3E8CC1730F754447D349BF93AA8683D226EBD2FD872CB8383A03058AE9210891886DB9E4DB2300D109B2C32E26C460DA6E362F72214999EFDEED5E7299AA4C6A9DC9A9BB5A8D59374F92C339314BCEDFE44E5F805F37934C94FB6D8C8E2C9045BF0C1CE9A659A40937870F51F36947A89EA941990F743666D6B27C71CDF6366666E3623471945AB3F52F98C6034CE808AF2F10F21541A3B3C1CBF2A204770E10953F63913D1A5695C1A68E48D21F65C210097F931E4DD82A31BEE9EC842D8898A73CB84E236B8A10D3B7D8BE6097E4679CC8BE8C77A1CB824F6231E7EB8F5A57
-20210525183229 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816BFE560FB
-20210525190732 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816C2E82C7B
-20210525191937 2 6 100 7679 5 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816C3EC147F
-20210525193159 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816C4F60C8B
-20210525194246 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816C5D97313
-20210525203443 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816CA459133
-20210525215204 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816D0DE4FDB
-20210525233543 2 6 100 7679 5 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816D9A29577
-20210525234619 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816DA7ADFAB
-20210525235329 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816DB0B2673
-20210525235513 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816DB26C1CB
-20210526022844 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816E7D6D73B
-20210526023323 2 6 100 7679 5 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816E82F077F
-20210526062933 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816FB41731B
-20210526065151 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816FCF0DCD3
-20210526070545 2 6 100 7679 5 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816FDF8DB8F
-20210526071052 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816FE572613
-20210526071809 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816FEDF35F3
-20210526072107 2 6 100 7679 5 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816FF13DABF
-20210526072624 2 6 100 7679 5 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37816FF7318C7
-20210526081148 2 6 100 7679 5 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F3781702F3953F
-20210526081939 2 6 100 7679 5 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F378170385D3EF
-20210526100857 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F378170BEE7A0B
-20210526104252 2 6 100 7679 5 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F378170E7ACB07
-20210526104946 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F378170EFA920B
-20210526105532 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F378170F653A13
-20210526110401 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F378171004A14B
-20210526110925 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F378171065B293
-20210526123113 2 6 100 7679 5 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F37817168DDC17
-20210526123356 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F3781716B7D3FB
-20210526135059 2 6 100 7679 5 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F378171C86775F
-20210526162058 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F3781727B688EB
-20210526173849 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F378172D7A5213
-20210526175432 2 6 100 7679 2 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F378172E9D4DF3
-20210526175746 2 6 100 7679 5 E3F4DC1A68758284B2950A16204A7D9CB3972B0E74E2CDF12518B48DA3F349640BFEDA5162CB2EC47E2593EDB3BB51D743F3F4948A4D940B37B724B6D7E5F5BFD44F9D3CFB0F6E2CC1B33AEB7FCA7C2E26EFC55208D15DD12B08925383346148CA7CEEE874499CBE6E5D34AF7EF47742F683398B5418E3FA261013922180C6EEB4250632A2F93CDC281E6E76A488FEB4CE7B4C9783A37201CE4B551B53EEBF291234454CD0A4DC1B78C2D0F1BF72EC5D64EDBE8CB662F373ED861194F02AFBC8B7133ED9BDDFEEBA8E7C19C58505DF691960346B4F9E0FC1076DE872E6CB4323B8AD7FB4B086B26E10A55ECEB23F6FE78A5224A0679E5EA529C1327D38EDCCD340788D6216D1388B33A8E93B41B0B13ECAB9B7D647BBFBA2181E752B9DE7230C13B38E0988CAD88E2B1F8B8B1C938B93BAD62F250289CE33E3BE77C04B8090B806B031C23413EAE7799E6FB6DFB02ACCD308EA8688245527ED4918ACE575748DC01C02A6420C9CEECCAF8CBA73F16282DEEC6697CF82C880E3FFC8FD149411C6AD19AAF3B30BF2EE89977B7536C9607777F6E4F6E83B84BB4D9B359EDA6A5A1167B6D352F4D6CCE10F2C974EB81CB1C75280406B2F891A7E500BD58648A5A88ACDD1A6D7A2D80690BB441E533171930ABA557A52BD2512E3FD9A3E5DE6A378E3FED42D6ED5480093D3B0E068F2A24B54FF43BEE12BDD5A646B4A2C1746C27328792A4B9528FB45F6AF56C6F917978B535D98C2441EE79D825E73BF97A7D49B5DC85B12B0C257DF6AF0907B771C5EA582C9DECDDC3CC1852AE403FDCA636DB4B111747646CF893260651567C4C63B391013CA9047AE7F77BCE46A16FBE54054CA8D74AE248A5C5A22B841D31B89C82C8D9567A03B249A07FC1CEFB03B569AB328B0028DA5F3D4D2E2BBE076D9DAAE0DA86DA2648E7311709D0A8C6083C42F9FE430418C2597BF533D294E15E53D5E045A95222A23F4CA7AC9FF35A0E1CBFB80227D800ADA8F79FE463F1C9FA0D8A4E9F6C42ACAB07B5A7CE6E1BB649264EF1EBBDE073A1892B3EDA5CF60D0921754A5848FE47F32168A094CAB1D242EF095BAAD113824511114B4714DDAAA585E3A653DEF46A70DB8D43E4813E6A03E5779B9A9194925CC967DF08F1EB9CEC35EA96BB3D78C40B0A4B8AA79D101CD8110E37119267CC3F2ADA62E3CA0F444C22CF5A73D46BBFDE56BBD1E4FC397A9D6975E77923B6E3AD4CAB4A4E3C5EEB01DC1B7690BF44197AAD7D1B802BB4F6494095E708F4A7F9642AAD64B0511037DC9A65663C4AA6046575A56226103E282B61286CFE6BD8672A3C297DB544E3CF08013BD2B32130D21E521351E9AA9F378172ED281E7
-20210526194658 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC72DF2567
-20210526205542 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC789BCF5B
-20210526211855 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC7A83E6AB
-20210526212819 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC7B4A5E7B
-20210526214431 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC7CA4162F
-20210526221404 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC7F1A2A03
-20210526224339 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC817DD633
-20210526232709 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC850A6253
-20210526233209 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC8568303F
-20210527003359 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC8A7766A3
-20210527004505 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC8B60FE03
-20210527005150 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC8BE3BDCF
-20210527010445 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC8CE83F03
-20210527012302 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC8E564BAB
-20210527031004 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC96F6A7D3
-20210527042035 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDC9C9071D3
-20210527051239 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCA0A5F80F
-20210527054907 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCA382DD3B
-20210527055430 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCA3E850B3
-20210527063343 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCA6FD9EFB
-20210527071327 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCAA0EBEC7
-20210527071630 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCAA41FB57
-20210527080058 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCADACEDC3
-20210527085945 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCB22EE113
-20210527101619 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCB8016A93
-20210527102548 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCB8B44C67
-20210527105317 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCBAC26CAF
-20210527111021 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCBC0189BB
-20210527120037 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCBFCB4D7B
-20210527120149 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCBFDA08E7
-20210527125327 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCC3B60853
-20210527125755 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCC4035243
-20210527133418 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCC6B03E83
-20210527141546 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCC9BF3B53
-20210527142810 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCCAA21133
-20210527143703 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCCB42B1A3
-20210527150004 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCCCEFC0DF
-20210527152242 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCCE94F76B
-20210527153438 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCCF7614B7
-20210527153537 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCCF7F4B23
-20210527155914 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCD13EEF3F
-20210527170116 2 6 100 7679 2 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCD5E5A47B
-20210527171119 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCD6975A67
-20210527173152 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCD815F687
-20210527180427 2 6 100 7679 5 C32E7FEED6DD76E659C6961141AEC4C2E086F62A1B6FBB851A142301550CCFC2E424C3D4B1B518D97BB7DBA9B7E0E40408EA5CE767F9276D112391D7D777FC14537F787F3ADD0DA7A45B64E1330E8F7A0D23C5AFB283E766F2BD69FD286599C68CFF239900CB849E720800D52B4D7FDFBE94C6B920AFD4FE3BAB7C9F19193F96ADC0EDE471FCFCD27ABFF54EFD8F589FD4FD5DF45FC03F832C4B137F4AEAE448E9FEC83A8E1BE47FA202A243BE467219C94A5B28908635E9794C4A4D471E17297E5584CAC109082787C01B8C32C3B0D89006EABD02F17D8BAA792C71A3CA3563501206E70786FC09605B91365EBC2F31EAA94778BB63895FE13ECEBDD005255672ED2768ACAA24E317FC4D4204AEF9B69C0A7EE845B3C228A878D385BE603145DFA087D480A41AEDFA887F7B058BBBEE7D702D83611132FDDF37D0ED1D1731B905D73CDCEF06F9F2BE2A1D01099A915F545F8FFE9B42B66C5FF5DDF2CFCD38B50D45620A364650F12A6E9E94D398FBA738ED66C764901F475CC0DB8B328343180DC70E77BAFC3D8F5CD168A9D9985BA98DD632FB6691B178DE4C276FD5EADABB891680118D0F1234C21AE7788981A33AEEB5D357C28B87F82E4D7314C2A5C9C756541C9CA0C038CA03EB4A75324BBD8DEB5817EDBE6EC15FEEE0E94DBADB19DB0C53467935672C9E8DA879D83619277D37109F4002884B45A69693E5E5C0919BB3A11C89D0BDE5B944602222405EA03F1CB8B8C171C1BD01489E5690EFBFD69CE50A3C7D57FB83857B18B98FFC999D0CA1CA5BFE196485D03E6CD9DE2964091827CC7FBD6D4708D6E8C27BD38A40CF06F713544A1A862DC650F13148A039BE09E55765E27E70490EA8D5AB67009A5834ED6972FF8D76F57B4EEE311E2F395C12DF65FB0DB8F9DD405F0CFEDF3BF08C391E628A0230B6F0ABBB4D07EC644DBBFBD4F48F9A89756F1004873C3D9F20E3566B6B1A2E1ABB6C7152EFB099723469A3D4408D0C27106E09D483C705E50556A35691C99B108D5629A3BFF434A196868E460046B26F4D1FC9725A3470229BF840C86EE0FE1239AF1992C6F7E960CAD0E0D82839CB67318A084AE5BBD8CE513C4DE6EC95B74F8CABADCD825775C36247B07F2CBDCF45B6C3ABF0C4EFED04733309D6CFEBE37871B9A4180A84A822742CD47496C310BCECB574EBED53C0BFDE574D49F3E180EF575B1BFB8799434305FAB7CB970AF999407F262FDBC13CC1809B1F34A962FE8D1348D52780C4AA173E769E70CAC6D8C2E97BF92F7624B4631952FC07FAF93E43A1A8C869C3423BD9A9387CFB4B5B8B2D8475174CCA1AF38CC64E514F0281D65A9AEE4876EB7CDCDA776E0F
-20210527185319 2 6 100 8191 5 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F513E1A12F
-20210527185735 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F51429194B
-20210527213255 2 6 100 8191 5 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F51F664F27
-20210527214610 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F52058B933
-20210528000741 2 6 100 8191 5 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F52A61610F
-20210528003717 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F52C738E73
-20210528014022 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F530CE1FFB
-20210528020015 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F5322397AB
-20210528050850 2 6 100 8191 5 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F53F20EBA7
-20210528054438 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F5418B5C4B
-20210528084340 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F54D8C79F3
-20210528091530 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F54FA20AAB
-20210528094806 2 6 100 8191 5 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F551BB35BF
-20210528123059 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F55C74EE33
-20210528123356 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F55C9BEE33
-20210528131007 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F55EF35FB3
-20210528131122 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F55EFEBC1B
-20210528133019 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F560345AEB
-20210528174944 2 6 100 8191 5 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F570F3AF57
-20210528180427 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F571DF3C6B
-20210528235428 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F587F3BDB3
-20210529021000 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F590536F63
-20210529024531 2 6 100 8191 2 F08476CF6891E7C1CE5A873D1D744FC41D579F53B1F877B0F280D44DF57BEBB3EFDEBC7B8DA48C885005E0F3D8167BE79FAA61DA67EAB112C599882D369A7446FFB888D483317B6A7E0A6AC0CCB6ADD70D511AD81FDCDD71D40C5A40B3627872CE2EDD092B2ED810F6F5F3AE3C02D97856002D646C750910C9B6917615BA8D8D0345514B5F7B37EF910BE98C8E42FF9F9C2FE04F3252C2894D67A033AB22CA3B1BFA9FEB208509654755F3B83121AB827BC481F2E435F68EA144ECCC19670F5C234369F97461A9AFEAE48917B2D767E925D3B94C6380F4A1891EE20A1413C358EC93C8D0D34E90C424BCA367AB4B7C63FDFA0931FB8735ECC5FE22694F8E2784389AC68974BBF1FB5196A5CFA63D30464968927752F1F8F216A07A467EFBCFD4078203DA384AC63A6A304AC56114D2BBDF9212F58BDE3AC556E168ACBF0AB63370D44E90D63E5CEDACA9D94F248B74A783E3852BE5BFF73E27F6FAE6BD0BE5A7A014262CBFB7ADB6A29477D9F2F5FB45E9AD5F16C07B06CA166455C83377C52BF61D06D8CCA11B692F7F05E96264C52295C73D6CD991190A54A2B097BFDBBA8B89A5DFCD1FF9DAFD24542B78FF5F00AF78890EA8297223CCAD28DEE98D829750A17298ABE7F3ED70E7370B1CDE1B4F23C24D69F0F4EA9F821B89BAA2D4577A247118EEF70F780FEF57DB587E1F3EAE54748615BE921CA766FC7EC2961E36EFB41CFC607B989ED0C4254057FD9D39715A35C872ED17407856C80C35F65BD181B181942CB5D62710FE60D0347FEEC2AC3ACE45EA72FCB4256EC07C0383B6CF930CF56CDB9803CEE74A66F83ABEF9C75A0D222BF02C3535B6E3C0DC3124A0E603B9E6A89A3BF636305D2174A2B379C4E36685993C8E8B4E44905D2D352B9EE9101910DCB6931C904D16CB0A079B6669DA3FF8F925A3119EF27F4164DA23405F8F135E454D09BEA876E27449E5884884A24833F3BE93165240285E43A3E4B296CAB04891F574787335DDF17085F77B37AFCD8221AB748FCB28CA2C664931C397E2CD70F8EC8D21C467A16A1F33EB1A5E9C0CA80EC81697A40FE6B01753AC39216301D9763D401DE1460DEC6BC546FDB648C79F9A7B80D6A8CD2AC8E09970D52B1FD4D780A51DBDDC4FDCB53A3D6DB50C6959C78AE8E1912BBD9B259159BEFE965834EB8F17F00A10DE857A49A6E94BA5E930998F283CB035C83174B17596B4C3ECFAC1912AB9799A92E2A01D6A0004753E3D2E5F8748A697D4007DF99C32C3E6C1C3DDDDEF90B9539D716DCF3F95CFC4CA0A9D9AD13E570C55A708986D1304740AAE543C4506D96DB45AC0547854735EFAB7814C8FF5029B256DA0C58E6BC618008117E92228B618103642E8AE533D5859178AB2B39E3B0D044195F531E8304DCA4B883E1B2DFDA12663E9D5FE976935CCC1594C6284A68C4CECAAF842F5927CEA53
-20210529031713 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CA36AA3B7
-20210529041139 2 6 100 8191 2 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CA75D422B
-20210529050432 2 6 100 8191 2 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CAB1C588B
-20210529050545 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CAB28E9FF
-20210529063055 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CB131E3CF
-20210529074241 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CB6403B37
-20210529084711 2 6 100 8191 2 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CBAB7BD1B
-20210529091139 2 6 100 8191 2 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CBC6896B3
-20210529091418 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CBC8EBF67
-20210529104434 2 6 100 8191 2 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CC2D31FCB
-20210529114106 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CC6BA9507
-20210529124457 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CCB1266F7
-20210529130632 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CCC8BF0A7
-20210529154413 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CD7337777
-20210529171849 2 6 100 8191 2 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CDD794B1B
-20210529201318 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CE8F228D7
-20210529210612 2 6 100 8191 2 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CEC4AD6BB
-20210529211901 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CED1A6127
-20210529213817 2 6 100 8191 2 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CEE51861B
-20210529215309 2 6 100 8191 2 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CEF3757F3
-20210529215904 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CEF8E8187
-20210530010351 2 6 100 8191 2 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CFB5346BB
-20210530015721 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CFE9B3287
-20210530020811 2 6 100 8191 2 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2CFF416103
-20210530062143 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2D0EB89917
-20210530071701 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2D1208E667
-20210530095307 2 6 100 8191 2 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2D1B675F3B
-20210530111421 2 6 100 8191 5 D8A2E2F024645B5A3FB339A2EF06A3E46CD2AA808530C320F121CE1EEBEE128D6DB4C49492881B35E5AA8C43CAA07E7F69A5C4ECD0EE62A29FC191B9C0DD6955E23E831A0573135B9931D03A5BBCA961410CA287D08D53C0E8CFEC19534C4FECBAD0F2BE625802AF1B504F59A4A88DAA5F52F221E0E9E0DB1396F07EAF2CA88B79D8CF35EF154A69569C545CA1D04A07ADE3628243039985880B79972FB9F5070951D40C9D21C1729348152724531B270C9DEBB5B2C730C72F4EA3932DB44BD3C746E082856A4109A37BA979164881D5B8007807FF1A7E0C48F99DBBE1709585203E579AE201D295E720CDD45B3A8652A7CE878765E699727641410F840871B4362DC51A3D4D15980876649089CE845B5733497FB8E7B2568EF8627EC1BEE0434A3A72094132A0BA0CA102A440952285823FB09684A1C52468193F6E8A6CC9D935C13FCC661DED5CB84B5D5DF721447531787F78AB31AA1D6342460A8B896518640B7DCF3825B52D46469351EF17E586B661D5C0E792C0AA0B0309B8A4BECB3B267BB459C7452387FF6028EEC1C6DFAE3EE9452EB7A7CFB9CDD361B45FF29E6648BD94712BEF29A1C86C492231F710BC66BF8CF83F8765EF6DBA6857C733789DD71245F17C6FA03DD07FCFFBC450029776FDB4F4B411D4B4A98E090CB79B4CF990398FE1C147CE959C8C11D5DE9A4271EA4CA3D8A50A6F7081A2B0F95AA4AD80081511C357D9F15B7547F0A725EED4EE7FDDAE32A3D00512984928679C51375777E968FE3363DCC495300762C7C6D32F4088DB4D4D4449610D05E87CECADA742827EF2B4EF1D064CEB0EEBB01264306F3E24D6260483829576F88B8346764429722BFD0FE3845F541837ACFFEDA101E0E082F618630B741BE1A9E44C677A947FEC31F08EB338798617A09C38EF3FF31A677E62DCDBA2C56D37B1F16AD2B06F41D3E5CDE9A9B7179B6EC46DF99D857521DF29E8012A1AFE6F2F0658171F56EEA20E531C3B2E02864B130BB0BA476F23024DCCA6411CE1BBD1D5C9F5346DB36334117AAF7A1B4ABE86470CABDF862010F5AE3129CA17F36BA89EE3DB83641804EC2455ED75686342E9F339068A77258BBC292E05AF5C233F5B74CA83080CC5DAE01E977E2F7D1ADC36803398B81DAC22DE391F512912148392371C658C416C96C8C3035928EDBB418CF249C9C02793AE6661AB04B4C6C944F55B23CB5621511DACD8EC5C1ECD463620CAC79C38B6CC95FA8993482EA255246D30DA6EA67C677889F56CDF4466F5D968069E152B0BE30B64E1B18607035D7D15503D364B73BAB5582CDF290FE30D2EB7A4F6F797D80702CC448E1153A3A9D882445C73BA490388588F31FA6C14BA7DBFAD39E1CE6B0E2FAD69015F81FF6DAAC56420A478CF717DD952A0DC51B1E38113CF5EF2AC2EC08B6F6CB427A06AD990213C09DB2D2044A90F
+20220414072358 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB5D1B922F
+20220414072402 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB5D3FAAB3
+20220414072411 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB5DA6E2EF
+20220414072429 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB5E5C2677
+20220414072430 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB5E5C4C6F
+20220414072435 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB5E8EADAB
+20220414072436 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB5E9B7C6F
+20220414072440 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB5EBA84AB
+20220414072442 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB5ECDB22B
+20220414072457 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB5F71BAC3
+20220414072517 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB6044356F
+20220414072521 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB60678097
+20220414072523 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB607297CF
+20220414072528 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB60A2A627
+20220414072529 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB60AAC38F
+20220414072533 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB60CD7B87
+20220414072538 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB60F9FD4B
+20220414072540 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB6103C8C7
+20220414072545 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB612FA3CF
+20220414072547 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB6139A9BF
+20220414072548 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB613E9CC7
+20220414072553 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB6171EBF3
+20220414072601 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB61BAEA33
+20220414072603 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB61CF5307
+20220414072606 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB61E8149F
+20220414072607 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB61EB7577
+20220414072607 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB61ED0BA3
+20220414072611 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB620FE4E3
+20220414072615 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB622D2F63
+20220414072616 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB623847EB
+20220414072628 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB62ABB94B
+20220414072638 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB6312214F
+20220414072643 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB633E1C73
+20220414072647 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB63669B3B
+20220414072650 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB638220F7
+20220414072653 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB6398ADAB
+20220414072654 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB639EBE43
+20220414072707 2 6 100 2047 2 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB641D23FB
+20220414072710 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB6434F4DF
+20220414072729 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF6436684F
+20220414072730 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF643C46A7
+20220414072734 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF64668B47
+20220414072739 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF648F9F5B
+20220414072741 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF64973923
+20220414072744 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF64B4BA7B
+20220414072749 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF64E993BB
+20220414072753 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF6515105B
+20220414072757 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF65323FDB
+20220414072809 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF65A7F357
+20220414072813 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF65CC809F
+20220414072817 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF65F46043
+20220414072829 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF666C8F9B
+20220414072832 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF668915E3
+20220414072835 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF66A68853
+20220414072848 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF672C226F
+20220414072851 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF674E2523
+20220414072854 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF67616DDF
+20220414072857 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF677613DF
+20220414072900 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF6792A07B
+20220414072903 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF67AC314F
+20220414072905 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF67B61CAB
+20220414072907 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF67CB88C3
+20220414072908 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF67CBC62B
+20220414072909 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF67D5028B
+20220414072925 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF6879A003
+20220414072927 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF68874667
+20220414072929 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF68967B9B
+20220414072935 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF68D81493
+20220414072953 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF69A1B363
+20220414072957 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF69C2BBA3
+20220414072959 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF69D13857
+20220414073003 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF69EF96CB
+20220414073004 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF69F43F4B
+20220414073006 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF6A06D42B
+20220414073016 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF6A6A7103
+20220414073018 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF6A7B9AFB
+20220414073018 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF6A7BD38F
+20220414073019 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF6A7F4A6F
+20220414073036 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF6B2FC84F
+20220414073041 2 6 100 2047 2 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF6B67F26B
+20220414073055 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF6C025837
+20220414073058 2 6 100 2047 5 E28FC4E08A6D57BC5842065F7028D34B56B517A920144E422159168C0CF6F65E1C9CB385AD0BAFFDA8A78C13A1D32CDC4C0E695426E46F524468E9FF7E423C61B626710F9F3BB9F67F058AC00FFD91AFF9061C88EC8D698F974AA4D7070633D1B7982FA906ED686783E607438859AF0E23BA99392DE67A01D4E2CB47E005EFF3C0DEE0AFFA72D80AD54803FA4C341F6B1B8680C6EB9E3B4A93931485B1F0E92ADA1F3D3F049430454E0C51492C5502BE844CF7AFABC9B6ED351B59098B457C17BBDF6E90B63EBA42E0F03818AB4250668C0F55C0DD8F64D5EE5BFB47713E7935129A97C5B3F917972D7F75263D20B9664DEC37045C7659039593F3AF6C19C927
+20220414073921 2 6 100 3071 5 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB839BF99CF
+20220414074048 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB83B22A8CB
+20220414074055 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB83B38DF4B
+20220414074204 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB83C4E96FB
+20220414074223 2 6 100 3071 5 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB83C952457
+20220414074458 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB83EF76EDB
+20220414074505 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB83F0B3E5B
+20220414074508 2 6 100 3071 5 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB83F1192F7
+20220414074657 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB840C320E3
+20220414074757 2 6 100 3071 5 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB841ACDB2F
+20220414074809 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB841D33923
+20220414074813 2 6 100 3071 5 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB841DCED47
+20220414074823 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB842009833
+20220414074835 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB842257813
+20220414074840 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB8423357CB
+20220414074844 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB8423B8E6B
+20220414074923 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB842CB64CB
+20220414075134 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB844C6295B
+20220414075206 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB8453EA8F3
+20220414075228 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB8458F2F8B
+20220414075251 2 6 100 3071 5 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB845E71A57
+20220414075317 2 6 100 3071 5 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB84648C5EF
+20220414075352 2 6 100 3071 5 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB846C72BBF
+20220414075450 2 6 100 3071 5 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB847A0F4F7
+20220414075521 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB84817FBD3
+20220414075541 2 6 100 3071 5 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB84866A397
+20220414075556 2 6 100 3071 5 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB8489919F7
+20220414075630 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB84916DB03
+20220414075833 2 6 100 3071 2 C51B2203994018FE66AF950975C59F6B678BD895CBD976250E5513528EF9B03B85B0DD85C17B519B1D41CB11CFCF86F9649C411D746E8ADA9A743D09458BE956D59D6C471945A92E1A6AD2B519D24373242BDD1A13BDE5EAE3518F17F8D2EB158F5340F76212DE07E67816FCC95EABAA1568116D400FC2EE789EB0C097AC9E94DB7B6A861F35B7F57C58934FD6034B4352F83978CB943D63921D8B29BC30A5CB5069A31F550206767EAB17FF80BD34A849F05CEA09CE2B374D70B25DFC31DD546310C948F9DAF4E0C873FA5AC0221EF1D761F581AE4C8C890FCC7D16E5A82B4DB3C9C713A3A13E8039D62AB2DC9B4AD3B1BB721D985C2DD6333E9871F5E4D76AC163D90CC629CC81783087DBC70739200FB5703FF4BEA4202FBEAD26311123672F1E6CBD0DA429CD253E4F579D5FFECEF1DDA78D2AF6B6D8B9818E334D42DFF3F7ACAFD350421BC6C551C004FBE620D397EB602AD2CEDD0D61C9E22D622AF8197393CFEB7250F6D13CBC5CB7625242B0CD23B174F66B00BEDA0E4CB84AFEC0BB
+20220414075927 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA416BC45B7
+20220414075956 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA4172ADEAF
+20220414080014 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA4176C3D1B
+20220414080031 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA417A81CB7
+20220414080111 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA41846F30B
+20220414080114 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA4184B28B3
+20220414080215 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA4193CE3E7
+20220414080230 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA41972BB5B
+20220414080234 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA4197B2B2B
+20220414080256 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA419CEB82F
+20220414080413 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA41B04B177
+20220414080440 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA41B6F0F87
+20220414080455 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA41BA8FF03
+20220414080531 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA41C38E9AF
+20220414080538 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA41C4CE0D7
+20220414080549 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA41C714107
+20220414080559 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA41C93CC8F
+20220414080612 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA41CC0E6F3
+20220414080632 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA41D090397
+20220414080739 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA41E0CE6AF
+20220414080844 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA41F0FD883
+20220414080927 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA41FAF88C3
+20220414080944 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA41FED798B
+20220414081010 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA4204E96A3
+20220414081036 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA420AE22CF
+20220414081101 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA42108AABF
+20220414081119 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA4214499C7
+20220414081154 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA421C7C413
+20220414081217 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA4221AEE5F
+20220414081236 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA42261B5C3
+20220414081253 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA4229C2F0F
+20220414081339 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA4234DEBD3
+20220414081352 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA4237ABDBF
+20220414081357 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA42388B4CF
+20220414081406 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA423A221F7
+20220414081420 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA423D608D3
+20220414081459 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA4246BBC83
+20220414081542 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA4250E9783
+20220414081700 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA42630DCAB
+20220414081734 2 6 100 3071 5 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA426B23DD7
+20220414081825 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA42776DBCB
+20220414081912 2 6 100 3071 2 F5A593C9AFA507A500AC0F2C6389F394E8818163FA32B928AC5A46FBC5556CFC88FC789A9EE0E99C002FC4E3DABCAA2BF268FD7FB49A26E986A300CAEEED3C55E43DD1681074B52C4DB264879CE4B96F2CBB172EBBEE34A7E87CC3818AB3E6AAF135C7CDB655F220B93C32B2CB69F538CCE40AF86994CB6D80D0456B3CAA38C46B0D09C0D26C8E67D4EE6E4FE219AC92FF244216E6DCB4267C0DA00E906730792FA9BDA189B9CE5D552B04F1314418936BF02B08FE3AC2033A6B17DF3956D1316FAA6347FD940DDA68FB8AAE1B42E225B2CB8C81BA82DD05A0284F4C08DA48B991DFC1DD08E8ED02AA3FAF82E34CAC009930DDA85040A5D380F8B9B79F69F46D860319636C5931E1C25EF07F5B3D9964ED066E8E0D1C9E73121907C3A27EDCDDBD231B0BAEB124C13F1EBAC60035DE0017D5B0DABA74763096E26F7C9A7394B73BB65A7733F2A69FA6B0D8543CE3D98C083DE93B48BF974556CE3B0230DE2B13D4BA011DB8272BA6DDAF54E0E26E10180C03397156FFCAE19A95ABA4282A042B
+20220414083041 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB23411639DA0F7DB
+20220414083420 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB23411639F33C3DB
+20220414083538 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB23411639FBF5323
+20220414083742 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163A0A39C73
+20220414083748 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163A0A515CB
+20220414083806 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163A0BD1AC3
+20220414083844 2 6 100 4095 5 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163A0FE2EEF
+20220414083857 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163A10F0FBB
+20220414084033 2 6 100 4095 5 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163A1B65ABF
+20220414084433 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163A3641CDB
+20220414084513 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163A3A411D3
+20220414084808 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163A4E0E273
+20220414085212 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163A6A1D0B3
+20220414085536 2 6 100 4095 5 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163A81A77BF
+20220414090236 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163AB233EFB
+20220414090316 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163AB65D58B
+20220414090426 2 6 100 4095 5 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163ABE1A11F
+20220414090629 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163ACC285FB
+20220414091059 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163AEC45C03
+20220414091158 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163AF2CCFF3
+20220414091314 2 6 100 4095 5 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163AFB69BF7
+20220414091552 2 6 100 4095 5 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163B0D7D40F
+20220414091928 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163B26330CB
+20220414092153 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163B3673963
+20220414092830 2 6 100 4095 5 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163B62CC3A7
+20220414092943 2 6 100 4095 5 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163B6A8C34F
+20220414093010 2 6 100 4095 5 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163B6D25E3F
+20220414093441 2 6 100 4095 5 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163B8C7B5FF
+20220414093544 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163B934C513
+20220414093731 2 6 100 4095 5 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163B9EC8F87
+20220414093843 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163BA69E11B
+20220414093925 2 6 100 4095 2 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163BAB069A3
+20220414094303 2 6 100 4095 5 F32919EC12E2FE5DCC900B63D26BA6DD1030C9D818431D43D7629C26DF0B797B85C4DE6D39A179EFDBF452D6FAEAFF7D89C80E2BF78133324537D863C67C527C8C8D321CCB69E1B4A97675179F0D581560D1BB4CB5FC0EE1BBE740DC53E81D509A2AB1C502E02196CB7910868E93FE8151C148430654A623949C8C985F169D78CF7143FADEA9363103FABE79F14F966061DAE8202CE667C23877B4375148E3FE6969270D90C0BB11983A725320FE2E110452D56CD29924687638285FF60F528FBCC8F9F21D1AF2C150265F6846BABF083F10B43D92FCC02F5794034DE043ED9EDD2088E590314930FDECCAF3BDE0D07ED9DB167BF2AF1634EF88C77D3016BFC17B0903449E3611BE247665FD4A2A4F1D988C67BA1B81B4C9453ADF5C98EEB584C5FB25F8B0EA3606C80A459DD58B0D10E50FE9A7E062E9E918765B1C5D2BE056F846BC7BBA649F2BCE549B2FA5A55D3F31388C1EFEA4E8F2800A2A050E8468E8DDD4DA986C6496159A26E2CA9CA26415EE53F6403DAB022C1F19EC1B311A39495AF6A82BD1FD9AE47BF5C10B013E7CA7DAB015BDA7B60EFA5FF4916BC6CB81C5B6132AA9EF4E49716D98FB66C349CB956DDE33CAAE1BEA93AC395C84B3F58FCDAEF3F58F9DEF5F7EDB527578D1711A754BFE19718A41CA16FAB7C106194455EEAF4E0D4FA29D2BF224B328F7B546382F2FB4E8EE41C96ECAB2341163BC328B97
+20220414094931 2 6 100 4095 5 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818DA7CECB7
+20220414095121 2 6 100 4095 5 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818DB3FEE97
+20220414095821 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818DE590FC3
+20220414100127 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818DFAAB9F3
+20220414100220 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818E005F20B
+20220414100244 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818E029D1B3
+20220414100254 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818E034AA33
+20220414100620 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818E1B8C073
+20220414100630 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818E1C2553B
+20220414101142 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818E40A1E13
+20220414101258 2 6 100 4095 5 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818E48D9E87
+20220414101626 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818E60387F3
+20220414101801 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818E6A9F503
+20220414102152 2 6 100 4095 5 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818E84F18E7
+20220414102225 2 6 100 4095 5 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818E886BDBF
+20220414102443 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818E97C4BFB
+20220414102556 2 6 100 4095 5 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818EA01679F
+20220414102609 2 6 100 4095 5 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818EA10FE8F
+20220414102639 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818EA3F86AB
+20220414102917 2 6 100 4095 5 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818EB641A1F
+20220414102948 2 6 100 4095 5 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818EB94F7A7
+20220414103222 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818ECA88E23
+20220414103323 2 6 100 4095 5 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818ED15B99F
+20220414103354 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818ED44961B
+20220414103407 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818ED54ECC3
+20220414103413 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818ED5700CB
+20220414103734 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818EEB53ED3
+20220414103800 2 6 100 4095 5 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818EEDDB6FF
+20220414104012 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818EFC5E0E3
+20220414104150 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818F0739283
+20220414104329 2 6 100 4095 5 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818F11E163F
+20220414105100 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818F451B803
+20220414110021 2 6 100 4095 2 E8B371757422F6F4C734F2E4380126789768169B37154E4E3A4A74A3DF6545653A5970CDE0F0BD17CCFDAABBEE7568E1285D5A704BB9739EAB680D7EF59C134D327B55CF4AD69A4128536E2F055F5FBF0DB661C322A4993E382B997B2A0C5E434678B1910862AE385C415FF811BA11727CFE39C559847E710AC2D4BDA8D658F2259887E78D54179287BFE112E9C532CB1D062419DFF6E031F82EC991523A1144385189A813DFACBC63D8DAD98199696715C6BC5A22A1943B2CFC4BDAD8473FBEB7BCEC204EC12CFDB1A9BB66DCF85B3121C9E1C3587960769115B2F27ACEEC29A1CDC717B7505A561051F0E88A3C51798CD829E234ED14C277E9635B3E05EB13FA36F117B46094CA68F45F3667D6E84E0214F1650BF080CC4CC5510D6569E0226E88CD842B2ACFBD31370B136E5FD22C6697090586F38323AB36FB5569FB0FD53BB4AF10C16F0B809C1FB5B1B1C56027244F5A174A37250721197CE425CB5E5C5A51D4A5EA4A1EBEED71511BBE0BFF03CB1AE76968166167A775AB1AD9C9665C6ACC04203E5B2E80AA9F7CF395C28EC432A36A97CDBB354E20BEA600F383D7729DE8B9DF5B16B721BEE8C6ADF51DA8EF5B7B3367EC8E6788F9772835586D09A9F8423AF1221CA87CBD54EC399E0BE49AEF19C017EEF36B3B18517DB2246EABBB21F6DF5CA2F4E1D178D0F42384CA192AA1461452BBC453FB59C54818F852CDBB
+20220414112534 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31B97D57323
+20220414112820 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31B9836476F
+20220414112915 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31B98509153
+20220414113222 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31B98BB7CAB
+20220414113851 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31B99A6C927
+20220414115900 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31B9C9A8187
+20220414121305 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31B9EAC674B
+20220414124550 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BA38974A7
+20220414124932 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BA40E655B
+20220414131030 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BA71F8DAF
+20220414131803 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BA82FCF2F
+20220414133154 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BAA30669B
+20220414133700 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BAAE42927
+20220414133729 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BAAECA503
+20220414135933 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BAE1D12A7
+20220414140132 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BAE5AE7DF
+20220414141651 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BB08CFCFF
+20220414141714 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BB091AD83
+20220414142320 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BB168D7F3
+20220414143527 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BB322E33B
+20220414144127 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BB3F516CB
+20220414145100 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BB545E7CF
+20220414145934 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BB676BF17
+20220414150941 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BB7E51E57
+20220414151158 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BB831F3E3
+20220414151904 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BB92D7ACF
+20220414154448 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BBCD2236F
+20220414154556 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BBCF2D2B7
+20220414162116 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BC1F88833
+20220414165146 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BC6458233
+20220414165524 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BC6C0DCC3
+20220414170020 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BC7669C1B
+20220414170406 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BC7E116A7
+20220414170516 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BC802E3C7
+20220414171447 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BC946FB1F
+20220414171849 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BC9D13AEB
+20220414173651 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BCC51B887
+20220414174909 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BCDFE595F
+20220414175707 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BCF0D967B
+20220414180209 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BCFB6BC33
+20220414180857 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BD09DEC93
+20220414183147 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BD3C3862B
+20220414183832 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BD4AAE607
+20220414184336 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BD559A367
+20220414184426 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BD56C4CAB
+20220414185501 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BD6D7EA1F
+20220414185956 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BD77C34DB
+20220414192107 2 6 100 6143 2 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BDA56DD2B
+20220414194147 2 6 100 6143 5 C008BA5D87ECC10B5E79F4C05438A7EAFA57C290A50C25A0DFD5FF2FF19F5D39568056AF4AA2FB56F1CEFB636A5E30D99379305FE9633EA9CF219FD87C501640F500E2AFAAF304B7EF862B6C4C8339B558E3B8F00AB714AD6460786AAE3B328D41806A94F270B4D1F13B958579F3C1A7ACB166FB2E5566ED4305AB36C357852B2ED67D4C877338D891E0FFBBDE512E976B754CA2BA1770D8CE7117D5CEB99715C99D97285F3744533CD9BE72A4FBE2CACD4796FA3EFCA27CCA1F7F96DC2A521CCD7776125A5DB2EE4A12B1DCFD797C47188CE5CB6859ACBB452F922F4FF7E2098CB090F83812A18D8DD9B7465B2572EED81332A84C1591F1BA1633B571423FE38BAA819B0AF2C30676B00EBD98D386FED880BB6D9FF4A05C206A8394E973350A597FC337260025BE097EB7409A182C500853B9C90A096708BB83A80F2EEF4EA23190B9CE095C92A1B675903B07149C34E9FFAF6908BCC27D495AFED5C652242B939F71690748895E93181C746CB6E94C2E58C97149F5F3FE3CE552F44AA859115AC5459C3CA343EAC5F98D076E661EE24E15F22FA81393F85E7D1B26FD4D6CC1DC7BFAC0E1C97438141A98D65EFD1592D4A1211DC089CEC0903DD7F333F55FFE70609FACDE7B7293036BAAB67E6DEE7FB82E16019AF642814BFF4AF6676446AE656ACD601812A86B8DB9A53A1EBB744ABDC7C88DBABE4AA023FC253B56B3B517DFE66156BE7DB0653B3DA80ACF010125D652C38DC91BBA2C247AD9F769A9C2F8FA16A0B0507CA632612F9AD03C5E281FFB3341A929E1EE9A946889AF525B348DE24362FABAE20E583D67B4624C96053960F4744BA71C1911D5A84B3615CC8F52E23C10C38E542B61969BD82257B2BE5B50EF63B5110D6D23B81D33176473020D363845C45BD03D2AEF81F2A87C1BADD4C1248A3004AE57562E38B0FB10124E23DFC0AB9257F5982748E39610A46A974459A2F30D852D560D45BAABEC8B8BE77F8AC9AC2424F69FBD9E23F226FD7FCBA827ACCC49E9EEDDF659ACA0E931B965401E416FB6969743B8CDEC4DEC49648D7C1B82B7B337AB496F9C5FD31BDD2AA5D7
+20220414200557 2 6 100 6143 5 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE440858687646A1E9F
+20220414201020 2 6 100 6143 5 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE44085868765073AC7
+20220414201829 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE440858687663CEA53
+20220414203003 2 6 100 6143 5 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE44085868767F30C97
+20220414203735 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE44085868769010163
+20220414204108 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE440858687697DB9D3
+20220414204650 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE4408586876A4AA523
+20220414210821 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE4408586876D725353
+20220414211625 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE4408586876E9775FB
+20220414212842 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE4408586877066A0AB
+20220414220717 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE44085868776159A7B
+20220414232618 2 6 100 6143 5 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE4408586878185133F
+20220414233421 2 6 100 6143 5 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE44085868782A4E2C7
+20220414234330 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE44085868783E43363
+20220415002146 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE44085868789570393
+20220415004554 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE4408586878CBF2353
+20220415005307 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE4408586878DBC5B9B
+20220415011041 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE44085868790357083
+20220415011858 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE440858687915FF2DB
+20220415011944 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE4408586879171F173
+20220415015846 2 6 100 6143 5 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE44085868796EBC7E7
+20220415020913 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE4408586879851976B
+20220415021312 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE44085868798D86EA3
+20220415023006 2 6 100 6143 5 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE4408586879B22E39F
+20220415030146 2 6 100 6143 5 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE4408586879F87F92F
+20220415031549 2 6 100 6143 2 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE440858687A169CCAB
+20220415040641 2 6 100 6143 5 ECFEBE907ED5229E0F2A017AAC2F662065526E4CD6767D11B9BC47C5C4D0E39E232885C9039387645B0C61FC91A5B5F97A3A3264DC42DD48A30C3E923D467D8CDDD98F0DE77067BFB45F466CA03EC5B86BF836D9C6298948D315FF4627FE23F62CE3E722A3B60F7D9D6F97D4B10E30924ABF0E094D5155F57DFBD93B17A3E958816225D458E063A4785F4D04A131D6C3AEFF9B405648DC2E0A64F061AB428E6C3B69C65266514A729829756E016CF55D1A917D9CE64ECEA6EB081A85F177BDEED9062CA130A23BB3D90817644F84890C55BB158DA2C0F590826B7073E933EC081268331D56BFB282D4DA250EC39EF3E477BAC8E5B64B712F4457C5B116D0D491AC7AF0E68F3337A51AADA71152604FF386C9CCB4F67204F6A2FBDBE18E5AF591DDA0B5A93382BC210A549262C0A250EF2CB3D3009C4EA412324E359DBEFF97ADA37287D08C11ED12B170B06B8055BC5B17B3F464BFDE141A145A6393750FE9D5EF33C33A43B575091076A24A9E67C56C7B41F023C42166C89E57D001E9161E924A693FD3712355AD60EAC3BD8AC16BA15F5BEABEE3D014B7F5361D7EB36B3F594E1BB98F6813A2D88FD6FC9F008713334AE962B0CB4C07FDB32D549C0F24D127486707C29A7F5EC7F8601961D2E4C189BA3129E48D0D2215E70D9115AAD993E78565715E50EA0E336EA456D469A23368CFB3F0ED6B8AC77738B2A2AC0A7F155CF6D402687212585A2DD9EEAAF614387C7C8D3089D3F42DBD1A594233ABB618AAD84D52F8A234281F2B0F62E3FE23B1E7F28DD89F6F79572506F9B02021CE44914237C190C82F1E5CB395844550EF279E9B50FA1D5B7AE84FE9F31538546244BD4C86FDADB5974396692A7BBE7AD493834DD13418929F8EA0F44BBF8E3D9DFCEF170DF138351932FA05468DE9A922953DF5AB791406E89F752A378A0D98A957773EC3B952DAE04200C1944F30B43D80450F8F83AC4F688D806DE9C9C406D30FC0D9098BE612EF0C4AD2E80B2C746944C727A1015538A53C69280EE0F00D6601CAA6CB0EAF4D3DADBF849D4C1F8F1FD7D438619C70364DACE440858687A85F5E8F
+20220415055156 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E02A82E93B
+20220415055855 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E02B0AF64B
+20220415080431 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E0357CD26B
+20220415104028 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E0420DED43
+20220415110553 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E0440C48AB
+20220415113849 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E0469931F3
+20220415122158 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E04A10FEC3
+20220415125947 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E04CFE8C63
+20220415130450 2 6 100 7679 5 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E04D5A7257
+20220415133311 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E04F929113
+20220415135605 2 6 100 7679 5 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E05156D2E7
+20220415142115 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E0534A50FB
+20220415151250 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E057418E9B
+20220415162045 2 6 100 7679 5 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E05C89A9FF
+20220415171606 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E060CD4F4B
+20220415180941 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E064E85D4B
+20220415194613 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E06C3089C3
+20220415202412 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E06F041BA3
+20220415204136 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E0704DA05B
+20220415205914 2 6 100 7679 5 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E07193837F
+20220415225928 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E07A9B3103
+20220416005936 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E083760473
+20220416011857 2 6 100 7679 5 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E084DB18EF
+20220416014012 2 6 100 7679 5 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E0865D0237
+20220416040204 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E090AFB413
+20220416043614 2 6 100 7679 2 D73E4A149D00067AF38F615C7920E3E58F83FDF73F493F4712369137702E94062D5E0857DA1D94CE7C7660F89D285B5DF0F8FC8A8CD2FF69819BED74B0F05EAA467BA2CB1337A7F6E9EE06670C393AD6C845C1743F511BEE7ED9D65AA1BF3FD41BD6F0EF131358CCEE448D0EFEE47EF75D3F4AA2FE7A70210CE62E2C6F791BCBB4852CDF41C5EF6B481ABB954A6AB79AB82ABC543C6CF66F971F590ECA63988A886308218202016278C80C8F7142E1CC482FCFC313123AAD101AF837EB8A210CE3522F0554FE4A00C29E51510678F9DAB40C21A644BC9237D982C24AD1788C3D20F6520144B491C77DB1C53CE98726DCF09DBD1978573CF32848096B44A72CEF3221D98C44BB32A524549A20D822F5531D7E7875B1B564ABDE9EE100A90A8E51B37EAEAE3E89E3E8348F3BC9D8FD284E0FA829406C5D8CE0826CB3EAD353B6052B9C7FC1CD4967090AFE5F2BC11B3280C93278A1396AFC640AD8AFE9101965306601723E689714C3190C41C4D4635F1541241F452C981A5F574DCE109014A274CDBA4CE6AD7C693AA7D3F18418AA4F1487E657858DF460D53BD835685581BB461310DAF203B67C23E0C17ADCD024033C40EEF27957151D01971F43254C6C4E3D86F6ACADB8BCDDCB300A21FEAA54E59A547C9C06ABA312A5B4736356230580FBCACD3FB08626BD622934B81B8697291C6DCB1124F7A6762DB30B9CFA22A92FEC007E7EDBB188F34755C350A884DE8890D0E5D6F491D9C23D951DEBADCB26E1D25D971F5FD23FFA0BCAA84646352DCA69C7A3BB991961E762E96C48E58A2F8FA52DE7CD9FE7C529289A73E13032154349ECA5CCCB3D5B89980B29872AC5B03EBAA726CFD9790AF85E371F0A5B0588E4874EA300C5A370ED42A97C6E372D1DB9825EA995C0B5FABFEC09A632010EE138E8E35794640D65CA647ECDDC20A4D453CA4C35EE78350A8045B3CAD6CF41D3DF5260E355EB03E819C0068C91C2F530F7C74F680386947FE3FD00C91C5CEB7D0AF97DDC251DE856355D16F7CE88E69B20BB20BDB3204C63EC00277B7D5DC9A77682DE0750EBFF7313289998DE1C6E940F0B172A173531140FDA7A3422FB739F8F1647907355B26C37A47EC420791F68C61CC7A55CA855DE158B43D0DB363153AB9F0DEEC632AE784F62775862C4319971738352448A4D653C1CD7380247C05D56198D19720CB284E6CBF137616D8DB5510FBE81A7F646E5356C998B56125895D10ECAE67FD4CCD73FA78ACAA774DB11BBD5314ABDA3DA139107FCD342BA6CBB9BDCBED536411BD50B38F7234511CE74B1362D07BF71DBD033E6F637C45FB0B25871B173BCE2337D963AD41693E0932065A3
+20220416062823 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB80218A9572A3
+20220416092832 2 6 100 7679 5 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021995B7A27
+20220416094426 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB80219A994F8B
+20220416095028 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB80219B0F266B
+20220416102802 2 6 100 7679 5 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB80219E13BF97
+20220416120843 2 6 100 7679 5 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021A609A13F
+20220416133156 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021ACA2E43B
+20220416135357 2 6 100 7679 5 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021AE55C347
+20220416150622 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021B404E4E3
+20220416151128 2 6 100 7679 5 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021B462EA07
+20220416155217 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021B782687B
+20220416155712 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021B7D8961B
+20220416165422 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021BC44747B
+20220416170631 2 6 100 7679 5 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021BD2BC4F7
+20220416185708 2 6 100 7679 5 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021C588EACF
+20220416193124 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021C8261C8B
+20220416194631 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021C941917B
+20220416200225 2 6 100 7679 5 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021CA6E54B7
+20220416201249 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021CB31B7C3
+20220416204005 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021CD39B303
+20220416214143 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021D1CB213B
+20220416222645 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021D51E3AB3
+20220416230352 2 6 100 7679 5 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021D7D44ED7
+20220416234159 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021DAA0700B
+20220417010500 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021E0C9B503
+20220417020435 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021E5207D2B
+20220417025157 2 6 100 7679 5 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021E88D137F
+20220417032310 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021EACBFA03
+20220417035624 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021ED21FED3
+20220417051440 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021F2C36493
+20220417052159 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021F342D84B
+20220417052424 2 6 100 7679 2 CBC85C4D4EBCF255C5C59577D8AA5AD90A69B25B5296F0E56375785F984F7C899F7F9AF6B2C9194B15A6986941981AC7F389B6B4929F2E376CBF404FC982D91B1D5D8742069C5FF04CB06F655261C68FB38232C141DF7E03297340FA6687EF802A2A9B616B998F04BA24B6657E65250B52DF17531834455D250CB3A0E8CDD070B4F89C82F996416365AB47F1028D66207A6BAD8BA74D0E27BB3CE3F234C59C9CD050ED201ED5C816CAA3DF52A43C612C1079BF51304ED475DDDC73A289AFFA650FC7C4C568ACA26474BD48122BC45354B3AB4F070F6B91F64DACB2FB6F3A6B9FC1182A6818184DDBDF76226DEACA74B78CBAAB347134ED242212BE83D5D1BCD7CD70040518875F00402BBD118E941AF4F038674617A6BCA30F22F40CCFBF6138C854020BDFA5D1336B55081EB46965F647EB1EBD9D290056180489B1E7104FBD061B751D0472124624607D2E6867F7079C0531FECF05A79ADEF6F22DD6FFF9431C6A077BAE0384D447F4085CC805165DD8EB9C8C309B2EDD032DF0D4568FC21E428D6049D809567C707829579A066AA7F62C70EC559586A0749109764F5AE32CAC0C2127BB3654141BA6F87F1911671906B60D77BEE322D71515086B4E9BDA8E853DCF1906CFAEB099B0A1BB5EF0A06752A9C89EB506C773DC12FA8DE2DD8FE789624D80406619AE1BB342C7F01F424E4D5908A02731F051996721E2C0CB6703E131F4B5D1768E386783ED41C1C1318F9E19D995CFEEF998D5659D4A9FBEEDE6313B9E4C1665F1E44BF213E66EAE4435DFC2533EB131F235E0075F406028B650E758F38A582705423BB661A095D24E79B6A1D5C6A36989B28FD2ADA228961C1574187F18D419B46545D7FB147358A8409F5CA3ABBFD14EDDE9C0768E84E77F6E61307908F0DD8CD49B9C413EDE4FD13E4D1FB5CFB0075297258D828C20FD01A261F8D5672BFD190FAE191250F533B548B5469879E8B6BDA77D650ADB83AE9FAEC37FBE8A9F5F85CF47159EBC54A9129692A2B253C735E2F629D183A2ED4F2747BCF143D6D673F0F3703D0122BEDC5255F003311A81FA236D0E93D6CCC3375C4C35474427756E58A245A8F0AD68F1226BDA8ABB969A68B0758F1229038CB16711996B27923A0AE7D81384C24763C72B72B6A23A6EED923D0C70A3E47E47BD572A3398F3D651614A47C942A26F785F75A2DE7EE6FC927BE209729BF52943889E8C14708F592036BD3E3E4990659A13D64A755C39BC588B7D03BBE6129A39746304FEF371C760B1986A6FBF4DD588873571984B10FA6624239082E2273F772BC4FB28BC1E57DCCD35511FB1303BA03BE961D3788131E7A106A63BEB8021F366931B
+20220417063546 2 6 100 8191 5 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAA824C207
+20220417073924 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAAC98E38B
+20220417084530 2 6 100 8191 5 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAB1415F77
+20220417090433 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAB29029DB
+20220417091538 2 6 100 8191 5 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAB351952F
+20220417105457 2 6 100 8191 5 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDABA287EEF
+20220417121015 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDABF594DF3
+20220417131800 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAC3FF4F83
+20220417160405 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDACF38B053
+20220417171411 2 6 100 8191 5 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAD3CDA357
+20220417172520 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAD4899F6B
+20220417200514 2 6 100 8191 5 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDADF12383F
+20220417203736 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAE12A45AB
+20220417215125 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAE5E926EB
+20220417224905 2 6 100 8191 5 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAE9A3B337
+20220417233642 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAECA4D2E3
+20220418001736 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAEF4202CB
+20220418013943 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAF48042DB
+20220418030345 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAF9C843DB
+20220418035729 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDAFD2E683B
+20220418071750 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDB09CEE313
+20220418075023 2 6 100 8191 5 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDB0BCCA41F
+20220418080602 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDB0CC11E8B
+20220418082746 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDB0E073263
+20220418083338 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDB0E5A8D33
+20220418100322 2 6 100 8191 5 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDB13D22C2F
+20220418122110 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDB1C284B33
+20220418125647 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDB1E510FB3
+20220418130116 2 6 100 8191 5 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDB1E90B78F
+20220418132740 2 6 100 8191 2 C52C5842553651D384813D75CCBD7B83BD255568A4C68FF4D52E1E7FF21591F027FCB743BE99262A53363C83B0A9C2D2E1C1DAEDCCF76A89344F891B001F588691CBC39D7582E69AB96E1E7A2AD2710D4870E1270A36FB44D7D358B0E7EB06AED2AE31FF68CE0198CF3A59EBAEAD81B1C823C4D88F490C2923C993D1B9E267E50DD8FAD09B83CA87A831B31B96DBF72089B9576FC5AFCA41AED93BBE1D5C627255CD02D6F98D097F8FE1F17B1B743B6E66DF5AC512AA430F04436E06793E7E73A914750833BC69830DEEE6FB57C32C3D7941529B915B1C4B6F37FCEC221A9DA83F050D47EA10DD4546309BB15CDC2A25C287B9A16CB0B2BB663A3D64BB7C26107034804C2C7569ECACBD609EF8A68E19768F86476DAEC2F12E14C325C5498DAD1BBFA5AB8F139E588C3B6BAE947D14283E944443B1DC19896D61730F5EA8A43D5AB9E48EC3861DC3D740FAFC39C408DB1E86F96681D630158C66FE42E187ABFB18304CDCF2718CE7B04F7FC55B78A19A0A43FDDB6CB9077FD680D50989DB1EB674BC03F20A1AEB6F9C546515F6C32C4276E5297A4A3AFBE8E6026C10FEA7F791F9049D0768668AFCCAA2D18878190353C870C6E9D4AC0DABF50BDA3B25EB99528566B9E0FAA44711FA57D1D15B75E00CCA8C1C0E76CDE80607556AAEBC173E0025FF7B05858610B85D868C92789BF1A9736B93E6B4AD7EB23A99F83E69B82BB1BFA26696C68D1066566AD45AA1BFF3C88ADDDF4181E9B9733B2D310B360D7865E4853C72AD5CA7614988B631926C237CBCEF8BFC9F861F9BD8FD92CACF2ABA9A72521CD7AF9465E00CA0F3CCECDBFAF75C148DEC07886536E1CCE9A68620F750657DD7EE912A1B9C7D35ED9AD81984544F7221DB21F2B47FA71BC1B76CFD51D3796F04323FEF98802EE57DE86BF7BC3C27CDAF15F00824CA24C928E0A2E9DE4E66097E382DE41B32769CFE9853EC1EB4B788364E9DE1CEAE0DF13545C9FF6DA8C0DC9289B4BE38A3600912AE233859D59BD1CE3A44C4EAFF6B1548C5D8CF7A63E449702ADBEE391C3BB1FB8A7217D74AFCEED66EC0E7C448B4B0D3FB011D666598F238968B66A3BE5D0D2F7E3D1D8D93736AE5FF605D8E17696F4FD6386FE2DB6BAEE6D142D184F5C088F9FC4DC05C1E7005092A6E7214BA7E5E85A7D9666A10B9AB7C14425FA7A1D82910E4B17E9B7DB09DA89CAE91D89277814A46A6F20E70AB75C45B0BD32227E0F7085C84B8A3864C25FB684DCF5B4512C46E04C7CFE7911C5E256CA017186A33447619E65C1839988874FCF00FCD2BB7FC4960B1107045898573AC4C7A7F0E3C17AE2DD5FBB92479B55517D435B4F582EEBE2CB6B926C424C3F1243F6FDDD33184E4132C08AE4DA1ABF5C5036FC8D3883855251B8589F7147889A37A300E7EAEDEDAD9262B626074F039DAE19BEEFB84320EDB201DF103
+20220418144902 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67858150C3
+20220418152824 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67884BD073
+20220418171630 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD678FEE66DB
+20220418182724 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD6794E3AFCB
+20220418183435 2 6 100 8191 5 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67955AEE87
+20220418185712 2 6 100 8191 5 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD6796E81A27
+20220418201627 2 6 100 8191 5 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD679C621EC7
+20220418211708 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67A079830B
+20220418213706 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67A1C79F63
+20220418222050 2 6 100 8191 5 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67A4C4F48F
+20220418224223 2 6 100 8191 5 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67A634298F
+20220419011431 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67B069D573
+20220419021153 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67B43DEC33
+20220419031338 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67B845003B
+20220419040146 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67BB6317DB
+20220419060359 2 6 100 8191 5 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67C35DBBA7
+20220419082948 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67CCD1BF53
+20220419084823 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67CDFBAF53
+20220419091604 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67CFB4406B
+20220419103659 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67D4D81393
+20220419110019 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67D653D053
+20220419124806 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67DD1EC41B
+20220419133200 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67DFE53A7B
+20220419144722 2 6 100 8191 5 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67E49063CF
+20220419152308 2 6 100 8191 5 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67E6C7E127
+20220419161040 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67E9B7FA1B
+20220419172345 2 6 100 8191 5 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67EE2EB17F
+20220419184212 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67F2FFC2FB
+20220419184630 2 6 100 8191 5 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67F3381C0F
+20220419193320 2 6 100 8191 5 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67F608FFDF
+20220419193640 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67F634CE4B
+20220419204750 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67FA7B8963
+20220419205514 2 6 100 8191 2 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD67FAE5B15B
+20220419225936 2 6 100 8191 5 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD6802713B8F
+20220419233957 2 6 100 8191 5 CF0A168167DAB1FDFD5C0376DC6E2C93907F486EF5576F14B83FAD667FCC774D179D9A0CB69771C381E7A3AC0F7561E06C8BFD155A9B527EE6F015BDFF6DAE1556CEB985BAAA83E40720B4D91830DDA2BC4BE8C137AB7EB0107D3E04DB39A092C84AEF71E223A40F18B586FA813ED2EC4453A8C15B3531DC651AAFA6136D5BA894B22FA94E96D6034E9A569F4D3366B323D656B5C480D0FC443BA5597B42071CB28466F084FA31856AEAB54268E7DF559C47D0F53F7584273FD41C9C59C130E9E43B0E5664B1FFAE5D3608EBFCDCA6E257B0AED1E270938A03C7494B16E725389F8106CFA4746BD350EFD6688AF36BA679CF2437E25C0335A4C7E51AD3043938D7D49EAD349D50B153346687EC29B70982760D6280C1B92F58AEFC66BAB600A905A40B720A8E75CC1C1D96557F1988FF927ED6C2C614357242CB03E314B19766B1C7D70575A1607B25C6E90F2412DE7D3F140B3B6CD743FEE66DD2F32B35F34C1C4F1523B03F9E68E873FB7697D0D09D387B8E4BA6FF9EE302A8B6D4BEBA2659E8933B8A411BEE451870CA8F388C96C0D1A59F2BCB29CBD5FFDCA855A7A9720E7BCA71037B417D9D54EFED70FB695EB8E3461262884DADE4C7E2F9ED544D650CB9853F1AEE8C48FD285F8C806823065A238AD70A99C832C815970C33E8326ECC759378A603C77D20248DFAAD6AC718D5F04AF2635061C904159E1EB37873B383C7A244C81F58A22553B1DC1A74AFB44B44A5AEA3B096DEB8B6FEFA7778ACBE1B1EF0331B2667611340085C51D092DD6AC47814A4D68384007F87EA2EF20E005ED221855CCF2B67FF58CAA28E40CD9C44586CB054670C2B0EF0E6B73852B5B475409BDD6A6042345630EB1A675F51A13F7453936B72FDACC671D863DEFE781698B6AE6CE15FB6936A27A9D5EE7442380812B8EB4FB525A518239E138112E6BCA6FEA3FB27B30E28F6D3084D8B5E01F20C7D3FD7EEF3E3EB55F392717BCA9CA76900EBADB7AEA8A26F704C8417708D51374E98D61E0D649BFCC0957FB0636762453C8D1CE08B95FB90BB5EFF6A50210679E167C1E0B67AEDC6E7000C1C4AA5509F8F81D679855BD6CF8FE556FADACE0E45F1C1387DD1A14BBC8A3097DC11C7E40E5A31BCE2188D99008BC3163D04D03ABFB8AA3F17DCFADF8A26F4F275886B1C3DE598068054BB5D8D1B4CB5BCA9E6E822377AA7625490BD4735DDB2B4558D677C1DC2AF39CD9C67242D1C41FF3109FBA72C9C22E362310A905738BF8CEB12697EA0A0885BE11AE0A44DD1FE5F6F863AA8740BAD7300FE1FE72062D3C1669CA796B541637141925DE49515D497F669A695C2735489B58A6E48FF5D6E884D262E5EE95F1EDF49DF55485891DE9B7F5B1E73AD0953C021E4E58D3B7001B702EB6A030E81DC6DB9265290FC224695CAB521CCA0449069CBF358949B03FD6804DDE8AF
diff --git a/moduli.0 b/moduli.0
index 495bd5205aa7..fc77c672c2ca 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.
+ An initial candidate generation pass, using ssh-keygen -M generate,
+ calculates numbers that are likely to be useful. A second primality
+ testing pass, using ssh-keygen -M screen, 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.
+ the Secure Shell (SSH) Transport Layer Protocol, RFC 4419, March 2006.
-OpenBSD 7.0 September 26, 2012 OpenBSD 7.0
+OpenBSD 7.1 April 16, 2022 OpenBSD 7.1
diff --git a/moduli.5 b/moduli.5
index ef0de08506b1..5086a6d42aff 100644
--- a/moduli.5
+++ b/moduli.5
@@ -1,127 +1,126 @@
-.\" $OpenBSD: moduli.5,v 1.17 2012/09/26 17:34:38 jmc Exp $
+.\" $OpenBSD: moduli.5,v 1.19 2022/04/16 04:30:10 dtucker Exp $
.\"
.\" Copyright (c) 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.
-.Dd $Mdocdate: September 26 2012 $
+.Dd $Mdocdate: April 16 2022 $
.Dt MODULI 5
.Os
.Sh NAME
.Nm moduli
.Nd Diffie-Hellman moduli
.Sh DESCRIPTION
The
.Pa /etc/moduli
file contains prime numbers and generators for use by
.Xr sshd 8
in the Diffie-Hellman Group Exchange key exchange method.
.Pp
New moduli may be generated with
.Xr ssh-keygen 1
using a two-step process.
An initial
.Em candidate generation
pass, using
-.Ic ssh-keygen -G ,
+.Ic ssh-keygen -M generate ,
calculates numbers that are likely to be useful.
A second
.Em primality testing
pass, using
-.Ic ssh-keygen -T ,
+.Ic ssh-keygen -M screen ,
provides a high degree of assurance that the numbers are prime and are
safe for use in Diffie-Hellman operations by
.Xr sshd 8 .
This
.Nm
format is used as the output from each pass.
.Pp
The file consists of newline-separated records, one per modulus,
containing seven space-separated fields.
These fields are as follows:
.Bl -tag -width Description -offset indent
.It timestamp
The time that the modulus was last processed as YYYYMMDDHHMMSS.
.It type
Decimal number specifying the internal structure of the prime modulus.
Supported types are:
.Pp
.Bl -tag -width 0x00 -compact
.It 0
Unknown, not tested.
.It 2
"Safe" prime; (p-1)/2 is also prime.
.It 4
Sophie Germain; 2p+1 is also prime.
.El
.Pp
Moduli candidates initially produced by
.Xr ssh-keygen 1
are Sophie Germain primes (type 4).
Further primality testing with
.Xr ssh-keygen 1
produces safe prime moduli (type 2) that are ready for use in
.Xr sshd 8 .
Other types are not used by OpenSSH.
.It tests
Decimal number indicating the type of primality tests that the number
has been subjected to represented as a bitmask of the following values:
.Pp
.Bl -tag -width 0x00 -compact
.It 0x00
Not tested.
.It 0x01
Composite number \(en not prime.
.It 0x02
Sieve of Eratosthenes.
.It 0x04
Probabilistic Miller-Rabin primality tests.
.El
.Pp
The
.Xr ssh-keygen 1
moduli candidate generation uses the Sieve of Eratosthenes (flag 0x02).
Subsequent
.Xr ssh-keygen 1
primality tests are Miller-Rabin tests (flag 0x04).
.It trials
Decimal number indicating the number of primality trials
that have been performed on the modulus.
.It size
Decimal number indicating the size of the prime in bits.
.It generator
The recommended generator for use with this modulus (hexadecimal).
.It modulus
The modulus itself in hexadecimal.
.El
.Pp
When performing Diffie-Hellman Group Exchange,
.Xr sshd 8
first estimates the size of the modulus required to produce enough
Diffie-Hellman output to sufficiently key the selected symmetric cipher.
.Xr sshd 8
then randomly selects a modulus from
.Fa /etc/moduli
that best meets the size requirement.
.Sh SEE ALSO
.Xr ssh-keygen 1 ,
.Xr sshd 8
.Sh STANDARDS
.Rs
.%A M. Friedl
.%A N. Provos
.%A W. Simpson
.%D March 2006
.%R RFC 4419
.%T Diffie-Hellman Group Exchange for the Secure Shell (SSH) Transport Layer Protocol
-.%D 2006
.Re
diff --git a/moduli.c b/moduli.c
index 8dd36b1cf231..9f660ef267ee 100644
--- a/moduli.c
+++ b/moduli.c
@@ -1,813 +1,813 @@
-/* $OpenBSD: moduli.c,v 1.37 2019/11/15 06:00:20 djm Exp $ */
+/* $OpenBSD: moduli.c,v 1.38 2022/05/01 23:20:30 djm Exp $ */
/*
* Copyright 1994 Phil Karn <karn@qualcomm.com>
* Copyright 1996-1998, 2003 William Allen Simpson <wsimpson@greendragon.com>
* Copyright 2000 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.
*/
/*
* Two-step process to generate safe primes for DHGEX
*
* Sieve candidates for "safe" primes,
* suitable for use as Diffie-Hellman moduli;
* that is, where q = (p-1)/2 is also prime.
*
* First step: generate candidate primes (memory intensive)
* Second step: test primes' safety (processor intensive)
*/
#include "includes.h"
#ifdef WITH_OPENSSL
#include <sys/types.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
#include <unistd.h>
#include <limits.h>
#include "xmalloc.h"
#include "dh.h"
#include "log.h"
#include "misc.h"
#include "openbsd-compat/openssl-compat.h"
/*
* File output defines
*/
/* need line long enough for largest moduli plus headers */
#define QLINESIZE (100+8192)
/*
* Size: decimal.
* Specifies the number of the most significant bit (0 to M).
* WARNING: internally, usually 1 to N.
*/
#define QSIZE_MINIMUM (511)
/*
* Prime sieving defines
*/
/* Constant: assuming 8 bit bytes and 32 bit words */
#define SHIFT_BIT (3)
#define SHIFT_BYTE (2)
#define SHIFT_WORD (SHIFT_BIT+SHIFT_BYTE)
#define SHIFT_MEGABYTE (20)
#define SHIFT_MEGAWORD (SHIFT_MEGABYTE-SHIFT_BYTE)
/*
* Using virtual memory can cause thrashing. This should be the largest
* number that is supported without a large amount of disk activity --
* that would increase the run time from hours to days or weeks!
*/
#define LARGE_MINIMUM (8UL) /* megabytes */
/*
* Do not increase this number beyond the unsigned integer bit size.
* Due to a multiple of 4, it must be LESS than 128 (yielding 2**30 bits).
*/
#define LARGE_MAXIMUM (127UL) /* megabytes */
/*
* Constant: when used with 32-bit integers, the largest sieve prime
* has to be less than 2**32.
*/
#define SMALL_MAXIMUM (0xffffffffUL)
/* Constant: can sieve all primes less than 2**32, as 65537**2 > 2**32-1. */
#define TINY_NUMBER (1UL<<16)
/* Ensure enough bit space for testing 2*q. */
#define TEST_MAXIMUM (1UL<<16)
#define TEST_MINIMUM (QSIZE_MINIMUM + 1)
/* real TEST_MINIMUM (1UL << (SHIFT_WORD - TEST_POWER)) */
#define TEST_POWER (3) /* 2**n, n < SHIFT_WORD */
/* bit operations on 32-bit words */
#define BIT_CLEAR(a,n) ((a)[(n)>>SHIFT_WORD] &= ~(1L << ((n) & 31)))
#define BIT_SET(a,n) ((a)[(n)>>SHIFT_WORD] |= (1L << ((n) & 31)))
#define BIT_TEST(a,n) ((a)[(n)>>SHIFT_WORD] & (1L << ((n) & 31)))
/*
* Prime testing defines
*/
/* Minimum number of primality tests to perform */
#define TRIAL_MINIMUM (4)
/*
* Sieving data (XXX - move to struct)
*/
/* sieve 2**16 */
static u_int32_t *TinySieve, tinybits;
/* sieve 2**30 in 2**16 parts */
static u_int32_t *SmallSieve, smallbits, smallbase;
/* sieve relative to the initial value */
static u_int32_t *LargeSieve, largewords, largetries, largenumbers;
static u_int32_t largebits, largememory; /* megabytes */
static BIGNUM *largebase;
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);
/*
* print moduli out in consistent form,
*/
static int
qfileout(FILE * ofile, u_int32_t otype, u_int32_t otests, u_int32_t otries,
u_int32_t osize, u_int32_t ogenerator, BIGNUM * omodulus)
{
struct tm *gtm;
time_t time_now;
int res;
time(&time_now);
gtm = gmtime(&time_now);
if (gtm == NULL)
return -1;
res = fprintf(ofile, "%04d%02d%02d%02d%02d%02d %u %u %u %u %x ",
gtm->tm_year + 1900, gtm->tm_mon + 1, gtm->tm_mday,
gtm->tm_hour, gtm->tm_min, gtm->tm_sec,
otype, otests, otries, osize, ogenerator);
if (res < 0)
return (-1);
if (BN_print_fp(ofile, omodulus) < 1)
return (-1);
res = fprintf(ofile, "\n");
fflush(ofile);
return (res > 0 ? 0 : -1);
}
/*
** Sieve p's and q's with small factors
*/
static void
-sieve_large(u_int32_t s)
+sieve_large(u_int32_t s32)
{
- u_int32_t r, u;
+ u_int64_t r, u, s = s32;
- debug3("sieve_large %u", s);
+ debug3("sieve_large %u", s32);
largetries++;
/* r = largebase mod s */
- r = BN_mod_word(largebase, s);
+ r = BN_mod_word(largebase, s32);
if (r == 0)
u = 0; /* s divides into largebase exactly */
else
u = s - r; /* largebase+u is first entry divisible by s */
- if (u < largebits * 2) {
+ if (u < largebits * 2ULL) {
/*
* The sieve omits p's and q's divisible by 2, so ensure that
* largebase+u is odd. Then, step through the sieve in
* increments of 2*s
*/
if (u & 0x1)
u += s; /* Make largebase+u odd, and u even */
/* Mark all multiples of 2*s */
for (u /= 2; u < largebits; u += s)
BIT_SET(LargeSieve, u);
}
/* r = p mod s */
r = (2 * r + 1) % s;
if (r == 0)
u = 0; /* s divides p exactly */
else
u = s - r; /* p+u is first entry divisible by s */
- if (u < largebits * 4) {
+ if (u < largebits * 4ULL) {
/*
* The sieve omits p's divisible by 4, so ensure that
* largebase+u is not. Then, step through the sieve in
* increments of 4*s
*/
while (u & 0x3) {
if (SMALL_MAXIMUM - u < s)
return;
u += s;
}
/* Mark all multiples of 4*s */
for (u /= 4; u < largebits; u += s)
BIT_SET(LargeSieve, u);
}
}
/*
* list candidates for Sophie-Germain primes (where q = (p-1)/2)
* to standard output.
* The list is checked against small known primes (less than 2**30).
*/
int
gen_candidates(FILE *out, u_int32_t memory, u_int32_t power, BIGNUM *start)
{
BIGNUM *q;
u_int32_t j, r, s, t;
u_int32_t smallwords = TINY_NUMBER >> 6;
u_int32_t tinywords = TINY_NUMBER >> 6;
time_t time_start, time_stop;
u_int32_t i;
int ret = 0;
largememory = memory;
if (memory != 0 &&
(memory < LARGE_MINIMUM || memory > LARGE_MAXIMUM)) {
error("Invalid memory amount (min %ld, max %ld)",
LARGE_MINIMUM, LARGE_MAXIMUM);
return (-1);
}
/*
* Set power to the length in bits of the prime to be generated.
* This is changed to 1 less than the desired safe prime moduli p.
*/
if (power > TEST_MAXIMUM) {
error("Too many bits: %u > %lu", power, TEST_MAXIMUM);
return (-1);
} else if (power < TEST_MINIMUM) {
error("Too few bits: %u < %u", power, TEST_MINIMUM);
return (-1);
}
power--; /* decrement before squaring */
/*
* The density of ordinary primes is on the order of 1/bits, so the
* density of safe primes should be about (1/bits)**2. Set test range
* to something well above bits**2 to be reasonably sure (but not
* guaranteed) of catching at least one safe prime.
*/
largewords = ((power * power) >> (SHIFT_WORD - TEST_POWER));
/*
* Need idea of how much memory is available. We don't have to use all
* of it.
*/
if (largememory > LARGE_MAXIMUM) {
logit("Limited memory: %u MB; limit %lu MB",
largememory, LARGE_MAXIMUM);
largememory = LARGE_MAXIMUM;
}
if (largewords <= (largememory << SHIFT_MEGAWORD)) {
logit("Increased memory: %u MB; need %u bytes",
largememory, (largewords << SHIFT_BYTE));
largewords = (largememory << SHIFT_MEGAWORD);
} else if (largememory > 0) {
logit("Decreased memory: %u MB; want %u bytes",
largememory, (largewords << SHIFT_BYTE));
largewords = (largememory << SHIFT_MEGAWORD);
}
TinySieve = xcalloc(tinywords, sizeof(u_int32_t));
tinybits = tinywords << SHIFT_WORD;
SmallSieve = xcalloc(smallwords, sizeof(u_int32_t));
smallbits = smallwords << SHIFT_WORD;
/*
* dynamically determine available memory
*/
while ((LargeSieve = calloc(largewords, sizeof(u_int32_t))) == NULL)
largewords -= (1L << (SHIFT_MEGAWORD - 2)); /* 1/4 MB chunks */
largebits = largewords << SHIFT_WORD;
largenumbers = largebits * 2; /* even numbers excluded */
/* validation check: count the number of primes tried */
largetries = 0;
if ((q = BN_new()) == NULL)
fatal("BN_new failed");
/*
* Generate random starting point for subprime search, or use
* specified parameter.
*/
if ((largebase = BN_new()) == NULL)
fatal("BN_new failed");
if (start == NULL) {
if (BN_rand(largebase, power, 1, 1) == 0)
fatal("BN_rand failed");
} else {
if (BN_copy(largebase, start) == NULL)
fatal("BN_copy: failed");
}
/* ensure odd */
if (BN_set_bit(largebase, 0) == 0)
fatal("BN_set_bit: failed");
time(&time_start);
logit("%.24s Sieve next %u plus %u-bit", ctime(&time_start),
largenumbers, power);
debug2("start point: 0x%s", BN_bn2hex(largebase));
/*
* TinySieve
*/
for (i = 0; i < tinybits; i++) {
if (BIT_TEST(TinySieve, i))
continue; /* 2*i+3 is composite */
/* The next tiny prime */
t = 2 * i + 3;
/* Mark all multiples of t */
for (j = i + t; j < tinybits; j += t)
BIT_SET(TinySieve, j);
sieve_large(t);
}
/*
* Start the small block search at the next possible prime. To avoid
* fencepost errors, the last pass is skipped.
*/
for (smallbase = TINY_NUMBER + 3;
smallbase < (SMALL_MAXIMUM - TINY_NUMBER);
smallbase += TINY_NUMBER) {
for (i = 0; i < tinybits; i++) {
if (BIT_TEST(TinySieve, i))
continue; /* 2*i+3 is composite */
/* The next tiny prime */
t = 2 * i + 3;
r = smallbase % t;
if (r == 0) {
s = 0; /* t divides into smallbase exactly */
} else {
/* smallbase+s is first entry divisible by t */
s = t - r;
}
/*
* The sieve omits even numbers, so ensure that
* smallbase+s is odd. Then, step through the sieve
* in increments of 2*t
*/
if (s & 1)
s += t; /* Make smallbase+s odd, and s even */
/* Mark all multiples of 2*t */
for (s /= 2; s < smallbits; s += t)
BIT_SET(SmallSieve, s);
}
/*
* SmallSieve
*/
for (i = 0; i < smallbits; i++) {
if (BIT_TEST(SmallSieve, i))
continue; /* 2*i+smallbase is composite */
/* The next small prime */
sieve_large((2 * i) + smallbase);
}
memset(SmallSieve, 0, smallwords << SHIFT_BYTE);
}
time(&time_stop);
logit("%.24s Sieved with %u small primes in %lld seconds",
ctime(&time_stop), largetries, (long long)(time_stop - time_start));
for (j = r = 0; j < largebits; j++) {
if (BIT_TEST(LargeSieve, j))
continue; /* Definitely composite, skip */
debug2("test q = largebase+%u", 2 * j);
if (BN_set_word(q, 2 * j) == 0)
fatal("BN_set_word failed");
if (BN_add(q, q, largebase) == 0)
fatal("BN_add failed");
if (qfileout(out, MODULI_TYPE_SOPHIE_GERMAIN,
MODULI_TESTS_SIEVE, largetries,
(power - 1) /* MSB */, (0), q) == -1) {
ret = -1;
break;
}
r++; /* count q */
}
time(&time_stop);
free(LargeSieve);
free(SmallSieve);
free(TinySieve);
logit("%.24s Found %u candidates", ctime(&time_stop), r);
return (ret);
}
static void
write_checkpoint(char *cpfile, u_int32_t lineno)
{
FILE *fp;
char tmp[PATH_MAX];
int r;
r = snprintf(tmp, sizeof(tmp), "%s.XXXXXXXXXX", cpfile);
if (r < 0 || r >= PATH_MAX) {
logit("write_checkpoint: temp pathname too long");
return;
}
if ((r = mkstemp(tmp)) == -1) {
logit("mkstemp(%s): %s", tmp, strerror(errno));
return;
}
if ((fp = fdopen(r, "w")) == NULL) {
logit("write_checkpoint: fdopen: %s", strerror(errno));
unlink(tmp);
close(r);
return;
}
if (fprintf(fp, "%lu\n", (unsigned long)lineno) > 0 && fclose(fp) == 0
&& rename(tmp, cpfile) == 0)
debug3("wrote checkpoint line %lu to '%s'",
(unsigned long)lineno, cpfile);
else
logit("failed to write to checkpoint file '%s': %s", cpfile,
strerror(errno));
}
static unsigned long
read_checkpoint(char *cpfile)
{
FILE *fp;
unsigned long lineno = 0;
if ((fp = fopen(cpfile, "r")) == NULL)
return 0;
if (fscanf(fp, "%lu\n", &lineno) < 1)
logit("Failed to load checkpoint from '%s'", cpfile);
else
logit("Loaded checkpoint from '%s' line %lu", cpfile, lineno);
fclose(fp);
return lineno;
}
static unsigned long
count_lines(FILE *f)
{
unsigned long count = 0;
char lp[QLINESIZE + 1];
if (fseek(f, 0, SEEK_SET) != 0) {
debug("input file is not seekable");
return ULONG_MAX;
}
while (fgets(lp, QLINESIZE + 1, f) != NULL)
count++;
rewind(f);
debug("input file has %lu lines", count);
return count;
}
static char *
fmt_time(time_t seconds)
{
int day, hr, min;
static char buf[128];
min = (seconds / 60) % 60;
hr = (seconds / 60 / 60) % 24;
day = seconds / 60 / 60 / 24;
if (day > 0)
snprintf(buf, sizeof buf, "%dd %d:%02d", day, hr, min);
else
snprintf(buf, sizeof buf, "%d:%02d", hr, min);
return buf;
}
static void
print_progress(unsigned long start_lineno, unsigned long current_lineno,
unsigned long end_lineno)
{
static time_t time_start, time_prev;
time_t time_now, elapsed;
unsigned long num_to_process, processed, remaining, percent, eta;
double time_per_line;
char *eta_str;
time_now = monotime();
if (time_start == 0) {
time_start = time_prev = time_now;
return;
}
/* print progress after 1m then once per 5m */
if (time_now - time_prev < 5 * 60)
return;
time_prev = time_now;
elapsed = time_now - time_start;
processed = current_lineno - start_lineno;
remaining = end_lineno - current_lineno;
num_to_process = end_lineno - start_lineno;
time_per_line = (double)elapsed / processed;
/* if we don't know how many we're processing just report count+time */
time(&time_now);
if (end_lineno == ULONG_MAX) {
logit("%.24s processed %lu in %s", ctime(&time_now),
processed, fmt_time(elapsed));
return;
}
percent = 100 * processed / num_to_process;
eta = time_per_line * remaining;
eta_str = xstrdup(fmt_time(eta));
logit("%.24s processed %lu of %lu (%lu%%) in %s, ETA %s",
ctime(&time_now), processed, num_to_process, percent,
fmt_time(elapsed), eta_str);
free(eta_str);
}
/*
* perform a Miller-Rabin primality test
* on the list of candidates
* (checking both q and p)
* The result is a list of so-call "safe" primes
*/
int
prime_test(FILE *in, FILE *out, u_int32_t trials, u_int32_t generator_wanted,
char *checkpoint_file, unsigned long start_lineno, unsigned long num_lines)
{
BIGNUM *q, *p, *a;
char *cp, *lp;
u_int32_t count_in = 0, count_out = 0, count_possible = 0;
u_int32_t generator_known, in_tests, in_tries, in_type, in_size;
unsigned long last_processed = 0, end_lineno;
time_t time_start, time_stop;
int res, is_prime;
if (trials < TRIAL_MINIMUM) {
error("Minimum primality trials is %d", TRIAL_MINIMUM);
return (-1);
}
if (num_lines == 0)
end_lineno = count_lines(in);
else
end_lineno = start_lineno + num_lines;
time(&time_start);
if ((p = BN_new()) == NULL)
fatal("BN_new failed");
if ((q = BN_new()) == NULL)
fatal("BN_new failed");
debug2("%.24s Final %u Miller-Rabin trials (%x generator)",
ctime(&time_start), trials, generator_wanted);
if (checkpoint_file != NULL)
last_processed = read_checkpoint(checkpoint_file);
last_processed = start_lineno = MAXIMUM(last_processed, start_lineno);
if (end_lineno == ULONG_MAX)
debug("process from line %lu from pipe", last_processed);
else
debug("process from line %lu to line %lu", last_processed,
end_lineno);
res = 0;
lp = xmalloc(QLINESIZE + 1);
while (fgets(lp, QLINESIZE + 1, in) != NULL && count_in < end_lineno) {
count_in++;
if (count_in <= last_processed) {
debug3("skipping line %u, before checkpoint or "
"specified start line", count_in);
continue;
}
if (checkpoint_file != NULL)
write_checkpoint(checkpoint_file, count_in);
print_progress(start_lineno, count_in, end_lineno);
if (strlen(lp) < 14 || *lp == '!' || *lp == '#') {
debug2("%10u: comment or short line", count_in);
continue;
}
/* XXX - fragile parser */
/* time */
cp = &lp[14]; /* (skip) */
/* type */
in_type = strtoul(cp, &cp, 10);
/* tests */
in_tests = strtoul(cp, &cp, 10);
if (in_tests & MODULI_TESTS_COMPOSITE) {
debug2("%10u: known composite", count_in);
continue;
}
/* tries */
in_tries = strtoul(cp, &cp, 10);
/* size (most significant bit) */
in_size = strtoul(cp, &cp, 10);
/* generator (hex) */
generator_known = strtoul(cp, &cp, 16);
/* Skip white space */
cp += strspn(cp, " ");
/* modulus (hex) */
switch (in_type) {
case MODULI_TYPE_SOPHIE_GERMAIN:
debug2("%10u: (%u) Sophie-Germain", count_in, in_type);
a = q;
if (BN_hex2bn(&a, cp) == 0)
fatal("BN_hex2bn failed");
/* p = 2*q + 1 */
if (BN_lshift(p, q, 1) == 0)
fatal("BN_lshift failed");
if (BN_add_word(p, 1) == 0)
fatal("BN_add_word failed");
in_size += 1;
generator_known = 0;
break;
case MODULI_TYPE_UNSTRUCTURED:
case MODULI_TYPE_SAFE:
case MODULI_TYPE_SCHNORR:
case MODULI_TYPE_STRONG:
case MODULI_TYPE_UNKNOWN:
debug2("%10u: (%u)", count_in, in_type);
a = p;
if (BN_hex2bn(&a, cp) == 0)
fatal("BN_hex2bn failed");
/* q = (p-1) / 2 */
if (BN_rshift(q, p, 1) == 0)
fatal("BN_rshift failed");
break;
default:
debug2("Unknown prime type");
break;
}
/*
* due to earlier inconsistencies in interpretation, check
* the proposed bit size.
*/
if ((u_int32_t)BN_num_bits(p) != (in_size + 1)) {
debug2("%10u: bit size %u mismatch", count_in, in_size);
continue;
}
if (in_size < QSIZE_MINIMUM) {
debug2("%10u: bit size %u too short", count_in, in_size);
continue;
}
if (in_tests & MODULI_TESTS_MILLER_RABIN)
in_tries += trials;
else
in_tries = trials;
/*
* guess unknown generator
*/
if (generator_known == 0) {
if (BN_mod_word(p, 24) == 11)
generator_known = 2;
else {
u_int32_t r = BN_mod_word(p, 10);
if (r == 3 || r == 7)
generator_known = 5;
}
}
/*
* skip tests when desired generator doesn't match
*/
if (generator_wanted > 0 &&
generator_wanted != generator_known) {
debug2("%10u: generator %d != %d",
count_in, generator_known, generator_wanted);
continue;
}
/*
* Primes with no known generator are useless for DH, so
* skip those.
*/
if (generator_known == 0) {
debug2("%10u: no known generator", count_in);
continue;
}
count_possible++;
/*
* The (1/4)^N performance bound on Miller-Rabin is
* extremely pessimistic, so don't spend a lot of time
* really verifying that q is prime until after we know
* that p is also prime. A single pass will weed out the
* vast majority of composite q's.
*/
is_prime = BN_is_prime_ex(q, 1, NULL, NULL);
if (is_prime < 0)
fatal("BN_is_prime_ex failed");
if (is_prime == 0) {
debug("%10u: q failed first possible prime test",
count_in);
continue;
}
/*
* q is possibly prime, so go ahead and really make sure
* that p is prime. If it is, then we can go back and do
* the same for q. If p is composite, chances are that
* will show up on the first Rabin-Miller iteration so it
* doesn't hurt to specify a high iteration count.
*/
is_prime = BN_is_prime_ex(p, trials, NULL, NULL);
if (is_prime < 0)
fatal("BN_is_prime_ex failed");
if (is_prime == 0) {
debug("%10u: p is not prime", count_in);
continue;
}
debug("%10u: p is almost certainly prime", count_in);
/* recheck q more rigorously */
is_prime = BN_is_prime_ex(q, trials - 1, NULL, NULL);
if (is_prime < 0)
fatal("BN_is_prime_ex failed");
if (is_prime == 0) {
debug("%10u: q is not prime", count_in);
continue;
}
debug("%10u: q is almost certainly prime", count_in);
if (qfileout(out, MODULI_TYPE_SAFE,
in_tests | MODULI_TESTS_MILLER_RABIN,
in_tries, in_size, generator_known, p)) {
res = -1;
break;
}
count_out++;
}
time(&time_stop);
free(lp);
BN_free(p);
BN_free(q);
if (checkpoint_file != NULL)
unlink(checkpoint_file);
logit("%.24s Found %u safe primes of %u candidates in %ld seconds",
ctime(&time_stop), count_out, count_possible,
(long) (time_stop - time_start));
return (res);
}
#endif /* WITH_OPENSSL */
diff --git a/monitor.c b/monitor.c
index 20b9f67b9349..91e0e62454b7 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1,1955 +1,1955 @@
-/* $OpenBSD: monitor.c,v 1.232 2022/02/25 02:09:27 djm Exp $ */
+/* $OpenBSD: monitor.c,v 1.234 2022/06/15 16:08:25 djm 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_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 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, 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_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);
sshlogdirect(level, forced, "%s [preauth]", msg);
sshbuf_free(logmsg);
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 %s signature len=%zu", alg,
is_proof ? "hostkey proof" : "KEX", 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)
{
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, &authctxt->user, NULL)) != 0)
fatal_fr(r, "parse");
pwent = getpwnamallow(ssh, authctxt->user);
setproctitle("%s [priv]", pwent ? authctxt->user : "unknown");
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 its 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.kbd_interactive_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;
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");
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 %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;
struct sshkey *hostkey = NULL;
const u_char *p;
char *userstyle, *cp;
size_t len;
u_char type;
int hostbound = 0, 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) {
if (strcmp("publickey-hostbound-v00@openssh.com", cp) == 0)
hostbound = 1;
else
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 */
(hostbound && (r = sshkey_froms(b, &hostkey)) != 0))
fatal_fr(r, "parse pk");
if (sshbuf_len(b) != 0)
fail++;
sshbuf_free(b);
if (hostkey != NULL) {
/*
* Ensure this is actually one of our hostkeys; unfortunately
* can't check ssh->kex->initial_hostkey directly at this point
* as packet state has not yet been exported to monitor.
*/
if (get_hostkey_index(hostkey, 1, ssh) == -1)
fatal_f("hostbound hostkey does not match");
sshkey_free(hostkey);
}
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 %s signature using %s %s%s%s", auth_method,
sshkey_type(key), sigalg == NULL ? "default" : sigalg,
(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 748333c75e59..b2c85205eb96 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1,1021 +1,1021 @@
-/* $OpenBSD: monitor_wrap.c,v 1.123 2021/04/15 16:24:31 markus Exp $ */
+/* $OpenBSD: monitor_wrap.c,v 1.125 2022/06/15 16:08:25 djm 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(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_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 a163b67d2878..0df49c25be11 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -1,102 +1,102 @@
-/* $OpenBSD: monitor_wrap.h,v 1.47 2021/04/15 16:24:31 markus Exp $ */
+/* $OpenBSD: monitor_wrap.h,v 1.49 2022/06/15 16:08:25 djm 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(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,
+int mm_user_key_allowed(struct ssh *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 176f035c86f5..3cb3876148aa 100644
--- a/mux.c
+++ b/mux.c
@@ -1,2343 +1,2344 @@
-/* $OpenBSD: mux.c,v 1.92 2022/01/11 01:26:47 djm Exp $ */
+/* $OpenBSD: mux.c,v 1.94 2022/06/03 04:30:47 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 char *host;
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)
+env_permitted(const char *env)
{
- int i, ret;
+ u_int i;
+ int 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));
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", CHANNEL_NONBLOCK_STDIO);
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);
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);
} 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, "
"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;
}
}
nc = channel_connect_stdio_fwd(ssh, chost, cport, new_fd[0], new_fd[1],
CHANNEL_NONBLOCK_STDIO);
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 = NULL;
- u_int echar, rid, sid, esid, exitval, type, exitval_seen;
+ u_int i, echar, rid, sid, esid, exitval, type, exitval_seen;
extern char **environ;
- int r, i, rawmode;
+ int r, 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 (options.stdin_null && stdfd_devnull(1, 0, 0) == -1)
fatal_f("stdfd_devnull failed");
if ((term = lookup_env_in_list("TERM", options.setenv,
options.num_setenv)) == NULL || *term == '\0')
term = getenv("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, options.session_type == SESSION_TYPE_SUBSYSTEM)) != 0 ||
(r = sshbuf_put_u32(m, echar)) != 0 ||
(r = sshbuf_put_cstring(m, term == NULL ? "" : 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_INFO)
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 (options.stdin_null && 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));
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/Makefile.in b/openbsd-compat/Makefile.in
index 5d53bef5757f..1d549954f9d6 100644
--- a/openbsd-compat/Makefile.in
+++ b/openbsd-compat/Makefile.in
@@ -1,120 +1,122 @@
sysconfdir=@sysconfdir@
piddir=@piddir@
srcdir=@srcdir@
top_srcdir=@top_srcdir@
VPATH=@srcdir@
CC=@CC@
LD=@LD@
CFLAGS=@CFLAGS@
CFLAGS_NOPIE=@CFLAGS_NOPIE@
CPPFLAGS=-I. -I.. -I$(srcdir) -I$(srcdir)/.. @CPPFLAGS@ @DEFS@
PICFLAG=@PICFLAG@
LIBS=@LIBS@
AR=@AR@
RANLIB=@RANLIB@
INSTALL=@INSTALL@
LDFLAGS=-L. @LDFLAGS@
LDFLAGS_NOPIE=-L. -Lopenbsd-compat/ @LDFLAGS_NOPIE@
-OPENBSD=base64.o \
+OPENBSD=arc4random.o \
+ arc4random_uniform.o \
+ base64.o \
basename.o \
bcrypt_pbkdf.o \
- bcrypt_pbkdf.o \
bindresvport.o \
blowfish.o \
daemon.o \
dirname.o \
explicit_bzero.o \
fmt_scaled.o \
freezero.o \
fnmatch.o \
getcwd.o \
getgrouplist.o \
getopt_long.o \
getrrsetbyname.o \
glob.o \
inet_aton.o \
inet_ntoa.o \
inet_ntop.o \
md5.o \
memmem.o \
mktemp.o \
pwcache.o \
readpassphrase.o \
reallocarray.o \
recallocarray.o \
rresvport.o \
setenv.o \
setproctitle.o \
sha1.o \
sha2.o \
sigact.o \
strcasestr.o \
strlcat.o \
strlcpy.o \
strmode.o \
strndup.o \
strnlen.o \
strptime.o \
strsep.o \
strtoll.o \
strtonum.o \
strtoull.o \
strtoul.o \
timingsafe_bcmp.o \
vis.o
-COMPAT= arc4random.o \
- bsd-asprintf.o \
+COMPAT= bsd-asprintf.o \
bsd-closefrom.o \
bsd-cygwin_util.o \
bsd-err.o \
bsd-flock.o \
+ bsd-getentropy.o \
bsd-getline.o \
bsd-getpagesize.o \
bsd-getpeereid.o \
bsd-malloc.o \
bsd-misc.o \
bsd-nextstep.o \
bsd-openpty.o \
bsd-poll.o \
bsd-pselect.o \
bsd-setres_id.o \
bsd-signal.o \
bsd-snprintf.o \
bsd-statvfs.o \
+ bsd-timegm.o \
bsd-waitpid.o \
fake-rfc2553.o \
getrrsetbyname-ldns.o \
kludge-fd_set.o \
openssl-compat.o \
libressl-api-compat.o \
xcrypt.o
PORTS= port-aix.o \
port-irix.o \
port-linux.o \
port-prngd.o \
port-solaris.o \
port-net.o \
port-uw.o
.c.o:
$(CC) $(CFLAGS_NOPIE) $(PICFLAG) $(CPPFLAGS) -c $<
all: libopenbsd-compat.a
$(COMPAT): ../config.h
$(OPENBSD): ../config.h
$(PORTS): ../config.h
libopenbsd-compat.a: $(COMPAT) $(OPENBSD) $(PORTS)
$(AR) rv $@ $(COMPAT) $(OPENBSD) $(PORTS)
$(RANLIB) $@
clean:
rm -f *.o *.a core
distclean: clean
rm -f Makefile *~
diff --git a/openbsd-compat/arc4random.c b/openbsd-compat/arc4random.c
index ce5f054f1e23..02f15f9c3bfa 100644
--- a/openbsd-compat/arc4random.c
+++ b/openbsd-compat/arc4random.c
@@ -1,346 +1,252 @@
-/* OPENBSD ORIGINAL: lib/libc/crypto/arc4random.c */
-
-/* $OpenBSD: arc4random.c,v 1.25 2013/10/01 18:34:57 markus Exp $ */
+/* $OpenBSD: arc4random.c,v 1.58 2022/07/31 13:41:45 tb Exp $ */
/*
* Copyright (c) 1996, David Mazieres <dm@uun.org>
* Copyright (c) 2008, Damien Miller <djm@openbsd.org>
* Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
+ * Copyright (c) 2014, Theo de Raadt <deraadt@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.
*/
/*
* ChaCha based random number generator for OpenBSD.
*/
+/* OPENBSD ORIGINAL: lib/libc/crypt/arc4random.c */
+
#include "includes.h"
#include <sys/types.h>
#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-
-#ifdef HAVE_SYS_RANDOM_H
-# include <sys/random.h>
-#endif
+#include <sys/types.h>
+#include <sys/time.h>
#ifndef HAVE_ARC4RANDOM
-#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
-
-#ifdef WITH_OPENSSL
-#include <openssl/rand.h>
-#include <openssl/err.h>
+/*
+ * If we're not using a native getentropy, use the one from bsd-getentropy.c
+ * under a different name, so that if in future these binaries are run on
+ * a system that has a native getentropy OpenSSL cannot call the wrong one.
+ */
+#ifndef HAVE_GETENTROPY
+# define getentropy(x, y) (_ssh_compat_getentropy((x), (y)))
#endif
#include "log.h"
#define KEYSTREAM_ONLY
#include "chacha_private.h"
-#ifdef __GNUC__
+#define minimum(a, b) ((a) < (b) ? (a) : (b))
+
+#if defined(__GNUC__) || defined(_MSC_VER)
#define inline __inline
-#else /* !__GNUC__ */
+#else /* __GNUC__ || _MSC_VER */
#define inline
-#endif /* !__GNUC__ */
-
-/* OpenSSH isn't multithreaded */
-#define _ARC4_LOCK()
-#define _ARC4_UNLOCK()
+#endif /* !__GNUC__ && !_MSC_VER */
#define KEYSZ 32
#define IVSZ 8
#define BLOCKSZ 64
#define RSBUFSZ (16*BLOCKSZ)
-static int rs_initialized;
-static pid_t rs_stir_pid;
-static chacha_ctx rs; /* chacha context for random keystream */
-static u_char rs_buf[RSBUFSZ]; /* keystream blocks */
-static size_t rs_have; /* valid bytes at end of rs_buf */
-static size_t rs_count; /* bytes till reseed */
+
+#define REKEY_BASE (1024*1024) /* NB. should be a power of 2 */
+
+/* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */
+static struct _rs {
+ size_t rs_have; /* valid bytes at end of rs_buf */
+ size_t rs_count; /* bytes till reseed */
+} *rs;
+
+/* Maybe be preserved in fork children, if _rs_allocate() decides. */
+static struct _rsx {
+ chacha_ctx rs_chacha; /* chacha context for random keystream */
+ u_char rs_buf[RSBUFSZ]; /* keystream blocks */
+} *rsx;
+
+static inline int _rs_allocate(struct _rs **, struct _rsx **);
+static inline void _rs_forkdetect(void);
+#include "arc4random.h"
static inline void _rs_rekey(u_char *dat, size_t datlen);
static inline void
_rs_init(u_char *buf, size_t n)
{
if (n < KEYSZ + IVSZ)
return;
- chacha_keysetup(&rs, buf, KEYSZ * 8);
- chacha_ivsetup(&rs, buf + KEYSZ);
-}
-#ifndef WITH_OPENSSL
-# ifndef SSH_RANDOM_DEV
-# define SSH_RANDOM_DEV "/dev/urandom"
-# endif /* SSH_RANDOM_DEV */
-static void
-getrnd(u_char *s, size_t len)
-{
- int fd, save_errno;
- ssize_t r;
- size_t o = 0;
-
-#ifdef HAVE_GETRANDOM
- if ((r = getrandom(s, len, 0)) > 0 && (size_t)r == len)
- return;
-#endif /* HAVE_GETRANDOM */
-
- if ((fd = open(SSH_RANDOM_DEV, O_RDONLY)) == -1) {
- save_errno = errno;
- /* Try egd/prngd before giving up. */
- if (seed_from_prngd(s, len) == 0)
- return;
- fatal("Couldn't open %s: %s", SSH_RANDOM_DEV,
- strerror(save_errno));
+ if (rs == NULL) {
+ if (_rs_allocate(&rs, &rsx) == -1)
+ _exit(1);
}
- while (o < len) {
- r = read(fd, s + o, len - o);
- if (r < 0) {
- if (errno == EAGAIN || errno == EINTR ||
- errno == EWOULDBLOCK)
- continue;
- fatal("read %s: %s", SSH_RANDOM_DEV, strerror(errno));
- }
- o += r;
- }
- close(fd);
+
+ chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8);
+ chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ);
}
-#endif /* WITH_OPENSSL */
static void
_rs_stir(void)
{
u_char rnd[KEYSZ + IVSZ];
+ uint32_t rekey_fuzz = 0;
-#ifdef WITH_OPENSSL
- if (RAND_bytes(rnd, sizeof(rnd)) <= 0)
- fatal("Couldn't obtain random bytes (error 0x%lx)",
- (unsigned long)ERR_get_error());
-#else
- getrnd(rnd, sizeof(rnd));
-#endif
+ if (getentropy(rnd, sizeof rnd) == -1)
+ _getentropy_fail();
- if (!rs_initialized) {
- rs_initialized = 1;
+ if (!rs)
_rs_init(rnd, sizeof(rnd));
- } else
+ else
_rs_rekey(rnd, sizeof(rnd));
- explicit_bzero(rnd, sizeof(rnd));
+ explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */
/* invalidate rs_buf */
- rs_have = 0;
- memset(rs_buf, 0, RSBUFSZ);
+ rs->rs_have = 0;
+ memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
- rs_count = 1600000;
+ /* rekey interval should not be predictable */
+ chacha_encrypt_bytes(&rsx->rs_chacha, (uint8_t *)&rekey_fuzz,
+ (uint8_t *)&rekey_fuzz, sizeof(rekey_fuzz));
+ rs->rs_count = REKEY_BASE + (rekey_fuzz % REKEY_BASE);
}
static inline void
_rs_stir_if_needed(size_t len)
{
- pid_t pid = getpid();
-
- if (rs_count <= len || !rs_initialized || rs_stir_pid != pid) {
- rs_stir_pid = pid;
+ _rs_forkdetect();
+ if (!rs || rs->rs_count <= len)
_rs_stir();
- } else
- rs_count -= len;
+ if (rs->rs_count <= len)
+ rs->rs_count = 0;
+ else
+ rs->rs_count -= len;
}
static inline void
_rs_rekey(u_char *dat, size_t datlen)
{
#ifndef KEYSTREAM_ONLY
- memset(rs_buf, 0,RSBUFSZ);
+ memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
#endif
/* fill rs_buf with the keystream */
- chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ);
+ chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf,
+ rsx->rs_buf, sizeof(rsx->rs_buf));
/* mix in optional user provided data */
if (dat) {
size_t i, m;
- m = MINIMUM(datlen, KEYSZ + IVSZ);
+ m = minimum(datlen, KEYSZ + IVSZ);
for (i = 0; i < m; i++)
- rs_buf[i] ^= dat[i];
+ rsx->rs_buf[i] ^= dat[i];
}
/* immediately reinit for backtracking resistance */
- _rs_init(rs_buf, KEYSZ + IVSZ);
- memset(rs_buf, 0, KEYSZ + IVSZ);
- rs_have = RSBUFSZ - KEYSZ - IVSZ;
+ _rs_init(rsx->rs_buf, KEYSZ + IVSZ);
+ memset(rsx->rs_buf, 0, KEYSZ + IVSZ);
+ rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ;
}
static inline void
_rs_random_buf(void *_buf, size_t n)
{
u_char *buf = (u_char *)_buf;
+ u_char *keystream;
size_t m;
_rs_stir_if_needed(n);
while (n > 0) {
- if (rs_have > 0) {
- m = MINIMUM(n, rs_have);
- memcpy(buf, rs_buf + RSBUFSZ - rs_have, m);
- memset(rs_buf + RSBUFSZ - rs_have, 0, m);
+ if (rs->rs_have > 0) {
+ m = minimum(n, rs->rs_have);
+ keystream = rsx->rs_buf + sizeof(rsx->rs_buf)
+ - rs->rs_have;
+ memcpy(buf, keystream, m);
+ memset(keystream, 0, m);
buf += m;
n -= m;
- rs_have -= m;
+ rs->rs_have -= m;
}
- if (rs_have == 0)
+ if (rs->rs_have == 0)
_rs_rekey(NULL, 0);
}
}
static inline void
-_rs_random_u32(u_int32_t *val)
+_rs_random_u32(uint32_t *val)
{
+ u_char *keystream;
+
_rs_stir_if_needed(sizeof(*val));
- if (rs_have < sizeof(*val))
+ if (rs->rs_have < sizeof(*val))
_rs_rekey(NULL, 0);
- memcpy(val, rs_buf + RSBUFSZ - rs_have, sizeof(*val));
- memset(rs_buf + RSBUFSZ - rs_have, 0, sizeof(*val));
- rs_have -= sizeof(*val);
- return;
+ keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have;
+ memcpy(val, keystream, sizeof(*val));
+ memset(keystream, 0, sizeof(*val));
+ rs->rs_have -= sizeof(*val);
}
-void
-arc4random_stir(void)
-{
- _ARC4_LOCK();
- _rs_stir();
- _ARC4_UNLOCK();
-}
-
-void
-arc4random_addrandom(u_char *dat, int datlen)
-{
- int m;
-
- _ARC4_LOCK();
- if (!rs_initialized)
- _rs_stir();
- while (datlen > 0) {
- m = MINIMUM(datlen, KEYSZ + IVSZ);
- _rs_rekey(dat, m);
- dat += m;
- datlen -= m;
- }
- _ARC4_UNLOCK();
-}
-
-u_int32_t
+uint32_t
arc4random(void)
{
- u_int32_t val;
+ uint32_t val;
_ARC4_LOCK();
_rs_random_u32(&val);
_ARC4_UNLOCK();
return val;
}
+DEF_WEAK(arc4random);
/*
- * If we are providing arc4random, then we can provide a more efficient
+ * If we are providing arc4random, then we can provide a more efficient
* arc4random_buf().
*/
# ifndef HAVE_ARC4RANDOM_BUF
void
arc4random_buf(void *buf, size_t n)
{
_ARC4_LOCK();
_rs_random_buf(buf, n);
_ARC4_UNLOCK();
}
+DEF_WEAK(arc4random_buf);
# endif /* !HAVE_ARC4RANDOM_BUF */
#endif /* !HAVE_ARC4RANDOM */
/* arc4random_buf() that uses platform arc4random() */
#if !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM)
void
arc4random_buf(void *_buf, size_t n)
{
size_t i;
u_int32_t r = 0;
char *buf = (char *)_buf;
for (i = 0; i < n; i++) {
if (i % 4 == 0)
r = arc4random();
buf[i] = r & 0xff;
r >>= 8;
}
explicit_bzero(&r, sizeof(r));
}
#endif /* !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) */
-#ifndef HAVE_ARC4RANDOM_UNIFORM
-/*
- * Calculate a uniformly distributed random number less than upper_bound
- * avoiding "modulo bias".
- *
- * Uniformity is achieved by generating new random numbers until the one
- * returned is outside the range [0, 2**32 % upper_bound). This
- * guarantees the selected random number will be inside
- * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
- * after reduction modulo upper_bound.
- */
-u_int32_t
-arc4random_uniform(u_int32_t upper_bound)
-{
- u_int32_t r, min;
-
- if (upper_bound < 2)
- return 0;
-
- /* 2**32 % x == (2**32 - x) % x */
- min = -upper_bound % upper_bound;
-
- /*
- * This could theoretically loop forever but each retry has
- * p > 0.5 (worst case, usually far better) of selecting a
- * number inside the range we need, so it should rarely need
- * to re-roll.
- */
- for (;;) {
- r = arc4random();
- if (r >= min)
- break;
- }
-
- return r % upper_bound;
-}
-#endif /* !HAVE_ARC4RANDOM_UNIFORM */
-
-#if 0
-/*-------- Test code for i386 --------*/
-#include <stdio.h>
-#include <machine/pctr.h>
-int
-main(int argc, char **argv)
-{
- const int iter = 1000000;
- int i;
- pctrval v;
-
- v = rdtsc();
- for (i = 0; i < iter; i++)
- arc4random();
- v = rdtsc() - v;
- v /= iter;
-
- printf("%qd cycles\n", v);
- exit(0);
-}
-#endif
diff --git a/openbsd-compat/arc4random.h b/openbsd-compat/arc4random.h
new file mode 100644
index 000000000000..2b57611f060c
--- /dev/null
+++ b/openbsd-compat/arc4random.h
@@ -0,0 +1,79 @@
+/* $OpenBSD: arc4random_linux.h,v 1.12 2019/07/11 10:37:28 inoguchi Exp $ */
+
+/*
+ * Copyright (c) 1996, David Mazieres <dm@uun.org>
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
+ * Copyright (c) 2014, Theo de Raadt <deraadt@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.
+ */
+
+/*
+ * Stub functions for portability. From LibreSSL with some adaptations.
+ */
+
+#include <sys/mman.h>
+
+#include <signal.h>
+
+/* OpenSSH isn't multithreaded */
+#define _ARC4_LOCK()
+#define _ARC4_UNLOCK()
+#define _ARC4_ATFORK(f)
+
+static inline void
+_getentropy_fail(void)
+{
+ fatal("getentropy failed");
+}
+
+static volatile sig_atomic_t _rs_forked;
+
+static inline void
+_rs_forkhandler(void)
+{
+ _rs_forked = 1;
+}
+
+static inline void
+_rs_forkdetect(void)
+{
+ static pid_t _rs_pid = 0;
+ pid_t pid = getpid();
+
+ if (_rs_pid == 0 || _rs_pid == 1 || _rs_pid != pid || _rs_forked) {
+ _rs_pid = pid;
+ _rs_forked = 0;
+ if (rs)
+ memset(rs, 0, sizeof(*rs));
+ }
+}
+
+static inline int
+_rs_allocate(struct _rs **rsp, struct _rsx **rsxp)
+{
+ if ((*rsp = mmap(NULL, sizeof(**rsp), PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
+ return (-1);
+
+ if ((*rsxp = mmap(NULL, sizeof(**rsxp), PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
+ munmap(*rsp, sizeof(**rsp));
+ *rsp = NULL;
+ return (-1);
+ }
+
+ _ARC4_ATFORK(_rs_forkhandler);
+ return (0);
+}
diff --git a/openbsd-compat/arc4random_uniform.c b/openbsd-compat/arc4random_uniform.c
new file mode 100644
index 000000000000..591f92d150fa
--- /dev/null
+++ b/openbsd-compat/arc4random_uniform.c
@@ -0,0 +1,64 @@
+/* $OpenBSD: arc4random_uniform.c,v 1.3 2019/01/20 02:59:07 bcook Exp $ */
+
+/*
+ * Copyright (c) 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/crypto/arc4random_uniform.c */
+
+#include "includes.h"
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#include <stdlib.h>
+
+#ifndef HAVE_ARC4RANDOM_UNIFORM
+/*
+ * Calculate a uniformly distributed random number less than upper_bound
+ * avoiding "modulo bias".
+ *
+ * Uniformity is achieved by generating new random numbers until the one
+ * returned is outside the range [0, 2**32 % upper_bound). This
+ * guarantees the selected random number will be inside
+ * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
+ * after reduction modulo upper_bound.
+ */
+uint32_t
+arc4random_uniform(uint32_t upper_bound)
+{
+ uint32_t r, min;
+
+ if (upper_bound < 2)
+ return 0;
+
+ /* 2**32 % x == (2**32 - x) % x */
+ min = -upper_bound % upper_bound;
+
+ /*
+ * This could theoretically loop forever but each retry has
+ * p > 0.5 (worst case, usually far better) of selecting a
+ * number inside the range we need, so it should rarely need
+ * to re-roll.
+ */
+ for (;;) {
+ r = arc4random();
+ if (r >= min)
+ break;
+ }
+
+ return r % upper_bound;
+}
+#endif /* !HAVE_ARC4RANDOM_UNIFORM */
diff --git a/openbsd-compat/bsd-asprintf.c b/openbsd-compat/bsd-asprintf.c
index 1092772717fd..511c817bb988 100644
--- a/openbsd-compat/bsd-asprintf.c
+++ b/openbsd-compat/bsd-asprintf.c
@@ -1,98 +1,99 @@
/*
* Copyright (c) 2004 Darren Tucker.
*
* Based originally on asprintf.c from OpenBSD:
* Copyright (c) 1997 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.
*/
#include "includes.h"
/*
* Don't let systems with broken printf(3) avoid our replacements
* via asprintf(3)/vasprintf(3) calling libc internally.
*/
#if defined(BROKEN_SNPRINTF)
# undef HAVE_VASPRINTF
# undef HAVE_ASPRINTF
#endif
#ifndef HAVE_VASPRINTF
#include <errno.h>
#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#define INIT_SZ 128
int
vasprintf(char **str, const char *fmt, va_list ap)
{
int ret = -1;
va_list ap2;
char *string, *newstr;
size_t len;
VA_COPY(ap2, ap);
if ((string = malloc(INIT_SZ)) == NULL)
goto fail;
ret = vsnprintf(string, INIT_SZ, fmt, ap2);
if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */
*str = string;
} else if (ret == INT_MAX || ret < 0) { /* Bad length */
free(string);
goto fail;
} else { /* bigger than initial, realloc allowing for nul */
len = (size_t)ret + 1;
if ((newstr = realloc(string, len)) == NULL) {
free(string);
goto fail;
} else {
va_end(ap2);
VA_COPY(ap2, ap);
ret = vsnprintf(newstr, len, fmt, ap2);
if (ret >= 0 && (size_t)ret < len) {
*str = newstr;
} else { /* failed with realloc'ed string, give up */
free(newstr);
goto fail;
}
}
}
va_end(ap2);
return (ret);
fail:
*str = NULL;
errno = ENOMEM;
va_end(ap2);
return (-1);
}
#endif
#ifndef HAVE_ASPRINTF
int asprintf(char **str, const char *fmt, ...)
{
va_list ap;
int ret;
*str = NULL;
va_start(ap, fmt);
ret = vasprintf(str, fmt, ap);
va_end(ap);
return ret;
}
#endif
diff --git a/openbsd-compat/bsd-getentropy.c b/openbsd-compat/bsd-getentropy.c
new file mode 100644
index 000000000000..bd4b6695acc6
--- /dev/null
+++ b/openbsd-compat/bsd-getentropy.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1996, David Mazieres <dm@uun.org>
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus@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"
+
+#ifndef HAVE_GETENTROPY
+
+#ifndef SSH_RANDOM_DEV
+# define SSH_RANDOM_DEV "/dev/urandom"
+#endif /* SSH_RANDOM_DEV */
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_RANDOM_H
+# include <sys/random.h>
+#endif
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef WITH_OPENSSL
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#endif
+
+#include "log.h"
+
+int
+_ssh_compat_getentropy(void *s, size_t len)
+{
+#ifdef WITH_OPENSSL
+ if (RAND_bytes(s, len) <= 0)
+ fatal("Couldn't obtain random bytes (error 0x%lx)",
+ (unsigned long)ERR_get_error());
+#else
+ int fd, save_errno;
+ ssize_t r;
+ size_t o = 0;
+
+#ifdef HAVE_GETRANDOM
+ if ((r = getrandom(s, len, 0)) > 0 && (size_t)r == len)
+ return 0;
+#endif /* HAVE_GETRANDOM */
+
+ if ((fd = open(SSH_RANDOM_DEV, O_RDONLY)) == -1) {
+ save_errno = errno;
+ /* Try egd/prngd before giving up. */
+ if (seed_from_prngd(s, len) == 0)
+ return 0;
+ fatal("Couldn't open %s: %s", SSH_RANDOM_DEV,
+ strerror(save_errno));
+ }
+ while (o < len) {
+ r = read(fd, (u_char *)s + o, len - o);
+ if (r < 0) {
+ if (errno == EAGAIN || errno == EINTR ||
+ errno == EWOULDBLOCK)
+ continue;
+ fatal("read %s: %s", SSH_RANDOM_DEV, strerror(errno));
+ }
+ o += r;
+ }
+ close(fd);
+#endif /* WITH_OPENSSL */
+ return 0;
+}
+#endif /* WITH_GETENTROPY */
diff --git a/openbsd-compat/bsd-misc.c b/openbsd-compat/bsd-misc.c
index 3b00ef6d240e..226a5915bd1d 100644
--- a/openbsd-compat/bsd-misc.c
+++ b/openbsd-compat/bsd-misc.c
@@ -1,448 +1,460 @@
/*
* Copyright (c) 1999-2004 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>
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#ifndef HAVE___PROGNAME
char *__progname;
#endif
/*
* NB. duplicate __progname in case it is an alias for argv[0]
* Otherwise it may get clobbered by setproctitle()
*/
char *ssh_get_progname(char *argv0)
{
char *p, *q;
#ifdef HAVE___PROGNAME
extern char *__progname;
p = __progname;
#else
if (argv0 == NULL)
return ("unknown"); /* XXX */
p = strrchr(argv0, '/');
if (p == NULL)
p = argv0;
else
p++;
#endif
if ((q = strdup(p)) == NULL) {
perror("strdup");
exit(1);
}
return q;
}
#ifndef HAVE_SETLOGIN
int setlogin(const char *name)
{
return (0);
}
#endif /* !HAVE_SETLOGIN */
#ifndef HAVE_INNETGR
int innetgr(const char *netgroup, const char *host,
const char *user, const char *domain)
{
return (0);
}
#endif /* HAVE_INNETGR */
#if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID)
int seteuid(uid_t euid)
{
return (setreuid(-1, euid));
}
#endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */
#if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID)
int setegid(uid_t egid)
{
return(setresgid(-1, egid, -1));
}
#endif /* !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */
#if !defined(HAVE_STRERROR) && defined(HAVE_SYS_ERRLIST) && defined(HAVE_SYS_NERR)
const char *strerror(int e)
{
extern int sys_nerr;
extern char *sys_errlist[];
if ((e >= 0) && (e < sys_nerr))
return (sys_errlist[e]);
return ("unlisted error");
}
#endif
#ifndef HAVE_UTIMES
int utimes(const char *filename, struct timeval *tvp)
{
struct utimbuf ub;
ub.actime = tvp[0].tv_sec;
ub.modtime = tvp[1].tv_sec;
return (utime(filename, &ub));
}
#endif
#ifndef HAVE_UTIMENSAT
/*
* A limited implementation of utimensat() that only implements the
* functionality used by OpenSSH, currently only AT_FDCWD and
* AT_SYMLINK_NOFOLLOW.
*/
int
utimensat(int fd, const char *path, const struct timespec times[2],
int flag)
{
struct timeval tv[2];
# ifdef HAVE_FUTIMES
int ret, oflags = O_WRONLY;
# endif
tv[0].tv_sec = times[0].tv_sec;
tv[0].tv_usec = times[0].tv_nsec / 1000;
tv[1].tv_sec = times[1].tv_sec;
tv[1].tv_usec = times[1].tv_nsec / 1000;
if (fd != AT_FDCWD) {
errno = ENOSYS;
return -1;
}
# ifndef HAVE_FUTIMES
return utimes(path, tv);
# else
# ifdef O_NOFOLLOW
if (flag & AT_SYMLINK_NOFOLLOW)
oflags |= O_NOFOLLOW;
# endif /* O_NOFOLLOW */
if ((fd = open(path, oflags)) == -1)
return -1;
ret = futimes(fd, tv);
close(fd);
return ret;
# endif
}
#endif
#ifndef HAVE_FCHOWNAT
/*
* A limited implementation of fchownat() that only implements the
* functionality used by OpenSSH, currently only AT_FDCWD and
* AT_SYMLINK_NOFOLLOW.
*/
int
fchownat(int fd, const char *path, uid_t owner, gid_t group, int flag)
{
int ret, oflags = O_WRONLY;
if (fd != AT_FDCWD) {
errno = ENOSYS;
return -1;
}
# ifndef HAVE_FCHOWN
return chown(path, owner, group);
# else
# ifdef O_NOFOLLOW
if (flag & AT_SYMLINK_NOFOLLOW)
oflags |= O_NOFOLLOW;
# endif /* O_NOFOLLOW */
if ((fd = open(path, oflags)) == -1)
return -1;
ret = fchown(fd, owner, group);
close(fd);
return ret;
# endif
}
#endif
#ifndef HAVE_FCHMODAT
/*
* A limited implementation of fchmodat() that only implements the
* functionality used by OpenSSH, currently only AT_FDCWD and
* AT_SYMLINK_NOFOLLOW.
*/
int
fchmodat(int fd, const char *path, mode_t mode, int flag)
{
int ret, oflags = O_WRONLY;
if (fd != AT_FDCWD) {
errno = ENOSYS;
return -1;
}
# ifndef HAVE_FCHMOD
return chmod(path, mode);
# else
# ifdef O_NOFOLLOW
if (flag & AT_SYMLINK_NOFOLLOW)
oflags |= O_NOFOLLOW;
# endif /* O_NOFOLLOW */
if ((fd = open(path, oflags)) == -1)
return -1;
ret = fchmod(fd, mode);
close(fd);
return ret;
# endif
}
#endif
#ifndef HAVE_TRUNCATE
int truncate(const char *path, off_t length)
{
int fd, ret, saverrno;
fd = open(path, O_WRONLY);
if (fd < 0)
return (-1);
ret = ftruncate(fd, length);
saverrno = errno;
close(fd);
if (ret == -1)
errno = saverrno;
return(ret);
}
#endif /* HAVE_TRUNCATE */
#if !defined(HAVE_NANOSLEEP) && !defined(HAVE_NSLEEP)
int nanosleep(const struct timespec *req, struct timespec *rem)
{
int rc, saverrno;
extern int errno;
struct timeval tstart, tstop, tremain, time2wait;
TIMESPEC_TO_TIMEVAL(&time2wait, req)
(void) gettimeofday(&tstart, NULL);
rc = select(0, NULL, NULL, NULL, &time2wait);
if (rc == -1) {
saverrno = errno;
(void) gettimeofday (&tstop, NULL);
errno = saverrno;
tremain.tv_sec = time2wait.tv_sec -
(tstop.tv_sec - tstart.tv_sec);
tremain.tv_usec = time2wait.tv_usec -
(tstop.tv_usec - tstart.tv_usec);
tremain.tv_sec += tremain.tv_usec / 1000000L;
tremain.tv_usec %= 1000000L;
} else {
tremain.tv_sec = 0;
tremain.tv_usec = 0;
}
if (rem != NULL)
TIMEVAL_TO_TIMESPEC(&tremain, rem)
return(rc);
}
#endif
#if !defined(HAVE_USLEEP)
int usleep(unsigned int useconds)
{
struct timespec ts;
ts.tv_sec = useconds / 1000000;
ts.tv_nsec = (useconds % 1000000) * 1000;
return nanosleep(&ts, NULL);
}
#endif
#ifndef HAVE_TCGETPGRP
pid_t
tcgetpgrp(int fd)
{
int ctty_pgrp;
if (ioctl(fd, TIOCGPGRP, &ctty_pgrp) == -1)
return(-1);
else
return(ctty_pgrp);
}
#endif /* HAVE_TCGETPGRP */
#ifndef HAVE_TCSENDBREAK
int
tcsendbreak(int fd, int duration)
{
# if defined(TIOCSBRK) && defined(TIOCCBRK)
struct timeval sleepytime;
sleepytime.tv_sec = 0;
sleepytime.tv_usec = 400000;
if (ioctl(fd, TIOCSBRK, 0) == -1)
return (-1);
(void)select(0, 0, 0, 0, &sleepytime);
if (ioctl(fd, TIOCCBRK, 0) == -1)
return (-1);
return (0);
# else
return -1;
# endif
}
#endif /* HAVE_TCSENDBREAK */
#ifndef HAVE_STRDUP
char *
strdup(const char *str)
{
size_t len;
char *cp;
len = strlen(str) + 1;
cp = malloc(len);
if (cp != NULL)
return(memcpy(cp, str, len));
return NULL;
}
#endif
#ifndef HAVE_ISBLANK
int
isblank(int c)
{
return (c == ' ' || c == '\t');
}
#endif
#ifndef HAVE_GETPGID
pid_t
getpgid(pid_t pid)
{
#if defined(HAVE_GETPGRP) && !defined(GETPGRP_VOID) && GETPGRP_VOID == 0
return getpgrp(pid);
#elif defined(HAVE_GETPGRP)
if (pid == 0)
return getpgrp();
#endif
errno = ESRCH;
return -1;
}
#endif
#ifndef HAVE_PLEDGE
int
pledge(const char *promises, const char *paths[])
{
return 0;
}
#endif
#ifndef HAVE_MBTOWC
/* a mbtowc that only supports ASCII */
int
mbtowc(wchar_t *pwc, const char *s, size_t n)
{
if (s == NULL || *s == '\0')
return 0; /* ASCII is not state-dependent */
if (*s < 0 || *s > 0x7f || n < 1) {
errno = EOPNOTSUPP;
return -1;
}
if (pwc != NULL)
*pwc = *s;
return 1;
}
#endif
#ifndef HAVE_LLABS
long long
llabs(long long j)
{
return (j < 0 ? -j : j);
}
#endif
#ifndef HAVE_BZERO
void
bzero(void *b, size_t n)
{
(void)memset(b, 0, n);
}
#endif
#ifndef HAVE_RAISE
int
raise(int sig)
{
kill(getpid(), sig);
}
#endif
#ifndef HAVE_GETSID
pid_t
getsid(pid_t pid)
{
errno = ENOSYS;
return -1;
}
#endif
#ifndef HAVE_KILLPG
int
killpg(pid_t pgrp, int sig)
{
return kill(pgrp, sig);
}
#endif
#ifdef FFLUSH_NULL_BUG
#undef fflush
int _ssh_compat_fflush(FILE *f)
{
int r1, r2;
if (f == NULL) {
r1 = fflush(stdout);
r2 = fflush(stderr);
if (r1 == -1 || r2 == -1)
return -1;
return 0;
}
return fflush(f);
}
#endif
#ifndef HAVE_LOCALTIME_R
struct tm *
localtime_r(const time_t *timep, struct tm *result)
{
struct tm *tm = localtime(timep);
*result = *tm;
return result;
}
#endif
+
+#ifdef ASAN_OPTIONS
+const char *__asan_default_options(void) {
+ return ASAN_OPTIONS;
+}
+#endif
+
+#ifdef MSAN_OPTIONS
+const char *__msan_default_options(void) {
+ return MSAN_OPTIONS;
+}
+#endif
diff --git a/openbsd-compat/bsd-timegm.c b/openbsd-compat/bsd-timegm.c
new file mode 100644
index 000000000000..14f6bbf14dad
--- /dev/null
+++ b/openbsd-compat/bsd-timegm.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/*
+ adapted for Samba4 by Andrew Tridgell
+*/
+
+#include "includes.h"
+
+#include <time.h>
+
+#ifndef HAVE_TIMEGM
+
+static int is_leap(unsigned y)
+{
+ y += 1900;
+ return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0);
+}
+
+time_t timegm(struct tm *tm)
+{
+ static const unsigned ndays[2][12] ={
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
+ time_t res = 0;
+ unsigned i;
+
+ if (tm->tm_mon > 12 ||
+ tm->tm_mon < 0 ||
+ tm->tm_mday > 31 ||
+ tm->tm_min > 60 ||
+ tm->tm_sec > 60 ||
+ tm->tm_hour > 24) {
+ /* invalid tm structure */
+ return 0;
+ }
+
+ for (i = 70; i < tm->tm_year; ++i)
+ res += is_leap(i) ? 366 : 365;
+
+ for (i = 0; i < tm->tm_mon; ++i)
+ res += ndays[is_leap(tm->tm_year)][i];
+ res += tm->tm_mday - 1;
+ res *= 24;
+ res += tm->tm_hour;
+ res *= 60;
+ res += tm->tm_min;
+ res *= 60;
+ res += tm->tm_sec;
+ return res;
+}
+#endif /* HAVE_TIMEGM */
diff --git a/openbsd-compat/getcwd.c b/openbsd-compat/getcwd.c
index 2d56bae19dd6..a904291a29d6 100644
--- a/openbsd-compat/getcwd.c
+++ b/openbsd-compat/getcwd.c
@@ -1,239 +1,242 @@
/* $OpenBSD: getcwd.c,v 1.14 2005/08/08 08:05:34 espie Exp */
/*
* Copyright (c) 1989, 1991, 1993
* 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.
*/
/* OPENBSD ORIGINAL: lib/libc/gen/getcwd.c */
#include "includes.h"
#if !defined(HAVE_GETCWD)
#include <sys/stat.h>
#include <errno.h>
#include <dirent.h>
#include <sys/dir.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "includes.h"
#define ISDOT(dp) \
(dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
(dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
char *
getcwd(char *pt, size_t size)
{
struct dirent *dp;
DIR *dir = NULL;
dev_t dev;
ino_t ino;
int first;
char *bpt, *bup;
struct stat s;
dev_t root_dev;
ino_t root_ino;
size_t ptsize, upsize;
int save_errno;
char *ept, *eup, *up;
/*
* If no buffer specified by the user, allocate one as necessary.
* If a buffer is specified, the size has to be non-zero. The path
* is built from the end of the buffer backwards.
*/
if (pt) {
ptsize = 0;
- if (!size) {
+ if (size == 0) {
errno = EINVAL;
return (NULL);
+ } else if (size == 1) {
+ errno = ERANGE;
+ return (NULL);
}
ept = pt + size;
} else {
if ((pt = malloc(ptsize = MAXPATHLEN)) == NULL)
return (NULL);
ept = pt + ptsize;
}
bpt = ept - 1;
*bpt = '\0';
/*
* Allocate bytes for the string of "../"'s.
* Should always be enough (it's 340 levels). If it's not, allocate
* as necessary. Special * case the first stat, it's ".", not "..".
*/
if ((up = malloc(upsize = MAXPATHLEN)) == NULL)
goto err;
eup = up + upsize;
bup = up;
up[0] = '.';
up[1] = '\0';
/* Save root values, so know when to stop. */
if (stat("/", &s))
goto err;
root_dev = s.st_dev;
root_ino = s.st_ino;
errno = 0; /* XXX readdir has no error return. */
for (first = 1;; first = 0) {
/* Stat the current level. */
if (lstat(up, &s))
goto err;
/* Save current node values. */
ino = s.st_ino;
dev = s.st_dev;
/* Check for reaching root. */
if (root_dev == dev && root_ino == ino) {
*--bpt = '/';
/*
* It's unclear that it's a requirement to copy the
* path to the beginning of the buffer, but it's always
* been that way and stuff would probably break.
*/
memmove(pt, bpt, ept - bpt);
free(up);
return (pt);
}
/*
* Build pointer to the parent directory, allocating memory
* as necessary. Max length is 3 for "../", the largest
* possible component name, plus a trailing NUL.
*/
if (bup + 3 + MAXNAMLEN + 1 >= eup) {
char *nup;
if ((nup = realloc(up, upsize *= 2)) == NULL)
goto err;
bup = nup + (bup - up);
up = nup;
eup = up + upsize;
}
*bup++ = '.';
*bup++ = '.';
*bup = '\0';
/* Open and stat parent directory. */
if (!(dir = opendir(up)) || fstat(dirfd(dir), &s))
goto err;
/* Add trailing slash for next directory. */
*bup++ = '/';
/*
* If it's a mount point, have to stat each element because
* the inode number in the directory is for the entry in the
* parent directory, not the inode number of the mounted file.
*/
save_errno = 0;
if (s.st_dev == dev) {
for (;;) {
if (!(dp = readdir(dir)))
goto notfound;
if (dp->d_fileno == ino)
break;
}
} else
for (;;) {
if (!(dp = readdir(dir)))
goto notfound;
if (ISDOT(dp))
continue;
memcpy(bup, dp->d_name, dp->d_namlen + 1);
/* Save the first error for later. */
if (lstat(up, &s)) {
if (!save_errno)
save_errno = errno;
errno = 0;
continue;
}
if (s.st_dev == dev && s.st_ino == ino)
break;
}
/*
* Check for length of the current name, preceding slash,
* leading slash.
*/
if (bpt - pt < dp->d_namlen + (first ? 1 : 2)) {
size_t len;
char *npt;
if (!ptsize) {
errno = ERANGE;
goto err;
}
len = ept - bpt;
if ((npt = realloc(pt, ptsize *= 2)) == NULL)
goto err;
bpt = npt + (bpt - pt);
pt = npt;
ept = pt + ptsize;
memmove(ept - len, bpt, len);
bpt = ept - len;
}
if (!first)
*--bpt = '/';
bpt -= dp->d_namlen;
memcpy(bpt, dp->d_name, dp->d_namlen);
(void)closedir(dir);
/* Truncate any file name. */
*bup = '\0';
}
notfound:
/*
* If readdir set errno, use it, not any saved error; otherwise,
* didn't find the current directory in its parent directory, set
* errno to ENOENT.
*/
if (!errno)
errno = save_errno ? save_errno : ENOENT;
/* FALLTHROUGH */
err:
save_errno = errno;
if (ptsize)
free(pt);
free(up);
if (dir)
(void)closedir(dir);
errno = save_errno;
return (NULL);
}
#endif /* !defined(HAVE_GETCWD) */
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h
index 4316ab84bf89..4af207cdd40f 100644
--- a/openbsd-compat/openbsd-compat.h
+++ b/openbsd-compat/openbsd-compat.h
@@ -1,374 +1,381 @@
/*
* Copyright (c) 1999-2003 Damien Miller. All rights reserved.
* Copyright (c) 2003 Ben Lindstrom. All rights reserved.
* Copyright (c) 2002 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.
*/
#ifndef _OPENBSD_COMPAT_H
#define _OPENBSD_COMPAT_H
#include "includes.h"
#include <sys/types.h>
#include <pwd.h>
#include <sys/socket.h>
#include <stddef.h> /* for wchar_t */
/* OpenBSD function replacements */
#include "base64.h"
#include "sigact.h"
#include "readpassphrase.h"
#include "vis.h"
#include "getrrsetbyname.h"
#include "sha1.h"
#include "sha2.h"
#include "md5.h"
#include "blf.h"
#include "fnmatch.h"
#if defined(HAVE_LOGIN_CAP) && !defined(HAVE_LOGIN_GETPWCLASS)
# include <login_cap.h>
# define login_getpwclass(pw) login_getclass(pw->pw_class)
#endif
#ifndef HAVE_BASENAME
char *basename(const char *path);
#endif
#ifndef HAVE_BINDRESVPORT_SA
int bindresvport_sa(int sd, struct sockaddr *sa);
#endif
#ifndef HAVE_CLOSEFROM
void closefrom(int);
#endif
#if defined(HAVE_DECL_FTRUNCATE) && HAVE_DECL_FTRUNCATE == 0
int ftruncate(int filedes, off_t length);
#endif
+#if defined(HAVE_DECL_GETENTROPY) && HAVE_DECL_GETENTROPY == 0
+int _ssh_compat_getentropy(void *, size_t);
+#endif
+
#ifndef HAVE_GETLINE
#include <stdio.h>
ssize_t getline(char **, size_t *, FILE *);
#endif
#ifndef HAVE_GETPAGESIZE
int getpagesize(void);
#endif
#ifndef HAVE_GETCWD
char *getcwd(char *pt, size_t size);
#endif
#ifndef HAVE_KILLPG
int killpg(pid_t, int);
#endif
#if defined(HAVE_DECL_MEMMEM) && HAVE_DECL_MEMMEM == 0
void *memmem(const void *, size_t, const void *, size_t);
#endif
#ifndef HAVE_REALLOCARRAY
void *reallocarray(void *, size_t, size_t);
#endif
#ifndef HAVE_RECALLOCARRAY
void *recallocarray(void *, size_t, size_t, size_t);
#endif
#ifndef HAVE_RRESVPORT_AF
int rresvport_af(int *alport, sa_family_t af);
#endif
#ifndef HAVE_STRLCPY
size_t strlcpy(char *dst, const char *src, size_t siz);
#endif
#ifndef HAVE_STRLCAT
size_t strlcat(char *dst, const char *src, size_t siz);
#endif
#ifndef HAVE_STRCASESTR
char *strcasestr(const char *, const char *);
#endif
#ifndef HAVE_STRNLEN
size_t strnlen(const char *, size_t);
#endif
#ifndef HAVE_STRNDUP
char *strndup(const char *s, size_t n);
#endif
#ifndef HAVE_SETENV
int setenv(register const char *name, register const char *value, int rewrite);
#endif
#ifndef HAVE_STRMODE
void strmode(int mode, char *p);
#endif
#ifndef HAVE_STRPTIME
#include <time.h>
char *strptime(const char *buf, const char *fmt, struct tm *tm);
#endif
#if !defined(HAVE_MKDTEMP)
int mkstemps(char *path, int slen);
int mkstemp(char *path);
char *mkdtemp(char *path);
#endif
#ifndef HAVE_DAEMON
int daemon(int nochdir, int noclose);
#endif
#ifndef HAVE_DIRNAME
char *dirname(const char *path);
#endif
#ifndef HAVE_FMT_SCALED
#define FMT_SCALED_STRSIZE 7
int fmt_scaled(long long number, char *result);
#endif
#ifndef HAVE_SCAN_SCALED
int scan_scaled(char *, long long *);
#endif
#if defined(BROKEN_INET_NTOA) || !defined(HAVE_INET_NTOA)
char *inet_ntoa(struct in_addr in);
#endif
#ifndef HAVE_INET_NTOP
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
#endif
#ifndef HAVE_INET_ATON
int inet_aton(const char *cp, struct in_addr *addr);
#endif
#ifndef HAVE_STRSEP
char *strsep(char **stringp, const char *delim);
#endif
#ifndef HAVE_SETPROCTITLE
void setproctitle(const char *fmt, ...);
void compat_init_setproctitle(int argc, char *argv[]);
#endif
#ifndef HAVE_GETGROUPLIST
int getgrouplist(const char *, gid_t, gid_t *, int *);
#endif
#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET)
int BSDgetopt(int argc, char * const *argv, const char *opts);
#include "openbsd-compat/getopt.h"
#endif
#if ((defined(HAVE_DECL_READV) && HAVE_DECL_READV == 0) || \
(defined(HAVE_DECL_WRITEV) && HAVE_DECL_WRITEV == 0))
# include <sys/types.h>
# include <sys/uio.h>
# if defined(HAVE_DECL_READV) && HAVE_DECL_READV == 0
int readv(int, struct iovec *, int);
# endif
# if defined(HAVE_DECL_WRITEV) && HAVE_DECL_WRITEV == 0
int writev(int, struct iovec *, int);
# endif
#endif
/* Home grown routines */
#include "bsd-signal.h"
#include "bsd-misc.h"
#include "bsd-setres_id.h"
#include "bsd-statvfs.h"
#include "bsd-waitpid.h"
#include "bsd-poll.h"
#if defined(HAVE_DECL_GETPEEREID) && HAVE_DECL_GETPEEREID == 0
int getpeereid(int , uid_t *, gid_t *);
#endif
-#ifdef HAVE_ARC4RANDOM
-# ifndef HAVE_ARC4RANDOM_STIR
-# define arc4random_stir()
-# endif
-#else
-unsigned int arc4random(void);
-void arc4random_stir(void);
+#ifndef HAVE_ARC4RANDOM
+uint32_t arc4random(void);
#endif /* !HAVE_ARC4RANDOM */
#ifndef HAVE_ARC4RANDOM_BUF
void arc4random_buf(void *, size_t);
#endif
+#ifndef HAVE_ARC4RANDOM_STIR
+# define arc4random_stir()
+#endif
+
#ifndef HAVE_ARC4RANDOM_UNIFORM
-u_int32_t arc4random_uniform(u_int32_t);
+uint32_t arc4random_uniform(uint32_t);
#endif
#ifndef HAVE_ASPRINTF
int asprintf(char **, const char *, ...);
#endif
#ifndef HAVE_OPENPTY
# include <sys/ioctl.h> /* for struct winsize */
int openpty(int *, int *, char *, struct termios *, struct winsize *);
#endif /* HAVE_OPENPTY */
#ifndef HAVE_SNPRINTF
int snprintf(char *, size_t, SNPRINTF_CONST char *, ...);
#endif
#ifndef HAVE_STRTOLL
long long strtoll(const char *, char **, int);
#endif
#ifndef HAVE_STRTOUL
unsigned long strtoul(const char *, char **, int);
#endif
#ifndef HAVE_STRTOULL
unsigned long long strtoull(const char *, char **, int);
#endif
#ifndef HAVE_STRTONUM
long long strtonum(const char *, long long, long long, const char **);
#endif
/* multibyte character support */
#ifndef HAVE_MBLEN
# define mblen(x, y) (1)
#endif
#ifndef HAVE_WCWIDTH
# define wcwidth(x) (((x) >= 0x20 && (x) <= 0x7e) ? 1 : -1)
/* force our no-op nl_langinfo and mbtowc */
# undef HAVE_NL_LANGINFO
# undef HAVE_MBTOWC
# undef HAVE_LANGINFO_H
#endif
#ifndef HAVE_NL_LANGINFO
# define nl_langinfo(x) ""
#endif
#ifndef HAVE_MBTOWC
int mbtowc(wchar_t *, const char*, size_t);
#endif
#if !defined(HAVE_VASPRINTF) || !defined(HAVE_VSNPRINTF)
# include <stdarg.h>
#endif
/*
* Some platforms unconditionally undefine va_copy() so we define VA_COPY()
* instead. This is known to be the case on at least some configurations of
* AIX with the xlc compiler.
*/
#ifndef VA_COPY
# ifdef HAVE_VA_COPY
# define VA_COPY(dest, src) va_copy(dest, src)
# else
# ifdef HAVE___VA_COPY
# define VA_COPY(dest, src) __va_copy(dest, src)
# else
# define VA_COPY(dest, src) (dest) = (src)
# endif
# endif
#endif
#ifndef HAVE_VASPRINTF
int vasprintf(char **, const char *, va_list);
#endif
#ifndef HAVE_VSNPRINTF
int vsnprintf(char *, size_t, const char *, va_list);
#endif
#ifndef HAVE_USER_FROM_UID
char *user_from_uid(uid_t, int);
#endif
#ifndef HAVE_GROUP_FROM_GID
char *group_from_gid(gid_t, int);
#endif
#ifndef HAVE_TIMINGSAFE_BCMP
int timingsafe_bcmp(const void *, const void *, size_t);
#endif
#ifndef HAVE_BCRYPT_PBKDF
int bcrypt_pbkdf(const char *, size_t, const uint8_t *, size_t,
uint8_t *, size_t, unsigned int);
#endif
#ifndef HAVE_EXPLICIT_BZERO
void explicit_bzero(void *p, size_t n);
#endif
#ifndef HAVE_FREEZERO
void freezero(void *, size_t);
#endif
#ifndef HAVE_LOCALTIME_R
struct tm *localtime_r(const time_t *, struct tm *);
#endif
+#ifndef HAVE_TIMEGM
+time_t timegm(struct tm *);
+#endif
+
char *xcrypt(const char *password, const char *salt);
char *shadow_pw(struct passwd *pw);
/* rfc2553 socket API replacements */
#include "fake-rfc2553.h"
/* Routines for a single OS platform */
#include "bsd-cygwin_util.h"
#include "port-aix.h"
#include "port-irix.h"
#include "port-linux.h"
#include "port-solaris.h"
#include "port-net.h"
#include "port-uw.h"
/* _FORTIFY_SOURCE breaks FD_ISSET(n)/FD_SET(n) for n > FD_SETSIZE. Avoid. */
#if defined(HAVE_FEATURES_H) && defined(_FORTIFY_SOURCE)
# include <features.h>
# if defined(__GNU_LIBRARY__) && defined(__GLIBC_PREREQ)
# if __GLIBC_PREREQ(2, 15) && (_FORTIFY_SOURCE > 0)
# include <sys/socket.h> /* Ensure include guard is defined */
# undef FD_SET
# undef FD_ISSET
# define FD_SET(n, set) kludge_FD_SET(n, set)
# define FD_ISSET(n, set) kludge_FD_ISSET(n, set)
void kludge_FD_SET(int, fd_set *);
int kludge_FD_ISSET(int, fd_set *);
# endif /* __GLIBC_PREREQ(2, 15) && (_FORTIFY_SOURCE > 0) */
# endif /* __GNU_LIBRARY__ && __GLIBC_PREREQ */
#endif /* HAVE_FEATURES_H && _FORTIFY_SOURCE */
#endif /* _OPENBSD_COMPAT_H */
diff --git a/openbsd-compat/openssl-compat.h b/openbsd-compat/openssl-compat.h
index 8ca50b5ace63..61a69dd56eb2 100644
--- a/openbsd-compat/openssl-compat.h
+++ b/openbsd-compat/openssl-compat.h
@@ -1,237 +1,212 @@
/*
* Copyright (c) 2005 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 MIND, 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.
*/
#ifndef _OPENSSL_COMPAT_H
#define _OPENSSL_COMPAT_H
#include "includes.h"
#ifdef WITH_OPENSSL
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#ifdef OPENSSL_HAS_ECC
#include <openssl/ecdsa.h>
#endif
#include <openssl/dh.h>
int ssh_compatible_openssl(long, long);
void ssh_libcrypto_init(void);
#if (OPENSSL_VERSION_NUMBER < 0x1000100fL)
# error OpenSSL 1.0.1 or greater is required
#endif
#ifndef OPENSSL_VERSION
# define OPENSSL_VERSION SSLEAY_VERSION
#endif
#ifndef HAVE_OPENSSL_VERSION
# define OpenSSL_version(x) SSLeay_version(x)
#endif
#ifndef HAVE_OPENSSL_VERSION_NUM
# define OpenSSL_version_num SSLeay
#endif
#if OPENSSL_VERSION_NUMBER < 0x10000001L
# define LIBCRYPTO_EVP_INL_TYPE unsigned int
#else
# define LIBCRYPTO_EVP_INL_TYPE size_t
#endif
#ifndef OPENSSL_RSA_MAX_MODULUS_BITS
# define OPENSSL_RSA_MAX_MODULUS_BITS 16384
#endif
#ifndef OPENSSL_DSA_MAX_MODULUS_BITS
# define OPENSSL_DSA_MAX_MODULUS_BITS 10000
#endif
#ifdef LIBRESSL_VERSION_NUMBER
# if LIBRESSL_VERSION_NUMBER < 0x3010000fL
# define HAVE_BROKEN_CHACHA20
# endif
#endif
-#ifndef OPENSSL_HAVE_EVPCTR
-# define EVP_aes_128_ctr evp_aes_128_ctr
-# define EVP_aes_192_ctr evp_aes_128_ctr
-# define EVP_aes_256_ctr evp_aes_128_ctr
-const EVP_CIPHER *evp_aes_128_ctr(void);
-void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, size_t);
-#endif
-
-/* Avoid some #ifdef. Code that uses these is unreachable without GCM */
-#if !defined(OPENSSL_HAVE_EVPGCM) && !defined(EVP_CTRL_GCM_SET_IV_FIXED)
-# define EVP_CTRL_GCM_SET_IV_FIXED -1
-# define EVP_CTRL_GCM_IV_GEN -1
-# define EVP_CTRL_GCM_SET_TAG -1
-# define EVP_CTRL_GCM_GET_TAG -1
-#endif
-
-/* Replace missing EVP_CIPHER_CTX_ctrl() with something that returns failure */
-#ifndef HAVE_EVP_CIPHER_CTX_CTRL
-# ifdef OPENSSL_HAVE_EVPGCM
-# error AES-GCM enabled without EVP_CIPHER_CTX_ctrl /* shouldn't happen */
-# else
-# define EVP_CIPHER_CTX_ctrl(a,b,c,d) (0)
-# endif
-#endif
-
/* LibreSSL/OpenSSL 1.1x API compat */
#ifndef HAVE_DSA_GET0_PQG
void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q,
const BIGNUM **g);
#endif /* HAVE_DSA_GET0_PQG */
#ifndef HAVE_DSA_SET0_PQG
int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
#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);
#endif /* HAVE_DSA_GET0_KEY */
#ifndef HAVE_DSA_SET0_KEY
int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key);
#endif /* HAVE_DSA_SET0_KEY */
#ifndef HAVE_EVP_CIPHER_CTX_GET_IV
# ifdef HAVE_EVP_CIPHER_CTX_GET_UPDATED_IV
# define EVP_CIPHER_CTX_get_iv EVP_CIPHER_CTX_get_updated_iv
# else /* HAVE_EVP_CIPHER_CTX_GET_UPDATED_IV */
int EVP_CIPHER_CTX_get_iv(const EVP_CIPHER_CTX *ctx,
unsigned char *iv, size_t len);
# endif /* HAVE_EVP_CIPHER_CTX_GET_UPDATED_IV */
#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);
#endif /* HAVE_EVP_CIPHER_CTX_SET_IV */
#ifndef HAVE_RSA_GET0_KEY
void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e,
const BIGNUM **d);
#endif /* HAVE_RSA_GET0_KEY */
#ifndef HAVE_RSA_SET0_KEY
int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
#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);
#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);
#endif /* HAVE_RSA_SET0_CRT_PARAMS */
#ifndef HAVE_RSA_GET0_FACTORS
void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
#endif /* HAVE_RSA_GET0_FACTORS */
#ifndef HAVE_RSA_SET0_FACTORS
int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q);
#endif /* HAVE_RSA_SET0_FACTORS */
#ifndef DSA_SIG_GET0
void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
#endif /* DSA_SIG_GET0 */
#ifndef DSA_SIG_SET0
int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s);
#endif /* 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);
#endif /* HAVE_ECDSA_SIG_GET0 */
#ifndef HAVE_ECDSA_SIG_SET0
int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s);
#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);
#endif /* HAVE_DH_GET0_PQG */
#ifndef HAVE_DH_SET0_PQG
int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g);
#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);
#endif /* HAVE_DH_GET0_KEY */
#ifndef HAVE_DH_SET0_KEY
int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key);
#endif /* HAVE_DH_SET0_KEY */
#ifndef HAVE_DH_SET_LENGTH
int DH_set_length(DH *dh, long length);
#endif /* HAVE_DH_SET_LENGTH */
#ifndef HAVE_RSA_METH_FREE
void RSA_meth_free(RSA_METHOD *meth);
#endif /* HAVE_RSA_METH_FREE */
#ifndef HAVE_RSA_METH_DUP
RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth);
#endif /* HAVE_RSA_METH_DUP */
#ifndef HAVE_RSA_METH_SET1_NAME
int RSA_meth_set1_name(RSA_METHOD *meth, const char *name);
#endif /* HAVE_RSA_METH_SET1_NAME */
#ifndef HAVE_RSA_METH_GET_FINISH
int (*RSA_meth_get_finish(const RSA_METHOD *meth))(RSA *rsa);
#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));
#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));
#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));
#endif /* HAVE_RSA_METH_SET_FINISH */
#ifndef HAVE_EVP_PKEY_GET0_RSA
RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey);
#endif /* HAVE_EVP_PKEY_GET0_RSA */
#ifndef HAVE_EVP_MD_CTX_new
EVP_MD_CTX *EVP_MD_CTX_new(void);
#endif /* HAVE_EVP_MD_CTX_new */
#ifndef HAVE_EVP_MD_CTX_free
void EVP_MD_CTX_free(EVP_MD_CTX *ctx);
#endif /* HAVE_EVP_MD_CTX_free */
#endif /* WITH_OPENSSL */
#endif /* _OPENSSL_COMPAT_H */
diff --git a/packet.c b/packet.c
index bde6c1045e8a..3f64d2d32854 100644
--- a/packet.c
+++ b/packet.c
@@ -1,2719 +1,2719 @@
-/* $OpenBSD: packet.c,v 1.307 2022/01/22 00:49:34 djm Exp $ */
+/* $OpenBSD: packet.c,v 1.308 2022/08/31 02:56: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))
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_SYNC_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_f("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);
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: %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) {
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
+ * 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));
}
int
ssh_packet_check_rekey(struct ssh *ssh)
{
if (!ssh_packet_need_rekeying(ssh, 0))
return 0;
debug3_f("rekex triggered");
return kex_start_rekex(ssh);
}
/*
* 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;
struct pollfd pfd;
char buf[8192];
struct timeval start;
struct timespec timespec, *timespecp = NULL;
DBG(debug("packet_read()"));
/*
* 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.
*/
pfd.fd = state->connection_in;
pfd.events = POLLIN;
if (state->packet_timeout_ms > 0) {
ms_remain = state->packet_timeout_ms;
timespecp = &timespec;
}
/* Wait for some data to arrive. */
for (;;) {
if (state->packet_timeout_ms > 0) {
ms_to_timespec(&timespec, ms_remain);
monotime_tv(&start);
}
if ((r = ppoll(&pfd, 1, timespecp, NULL)) >= 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:
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;
if ((r = ssh_packet_check_rekey(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 supplied input data. 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(state->input, buf, len)) != 0)
return r;
return 0;
}
/* Reads and buffers data from the specified fd */
int
ssh_packet_process_read(struct ssh *ssh, int fd)
{
struct session_state *state = ssh->state;
int r;
size_t rlen;
if ((r = sshbuf_read(fd, state->input, PACKET_MAX_SIZE, &rlen)) != 0)
return r;
if (state->packet_discard) {
if ((r = sshbuf_consume_end(state->input, rlen)) != 0)
return r;
state->keep_alive_timeouts = 0; /* ?? */
if (rlen >= state->packet_discard) {
if ((r = ssh_packet_stop_discard(ssh)) != 0)
return r;
}
state->packet_discard -= rlen;
return 0;
}
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)
{
int ret, r, ms_remain = 0;
struct timeval start;
struct timespec timespec, *timespecp = NULL;
struct session_state *state = ssh->state;
struct pollfd pfd;
if ((r = ssh_packet_write_poll(ssh)) != 0)
return r;
while (ssh_packet_have_data_to_write(ssh)) {
pfd.fd = state->connection_out;
pfd.events = POLLOUT;
if (state->packet_timeout_ms > 0) {
ms_remain = state->packet_timeout_ms;
timespecp = &timespec;
}
for (;;) {
if (state->packet_timeout_ms > 0) {
ms_to_timespec(&timespec, ms_remain);
monotime_tv(&start);
}
if ((ret = ppoll(&pfd, 1, timespecp, NULL)) >= 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)
return SSH_ERR_CONN_TIMEOUT;
if ((r = ssh_packet_write_poll(ssh)) != 0)
return r;
}
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_f("called twice: old %d new %d",
state->max_packet_size, s);
return -1;
}
if (s < 4 * 1024 || s > 1024 * 1024) {
logit_f("bad size %d", s);
return -1;
}
state->set_maxsize_called = 1;
debug_f("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 f26fabaa6af4..42be690b13d5 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,3476 +1,3470 @@
-/* $OpenBSD: readconf.c,v 1.366 2022/02/08 08:59:12 dtucker Exp $ */
+/* $OpenBSD: readconf.c,v 1.369 2022/09/17 10:33:18 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,
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, oSessionType, oStdinNull,
oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass,
oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
- oSecurityKeyProvider, oKnownHostsCommand,
+ oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize,
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 },
{ "challengeresponseauthentication", oKbdInteractiveAuthentication }, /* alias */
{ "skeyauthentication", oKbdInteractiveAuthentication }, /* alias */
{ "tisauthentication", oKbdInteractiveAuthentication }, /* alias */
{ "pubkeyauthentication", oPubkeyAuthentication },
{ "dsaauthentication", oPubkeyAuthentication }, /* alias */
{ "hostbasedauthentication", oHostbasedAuthentication },
{ "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 },
{ "sessiontype", oSessionType },
{ "stdinnull", oStdinNull },
{ "forkafterauthentication", oForkAfterAuthentication },
{ "proxyusefdpass", oProxyUseFdpass },
{ "canonicaldomains", oCanonicalDomains },
{ "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
{ "canonicalizehostname", oCanonicalizeHostname },
{ "canonicalizemaxdots", oCanonicalizeMaxDots },
{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
{ "streamlocalbindmask", oStreamLocalBindMask },
{ "streamlocalbindunlink", oStreamLocalBindUnlink },
{ "revokedhostkeys", oRevokedHostKeys },
{ "fingerprinthash", oFingerprintHash },
{ "updatehostkeys", oUpdateHostkeys },
{ "hostbasedacceptedalgorithms", oHostbasedAcceptedAlgorithms },
{ "hostbasedkeytypes", oHostbasedAcceptedAlgorithms }, /* obsolete */
{ "pubkeyacceptedalgorithms", oPubkeyAcceptedAlgorithms },
{ "pubkeyacceptedkeytypes", oPubkeyAcceptedAlgorithms }, /* obsolete */
{ "ignoreunknown", oIgnoreUnknown },
{ "proxyjump", oProxyJump },
{ "securitykeyprovider", oSecurityKeyProvider },
{ "knownhostscommand", oKnownHostsCommand },
+ { "requiredrsasize", oRequiredRSASize },
{ 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') {
/* Terminate on comment */
if (*attrib == '#') {
cp = NULL; /* mark all arguments consumed */
break;
}
arg = criteria = NULL;
this_result = 1;
if ((negate = attrib[0] == '!'))
attrib++;
/* Criterion "all" has no argument and must appear alone */
if (strcasecmp(attrib, "all") == 0) {
if (attributes > 1 || ((arg = strdelim(&cp)) != NULL &&
*arg != '\0' && *arg != '#')) {
error("%.200s line %d: '%s' cannot be combined "
"with other Match attributes",
filename, linenum, oattrib);
result = -1;
goto out;
}
if (arg != NULL && *arg == '#')
cp = NULL; /* mark all arguments consumed */
if (result)
result = negate ? 0 : 1;
goto out;
}
attributes++;
/* criteria "final" and "canonical" have no argument */
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' || *arg == '#') {
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);
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;
+ u_int i, j, onum_send_env = options->num_send_env;
/* 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);
+ if (!match_pattern(options->send_env[i], arg + 1)) {
i++;
continue;
}
debug3("%s line %d: removing environment %s",
- filename, linenum, cp);
- free(cp);
+ filename, linenum, options->send_env[i]);
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_sessiontype[] = {
{ "none", SESSION_TYPE_NONE },
{ "subsystem", SESSION_TYPE_SUBSYSTEM },
{ "default", SESSION_TYPE_DEFAULT },
{ 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_pubkey_auth[] = {
{ "true", SSH_PUBKEY_AUTH_ALL },
{ "false", SSH_PUBKEY_AUTH_NO },
{ "yes", SSH_PUBKEY_AUTH_ALL },
{ "no", SSH_PUBKEY_AUTH_NO },
{ "unbound", SSH_PUBKEY_AUTH_UNBOUND },
{ "host-bound", SSH_PUBKEY_AUTH_HBOUND },
{ 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 *str, **charptr, *endofnumber, *keyword, *arg, *arg2, *p;
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;
char **oav = NULL, **av;
int oac = 0, ac;
int ret = -1;
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';
}
str = line;
/* Get the keyword. (Each line is supposed to begin with a keyword). */
if ((keyword = strdelim(&str)) == NULL)
return 0;
/* Ignore leading whitespace. */
if (*keyword == '\0')
keyword = strdelim(&str);
if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
return 0;
/* Match lowercase keyword */
lowercase(keyword);
/* Prepare to parse remainder of line */
if (str != NULL)
str += strspn(str, WHITESPACE);
if (str == NULL || *str == '\0') {
error("%s line %d: no argument after keyword \"%s\"",
filename, linenum, keyword);
return -1;
}
opcode = parse_token(keyword, filename, linenum,
options->ignored_unknown);
if (argv_split(str, &oac, &oav, 1) != 0) {
error("%s line %d: invalid quotes", filename, linenum);
return -1;
}
ac = oac;
av = oav;
switch (opcode) {
case oBadOption:
/* don't panic, but count bad options */
goto out;
case oIgnore:
argv_consume(&ac);
break;
case oIgnoredUnknownOption:
debug("%s line %d: Ignored unknown option \"%s\"",
filename, linenum, keyword);
argv_consume(&ac);
break;
case oConnectTimeout:
intptr = &options->connection_timeout;
parse_time:
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%s line %d: missing time value.",
filename, linenum);
goto out;
}
if (strcmp(arg, "none") == 0)
value = -1;
else if ((value = convtime(arg)) == -1) {
error("%s line %d: invalid time value.",
filename, linenum);
goto out;
}
if (*activep && *intptr == -1)
*intptr = value;
break;
case oForwardAgent:
intptr = &options->forward_agent;
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%s line %d: missing argument.",
filename, linenum);
goto out;
}
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 = argv_next(&ac, &av);
if ((value = parse_multistate_value(arg, filename, linenum,
multistate_ptr)) == -1) {
error("%s line %d: unsupported option \"%s\".",
filename, linenum, arg);
goto out;
}
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:
multistate_ptr = multistate_pubkey_auth;
intptr = &options->pubkey_authentication;
goto parse_multistate;
case oHostbasedAuthentication:
intptr = &options->hostbased_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 = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.", filename,
linenum);
goto out;
}
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));
goto out;
}
if (val64 != 0 && val64 < 16) {
error("%.200s line %d: RekeyLimit too small",
filename, linenum);
goto out;
}
}
if (*activep && options->rekey_limit == -1)
options->rekey_limit = val64;
if (ac != 0) { /* optional rekey interval present */
if (strcmp(av[0], "none") == 0) {
(void)argv_next(&ac, &av); /* discard */
break;
}
intptr = &options->rekey_interval;
goto parse_time;
}
break;
case oIdentityFile:
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
goto out;
}
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);
goto out;
}
add_identity_file(options, NULL,
arg, flags & SSHCONF_USERCONF);
}
break;
case oCertificateFile:
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
goto out;
}
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);
goto out;
}
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 = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
goto out;
}
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:
i = 0;
value = *uintptr == 0; /* was array empty when we started? */
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0') {
error("%s line %d: keyword %s empty argument",
filename, linenum, keyword);
goto out;
}
/* Allow "none" only in first position */
if (strcasecmp(arg, "none") == 0) {
if (i > 0 || ac > 0) {
error("%s line %d: keyword %s \"none\" "
"argument must appear alone.",
filename, linenum, keyword);
goto out;
}
}
i++;
if (*activep && value) {
if ((*uintptr) >= max_entries) {
error("%s line %d: too many %s "
"entries.", filename, linenum,
keyword);
goto out;
}
cpptr[(*uintptr)++] = xstrdup(arg);
}
}
break;
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 (str == NULL) {
error("%.200s line %d: Missing argument.",
filename, linenum);
goto out;
}
len = strspn(str, WHITESPACE "=");
if (*activep && *charptr == NULL)
*charptr = xstrdup(str + len);
argv_consume(&ac);
break;
case oProxyJump:
if (str == NULL) {
error("%.200s line %d: Missing argument.",
filename, linenum);
goto out;
}
len = strspn(str, WHITESPACE "=");
/* XXX use argv? */
if (parse_jump(str + len, options, *activep) == -1) {
error("%.200s line %d: Invalid ProxyJump \"%s\"",
filename, linenum, str + len);
goto out;
}
argv_consume(&ac);
break;
case oPort:
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
goto out;
}
value = a2port(arg);
if (value <= 0) {
error("%.200s line %d: Bad port '%s'.",
filename, linenum, arg);
goto out;
}
if (*activep && options->port == -1)
options->port = value;
break;
case oConnectionAttempts:
intptr = &options->connection_attempts;
parse_int:
arg = argv_next(&ac, &av);
if ((errstr = atoi_err(arg, &value)) != NULL) {
error("%s line %d: integer value %s.",
filename, linenum, errstr);
goto out;
}
if (*activep && *intptr == -1)
*intptr = value;
break;
case oCiphers:
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
goto out;
}
if (*arg != '-' &&
!ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)){
error("%.200s line %d: Bad SSH2 cipher spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
goto out;
}
if (*activep && options->ciphers == NULL)
options->ciphers = xstrdup(arg);
break;
case oMacs:
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
goto out;
}
if (*arg != '-' &&
!mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) {
error("%.200s line %d: Bad SSH2 MAC spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
goto out;
}
if (*activep && options->macs == NULL)
options->macs = xstrdup(arg);
break;
case oKexAlgorithms:
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
goto out;
}
if (*arg != '-' &&
!kex_names_valid(*arg == '+' || *arg == '^' ?
arg + 1 : arg)) {
error("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
filename, linenum, arg ? arg : "<NONE>");
goto out;
}
if (*activep && options->kex_algorithms == NULL)
options->kex_algorithms = xstrdup(arg);
break;
case oHostKeyAlgorithms:
charptr = &options->hostkeyalgorithms;
parse_pubkey_algos:
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
goto out;
}
if (*arg != '-' &&
!sshkey_names_valid2(*arg == '+' || *arg == '^' ?
arg + 1 : arg, 1)) {
error("%s line %d: Bad key types '%s'.",
filename, linenum, arg ? arg : "<NONE>");
goto out;
}
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 = argv_next(&ac, &av);
value = log_level_number(arg);
if (value == SYSLOG_LEVEL_NOT_SET) {
error("%.200s line %d: unsupported log level '%s'",
filename, linenum, arg ? arg : "<NONE>");
goto out;
}
if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
*log_level_ptr = (LogLevel) value;
break;
case oLogFacility:
log_facility_ptr = &options->log_facility;
arg = argv_next(&ac, &av);
value = log_facility_number(arg);
if (value == SYSLOG_FACILITY_NOT_SET) {
error("%.200s line %d: unsupported log facility '%s'",
filename, linenum, arg ? arg : "<NONE>");
goto out;
}
if (*log_facility_ptr == -1)
*log_facility_ptr = (SyslogFacility) value;
break;
case oLogVerbose:
cppptr = &options->log_verbose;
uintptr = &options->num_log_verbose;
i = 0;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0') {
error("%s line %d: keyword %s empty argument",
filename, linenum, keyword);
goto out;
}
/* Allow "none" only in first position */
if (strcasecmp(arg, "none") == 0) {
if (i > 0 || ac > 0) {
error("%s line %d: keyword %s \"none\" "
"argument must appear alone.",
filename, linenum, keyword);
goto out;
}
}
i++;
if (*activep && *uintptr == 0) {
*cppptr = xrecallocarray(*cppptr, *uintptr,
*uintptr + 1, sizeof(**cppptr));
(*cppptr)[(*uintptr)++] = xstrdup(arg);
}
}
break;
case oLocalForward:
case oRemoteForward:
case oDynamicForward:
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
goto out;
}
remotefwd = (opcode == oRemoteForward);
dynamicfwd = (opcode == oDynamicForward);
if (!dynamicfwd) {
arg2 = argv_next(&ac, &av);
if (arg2 == NULL || *arg2 == '\0') {
if (remotefwd)
dynamicfwd = 1;
else {
error("%.200s line %d: Missing target "
"argument.", filename, linenum);
goto out;
}
} 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);
goto out;
}
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 = argv_next(&ac, &av);
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;
}
while ((arg = argv_next(&ac, &av)) != NULL) {
arg2 = xstrdup(arg);
p = hpdelim(&arg);
if (p == NULL) {
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");
goto out;
}
*activep = 0;
arg2 = NULL;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0') {
error("%s line %d: keyword %s empty argument",
filename, linenum, keyword);
goto out;
}
if ((flags & SSHCONF_NEVERMATCH) != 0) {
argv_consume(&ac);
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;
argv_consume(&ac);
break;
}
if (!*activep)
arg2 = arg; /* logged below */
*activep = 1;
}
}
if (*activep)
debug("%.200s line %d: Applying options for %.100s",
filename, linenum, arg2);
break;
case oMatch:
if (cmdline) {
error("Host directive not supported as a command-line "
"option");
goto out;
}
value = match_cfg_line(options, &str, pw, host, original_host,
flags & SSHCONF_FINAL, want_final_pass,
filename, linenum);
if (value < 0) {
error("%.200s line %d: Bad Match condition", filename,
linenum);
goto out;
}
*activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
/*
* If match_cfg_line() didn't consume all its arguments then
* arrange for the extra arguments check below to fail.
*/
if (str == NULL || *str == '\0')
argv_consume(&ac);
break;
case oEscapeChar:
intptr = &options->escape_char;
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
goto out;
}
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);
goto out;
}
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 = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0' || strchr(arg, '=') != NULL) {
error("%s line %d: Invalid environment name.",
filename, linenum);
goto out;
}
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);
- goto out;
- }
- 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);
}
+ opt_array_append(filename, linenum,
+ lookup_opcode_name(opcode),
+ &options->send_env, &options->num_send_env, arg);
}
break;
case oSetEnv:
value = options->num_setenv;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (strchr(arg, '=') == NULL) {
error("%s line %d: Invalid SetEnv.",
filename, linenum);
goto out;
}
if (!*activep || value != 0)
continue;
- /* Adding a setenv var */
- if (options->num_setenv >= INT_MAX) {
- error("%s line %d: too many SetEnv.",
- filename, linenum);
- goto out;
+ if (lookup_setenv_in_list(arg, options->setenv,
+ options->num_setenv) != NULL) {
+ debug2("%s line %d: ignoring duplicate env "
+ "name \"%.64s\"", filename, linenum, arg);
+ continue;
}
- options->setenv = xrecallocarray(
- options->setenv, options->num_setenv,
- options->num_setenv + 1, sizeof(*options->setenv));
- options->setenv[options->num_setenv++] = xstrdup(arg);
+ opt_array_append(filename, linenum,
+ lookup_opcode_name(opcode),
+ &options->setenv, &options->num_setenv, 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 = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing ControlPersist"
" argument.", filename, linenum);
goto out;
}
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);
goto out;
}
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 = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
goto out;
}
value = a2tun(arg, &value2);
if (value == SSH_TUNID_ERR) {
error("%.200s line %d: Bad tun device.",
filename, linenum);
goto out;
}
if (*activep && options->tun_local == -1) {
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");
goto out;
}
value = 0;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0') {
error("%s line %d: keyword %s empty argument",
filename, linenum, keyword);
goto out;
}
/*
* 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);
goto out;
}
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);
goto out;
}
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);
goto out;
}
/*
* 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)
ret = value;
break;
case oIPQoS:
arg = argv_next(&ac, &av);
if ((value = parse_ipqos(arg)) == -1) {
error("%s line %d: Bad IPQoS value: %s",
filename, linenum, arg);
goto out;
}
arg = argv_next(&ac, &av);
if (arg == NULL)
value2 = value;
else if ((value2 = parse_ipqos(arg)) == -1) {
error("%s line %d: Bad IPQoS value: %s",
filename, linenum, arg);
goto out;
}
if (*activep && options->ip_qos_interactive == -1) {
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 oSessionType:
intptr = &options->session_type;
multistate_ptr = multistate_sessiontype;
goto parse_multistate;
case oStdinNull:
intptr = &options->stdin_null;
goto parse_flag;
case oForkAfterAuthentication:
intptr = &options->fork_after_authentication;
goto parse_flag;
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;
i = 0;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0') {
error("%s line %d: keyword %s empty argument",
filename, linenum, keyword);
goto out;
}
/* Allow "none" only in first position */
if (strcasecmp(arg, "none") == 0) {
if (i > 0 || ac > 0) {
error("%s line %d: keyword %s \"none\" "
"argument must appear alone.",
filename, linenum, keyword);
goto out;
}
}
i++;
if (!valid_domain(arg, 1, &errstr)) {
error("%s line %d: %s", filename, linenum,
errstr);
goto out;
}
if (!*activep || value)
continue;
if (options->num_canonical_domains >=
MAX_CANON_DOMAINS) {
error("%s line %d: too many hostname suffixes.",
filename, linenum);
goto out;
}
options->canonical_domains[
options->num_canonical_domains++] = xstrdup(arg);
}
break;
case oCanonicalizePermittedCNAMEs:
value = options->num_permitted_cnames != 0;
i = 0;
while ((arg = argv_next(&ac, &av)) != NULL) {
/*
* Either 'none' (only in first position), '*' for
* everything or 'list:list'
*/
if (strcasecmp(arg, "none") == 0) {
if (i > 0 || ac > 0) {
error("%s line %d: keyword %s \"none\" "
"argument must appear alone.",
filename, linenum, keyword);
goto out;
}
arg2 = "";
} else 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);
goto out;
}
*arg2 = '\0';
arg2++;
}
i++;
if (!*activep || value)
continue;
if (options->num_permitted_cnames >=
MAX_CANON_DOMAINS) {
error("%s line %d: too many permitted CNAMEs.",
filename, linenum);
goto out;
}
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 = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing StreamLocalBindMask "
"argument.", filename, linenum);
goto out;
}
/* 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);
goto out;
}
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 = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
goto out;
}
if ((value = ssh_digest_alg_by_name(arg)) == -1) {
error("%.200s line %d: Invalid hash algorithm \"%s\".",
filename, linenum, arg);
goto out;
}
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 = argv_next(&ac, &av);
arg2 = argv_next(&ac, &av);
value = parse_multistate_value(arg, filename, linenum,
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);
goto out;
}
} else if (value == -1 && arg2 == NULL) {
if ((value2 = convtime(arg)) == -1 ||
value2 > INT_MAX) {
error("%s line %d: unsupported option",
filename, linenum);
goto out;
}
value = 1; /* yes */
} else if (value == -1 || arg2 != NULL) {
error("%s line %d: unsupported option",
filename, linenum);
goto out;
}
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 = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
goto out;
}
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);
goto out;
}
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);
goto out;
}
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
break;
+ case oRequiredRSASize:
+ intptr = &options->required_rsa_size;
+ goto parse_int;
+
case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
argv_consume(&ac);
break;
case oUnsupported:
error("%s line %d: Unsupported option \"%s\"",
filename, linenum, keyword);
argv_consume(&ac);
break;
default:
error("%s line %d: Unimplemented opcode %d",
filename, linenum, opcode);
goto out;
}
/* Check that there is no garbage at end of line. */
if (ac > 0) {
error("%.200s line %d: keyword %s extra arguments "
"at end of line", filename, linenum, keyword);
goto out;
}
/* success */
ret = 0;
out:
argv_free(oav, oac);
return ret;
}
/*
* 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 *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 (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;
}
/*
* Returns 1 if CanonicalizePermittedCNAMEs have been specified, 0 otherwise.
* Allowed to be called on non-final configuration.
*/
int
config_has_permitted_cnames(Options *options)
{
if (options->num_permitted_cnames == 1 &&
strcasecmp(options->permitted_cnames[0].source_list, "none") == 0 &&
strcmp(options->permitted_cnames[0].target_list, "") == 0)
return 0;
return options->num_permitted_cnames > 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->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->session_type = -1;
options->stdin_null = -1;
options->fork_after_authentication = -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;
+ options->required_rsa_size = -1;
}
/*
* 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 = SSH_PUBKEY_AUTH_ALL;
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);
#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);
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 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->session_type == -1)
options->session_type = SESSION_TYPE_DEFAULT;
if (options->stdin_null == -1)
options->stdin_null = 0;
if (options->fork_after_authentication == -1)
options->fork_after_authentication = 0;
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
+ if (options->required_rsa_size == -1)
+ options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
/* 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;
}
if (options->num_permitted_cnames == 1 &&
!config_has_permitted_cnames(options)) {
/* clean up CanonicalizePermittedCNAMEs=none */
free(options->permitted_cnames[0].source_list);
free(options->permitted_cnames[0].target_list);
memset(options->permitted_cnames, '\0',
sizeof(*options->permitted_cnames));
options->num_permitted_cnames = 0;
}
/* 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_ARRAY(u_int, o->num_send_env, o->send_env);
free(o->send_env);
- FREE_ARRAY(int, o->num_setenv, o->setenv);
+ FREE_ARRAY(u_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);
/* Remove comment and trailing whitespace */
if ((cp = strchr(orig, '#')) != NULL)
*cp = '\0';
rtrim(orig);
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 oSessionType:
return fmt_multistate_int(val, multistate_sessiontype);
case oCanonicalizeHostname:
return fmt_multistate_int(val, multistate_canonicalizehostname);
case oAddKeysToAgent:
return fmt_multistate_int(val, multistate_yesnoaskconfirm);
case oPubkeyAuthentication:
return fmt_multistate_int(val, multistate_pubkey_auth);
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));
if (count == 0)
printf(" none");
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(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(oSessionType, o->session_type);
dump_cfg_fmtint(oStdinNull, o->stdin_null);
dump_cfg_fmtint(oForkAfterAuthentication, o->fork_after_authentication);
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);
+ dump_cfg_int(oRequiredRSASize, o->required_rsa_size);
/* 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 */
printf("canonicalizePermittedcnames");
if (o->num_permitted_cnames == 0)
printf(" none");
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/readconf.h b/readconf.h
index ded13c943d3f..ffb5ec4f2262 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,244 +1,246 @@
-/* $OpenBSD: readconf.h,v 1.146 2021/12/19 22:14:47 djm Exp $ */
+/* $OpenBSD: readconf.h,v 1.148 2022/09/17 10:33:18 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 file.
*
* 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 READCONF_H
#define READCONF_H
/* Data structure for representing option data. */
#define SSH_MAX_HOSTS_FILES 32
#define MAX_CANON_DOMAINS 32
#define PATH_MAX_SUN (sizeof((struct sockaddr_un *)0)->sun_path)
struct allowed_cname {
char *source_list;
char *target_list;
};
typedef struct {
int forward_agent; /* Forward authentication agent. */
char *forward_agent_sock_path; /* Optional path of the agent. */
int forward_x11; /* Forward X11 display. */
int forward_x11_timeout; /* Expiration for Cookies */
int forward_x11_trusted; /* Trust Forward X11 display. */
int exit_on_forward_failure; /* Exit if bind(2) fails for -L/-R */
char *xauth_location; /* Location for xauth program */
struct ForwardOptions fwd_opts; /* forwarding options */
int pubkey_authentication; /* Try ssh2 pubkey authentication. */
int hostbased_authentication; /* ssh2's rhosts_rsa */
int gss_authentication; /* Try GSS authentication */
int gss_deleg_creds; /* Delegate GSS credentials */
int password_authentication; /* Try password
* authentication. */
int kbd_interactive_authentication; /* Try keyboard-interactive auth. */
char *kbd_interactive_devices; /* Keyboard-interactive auth devices. */
int batch_mode; /* Batch mode: do not ask for passwords. */
int check_host_ip; /* Also keep track of keys for IP address */
int strict_host_key_checking; /* Strict host key checking. */
int compression; /* Compress packets in both directions. */
int tcp_keep_alive; /* Set SO_KEEPALIVE. */
int ip_qos_interactive; /* IP ToS/DSCP/class for interactive */
int ip_qos_bulk; /* IP ToS/DSCP/class for bulk traffic */
SyslogFacility log_facility; /* Facility for system logging. */
LogLevel log_level; /* Level for logging. */
u_int num_log_verbose; /* Verbose log overrides */
char **log_verbose;
int port; /* Port to connect. */
int address_family;
int connection_attempts; /* Max attempts (seconds) before
* giving up */
int connection_timeout; /* Max time (seconds) before
* aborting connection attempt */
int number_of_password_prompts; /* Max number of password
* prompts. */
char *ciphers; /* SSH2 ciphers in order of preference. */
char *macs; /* SSH2 macs in order of preference. */
char *hostkeyalgorithms; /* SSH2 server key types in order of preference. */
char *kex_algorithms; /* SSH2 kex methods in order of preference. */
char *ca_sign_algorithms; /* Allowed CA signature algorithms */
char *hostname; /* Real host to connect. */
char *host_key_alias; /* hostname alias for .ssh/known_hosts */
char *proxy_command; /* Proxy command for connecting the host. */
char *user; /* User to log in as. */
int escape_char; /* Escape character; -2 = none */
u_int num_system_hostfiles; /* Paths for /etc/ssh/ssh_known_hosts */
char *system_hostfiles[SSH_MAX_HOSTS_FILES];
u_int num_user_hostfiles; /* Path for $HOME/.ssh/known_hosts */
char *user_hostfiles[SSH_MAX_HOSTS_FILES];
char *preferred_authentications;
char *bind_address; /* local socket address for connection to sshd */
char *bind_interface; /* local interface for bind address */
char *pkcs11_provider; /* PKCS#11 provider */
char *sk_provider; /* Security key provider */
int verify_host_key_dns; /* Verify host key using DNS */
int num_identity_files; /* Number of files for RSA/DSA identities. */
char *identity_files[SSH_MAX_IDENTITY_FILES];
int identity_file_userprovided[SSH_MAX_IDENTITY_FILES];
struct sshkey *identity_keys[SSH_MAX_IDENTITY_FILES];
int num_certificate_files; /* Number of extra certificates for ssh. */
char *certificate_files[SSH_MAX_CERTIFICATE_FILES];
int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES];
struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES];
int add_keys_to_agent;
int add_keys_to_agent_lifespan;
char *identity_agent; /* Optional path to ssh-agent socket */
/* Local TCP/IP forward requests. */
int num_local_forwards;
struct Forward *local_forwards;
/* Remote TCP/IP forward requests. */
int num_remote_forwards;
struct Forward *remote_forwards;
int clear_forwardings;
/* Restrict remote dynamic forwarding */
char **permitted_remote_opens;
u_int num_permitted_remote_opens;
/* stdio forwarding (-W) host and port */
char *stdio_forward_host;
int stdio_forward_port;
int enable_ssh_keysign;
int64_t rekey_limit;
int rekey_interval;
int no_host_authentication_for_localhost;
int identities_only;
int server_alive_interval;
int server_alive_count_max;
- int num_send_env;
- char **send_env;
- int num_setenv;
- char **setenv;
+ u_int num_send_env;
+ char **send_env;
+ u_int num_setenv;
+ char **setenv;
char *control_path;
int control_master;
int control_persist; /* ControlPersist flag */
int control_persist_timeout; /* ControlPersist timeout (seconds) */
int hash_known_hosts;
int tun_open; /* tun(4) */
int tun_local; /* force tun device (optional) */
int tun_remote; /* force tun device (optional) */
char *local_command;
int permit_local_command;
char *remote_command;
int visual_host_key;
int request_tty;
int session_type;
int stdin_null;
int fork_after_authentication;
int proxy_use_fdpass;
int num_canonical_domains;
char *canonical_domains[MAX_CANON_DOMAINS];
int canonicalize_hostname;
int canonicalize_max_dots;
int canonicalize_fallback_local;
int num_permitted_cnames;
struct allowed_cname permitted_cnames[MAX_CANON_DOMAINS];
char *revoked_host_keys;
int fingerprint_hash;
int update_hostkeys; /* one of SSH_UPDATE_HOSTKEYS_* */
char *hostbased_accepted_algos;
char *pubkey_accepted_algos;
char *jump_user;
char *jump_host;
int jump_port;
char *jump_extra;
char *known_hosts_command;
+ int required_rsa_size; /* minimum size of RSA keys */
+
char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
} Options;
#define SSH_PUBKEY_AUTH_NO 0x00
#define SSH_PUBKEY_AUTH_UNBOUND 0x01
#define SSH_PUBKEY_AUTH_HBOUND 0x02
#define SSH_PUBKEY_AUTH_ALL 0x03
#define SSH_CANONICALISE_NO 0
#define SSH_CANONICALISE_YES 1
#define SSH_CANONICALISE_ALWAYS 2
#define SSHCTL_MASTER_NO 0
#define SSHCTL_MASTER_YES 1
#define SSHCTL_MASTER_AUTO 2
#define SSHCTL_MASTER_ASK 3
#define SSHCTL_MASTER_AUTO_ASK 4
#define REQUEST_TTY_AUTO 0
#define REQUEST_TTY_NO 1
#define REQUEST_TTY_YES 2
#define REQUEST_TTY_FORCE 3
#define SESSION_TYPE_NONE 0
#define SESSION_TYPE_SUBSYSTEM 1
#define SESSION_TYPE_DEFAULT 2
#define SSHCONF_CHECKPERM 1 /* check permissions on config file */
#define SSHCONF_USERCONF 2 /* user provided config file not system */
#define SSHCONF_FINAL 4 /* Final pass over config, after canon. */
#define SSHCONF_NEVERMATCH 8 /* Match/Host never matches; internal only */
#define SSH_UPDATE_HOSTKEYS_NO 0
#define SSH_UPDATE_HOSTKEYS_YES 1
#define SSH_UPDATE_HOSTKEYS_ASK 2
#define SSH_STRICT_HOSTKEY_OFF 0
#define SSH_STRICT_HOSTKEY_NEW 1
#define SSH_STRICT_HOSTKEY_YES 2
#define SSH_STRICT_HOSTKEY_ASK 3
const char *kex_default_pk_alg(void);
char *ssh_connection_hash(const char *thishost, const char *host,
const char *portstr, const char *user);
void initialize_options(Options *);
int fill_default_options(Options *);
void fill_default_options_for_canonicalization(Options *);
void free_options(Options *o);
int process_config_line(Options *, struct passwd *, const char *,
const char *, char *, const char *, int, int *, int);
int read_config_file(const char *, struct passwd *, const char *,
const char *, Options *, int, int *);
int parse_forward(struct Forward *, const char *, int, int);
int parse_jump(const char *, Options *, int);
int parse_ssh_uri(const char *, char **, char **, int *);
int default_ssh_port(void);
int option_clear_or_none(const char *);
int config_has_permitted_cnames(Options *);
void dump_client_config(Options *o, const char *host);
void add_local_forward(Options *, const struct Forward *);
void add_remote_forward(Options *, const struct Forward *);
void add_identity_file(Options *, const char *, const char *, int);
void add_certificate_file(Options *, const char *, int);
#endif /* READCONF_H */
diff --git a/readpass.c b/readpass.c
index 39af25c88729..b52f3d6b1e1a 100644
--- a/readpass.c
+++ b/readpass.c
@@ -1,331 +1,332 @@
-/* $OpenBSD: readpass.c,v 1.69 2021/07/23 05:56:47 djm Exp $ */
+/* $OpenBSD: readpass.c,v 1.70 2022/05/27 04:27:49 dtucker Exp $ */
/*
* Copyright (c) 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 <errno.h>
#include <fcntl.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "xmalloc.h"
#include "misc.h"
#include "pathnames.h"
#include "log.h"
#include "ssh.h"
#include "uidswap.h"
static char *
ssh_askpass(char *askpass, const char *msg, const char *env_hint)
{
pid_t pid, ret;
size_t len;
char *pass;
int p[2], status;
char buf[1024];
void (*osigchld)(int);
if (fflush(stdout) != 0)
error_f("fflush: %s", strerror(errno));
if (askpass == NULL)
fatal("internal error: askpass undefined");
if (pipe(p) == -1) {
error_f("pipe: %s", strerror(errno));
return NULL;
}
osigchld = ssh_signal(SIGCHLD, SIG_DFL);
if ((pid = fork()) == -1) {
error_f("fork: %s", strerror(errno));
ssh_signal(SIGCHLD, osigchld);
return NULL;
}
if (pid == 0) {
close(p[0]);
if (dup2(p[1], STDOUT_FILENO) == -1)
fatal_f("dup2: %s", strerror(errno));
if (env_hint != NULL)
setenv("SSH_ASKPASS_PROMPT", env_hint, 1);
execlp(askpass, askpass, msg, (char *)NULL);
fatal_f("exec(%s): %s", askpass, strerror(errno));
}
close(p[1]);
len = 0;
do {
ssize_t r = read(p[0], buf + len, sizeof(buf) - 1 - len);
if (r == -1 && errno == EINTR)
continue;
if (r <= 0)
break;
len += r;
} while (sizeof(buf) - 1 - len > 0);
buf[len] = '\0';
close(p[0]);
while ((ret = waitpid(pid, &status, 0)) == -1)
if (errno != EINTR)
break;
ssh_signal(SIGCHLD, osigchld);
if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
explicit_bzero(buf, sizeof(buf));
return NULL;
}
buf[strcspn(buf, "\r\n")] = '\0';
pass = xstrdup(buf);
explicit_bzero(buf, sizeof(buf));
return pass;
}
/* private/internal read_passphrase flags */
#define RP_ASK_PERMISSION 0x8000 /* pass hint to askpass for confirm UI */
/*
* Reads a passphrase from /dev/tty with echo turned off/on. Returns the
* passphrase (allocated with xmalloc). Exits if EOF is encountered. If
* RP_ALLOW_STDIN is set, the passphrase will be read from stdin if no
* tty is or askpass program is available
*/
char *
read_passphrase(const char *prompt, int flags)
{
char cr = '\r', *askpass = NULL, *ret, buf[1024];
int rppflags, ttyfd, use_askpass = 0, allow_askpass = 0;
const char *askpass_hint = NULL;
const char *s;
if ((s = getenv("DISPLAY")) != NULL)
allow_askpass = *s != '\0';
if ((s = getenv(SSH_ASKPASS_REQUIRE_ENV)) != NULL) {
if (strcasecmp(s, "force") == 0) {
use_askpass = 1;
allow_askpass = 1;
} else if (strcasecmp(s, "prefer") == 0)
use_askpass = allow_askpass;
else if (strcasecmp(s, "never") == 0)
allow_askpass = 0;
}
rppflags = (flags & RP_ECHO) ? RPP_ECHO_ON : RPP_ECHO_OFF;
if (use_askpass)
debug_f("requested to askpass");
else if (flags & RP_USE_ASKPASS)
use_askpass = 1;
else if (flags & RP_ALLOW_STDIN) {
if (!isatty(STDIN_FILENO)) {
debug_f("stdin is not a tty");
use_askpass = 1;
}
} else {
rppflags |= RPP_REQUIRE_TTY;
ttyfd = open(_PATH_TTY, O_RDWR);
if (ttyfd >= 0) {
/*
* If we're on a tty, ensure that show the prompt at
* the beginning of the line. This will hopefully
* clobber any password characters the user has
* optimistically typed before echo is disabled.
*/
(void)write(ttyfd, &cr, 1);
close(ttyfd);
} else {
debug_f("can't open %s: %s", _PATH_TTY,
strerror(errno));
use_askpass = 1;
}
}
if ((flags & RP_USE_ASKPASS) && !allow_askpass)
return (flags & RP_ALLOW_EOF) ? NULL : xstrdup("");
if (use_askpass && allow_askpass) {
if (getenv(SSH_ASKPASS_ENV))
askpass = getenv(SSH_ASKPASS_ENV);
else
askpass = _PATH_SSH_ASKPASS_DEFAULT;
if ((flags & RP_ASK_PERMISSION) != 0)
askpass_hint = "confirm";
if ((ret = ssh_askpass(askpass, prompt, askpass_hint)) == NULL)
if (!(flags & RP_ALLOW_EOF))
return xstrdup("");
return ret;
}
if (readpassphrase(prompt, buf, sizeof buf, rppflags) == NULL) {
if (flags & RP_ALLOW_EOF)
return NULL;
return xstrdup("");
}
ret = xstrdup(buf);
explicit_bzero(buf, sizeof(buf));
return ret;
}
int
ask_permission(const char *fmt, ...)
{
va_list args;
char *p, prompt[1024];
int allowed = 0;
va_start(args, fmt);
vsnprintf(prompt, sizeof(prompt), fmt, args);
va_end(args);
p = read_passphrase(prompt,
RP_USE_ASKPASS|RP_ALLOW_EOF|RP_ASK_PERMISSION);
if (p != NULL) {
/*
* Accept empty responses and responses consisting
* of the word "yes" as affirmative.
*/
if (*p == '\0' || *p == '\n' ||
strcasecmp(p, "yes") == 0)
allowed = 1;
free(p);
}
return (allowed);
}
static void
writemsg(const char *msg)
{
(void)write(STDERR_FILENO, "\r", 1);
(void)write(STDERR_FILENO, msg, strlen(msg));
(void)write(STDERR_FILENO, "\r\n", 2);
}
struct notifier_ctx {
pid_t pid;
void (*osigchld)(int);
};
struct notifier_ctx *
notify_start(int force_askpass, const char *fmt, ...)
{
va_list args;
char *prompt = NULL;
pid_t pid = -1;
void (*osigchld)(int) = NULL;
const char *askpass, *s;
struct notifier_ctx *ret = NULL;
va_start(args, fmt);
xvasprintf(&prompt, fmt, args);
va_end(args);
if (fflush(NULL) != 0)
error_f("fflush: %s", strerror(errno));
if (!force_askpass && isatty(STDERR_FILENO)) {
writemsg(prompt);
goto out_ctx;
}
if ((askpass = getenv("SSH_ASKPASS")) == NULL)
askpass = _PATH_SSH_ASKPASS_DEFAULT;
if (*askpass == '\0') {
debug3_f("cannot notify: no askpass");
goto out;
}
if (getenv("DISPLAY") == NULL &&
((s = getenv(SSH_ASKPASS_REQUIRE_ENV)) == NULL ||
strcmp(s, "force") != 0)) {
debug3_f("cannot notify: no display");
goto out;
}
osigchld = ssh_signal(SIGCHLD, SIG_DFL);
if ((pid = fork()) == -1) {
error_f("fork: %s", strerror(errno));
ssh_signal(SIGCHLD, osigchld);
free(prompt);
return NULL;
}
if (pid == 0) {
if (stdfd_devnull(1, 1, 0) == -1)
fatal_f("stdfd_devnull failed");
closefrom(STDERR_FILENO + 1);
setenv("SSH_ASKPASS_PROMPT", "none", 1); /* hint to UI */
execlp(askpass, askpass, prompt, (char *)NULL);
error_f("exec(%s): %s", askpass, strerror(errno));
_exit(1);
/* NOTREACHED */
}
out_ctx:
if ((ret = calloc(1, sizeof(*ret))) == NULL) {
- kill(pid, SIGTERM);
+ if (pid != -1)
+ kill(pid, SIGTERM);
fatal_f("calloc failed");
}
ret->pid = pid;
ret->osigchld = osigchld;
out:
free(prompt);
return ret;
}
void
notify_complete(struct notifier_ctx *ctx, const char *fmt, ...)
{
int ret;
char *msg = NULL;
va_list args;
if (ctx != NULL && fmt != NULL && ctx->pid == -1) {
/*
* notify_start wrote to stderr, so send conclusion message
* there too
*/
va_start(args, fmt);
xvasprintf(&msg, fmt, args);
va_end(args);
writemsg(msg);
free(msg);
}
if (ctx == NULL || ctx->pid <= 0) {
free(ctx);
return;
}
kill(ctx->pid, SIGTERM);
while ((ret = waitpid(ctx->pid, NULL, 0)) == -1) {
if (errno != EINTR)
break;
}
if (ret == -1)
fatal_f("waitpid: %s", strerror(errno));
ssh_signal(SIGCHLD, ctx->osigchld);
free(ctx);
}
diff --git a/regress/agent-ptrace.sh b/regress/agent-ptrace.sh
index 9cd68d7ec84e..feef52416f7c 100644
--- a/regress/agent-ptrace.sh
+++ b/regress/agent-ptrace.sh
@@ -1,66 +1,66 @@
-# $OpenBSD: agent-ptrace.sh,v 1.3 2015/09/11 04:55:01 djm Exp $
+# $OpenBSD: agent-ptrace.sh,v 1.5 2022/04/22 05:08:43 anton Exp $
# Placed in the Public Domain.
tid="disallow agent ptrace attach"
if have_prog uname ; then
case `uname` in
AIX|CYGWIN*|OSF1)
echo "skipped (not supported on this platform)"
exit 0
;;
esac
fi
if [ "x$USER" = "xroot" ]; then
echo "Skipped: running as root"
exit 0
fi
if have_prog gdb ; then
: ok
else
echo "skipped (gdb not found)"
exit 0
fi
if $OBJ/setuid-allowed ${SSHAGENT} ; then
: ok
else
echo "skipped (${SSHAGENT} is mounted on a no-setuid filesystem)"
exit 0
fi
if test -z "$SUDO" ; then
echo "skipped (SUDO not set)"
exit 0
else
$SUDO chown 0 ${SSHAGENT}
$SUDO chgrp 0 ${SSHAGENT}
$SUDO chmod 2755 ${SSHAGENT}
fi
trace "start agent"
eval `${SSHAGENT} ${EXTRA_AGENT_ARGS} -s` > /dev/null
r=$?
if [ $r -ne 0 ]; then
fail "could not start ssh-agent: exit code $r"
else
# ls -l ${SSH_AUTH_SOCK}
gdb ${SSHAGENT} ${SSH_AGENT_PID} > ${OBJ}/gdb.out 2>&1 << EOF
quit
EOF
r=$?
if [ $r -ne 0 ]; then
fail "gdb failed: exit code $r"
fi
egrep 'ptrace: Operation not permitted.|procfs:.*Permission denied.|ttrace.*Permission denied.|procfs:.*: Invalid argument.|Unable to access task ' >/dev/null ${OBJ}/gdb.out
r=$?
rm -f ${OBJ}/gdb.out
if [ $r -ne 0 ]; then
fail "ptrace succeeded?: exit code $r"
fi
trace "kill agent"
${SSHAGENT} -k > /dev/null
fi
diff --git a/regress/envpass.sh b/regress/envpass.sh
index af7eafe3d16e..cb104686bb70 100644
--- a/regress/envpass.sh
+++ b/regress/envpass.sh
@@ -1,60 +1,125 @@
-# $OpenBSD: envpass.sh,v 1.4 2005/03/04 08:48:46 djm Exp $
+# $OpenBSD: envpass.sh,v 1.5 2022/06/03 04:31:54 djm Exp $
# Placed in the Public Domain.
tid="environment passing"
# NB accepted env vars are in test-exec.sh (_XXX_TEST_* and _XXX_TEST)
# Prepare a custom config to test for a configuration parsing bug fixed in 4.0
cat << EOF > $OBJ/ssh_proxy_envpass
Host test-sendenv-confparse-bug
SendEnv *
EOF
cat $OBJ/ssh_proxy >> $OBJ/ssh_proxy_envpass
+cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
trace "pass env, don't accept"
verbose "test $tid: pass env, don't accept"
_TEST_ENV=blah ${SSH} -oSendEnv="*" -F $OBJ/ssh_proxy_envpass otherhost \
sh << 'EOF'
test -z "$_TEST_ENV"
EOF
r=$?
if [ $r -ne 0 ]; then
fail "environment found"
fi
+trace "setenv, don't accept"
+verbose "test $tid: setenv, don't accept"
+${SSH} -oSendEnv="*" -F $OBJ/ssh_proxy_envpass -oSetEnv="_TEST_ENV=blah" \
+ otherhost \
+ sh << 'EOF'
+ test -z "$_TEST_ENV"
+EOF
+r=$?
+if [ $r -ne 0 ]; then
+ fail "environment found"
+fi
+
trace "don't pass env, accept"
verbose "test $tid: don't pass env, accept"
_XXX_TEST_A=1 _XXX_TEST_B=2 ${SSH} -F $OBJ/ssh_proxy_envpass otherhost \
sh << 'EOF'
test -z "$_XXX_TEST_A" && test -z "$_XXX_TEST_B"
EOF
r=$?
if [ $r -ne 0 ]; then
fail "environment found"
fi
trace "pass single env, accept single env"
verbose "test $tid: pass single env, accept single env"
_XXX_TEST=blah ${SSH} -oSendEnv="_XXX_TEST" -F $OBJ/ssh_proxy_envpass \
otherhost sh << 'EOF'
test X"$_XXX_TEST" = X"blah"
EOF
r=$?
if [ $r -ne 0 ]; then
fail "environment not found"
fi
trace "pass multiple env, accept multiple env"
verbose "test $tid: pass multiple env, accept multiple env"
_XXX_TEST_A=1 _XXX_TEST_B=2 ${SSH} -oSendEnv="_XXX_TEST_*" \
-F $OBJ/ssh_proxy_envpass otherhost \
sh << 'EOF'
test X"$_XXX_TEST_A" = X"1" -a X"$_XXX_TEST_B" = X"2"
EOF
r=$?
if [ $r -ne 0 ]; then
fail "environment not found"
fi
+trace "setenv, accept"
+verbose "test $tid: setenv, accept"
+${SSH} -F $OBJ/ssh_proxy_envpass \
+ -oSetEnv="_XXX_TEST_A=1 _XXX_TEST_B=2" otherhost \
+ sh << 'EOF'
+ test X"$_XXX_TEST_A" = X"1" -a X"$_XXX_TEST_B" = X"2"
+EOF
+r=$?
+if [ $r -ne 0 ]; then
+ fail "environment not found"
+fi
+trace "setenv, first match wins"
+verbose "test $tid: setenv, first match wins"
+${SSH} -F $OBJ/ssh_proxy_envpass \
+ -oSetEnv="_XXX_TEST_A=1 _XXX_TEST_A=11 _XXX_TEST_B=2" otherhost \
+ sh << 'EOF'
+ test X"$_XXX_TEST_A" = X"1" -a X"$_XXX_TEST_B" = X"2"
+EOF
+r=$?
+if [ $r -ne 0 ]; then
+ fail "environment not found"
+fi
+
+trace "server setenv wins"
+verbose "test $tid: server setenv wins"
+cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
+echo "SetEnv _XXX_TEST_A=23" >> $OBJ/sshd_proxy
+${SSH} -F $OBJ/ssh_proxy_envpass \
+ -oSetEnv="_XXX_TEST_A=1 _XXX_TEST_B=2" otherhost \
+ sh << 'EOF'
+ test X"$_XXX_TEST_A" = X"23" -a X"$_XXX_TEST_B" = X"2"
+EOF
+r=$?
+if [ $r -ne 0 ]; then
+ fail "environment not found"
+fi
+
+trace "server setenv first match wins"
+verbose "test $tid: server setenv wins"
+cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
+echo "SetEnv _XXX_TEST_A=23 _XXX_TEST_A=42" >> $OBJ/sshd_proxy
+${SSH} -F $OBJ/ssh_proxy_envpass \
+ -oSetEnv="_XXX_TEST_A=1 _XXX_TEST_B=2" otherhost \
+ sh << 'EOF'
+ test X"$_XXX_TEST_A" = X"23" -a X"$_XXX_TEST_B" = X"2"
+EOF
+r=$?
+if [ $r -ne 0 ]; then
+ fail "environment not found"
+fi
+
+
rm -f $OBJ/ssh_proxy_envpass
diff --git a/regress/forward-control.sh b/regress/forward-control.sh
index 02f7667a665b..63bbdebe5cb6 100644
--- a/regress/forward-control.sh
+++ b/regress/forward-control.sh
@@ -1,235 +1,228 @@
-# $OpenBSD: forward-control.sh,v 1.8 2021/05/07 09:23:40 dtucker Exp $
+# $OpenBSD: forward-control.sh,v 1.11 2022/04/21 01:36:46 dtucker Exp $
# Placed in the Public Domain.
tid="sshd control of local and remote forwarding"
LFWD_PORT=3320
RFWD_PORT=3321
CTL=$OBJ/ctl-sock
-READY=$OBJ/ready
-
-wait_for_file_to_appear() {
- _path=$1
- _n=0
- while test ! -f $_path ; do
- test $_n -eq 1 && trace "waiting for $_path to appear"
- _n=`expr $_n + 1`
- test $_n -ge 20 && return 1
- sleep 1
- done
- return 0
-}
+WAIT_SECONDS=20
wait_for_process_to_exit() {
_pid=$1
_n=0
while kill -0 $_pid 2>/dev/null ; do
test $_n -eq 1 && trace "waiting for $_pid to exit"
_n=`expr $_n + 1`
- test $_n -ge 20 && return 1
+ test $_n -ge $WAIT_SECONDS && return 1
sleep 1
done
return 0
}
+mux_cmd() {
+ ${SSH} -F $OBJ/ssh_proxy -S $CTL -O $1 host 2>&1
+}
+
+controlmaster_pid() {
+ mux_cmd check | cut -f2 -d= | cut -f1 -d')'
+}
+
# usage: check_lfwd Y|N message
check_lfwd() {
_expected=$1
_message=$2
- rm -f $READY
${SSH} -F $OBJ/ssh_proxy \
-L$LFWD_PORT:127.0.0.1:$PORT \
-o ExitOnForwardFailure=yes \
- -n host exec sh -c \'"sleep 60 & echo \$! > $READY ; wait "\' \
- >/dev/null 2>&1 &
- _sshpid=$!
- wait_for_file_to_appear $READY || \
- fatal "check_lfwd ssh fail: $_message"
+ -MS $CTL -o ControlPersist=yes \
+ -f host true
+ mux_cmd check >/dev/null || fatal "check_lfwd ssh fail: $_message"
${SSH} -F $OBJ/ssh_config -p $LFWD_PORT \
-oConnectionAttempts=10 host true >/dev/null 2>&1
_result=$?
- kill $_sshpid `cat $READY` 2>/dev/null
+ _sshpid=`controlmaster_pid`
+ mux_cmd exit >/dev/null
wait_for_process_to_exit $_sshpid
if test "x$_expected" = "xY" -a $_result -ne 0 ; then
fail "check_lfwd failed (expecting success): $_message"
elif test "x$_expected" = "xN" -a $_result -eq 0 ; then
fail "check_lfwd succeeded (expecting failure): $_message"
elif test "x$_expected" != "xY" -a "x$_expected" != "xN" ; then
fatal "check_lfwd invalid argument \"$_expected\""
else
verbose "check_lfwd done (expecting $_expected): $_message"
fi
}
# usage: check_rfwd Y|N message
check_rfwd() {
_expected=$1
_message=$2
- rm -f $READY
${SSH} -F $OBJ/ssh_proxy \
-R127.0.0.1:$RFWD_PORT:127.0.0.1:$PORT \
-o ExitOnForwardFailure=yes \
- -n host exec sh -c \'"sleep 60 & echo \$! > $READY ; wait "\' \
- >/dev/null 2>&1 &
- _sshpid=$!
- wait_for_file_to_appear $READY
+ -MS $CTL -o ControlPersist=yes \
+ -f host true
+ mux_cmd check >/dev/null
_result=$?
- if test $_result -eq 0 ; then
+ _sshpid=`controlmaster_pid`
+ if test $_result -eq 0; then
${SSH} -F $OBJ/ssh_config -p $RFWD_PORT \
-oConnectionAttempts=10 host true >/dev/null 2>&1
_result=$?
- kill $_sshpid `cat $READY` 2>/dev/null
+ mux_cmd exit >/dev/null
wait_for_process_to_exit $_sshpid
fi
if test "x$_expected" = "xY" -a $_result -ne 0 ; then
fail "check_rfwd failed (expecting success): $_message"
elif test "x$_expected" = "xN" -a $_result -eq 0 ; then
fail "check_rfwd succeeded (expecting failure): $_message"
elif test "x$_expected" != "xY" -a "x$_expected" != "xN" ; then
fatal "check_rfwd invalid argument \"$_expected\""
else
verbose "check_rfwd done (expecting $_expected): $_message"
fi
}
start_sshd
cp ${OBJ}/sshd_proxy ${OBJ}/sshd_proxy.bak
cp ${OBJ}/authorized_keys_${USER} ${OBJ}/authorized_keys_${USER}.bak
# Sanity check: ensure the default config allows forwarding
check_lfwd Y "default configuration"
check_rfwd Y "default configuration"
# Usage: lperm_tests yes|local|remote|no Y|N Y|N Y|N Y|N Y|N Y|N
lperm_tests() {
_tcpfwd=$1
_plain_lfwd=$2
_plain_rfwd=$3
_nopermit_lfwd=$4
_nopermit_rfwd=$5
_permit_lfwd=$6
_permit_rfwd=$7
_badfwd1=127.0.0.1:22
_badfwd2=127.0.0.2:22
_goodfwd=127.0.0.1:${PORT}
cp ${OBJ}/authorized_keys_${USER}.bak ${OBJ}/authorized_keys_${USER}
_prefix="AllowTcpForwarding=$_tcpfwd"
# No PermitOpen
( cat ${OBJ}/sshd_proxy.bak ;
echo "AllowTcpForwarding $_tcpfwd" ) \
> ${OBJ}/sshd_proxy
check_lfwd $_plain_lfwd "$_prefix"
check_rfwd $_plain_rfwd "$_prefix"
# PermitOpen via sshd_config that doesn't match
( cat ${OBJ}/sshd_proxy.bak ;
echo "AllowTcpForwarding $_tcpfwd" ;
echo "PermitOpen $_badfwd1 $_badfwd2" ) \
> ${OBJ}/sshd_proxy
check_lfwd $_nopermit_lfwd "$_prefix, !PermitOpen"
check_rfwd $_nopermit_rfwd "$_prefix, !PermitOpen"
# PermitOpen via sshd_config that does match
( cat ${OBJ}/sshd_proxy.bak ;
echo "AllowTcpForwarding $_tcpfwd" ;
echo "PermitOpen $_badfwd1 $_goodfwd $_badfwd2" ) \
> ${OBJ}/sshd_proxy
check_lfwd $_plain_lfwd "$_prefix, PermitOpen"
check_rfwd $_plain_rfwd "$_prefix, PermitOpen"
# permitopen keys option.
# NB. permitopen via authorized_keys should have same
# success/fail as via sshd_config
# permitopen via authorized_keys that doesn't match
sed "s/^/permitopen=\"$_badfwd1\",permitopen=\"$_badfwd2\" /" \
< ${OBJ}/authorized_keys_${USER}.bak \
> ${OBJ}/authorized_keys_${USER} || fatal "sed 1 fail"
( cat ${OBJ}/sshd_proxy.bak ;
echo "AllowTcpForwarding $_tcpfwd" ) \
> ${OBJ}/sshd_proxy
check_lfwd $_nopermit_lfwd "$_prefix, !permitopen"
check_rfwd $_nopermit_rfwd "$_prefix, !permitopen"
# permitopen via authorized_keys that does match
sed "s/^/permitopen=\"$_badfwd1\",permitopen=\"$_goodfwd\" /" \
< ${OBJ}/authorized_keys_${USER}.bak \
> ${OBJ}/authorized_keys_${USER} || fatal "sed 2 fail"
( cat ${OBJ}/sshd_proxy.bak ;
echo "AllowTcpForwarding $_tcpfwd" ) \
> ${OBJ}/sshd_proxy
check_lfwd $_permit_lfwd "$_prefix, permitopen"
check_rfwd $_permit_rfwd "$_prefix, permitopen"
# Check port-forwarding flags in authorized_keys.
# These two should refuse all.
sed "s/^/no-port-forwarding /" \
< ${OBJ}/authorized_keys_${USER}.bak \
> ${OBJ}/authorized_keys_${USER} || fatal "sed 3 fail"
( cat ${OBJ}/sshd_proxy.bak ;
echo "AllowTcpForwarding $_tcpfwd" ) \
> ${OBJ}/sshd_proxy
check_lfwd N "$_prefix, no-port-forwarding"
check_rfwd N "$_prefix, no-port-forwarding"
sed "s/^/restrict /" \
< ${OBJ}/authorized_keys_${USER}.bak \
> ${OBJ}/authorized_keys_${USER} || fatal "sed 4 fail"
( cat ${OBJ}/sshd_proxy.bak ;
echo "AllowTcpForwarding $_tcpfwd" ) \
> ${OBJ}/sshd_proxy
check_lfwd N "$_prefix, restrict"
check_rfwd N "$_prefix, restrict"
# This should pass the same cases as _nopermit*
sed "s/^/restrict,port-forwarding /" \
< ${OBJ}/authorized_keys_${USER}.bak \
> ${OBJ}/authorized_keys_${USER} || fatal "sed 5 fail"
( cat ${OBJ}/sshd_proxy.bak ;
echo "AllowTcpForwarding $_tcpfwd" ) \
> ${OBJ}/sshd_proxy
check_lfwd $_plain_lfwd "$_prefix, restrict,port-forwarding"
check_rfwd $_plain_rfwd "$_prefix, restrict,port-forwarding"
}
# permit-open none mismatch match
# AllowTcpForwarding local remote local remote local remote
lperm_tests yes Y Y N Y Y Y
lperm_tests local Y N N N Y N
lperm_tests remote N Y N Y N Y
lperm_tests no N N N N N N
# Usage: rperm_tests yes|local|remote|no Y|N Y|N Y|N Y|N Y|N Y|N
rperm_tests() {
_tcpfwd=$1
_plain_lfwd=$2
_plain_rfwd=$3
_nopermit_lfwd=$4
_nopermit_rfwd=$5
_permit_lfwd=$6
_permit_rfwd=$7
_badfwd1=127.0.0.1:22
_badfwd2=127.0.0.2:${RFWD_PORT}
_goodfwd=127.0.0.1:${RFWD_PORT}
cp ${OBJ}/authorized_keys_${USER}.bak ${OBJ}/authorized_keys_${USER}
_prefix="AllowTcpForwarding=$_tcpfwd"
# PermitListen via sshd_config that doesn't match
( cat ${OBJ}/sshd_proxy.bak ;
echo "AllowTcpForwarding $_tcpfwd" ;
echo "PermitListen $_badfwd1 $_badfwd2" ) \
> ${OBJ}/sshd_proxy
check_lfwd $_nopermit_lfwd "$_prefix, !PermitListen"
check_rfwd $_nopermit_rfwd "$_prefix, !PermitListen"
# PermitListen via sshd_config that does match
( cat ${OBJ}/sshd_proxy.bak ;
echo "AllowTcpForwarding $_tcpfwd" ;
echo "PermitListen $_badfwd1 $_goodfwd $_badfwd2" ) \
> ${OBJ}/sshd_proxy
check_lfwd $_plain_lfwd "$_prefix, PermitListen"
check_rfwd $_plain_rfwd "$_prefix, PermitListen"
}
# permit-remote-open none mismatch match
# AllowTcpForwarding local remote local remote local remote
rperm_tests yes Y Y Y N Y Y
rperm_tests local Y N Y N Y N
rperm_tests remote N Y N N N Y
rperm_tests no N N N N N N
diff --git a/regress/misc/fuzz-harness/Makefile b/regress/misc/fuzz-harness/Makefile
index 3938ac853d31..0b4238fd39a4 100644
--- a/regress/misc/fuzz-harness/Makefile
+++ b/regress/misc/fuzz-harness/Makefile
@@ -1,52 +1,55 @@
# NB. libssh and libopenbsd-compat should be built with the same sanitizer opts.
CC=clang-11
CXX=clang++-11
FUZZ_FLAGS=-fsanitize=address,fuzzer -fno-omit-frame-pointer
FUZZ_LIBS=-lFuzzer
CXXFLAGS=-O2 -g -Wall -Wextra -Wno-unused-parameter -I ../../.. $(FUZZ_FLAGS)
CFLAGS=$(CXXFLAGS)
LDFLAGS=-L ../../.. -L ../../../openbsd-compat -g $(FUZZ_FLAGS)
LIBS=-lssh -lopenbsd-compat -lmd -lcrypto -lfido2 -lcbor $(FUZZ_LIBS)
SK_NULL_OBJS=ssh-sk-null.o
COMMON_DEPS=../../../libssh.a
-TARGETS=pubkey_fuzz sig_fuzz authopt_fuzz sshsig_fuzz \
+TARGETS=pubkey_fuzz sig_fuzz authopt_fuzz authkeys_fuzz sshsig_fuzz \
sshsigopt_fuzz privkey_fuzz kex_fuzz agent_fuzz
all: $(TARGETS)
.cc.o:
$(CXX) $(CXXFLAGS) -c $< -o $@
pubkey_fuzz: pubkey_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
$(CXX) -o $@ pubkey_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS)
sig_fuzz: sig_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
$(CXX) -o $@ sig_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS)
authopt_fuzz: authopt_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
$(CXX) -o $@ authopt_fuzz.o $(SK_NULL_OBJS) ../../../auth-options.o $(LDFLAGS) $(LIBS)
+authkeys_fuzz: authkeys_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+ $(CXX) -o $@ authkeys_fuzz.o $(SK_NULL_OBJS) ../../../auth-options.o ../../../auth2-pubkeyfile.o $(LDFLAGS) $(LIBS)
+
sshsig_fuzz: sshsig_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
$(CXX) -o $@ sshsig_fuzz.o $(SK_NULL_OBJS) ../../../sshsig.o $(LDFLAGS) $(LIBS)
sshsigopt_fuzz: sshsigopt_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
$(CXX) -o $@ sshsigopt_fuzz.o $(SK_NULL_OBJS) ../../../sshsig.o $(LDFLAGS) $(LIBS)
privkey_fuzz: privkey_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
$(CXX) -o $@ privkey_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS)
kex_fuzz: kex_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
$(CXX) -o $@ kex_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS) -lz
agent_fuzz: agent_fuzz.o agent_fuzz_helper.o sk-dummy.o ../../../ssh-sk.o $(COMMON_DEPS)
$(CXX) -o $@ agent_fuzz.o agent_fuzz_helper.o sk-dummy.o ../../../ssh-sk.o $(LDFLAGS) $(LIBS) -lz
agent_fuzz_helper.o: agent_fuzz_helper.c ../../../ssh-agent.c
sk-dummy.o: ../sk-dummy/sk-dummy.c
$(CC) $(CFLAGS) -c -o $@ ../sk-dummy/sk-dummy.c -DSK_DUMMY_INTEGRATE=1 $(LDFLAGS)
clean:
-rm -f *.o $(TARGETS)
diff --git a/regress/misc/fuzz-harness/authkeys_fuzz.cc b/regress/misc/fuzz-harness/authkeys_fuzz.cc
new file mode 100644
index 000000000000..8b3e54e543d8
--- /dev/null
+++ b/regress/misc/fuzz-harness/authkeys_fuzz.cc
@@ -0,0 +1,81 @@
+#include <stddef.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <unistd.h>
+
+extern "C" {
+
+#include "hostfile.h"
+#include "auth.h"
+#include "auth-options.h"
+#include "sshkey.h"
+
+// testdata/id_ed25519.pub and testdata/id_ed25519-cert.pub
+const char *pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMD";
+const char *certtext = "ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIMDQjYH6XRzH3j3MW1DdjCoAfvrHfgjnVGF+sLK0pBfqAAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMDAAAAAAAAA+sAAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQBj0og+s09/HpwdHZbzN0twooKPDWWrxGfnP1Joy6cDnY2BCSQ7zg9vbq11kLF8H/sKOTZWAQrUZ7LlChOu9Ogw= id_ed25519.pub";
+
+// stubs
+void auth_debug_add(const char *fmt,...)
+{
+}
+
+void
+auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote)
+{
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
+{
+ char *tmp, *o, *cp = (char *)malloc(size + 1 + strlen(pubkey) + 1);
+ struct sshauthopt *opts = NULL;
+ struct passwd *pw = getpwuid(getuid());
+ static struct sshkey *key, *cert;
+
+ if (key == NULL) {
+ if ((key = sshkey_new(KEY_UNSPEC)) == NULL ||
+ (cert = sshkey_new(KEY_UNSPEC)) == NULL)
+ abort();
+ if ((o = tmp = strdup(pubkey)) == NULL ||
+ sshkey_read(key, &tmp) != 0)
+ abort();
+ free(o);
+ if ((o = tmp = strdup(certtext)) == NULL ||
+ sshkey_read(cert, &tmp) != 0)
+ abort();
+ free(o);
+ }
+ if (cp == NULL || pw == NULL || key == NULL || cert == NULL)
+ abort();
+
+ // Cleanup whitespace at input EOL.
+ for (; size > 0 && strchr(" \t\r\n", data[size - 1]) != NULL; size--) ;
+
+ // Append a pubkey that will match.
+ memcpy(cp, data, size);
+ cp[size] = ' ';
+ memcpy(cp + size + 1, pubkey, strlen(pubkey) + 1);
+
+ // Try key.
+ if ((tmp = strdup(cp)) == NULL)
+ abort();
+ (void) auth_check_authkey_line(pw, key, tmp, "127.0.0.1", "localhost",
+ "fuzz", &opts);
+ free(tmp);
+ sshauthopt_free(opts);
+
+ // Try cert.
+ if ((tmp = strdup(cp)) == NULL)
+ abort();
+ (void) auth_check_authkey_line(pw, cert, tmp, "127.0.0.1", "localhost",
+ "fuzz", &opts);
+ free(tmp);
+ sshauthopt_free(opts);
+
+ free(cp);
+ return 0;
+}
+
+} // extern "C"
diff --git a/regress/misc/sk-dummy/sk-dummy.c b/regress/misc/sk-dummy/sk-dummy.c
index a10c0be281b1..ad5e4745237d 100644
--- a/regress/misc/sk-dummy/sk-dummy.c
+++ b/regress/misc/sk-dummy/sk-dummy.c
@@ -1,552 +1,552 @@
/*
* Copyright (c) 2019 Markus Friedl
*
* 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 HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
#ifdef HAVE_SHA2_H
#include <sha2.h>
#endif
#include "crypto_api.h"
#include "sk-api.h"
#if defined(WITH_OPENSSL) && !defined(OPENSSL_HAS_ECC)
# undef WITH_OPENSSL
#endif
#ifdef WITH_OPENSSL
/* We don't use sha2 from OpenSSL and they can conflict with system sha2.h */
#define OPENSSL_NO_SHA
#define USE_LIBC_SHA2 /* NetBSD 9 */
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/pem.h>
/* Compatibility with OpenSSH 1.0.x */
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
#define ECDSA_SIG_get0(sig, pr, ps) \
do { \
(*pr) = sig->r; \
(*ps) = sig->s; \
} while (0)
#endif
#endif /* WITH_OPENSSL */
/* #define SK_DEBUG 1 */
-#if SSH_SK_VERSION_MAJOR != 0x00090000
+#if SSH_SK_VERSION_MAJOR != 0x000a0000
# error SK API has changed, sk-dummy.c needs an update
#endif
#ifdef SK_DUMMY_INTEGRATE
# define sk_api_version ssh_sk_api_version
# define sk_enroll ssh_sk_enroll
# define sk_sign ssh_sk_sign
# define sk_load_resident_keys ssh_sk_load_resident_keys
#endif /* !SK_STANDALONE */
static void skdebug(const char *func, const char *fmt, ...)
__attribute__((__format__ (printf, 2, 3)));
static void
skdebug(const char *func, const char *fmt, ...)
{
#if defined(SK_DEBUG)
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "sk-dummy %s: ", func);
vfprintf(stderr, fmt, ap);
fputc('\n', stderr);
va_end(ap);
#else
(void)func; /* XXX */
(void)fmt; /* XXX */
#endif
}
uint32_t
sk_api_version(void)
{
return SSH_SK_VERSION_MAJOR;
}
static int
pack_key_ecdsa(struct sk_enroll_response *response)
{
#ifdef OPENSSL_HAS_ECC
EC_KEY *key = NULL;
const EC_GROUP *g;
const EC_POINT *q;
int ret = -1;
long privlen;
BIO *bio = NULL;
char *privptr;
response->public_key = NULL;
response->public_key_len = 0;
response->key_handle = NULL;
response->key_handle_len = 0;
if ((key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) == NULL) {
skdebug(__func__, "EC_KEY_new_by_curve_name");
goto out;
}
if (EC_KEY_generate_key(key) != 1) {
skdebug(__func__, "EC_KEY_generate_key");
goto out;
}
EC_KEY_set_asn1_flag(key, OPENSSL_EC_NAMED_CURVE);
if ((bio = BIO_new(BIO_s_mem())) == NULL ||
(g = EC_KEY_get0_group(key)) == NULL ||
(q = EC_KEY_get0_public_key(key)) == NULL) {
skdebug(__func__, "couldn't get key parameters");
goto out;
}
response->public_key_len = EC_POINT_point2oct(g, q,
POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
if (response->public_key_len == 0 || response->public_key_len > 2048) {
skdebug(__func__, "bad pubkey length %zu",
response->public_key_len);
goto out;
}
if ((response->public_key = malloc(response->public_key_len)) == NULL) {
skdebug(__func__, "malloc pubkey failed");
goto out;
}
if (EC_POINT_point2oct(g, q, POINT_CONVERSION_UNCOMPRESSED,
response->public_key, response->public_key_len, NULL) == 0) {
skdebug(__func__, "EC_POINT_point2oct failed");
goto out;
}
/* Key handle contains PEM encoded private key */
if (!PEM_write_bio_ECPrivateKey(bio, key, NULL, NULL, 0, NULL, NULL)) {
skdebug(__func__, "PEM_write_bio_ECPrivateKey failed");
goto out;
}
if ((privlen = BIO_get_mem_data(bio, &privptr)) <= 0) {
skdebug(__func__, "BIO_get_mem_data failed");
goto out;
}
if ((response->key_handle = malloc(privlen)) == NULL) {
skdebug(__func__, "malloc key_handle failed");
goto out;
}
response->key_handle_len = (size_t)privlen;
memcpy(response->key_handle, privptr, response->key_handle_len);
/* success */
ret = 0;
out:
if (ret != 0) {
if (response->public_key != NULL) {
memset(response->public_key, 0,
response->public_key_len);
free(response->public_key);
response->public_key = NULL;
}
if (response->key_handle != NULL) {
memset(response->key_handle, 0,
response->key_handle_len);
free(response->key_handle);
response->key_handle = NULL;
}
}
BIO_free(bio);
EC_KEY_free(key);
return ret;
#else
return -1;
#endif
}
static int
pack_key_ed25519(struct sk_enroll_response *response)
{
int ret = -1;
u_char pk[crypto_sign_ed25519_PUBLICKEYBYTES];
u_char sk[crypto_sign_ed25519_SECRETKEYBYTES];
response->public_key = NULL;
response->public_key_len = 0;
response->key_handle = NULL;
response->key_handle_len = 0;
memset(pk, 0, sizeof(pk));
memset(sk, 0, sizeof(sk));
crypto_sign_ed25519_keypair(pk, sk);
response->public_key_len = sizeof(pk);
if ((response->public_key = malloc(response->public_key_len)) == NULL) {
skdebug(__func__, "malloc pubkey failed");
goto out;
}
memcpy(response->public_key, pk, sizeof(pk));
/* Key handle contains sk */
response->key_handle_len = sizeof(sk);
if ((response->key_handle = malloc(response->key_handle_len)) == NULL) {
skdebug(__func__, "malloc key_handle failed");
goto out;
}
memcpy(response->key_handle, sk, sizeof(sk));
/* success */
ret = 0;
out:
if (ret != 0)
free(response->public_key);
return ret;
}
static int
check_options(struct sk_option **options)
{
size_t i;
if (options == NULL)
return 0;
for (i = 0; options[i] != NULL; i++) {
skdebug(__func__, "requested unsupported option %s",
options[i]->name);
if (options[i]->required) {
skdebug(__func__, "unknown required option");
return -1;
}
}
return 0;
}
int
sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
const char *application, uint8_t flags, const char *pin,
struct sk_option **options, struct sk_enroll_response **enroll_response)
{
struct sk_enroll_response *response = NULL;
int ret = SSH_SK_ERR_GENERAL;
(void)flags; /* XXX; unused */
if (enroll_response == NULL) {
skdebug(__func__, "enroll_response == NULL");
goto out;
}
*enroll_response = NULL;
if (check_options(options) != 0)
goto out; /* error already logged */
if ((response = calloc(1, sizeof(*response))) == NULL) {
skdebug(__func__, "calloc response failed");
goto out;
}
response->flags = flags;
switch(alg) {
case SSH_SK_ECDSA:
if (pack_key_ecdsa(response) != 0)
goto out;
break;
case SSH_SK_ED25519:
if (pack_key_ed25519(response) != 0)
goto out;
break;
default:
skdebug(__func__, "unsupported key type %d", alg);
return -1;
}
/* Have to return something here */
if ((response->signature = calloc(1, 1)) == NULL) {
skdebug(__func__, "calloc signature failed");
goto out;
}
response->signature_len = 0;
*enroll_response = response;
response = NULL;
ret = 0;
out:
if (response != NULL) {
free(response->public_key);
free(response->key_handle);
free(response->signature);
free(response->attestation_cert);
free(response);
}
return ret;
}
static void
dump(const char *preamble, const void *sv, size_t l)
{
#ifdef SK_DEBUG
const u_char *s = (const u_char *)sv;
size_t i;
fprintf(stderr, "%s (len %zu):\n", preamble, l);
for (i = 0; i < l; i++) {
if (i % 16 == 0)
fprintf(stderr, "%04zu: ", i);
fprintf(stderr, "%02x", s[i]);
if (i % 16 == 15 || i == l - 1)
fprintf(stderr, "\n");
}
#endif
}
static int
sig_ecdsa(const uint8_t *message, size_t message_len,
const char *application, uint32_t counter, uint8_t flags,
const uint8_t *key_handle, size_t key_handle_len,
struct sk_sign_response *response)
{
#ifdef OPENSSL_HAS_ECC
ECDSA_SIG *sig = NULL;
const BIGNUM *sig_r, *sig_s;
int ret = -1;
BIO *bio = NULL;
EVP_PKEY *pk = NULL;
EC_KEY *ec = NULL;
SHA2_CTX ctx;
uint8_t apphash[SHA256_DIGEST_LENGTH];
uint8_t sighash[SHA256_DIGEST_LENGTH];
uint8_t countbuf[4];
/* Decode EC_KEY from key handle */
if ((bio = BIO_new(BIO_s_mem())) == NULL ||
BIO_write(bio, key_handle, key_handle_len) != (int)key_handle_len) {
skdebug(__func__, "BIO setup failed");
goto out;
}
if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, "")) == NULL) {
skdebug(__func__, "PEM_read_bio_PrivateKey failed");
goto out;
}
if (EVP_PKEY_base_id(pk) != EVP_PKEY_EC) {
skdebug(__func__, "Not an EC key: %d", EVP_PKEY_base_id(pk));
goto out;
}
if ((ec = EVP_PKEY_get1_EC_KEY(pk)) == NULL) {
skdebug(__func__, "EVP_PKEY_get1_EC_KEY failed");
goto out;
}
/* Expect message to be pre-hashed */
if (message_len != SHA256_DIGEST_LENGTH) {
skdebug(__func__, "bad message len %zu", message_len);
goto out;
}
/* Prepare data to be signed */
dump("message", message, message_len);
SHA256Init(&ctx);
SHA256Update(&ctx, (const u_char *)application, strlen(application));
SHA256Final(apphash, &ctx);
dump("apphash", apphash, sizeof(apphash));
countbuf[0] = (counter >> 24) & 0xff;
countbuf[1] = (counter >> 16) & 0xff;
countbuf[2] = (counter >> 8) & 0xff;
countbuf[3] = counter & 0xff;
dump("countbuf", countbuf, sizeof(countbuf));
dump("flags", &flags, sizeof(flags));
SHA256Init(&ctx);
SHA256Update(&ctx, apphash, sizeof(apphash));
SHA256Update(&ctx, &flags, sizeof(flags));
SHA256Update(&ctx, countbuf, sizeof(countbuf));
SHA256Update(&ctx, message, message_len);
SHA256Final(sighash, &ctx);
dump("sighash", sighash, sizeof(sighash));
/* create and encode signature */
if ((sig = ECDSA_do_sign(sighash, sizeof(sighash), ec)) == NULL) {
skdebug(__func__, "ECDSA_do_sign failed");
goto out;
}
ECDSA_SIG_get0(sig, &sig_r, &sig_s);
response->sig_r_len = BN_num_bytes(sig_r);
response->sig_s_len = BN_num_bytes(sig_s);
if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL ||
(response->sig_s = calloc(1, response->sig_s_len)) == NULL) {
skdebug(__func__, "calloc signature failed");
goto out;
}
BN_bn2bin(sig_r, response->sig_r);
BN_bn2bin(sig_s, response->sig_s);
ret = 0;
out:
explicit_bzero(&ctx, sizeof(ctx));
explicit_bzero(&apphash, sizeof(apphash));
explicit_bzero(&sighash, sizeof(sighash));
ECDSA_SIG_free(sig);
if (ret != 0) {
free(response->sig_r);
free(response->sig_s);
response->sig_r = NULL;
response->sig_s = NULL;
}
BIO_free(bio);
EC_KEY_free(ec);
EVP_PKEY_free(pk);
return ret;
#else
return -1;
#endif
}
static int
sig_ed25519(const uint8_t *message, size_t message_len,
const char *application, uint32_t counter, uint8_t flags,
const uint8_t *key_handle, size_t key_handle_len,
struct sk_sign_response *response)
{
size_t o;
int ret = -1;
SHA2_CTX ctx;
uint8_t apphash[SHA256_DIGEST_LENGTH];
uint8_t signbuf[sizeof(apphash) + sizeof(flags) +
sizeof(counter) + SHA256_DIGEST_LENGTH];
uint8_t sig[crypto_sign_ed25519_BYTES + sizeof(signbuf)];
unsigned long long smlen;
if (key_handle_len != crypto_sign_ed25519_SECRETKEYBYTES) {
skdebug(__func__, "bad key handle length %zu", key_handle_len);
goto out;
}
/* Expect message to be pre-hashed */
if (message_len != SHA256_DIGEST_LENGTH) {
skdebug(__func__, "bad message len %zu", message_len);
goto out;
}
/* Prepare data to be signed */
dump("message", message, message_len);
SHA256Init(&ctx);
SHA256Update(&ctx, (const u_char *)application, strlen(application));
SHA256Final(apphash, &ctx);
dump("apphash", apphash, sizeof(apphash));
memcpy(signbuf, apphash, sizeof(apphash));
o = sizeof(apphash);
signbuf[o++] = flags;
signbuf[o++] = (counter >> 24) & 0xff;
signbuf[o++] = (counter >> 16) & 0xff;
signbuf[o++] = (counter >> 8) & 0xff;
signbuf[o++] = counter & 0xff;
memcpy(signbuf + o, message, message_len);
o += message_len;
if (o != sizeof(signbuf)) {
skdebug(__func__, "bad sign buf len %zu, expected %zu",
o, sizeof(signbuf));
goto out;
}
dump("signbuf", signbuf, sizeof(signbuf));
/* create and encode signature */
smlen = sizeof(signbuf);
if (crypto_sign_ed25519(sig, &smlen, signbuf, sizeof(signbuf),
key_handle) != 0) {
skdebug(__func__, "crypto_sign_ed25519 failed");
goto out;
}
if (smlen <= sizeof(signbuf)) {
skdebug(__func__, "bad sign smlen %llu, expected min %zu",
smlen, sizeof(signbuf) + 1);
goto out;
}
response->sig_r_len = (size_t)(smlen - sizeof(signbuf));
if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL) {
skdebug(__func__, "calloc signature failed");
goto out;
}
memcpy(response->sig_r, sig, response->sig_r_len);
dump("sig_r", response->sig_r, response->sig_r_len);
ret = 0;
out:
explicit_bzero(&ctx, sizeof(ctx));
explicit_bzero(&apphash, sizeof(apphash));
explicit_bzero(&signbuf, sizeof(signbuf));
explicit_bzero(&sig, sizeof(sig));
if (ret != 0) {
free(response->sig_r);
response->sig_r = NULL;
}
return ret;
}
int
sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
const char *application, const uint8_t *key_handle, size_t key_handle_len,
uint8_t flags, const char *pin, struct sk_option **options,
struct sk_sign_response **sign_response)
{
struct sk_sign_response *response = NULL;
int ret = SSH_SK_ERR_GENERAL;
SHA2_CTX ctx;
uint8_t message[32];
if (sign_response == NULL) {
skdebug(__func__, "sign_response == NULL");
goto out;
}
*sign_response = NULL;
if (check_options(options) != 0)
goto out; /* error already logged */
if ((response = calloc(1, sizeof(*response))) == NULL) {
skdebug(__func__, "calloc response failed");
goto out;
}
SHA256Init(&ctx);
SHA256Update(&ctx, data, datalen);
SHA256Final(message, &ctx);
response->flags = flags;
response->counter = 0x12345678;
switch(alg) {
case SSH_SK_ECDSA:
if (sig_ecdsa(message, sizeof(message), application,
response->counter, flags, key_handle, key_handle_len,
response) != 0)
goto out;
break;
case SSH_SK_ED25519:
if (sig_ed25519(message, sizeof(message), application,
response->counter, flags, key_handle, key_handle_len,
response) != 0)
goto out;
break;
default:
skdebug(__func__, "unsupported key type %d", alg);
return -1;
}
*sign_response = response;
response = NULL;
ret = 0;
out:
explicit_bzero(message, sizeof(message));
if (response != NULL) {
free(response->sig_r);
free(response->sig_s);
free(response);
}
return ret;
}
int
sk_load_resident_keys(const char *pin, struct sk_option **options,
struct sk_resident_key ***rks, size_t *nrks)
{
return SSH_SK_ERR_UNSUPPORTED;
}
diff --git a/regress/multiplex.sh b/regress/multiplex.sh
index 4744fa3d97d6..2950d955aa3f 100644
--- a/regress/multiplex.sh
+++ b/regress/multiplex.sh
@@ -1,199 +1,209 @@
-# $OpenBSD: multiplex.sh,v 1.33 2020/06/24 15:16:23 markus Exp $
+# $OpenBSD: multiplex.sh,v 1.34 2022/06/03 04:31:54 djm Exp $
# Placed in the Public Domain.
make_tmpdir
CTL=${SSH_REGRESS_TMP}/ctl-sock
tid="connection multiplexing"
trace "will use ProxyCommand $proxycmd"
if config_defined DISABLE_FD_PASSING ; then
echo "skipped (not supported on this platform)"
exit 0
fi
P=3301 # test port
wait_for_mux_master_ready()
{
for i in 1 2 3 4 5 6 7 8 9; do
${SSH} -F $OBJ/ssh_config -S $CTL -Ocheck otherhost \
>/dev/null 2>&1 && return 0
sleep $i
done
fatal "mux master never becomes ready"
}
start_sshd
start_mux_master()
{
trace "start master, fork to background"
${SSH} -Nn2 -MS$CTL -F $OBJ/ssh_config -oSendEnv="_XXX_TEST" somehost \
-E $TEST_REGRESS_LOGFILE 2>&1 &
# NB. $SSH_PID will be killed by test-exec.sh:cleanup on fatal errors.
SSH_PID=$!
wait_for_mux_master_ready
}
start_mux_master
-verbose "test $tid: envpass"
-trace "env passing over multiplexed connection"
+verbose "test $tid: setenv"
+trace "setenv over multiplexed connection"
_XXX_TEST=blah ${SSH} -F $OBJ/ssh_config -oSendEnv="_XXX_TEST" -S$CTL otherhost sh << 'EOF'
test X"$_XXX_TEST" = X"blah"
EOF
if [ $? -ne 0 ]; then
fail "environment not found"
fi
+verbose "test $tid: envpass"
+trace "env passing over multiplexed connection"
+${SSH} -F $OBJ/ssh_config -oSetEnv="_XXX_TEST=foo" -S$CTL otherhost sh << 'EOF'
+ test X"$_XXX_TEST" = X"foo"
+EOF
+if [ $? -ne 0 ]; then
+ fail "environment not found"
+fi
+
+
verbose "test $tid: transfer"
rm -f ${COPY}
trace "ssh transfer over multiplexed connection and check result"
${SSH} -F $OBJ/ssh_config -S$CTL otherhost cat ${DATA} > ${COPY}
test -f ${COPY} || fail "ssh -Sctl: failed copy ${DATA}"
cmp ${DATA} ${COPY} || fail "ssh -Sctl: corrupted copy of ${DATA}"
rm -f ${COPY}
trace "ssh transfer over multiplexed connection and check result"
${SSH} -F $OBJ/ssh_config -S $CTL otherhost cat ${DATA} > ${COPY}
test -f ${COPY} || fail "ssh -S ctl: failed copy ${DATA}"
cmp ${DATA} ${COPY} || fail "ssh -S ctl: corrupted copy of ${DATA}"
rm -f ${COPY}
trace "sftp transfer over multiplexed connection and check result"
echo "get ${DATA} ${COPY}" | \
${SFTP} -S ${SSH} -F $OBJ/ssh_config -oControlPath=$CTL otherhost >>$TEST_REGRESS_LOGFILE 2>&1
test -f ${COPY} || fail "sftp: failed copy ${DATA}"
cmp ${DATA} ${COPY} || fail "sftp: corrupted copy of ${DATA}"
rm -f ${COPY}
trace "scp transfer over multiplexed connection and check result"
${SCP} -S ${SSH} -F $OBJ/ssh_config -oControlPath=$CTL otherhost:${DATA} ${COPY} >>$TEST_REGRESS_LOGFILE 2>&1
test -f ${COPY} || fail "scp: failed copy ${DATA}"
cmp ${DATA} ${COPY} || fail "scp: corrupted copy of ${DATA}"
rm -f ${COPY}
verbose "test $tid: forward"
trace "forward over TCP/IP and check result"
$NC -N -l 127.0.0.1 $((${PORT} + 1)) < ${DATA} > /dev/null &
netcat_pid=$!
${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L127.0.0.1:$((${PORT} + 2)):127.0.0.1:$((${PORT} + 1)) otherhost >>$TEST_SSH_LOGFILE 2>&1
sleep 1 # XXX remove once race fixed
$NC 127.0.0.1 $((${PORT} + 2)) < /dev/null > ${COPY}
cmp ${DATA} ${COPY} || fail "ssh: corrupted copy of ${DATA}"
kill $netcat_pid 2>/dev/null
rm -f ${COPY} $OBJ/unix-[123].fwd
trace "forward over UNIX and check result"
$NC -N -Ul $OBJ/unix-1.fwd < ${DATA} > /dev/null &
netcat_pid=$!
${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L$OBJ/unix-2.fwd:$OBJ/unix-1.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1
${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R$OBJ/unix-3.fwd:$OBJ/unix-2.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1
sleep 1 # XXX remove once race fixed
$NC -U $OBJ/unix-3.fwd < /dev/null > ${COPY}
cmp ${DATA} ${COPY} || fail "ssh: corrupted copy of ${DATA}"
kill $netcat_pid 2>/dev/null
rm -f ${COPY} $OBJ/unix-[123].fwd
for s in 0 1 4 5 44; do
for mode in "" "-Oproxy"; do
trace "exit status $s over multiplexed connection ($mode)"
verbose "test $tid: status $s ($mode)"
${SSH} -F $OBJ/ssh_config -S $CTL $mode otherhost exit $s
r=$?
if [ $r -ne $s ]; then
fail "exit code mismatch: $r != $s"
fi
# same with early close of stdout/err
trace "exit status $s with early close over multiplexed connection ($mode)"
${SSH} -F $OBJ/ssh_config -S $CTL -n $mode otherhost \
exec sh -c \'"sleep 2; exec > /dev/null 2>&1; sleep 3; exit $s"\'
r=$?
if [ $r -ne $s ]; then
fail "exit code (with sleep) mismatch: $r != $s"
fi
done
done
verbose "test $tid: cmd check"
${SSH} -F $OBJ/ssh_config -S $CTL -Ocheck otherhost >>$TEST_REGRESS_LOGFILE 2>&1 \
|| fail "check command failed"
verbose "test $tid: cmd forward local (TCP)"
${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L $P:localhost:$PORT otherhost \
|| fail "request local forward failed"
sleep 1 # XXX remove once race fixed
${SSH} -F $OBJ/ssh_config -p$P otherhost true \
|| fail "connect to local forward port failed"
${SSH} -F $OBJ/ssh_config -S $CTL -Ocancel -L $P:localhost:$PORT otherhost \
|| fail "cancel local forward failed"
${SSH} -F $OBJ/ssh_config -p$P otherhost true \
&& fail "local forward port still listening"
verbose "test $tid: cmd forward remote (TCP)"
${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R $P:localhost:$PORT otherhost \
|| fail "request remote forward failed"
sleep 1 # XXX remove once race fixed
${SSH} -F $OBJ/ssh_config -p$P otherhost true \
|| fail "connect to remote forwarded port failed"
${SSH} -F $OBJ/ssh_config -S $CTL -Ocancel -R $P:localhost:$PORT otherhost \
|| fail "cancel remote forward failed"
${SSH} -F $OBJ/ssh_config -p$P otherhost true \
&& fail "remote forward port still listening"
verbose "test $tid: cmd forward local (UNIX)"
${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L $OBJ/unix-1.fwd:localhost:$PORT otherhost \
|| fail "request local forward failed"
sleep 1 # XXX remove once race fixed
echo "" | $NC -U $OBJ/unix-1.fwd | \
grep "Invalid SSH identification string" >/dev/null 2>&1 \
|| fail "connect to local forward path failed"
${SSH} -F $OBJ/ssh_config -S $CTL -Ocancel -L $OBJ/unix-1.fwd:localhost:$PORT otherhost \
|| fail "cancel local forward failed"
N=$(echo "xyzzy" | $NC -U $OBJ/unix-1.fwd 2>&1 | grep "xyzzy" | wc -l)
test ${N} -eq 0 || fail "local forward path still listening"
rm -f $OBJ/unix-1.fwd
verbose "test $tid: cmd forward remote (UNIX)"
${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R $OBJ/unix-1.fwd:localhost:$PORT otherhost \
|| fail "request remote forward failed"
sleep 1 # XXX remove once race fixed
echo "" | $NC -U $OBJ/unix-1.fwd | \
grep "Invalid SSH identification string" >/dev/null 2>&1 \
|| fail "connect to remote forwarded path failed"
${SSH} -F $OBJ/ssh_config -S $CTL -Ocancel -R $OBJ/unix-1.fwd:localhost:$PORT otherhost \
|| fail "cancel remote forward failed"
N=$(echo "xyzzy" | $NC -U $OBJ/unix-1.fwd 2>&1 | grep "xyzzy" | wc -l)
test ${N} -eq 0 || fail "remote forward path still listening"
rm -f $OBJ/unix-1.fwd
verbose "test $tid: cmd exit"
${SSH} -F $OBJ/ssh_config -S $CTL -Oexit otherhost >>$TEST_REGRESS_LOGFILE 2>&1 \
|| fail "send exit command failed"
# Wait for master to exit
wait $SSH_PID
kill -0 $SSH_PID >/dev/null 2>&1 && fail "exit command failed"
# Restart master and test -O stop command with master using -N
verbose "test $tid: cmd stop"
trace "restart master, fork to background"
start_mux_master
# start a long-running command then immediately request a stop
${SSH} -F $OBJ/ssh_config -S $CTL otherhost "sleep 10; exit 0" \
>>$TEST_REGRESS_LOGFILE 2>&1 &
SLEEP_PID=$!
${SSH} -F $OBJ/ssh_config -S $CTL -Ostop otherhost >>$TEST_REGRESS_LOGFILE 2>&1 \
|| fail "send stop command failed"
# wait until both long-running command and master have exited.
wait $SLEEP_PID
[ $! != 0 ] || fail "waiting for concurrent command"
wait $SSH_PID
[ $! != 0 ] || fail "waiting for master stop"
kill -0 $SSH_PID >/dev/null 2>&1 && fatal "stop command failed"
SSH_PID="" # Already gone, so don't kill in cleanup
diff --git a/regress/scp.sh b/regress/scp.sh
index 358a8df66b1c..f47c594572fd 100644
--- a/regress/scp.sh
+++ b/regress/scp.sh
@@ -1,143 +1,168 @@
-# $OpenBSD: scp.sh,v 1.13 2021/08/10 03:35:45 djm Exp $
+# $OpenBSD: scp.sh,v 1.14 2022/05/15 23:48:07 djm Exp $
# Placed in the Public Domain.
tid="scp"
#set -x
# Figure out if diff understands "-N"
if diff -N ${SRC}/scp.sh ${SRC}/scp.sh 2>/dev/null; then
DIFFOPT="-rN"
else
DIFFOPT="-r"
fi
COPY2=${OBJ}/copy2
DIR=${COPY}.dd
DIR2=${COPY}.dd2
SRC=`dirname ${SCRIPT}`
cp ${SRC}/scp-ssh-wrapper.sh ${OBJ}/scp-ssh-wrapper.scp
chmod 755 ${OBJ}/scp-ssh-wrapper.scp
export SCP # used in scp-ssh-wrapper.scp
scpclean() {
rm -rf ${COPY} ${COPY2} ${DIR} ${DIR2}
mkdir ${DIR} ${DIR2}
chmod 755 ${DIR} ${DIR2}
}
for mode in scp sftp ; do
tag="$tid: $mode mode"
if test $mode = scp ; then
scpopts="-O -q -S ${OBJ}/scp-ssh-wrapper.scp"
else
scpopts="-s -D ${SFTPSERVER}"
fi
verbose "tid: simple copy local file to local file"
scpclean
$SCP $scpopts ${DATA} ${COPY} || fail "copy failed"
cmp ${DATA} ${COPY} || fail "corrupted copy"
verbose "$tag: simple copy local file to remote file"
scpclean
$SCP $scpopts ${DATA} somehost:${COPY} || fail "copy failed"
cmp ${DATA} ${COPY} || fail "corrupted copy"
verbose "$tag: simple copy remote file to local file"
scpclean
$SCP $scpopts somehost:${DATA} ${COPY} || fail "copy failed"
cmp ${DATA} ${COPY} || fail "corrupted copy"
+ verbose "$tag: copy local file to remote file in place"
+ scpclean
+ cp ${DATA} ${COPY}
+ $SCP $scpopts ${COPY} somehost:${COPY} || fail "copy failed"
+ cmp ${DATA} ${COPY} || fail "corrupted copy"
+
+ verbose "$tag: copy remote file to local file in place"
+ scpclean
+ cp ${DATA} ${COPY}
+ $SCP $scpopts somehost:${COPY} ${COPY} || fail "copy failed"
+ cmp ${DATA} ${COPY} || fail "corrupted copy"
+
+ verbose "$tag: copy local file to remote file clobber"
+ scpclean
+ cat ${DATA} ${DATA} > ${COPY}
+ $SCP $scpopts ${DATA} somehost:${COPY} || fail "copy failed"
+ ls -l $DATA $COPY
+ cmp ${DATA} ${COPY} || fail "corrupted copy"
+
+ verbose "$tag: copy remote file to local file clobber"
+ scpclean
+ cat ${DATA} ${DATA} > ${COPY}
+ $SCP $scpopts somehost:${DATA} ${COPY} || fail "copy failed"
+ cmp ${DATA} ${COPY} || fail "corrupted copy"
+
verbose "$tag: simple copy local file to remote dir"
scpclean
cp ${DATA} ${COPY}
$SCP $scpopts ${COPY} somehost:${DIR} || fail "copy failed"
cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
verbose "$tag: simple copy local file to local dir"
scpclean
cp ${DATA} ${COPY}
$SCP $scpopts ${COPY} ${DIR} || fail "copy failed"
cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
verbose "$tag: simple copy remote file to local dir"
scpclean
cp ${DATA} ${COPY}
$SCP $scpopts somehost:${COPY} ${DIR} || fail "copy failed"
cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
verbose "$tag: recursive local dir to remote dir"
scpclean
rm -rf ${DIR2}
cp ${DATA} ${DIR}/copy
$SCP $scpopts -r ${DIR} somehost:${DIR2} || fail "copy failed"
diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
verbose "$tag: recursive local dir to local dir"
scpclean
rm -rf ${DIR2}
cp ${DATA} ${DIR}/copy
$SCP $scpopts -r ${DIR} ${DIR2} || fail "copy failed"
diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
verbose "$tag: recursive remote dir to local dir"
scpclean
rm -rf ${DIR2}
cp ${DATA} ${DIR}/copy
$SCP $scpopts -r somehost:${DIR} ${DIR2} || fail "copy failed"
diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
verbose "$tag: shell metacharacters"
scpclean
(cd ${DIR} && \
touch '`touch metachartest`' && \
$SCP $scpopts *metachar* ${DIR2} 2>/dev/null; \
[ ! -f metachartest ] ) || fail "shell metacharacters"
if [ ! -z "$SUDO" ]; then
verbose "$tag: skipped file after scp -p with failed chown+utimes"
scpclean
cp -p ${DATA} ${DIR}/copy
cp -p ${DATA} ${DIR}/copy2
cp ${DATA} ${DIR2}/copy
chmod 660 ${DIR2}/copy
$SUDO chown root ${DIR2}/copy
$SCP -p $scpopts somehost:${DIR}/\* ${DIR2} >/dev/null 2>&1
$SUDO diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
$SUDO rm ${DIR2}/copy
fi
for i in 0 1 2 3 4 5 6 7; do
verbose "$tag: disallow bad server #$i"
SCPTESTMODE=badserver_$i
export DIR SCPTESTMODE
scpclean
$SCP $scpopts somehost:${DATA} ${DIR} >/dev/null 2>/dev/null
[ -d {$DIR}/rootpathdir ] && fail "allows dir relative to root dir"
[ -d ${DIR}/dotpathdir ] && fail "allows dir creation in non-recursive mode"
scpclean
$SCP -r $scpopts somehost:${DATA} ${DIR2} >/dev/null 2>/dev/null
[ -d ${DIR}/dotpathdir ] && fail "allows dir creation outside of subdir"
scpclean
$SCP -pr $scpopts somehost:${DATA} ${DIR2} >/dev/null 2>/dev/null
[ ! -w ${DIR2} ] && fail "allows target root attribute change"
scpclean
$SCP $scpopts somehost:${DATA} ${DIR2} >/dev/null 2>/dev/null
[ -e ${DIR2}/extrafile ] && fail "allows unauth object creation"
rm -f ${DIR2}/extrafile
done
verbose "$tag: detect non-directory target"
scpclean
echo a > ${COPY}
echo b > ${COPY2}
$SCP $scpopts ${DATA} ${COPY} ${COPY2}
cmp ${COPY} ${COPY2} >/dev/null && fail "corrupt target"
done
scpclean
rm -f ${OBJ}/scp-ssh-wrapper.scp
diff --git a/regress/scp3.sh b/regress/scp3.sh
index f71b1567755b..47db47cd6a7d 100644
--- a/regress/scp3.sh
+++ b/regress/scp3.sh
@@ -1,60 +1,66 @@
# $OpenBSD: scp3.sh,v 1.3 2021/08/10 03:35:45 djm Exp $
# Placed in the Public Domain.
tid="scp3"
#set -x
COPY2=${OBJ}/copy2
DIR=${COPY}.dd
DIR2=${COPY}.dd2
+$SSH -F $OBJ/ssh_proxy somehost \
+ 'IFS=":"; for i in $PATH;do [ -x "$i/scp" ] && exit 0; done; exit 1'
+if [ $? -eq 1 ]; then
+ skip "No scp on remote path."
+fi
+
SRC=`dirname ${SCRIPT}`
cp ${SRC}/scp-ssh-wrapper.sh ${OBJ}/scp-ssh-wrapper.scp
chmod 755 ${OBJ}/scp-ssh-wrapper.scp
export SCP # used in scp-ssh-wrapper.scp
scpclean() {
rm -rf ${COPY} ${COPY2} ${DIR} ${DIR2}
mkdir ${DIR} ${DIR2}
chmod 755 ${DIR} ${DIR2}
}
for mode in scp sftp ; do
scpopts="-F${OBJ}/ssh_proxy -S ${SSH} -q"
tag="$tid: $mode mode"
if test $mode = scp ; then
scpopts="$scpopts -O"
else
scpopts="-s -D ${SFTPSERVER}"
fi
verbose "$tag: simple copy remote file to remote file"
scpclean
$SCP $scpopts -3 hostA:${DATA} hostB:${COPY} || fail "copy failed"
cmp ${DATA} ${COPY} || fail "corrupted copy"
verbose "$tag: simple copy remote file to remote dir"
scpclean
cp ${DATA} ${COPY}
$SCP $scpopts -3 hostA:${COPY} hostB:${DIR} || fail "copy failed"
cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
verbose "$tag: recursive remote dir to remote dir"
scpclean
rm -rf ${DIR2}
cp ${DATA} ${DIR}/copy
$SCP $scpopts -3r hostA:${DIR} hostB:${DIR2} || fail "copy failed"
diff -r ${DIR} ${DIR2} || fail "corrupted copy"
diff -r ${DIR2} ${DIR} || fail "corrupted copy"
verbose "$tag: detect non-directory target"
scpclean
echo a > ${COPY}
echo b > ${COPY2}
$SCP $scpopts -3 hostA:${DATA} hostA:${COPY} hostB:${COPY2}
cmp ${COPY} ${COPY2} >/dev/null && fail "corrupt target"
done
scpclean
rm -f ${OBJ}/scp-ssh-wrapper.exe
diff --git a/regress/sftp-cmds.sh b/regress/sftp-cmds.sh
index 1289c4089c6c..85f0e9767285 100644
--- a/regress/sftp-cmds.sh
+++ b/regress/sftp-cmds.sh
@@ -1,228 +1,233 @@
-# $OpenBSD: sftp-cmds.sh,v 1.14 2013/06/21 02:26:26 djm Exp $
+# $OpenBSD: sftp-cmds.sh,v 1.15 2022/03/31 03:07:33 djm Exp $
# Placed in the Public Domain.
# XXX - TODO:
# - chmod / chown / chgrp
# - -p flag for get & put
tid="sftp commands"
# test that these files are readable!
for i in `(cd /bin;echo l*)`
do
if [ -r $i ]; then
GLOBFILES="$GLOBFILES $i"
fi
done
# Path with embedded quote
QUOTECOPY=${COPY}".\"blah\""
QUOTECOPY_ARG=${COPY}'.\"blah\"'
# File with spaces
SPACECOPY="${COPY} this has spaces.txt"
SPACECOPY_ARG="${COPY}\ this\ has\ spaces.txt"
# File with glob metacharacters
GLOBMETACOPY="${COPY} [metachar].txt"
rm -rf ${COPY} ${COPY}.1 ${COPY}.2 ${COPY}.dd ${COPY}.dd2
mkdir ${COPY}.dd
verbose "$tid: lls"
(echo "lcd ${OBJ}" ; echo "lls") | ${SFTP} -D ${SFTPSERVER} 2>&1 | \
grep copy.dd >/dev/null 2>&1 || fail "lls failed"
verbose "$tid: lls w/path"
echo "lls ${OBJ}" | ${SFTP} -D ${SFTPSERVER} 2>&1 | \
grep copy.dd >/dev/null 2>&1 || fail "lls w/path failed"
verbose "$tid: ls"
echo "ls ${OBJ}" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "ls failed"
# XXX always successful
verbose "$tid: shell"
echo "!echo hi there" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "shell failed"
# XXX always successful
verbose "$tid: pwd"
echo "pwd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "pwd failed"
# XXX always successful
verbose "$tid: lpwd"
echo "lpwd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "lpwd failed"
# XXX always successful
verbose "$tid: quit"
echo "quit" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "quit failed"
# XXX always successful
verbose "$tid: help"
echo "help" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "help failed"
# XXX always successful
rm -f ${COPY}
verbose "$tid: get"
echo "get $DATA $COPY" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "get failed"
cmp $DATA ${COPY} || fail "corrupted copy after get"
rm -f ${COPY}
verbose "$tid: get quoted"
echo "get \"$DATA\" $COPY" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "get failed"
cmp $DATA ${COPY} || fail "corrupted copy after get"
rm -f ${QUOTECOPY}
cp $DATA ${QUOTECOPY}
verbose "$tid: get filename with quotes"
echo "get \"$QUOTECOPY_ARG\" ${COPY}" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "get failed"
cmp ${COPY} ${QUOTECOPY} || fail "corrupted copy after get with quotes"
rm -f ${QUOTECOPY} ${COPY}
rm -f "$SPACECOPY" ${COPY}
cp $DATA "$SPACECOPY"
verbose "$tid: get filename with spaces"
echo "get ${SPACECOPY_ARG} ${COPY}" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "get failed"
cmp ${COPY} "$SPACECOPY" || fail "corrupted copy after get with spaces"
rm -f "$GLOBMETACOPY" ${COPY}
cp $DATA "$GLOBMETACOPY"
verbose "$tid: get filename with glob metacharacters"
echo "get \"${GLOBMETACOPY}\" ${COPY}" | \
${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "get failed"
cmp ${COPY} "$GLOBMETACOPY" || \
fail "corrupted copy after get with glob metacharacters"
rm -f ${COPY}.dd/*
verbose "$tid: get to directory"
echo "get $DATA ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "get failed"
cmp $DATA ${COPY}.dd/$DATANAME || fail "corrupted copy after get"
rm -f ${COPY}.dd/*
verbose "$tid: glob get to directory"
echo "get /bin/l* ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "get failed"
for x in $GLOBFILES; do
cmp /bin/$x ${COPY}.dd/$x || fail "corrupted copy after get"
done
rm -f ${COPY}.dd/*
verbose "$tid: get to local dir"
(echo "lcd ${COPY}.dd"; echo "get $DATA" ) | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "get failed"
cmp $DATA ${COPY}.dd/$DATANAME || fail "corrupted copy after get"
rm -f ${COPY}.dd/*
verbose "$tid: glob get to local dir"
(echo "lcd ${COPY}.dd"; echo "get /bin/l*") | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "get failed"
for x in $GLOBFILES; do
cmp /bin/$x ${COPY}.dd/$x || fail "corrupted copy after get"
done
rm -f ${COPY}
verbose "$tid: put"
echo "put $DATA $COPY" | \
${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "put failed"
cmp $DATA ${COPY} || fail "corrupted copy after put"
rm -f ${QUOTECOPY}
verbose "$tid: put filename with quotes"
echo "put $DATA \"$QUOTECOPY_ARG\"" | \
${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "put failed"
cmp $DATA ${QUOTECOPY} || fail "corrupted copy after put with quotes"
rm -f "$SPACECOPY"
verbose "$tid: put filename with spaces"
echo "put $DATA ${SPACECOPY_ARG}" | \
${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "put failed"
cmp $DATA "$SPACECOPY" || fail "corrupted copy after put with spaces"
rm -f ${COPY}.dd/*
verbose "$tid: put to directory"
echo "put $DATA ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "put failed"
cmp $DATA ${COPY}.dd/$DATANAME || fail "corrupted copy after put"
rm -f ${COPY}.dd/*
verbose "$tid: glob put to directory"
echo "put /bin/l? ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "put failed"
for x in $GLOBFILES; do
cmp /bin/$x ${COPY}.dd/$x || fail "corrupted copy after put"
done
rm -f ${COPY}.dd/*
verbose "$tid: put to local dir"
(echo "cd ${COPY}.dd"; echo "put $DATA") | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "put failed"
cmp $DATA ${COPY}.dd/$DATANAME || fail "corrupted copy after put"
rm -f ${COPY}.dd/*
verbose "$tid: glob put to local dir"
(echo "cd ${COPY}.dd"; echo "put /bin/l?") | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "put failed"
for x in $GLOBFILES; do
cmp /bin/$x ${COPY}.dd/$x || fail "corrupted copy after put"
done
verbose "$tid: rename"
echo "rename $COPY ${COPY}.1" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "rename failed"
test -f ${COPY}.1 || fail "missing file after rename"
cmp $DATA ${COPY}.1 >/dev/null 2>&1 || fail "corrupted copy after rename"
verbose "$tid: rename directory"
echo "rename ${COPY}.dd ${COPY}.dd2" | \
${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || \
fail "rename directory failed"
test -d ${COPY}.dd && fail "oldname exists after rename directory"
test -d ${COPY}.dd2 || fail "missing newname after rename directory"
verbose "$tid: ln"
echo "ln ${COPY}.1 ${COPY}.2" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "ln failed"
test -f ${COPY}.2 || fail "missing file after ln"
cmp ${COPY}.1 ${COPY}.2 || fail "created file is not equal after ln"
verbose "$tid: ln -s"
rm -f ${COPY}.2
echo "ln -s ${COPY}.1 ${COPY}.2" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "ln -s failed"
test -h ${COPY}.2 || fail "missing file after ln -s"
+verbose "$tid: cp"
+rm -f ${COPY}.2
+echo "cp ${COPY}.1 ${COPY}.2" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "cp failed"
+cmp ${COPY}.1 ${COPY}.2 || fail "created file is not equal after cp"
+
verbose "$tid: mkdir"
echo "mkdir ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "mkdir failed"
test -d ${COPY}.dd || fail "missing directory after mkdir"
# XXX do more here
verbose "$tid: chdir"
echo "chdir ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "chdir failed"
verbose "$tid: rmdir"
echo "rmdir ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "rmdir failed"
test -d ${COPY}.1 && fail "present directory after rmdir"
verbose "$tid: lmkdir"
echo "lmkdir ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "lmkdir failed"
test -d ${COPY}.dd || fail "missing directory after lmkdir"
# XXX do more here
verbose "$tid: lchdir"
echo "lchdir ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
|| fail "lchdir failed"
rm -rf ${COPY} ${COPY}.1 ${COPY}.2 ${COPY}.dd ${COPY}.dd2
rm -rf ${QUOTECOPY} "$SPACECOPY" "$GLOBMETACOPY"
diff --git a/regress/test-exec.sh b/regress/test-exec.sh
index 9fb02d1cbc8c..c51f8eac162f 100644
--- a/regress/test-exec.sh
+++ b/regress/test-exec.sh
@@ -1,769 +1,804 @@
-# $OpenBSD: test-exec.sh,v 1.89 2022/01/06 22:14:25 dtucker Exp $
+# $OpenBSD: test-exec.sh,v 1.92 2022/07/25 07:12:45 dtucker Exp $
# Placed in the Public Domain.
#SUDO=sudo
-if [ ! -x "$TEST_SSH_ELAPSED_TIMES" ]; then
+if [ ! -z "$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
# Portable-specific settings.
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
# 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 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
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
OPENSSL_BIN="${OPENSSL_BIN:-openssl}"
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
if [ "x$TEST_SSH_OPENSSL" != "x" ]; then
OPENSSL_BIN="${TEST_SSH_OPENSSL}"
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
+# If set, keep track of successful tests and skip them them if we've
+# previously completed that test.
+if [ "x$TEST_REGRESS_CACHE_DIR" != "x" ]; then
+ if [ ! -d "$TEST_REGRESS_CACHE_DIR" ]; then
+ mkdir -p "$TEST_REGRESS_CACHE_DIR"
+ fi
+ TEST="`basename $SCRIPT .sh`"
+ CACHE="${TEST_REGRESS_CACHE_DIR}/${TEST}.cache"
+ for i in ${SSH} ${SSHD} ${SSHAGENT} ${SSHADD} ${SSHKEYGEN} ${SCP} \
+ ${SFTP} ${SFTPSERVER} ${SSHKEYSCAN}; do
+ case $i in
+ /*) bin="$i" ;;
+ *) bin="`which $i`" ;;
+ esac
+ if [ "$bin" -nt "$CACHE" ]; then
+ rm -f "$CACHE"
+ fi
+ done
+ if [ -f "$CACHE" ]; then
+ echo ok cached $CACHE
+ exit 0
+ fi
+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. scp and sftp like
# to use -q so we remove those to preserve our debug logging. In the rare
# instance where -q is desirable -qq is equivalent and is not removed.
SSHLOGWRAP=$OBJ/ssh-log-wrapper.sh
cat >$SSHLOGWRAP <<EOD
#!/bin/sh
echo "Executing: ${SSH} \$@" >>${TEST_SSH_LOGFILE}
for i in "\$@";do shift;case "\$i" in -q):;; *) set -- "\$@" "\$i";;esac;done
exec ${SSH} -E${TEST_SSH_LOGFILE} "\$@"
EOD
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()
+which()
{
saved_IFS="$IFS"
IFS=":"
for i in $PATH
do
if [ -x $i/$1 ]; then
IFS="$saved_IFS"
+ echo "$i/$1"
return 0
fi
done
IFS="$saved_IFS"
+ echo "$i/$1"
return 1
}
+have_prog()
+{
+ which "$1" >/dev/null 2>&1
+ return $?
+}
+
jot() {
awk "BEGIN { for (i = $2; i < $2 + $1; i++) { printf \"%d\n\", i } exit }"
}
if [ ! -x "`which rev`" ]; then
rev()
{
awk '{for (i=length; i>0; i--) printf "%s", substr($0, i, 1); print ""}'
}
fi
# 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
elif [ -x ${OPENSSL_BIN} ]; then
${OPENSSL_BIN} md5
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
}
# 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
}
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
}
# Skip remaining tests in script.
skip ()
{
echo "SKIPPED: $@"
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
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
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 "${OBJ}/misc/sk-dummy/sk-dummy.so" ] ; then
SSH_SK_PROVIDER="${OBJ}/misc/sk-dummy/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
(umask 077; $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
# If there is an EXIT trap handler, invoke it now.
# Some tests set these to clean up processes such as ssh-agent. We
# need to wait for all valgrind processes to complete so we can check
# their logs, but since the EXIT traps are not invoked until
# test-exec.sh exits, waiting here will deadlock.
# This is not very portable but then neither is valgrind itself.
# As a bonus, dash (as used on the runners) has a "trap" that doesn't
# work in a pipeline (hence the temp file) or a subshell.
exithandler=""
trap >/tmp/trap.$$ && exithandler=$(cat /tmp/trap.$$ | \
awk -F "'" '/EXIT$/{print $2}')
rm -f /tmp/trap.$$
if [ "x${exithandler}" != "x" ]; then
verbose invoking EXIT trap handler early: ${exithandler}
eval "${exithandler}"
trap '' EXIT
fi
# 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
+ if [ "x$CACHE" != "x" ]; then
+ touch "$CACHE"
+ fi
else
echo failed $tid
fi
exit $RESULT
diff --git a/regress/unittests/misc/test_convtime.c b/regress/unittests/misc/test_convtime.c
index ef6fd77deda5..4794dbd9daae 100644
--- a/regress/unittests/misc/test_convtime.c
+++ b/regress/unittests/misc/test_convtime.c
@@ -1,59 +1,121 @@
-/* $OpenBSD: test_convtime.c,v 1.2 2021/12/14 21:25:27 deraadt Exp $ */
+/* $OpenBSD: test_convtime.c,v 1.3 2022/08/11 01:57:50 djm Exp $ */
/*
* Regress test for misc time conversion functions.
*
* Placed in the public domain.
*/
#include "includes.h"
#include <sys/types.h>
#include <limits.h>
#include <stdio.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "../test_helper/test_helper.h"
#include "log.h"
#include "misc.h"
+#include "ssherr.h"
void test_convtime(void);
void
test_convtime(void)
{
char buf[1024];
+ uint64_t t;
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();
+
+ /* XXX timezones/DST make verification of this tricky */
+ /* XXX maybe setenv TZ and tzset() to make it unambiguous? */
+ TEST_START("misc_parse_absolute_time");
+ ASSERT_INT_EQ(parse_absolute_time("20000101", &t), 0);
+ ASSERT_INT_EQ(parse_absolute_time("200001011223", &t), 0);
+ ASSERT_INT_EQ(parse_absolute_time("20000101122345", &t), 0);
+
+ /* forced UTC TZ */
+ ASSERT_INT_EQ(parse_absolute_time("20000101Z", &t), 0);
+ ASSERT_U64_EQ(t, 946684800);
+ ASSERT_INT_EQ(parse_absolute_time("200001011223Z", &t), 0);
+ ASSERT_U64_EQ(t, 946729380);
+ ASSERT_INT_EQ(parse_absolute_time("20000101122345Z", &t), 0);
+ ASSERT_U64_EQ(t, 946729425);
+ ASSERT_INT_EQ(parse_absolute_time("20000101UTC", &t), 0);
+ ASSERT_U64_EQ(t, 946684800);
+ ASSERT_INT_EQ(parse_absolute_time("200001011223UTC", &t), 0);
+ ASSERT_U64_EQ(t, 946729380);
+ ASSERT_INT_EQ(parse_absolute_time("20000101122345UTC", &t), 0);
+ ASSERT_U64_EQ(t, 946729425);
+
+ /* Bad month */
+ ASSERT_INT_EQ(parse_absolute_time("20001301", &t),
+ SSH_ERR_INVALID_FORMAT);
+ ASSERT_INT_EQ(parse_absolute_time("20000001", &t),
+ SSH_ERR_INVALID_FORMAT);
+ /* Incomplete */
+ ASSERT_INT_EQ(parse_absolute_time("2", &t),
+ SSH_ERR_INVALID_FORMAT);
+ ASSERT_INT_EQ(parse_absolute_time("2000", &t),
+ SSH_ERR_INVALID_FORMAT);
+ ASSERT_INT_EQ(parse_absolute_time("20000", &t),
+ SSH_ERR_INVALID_FORMAT);
+ ASSERT_INT_EQ(parse_absolute_time("200001", &t),
+ SSH_ERR_INVALID_FORMAT);
+ ASSERT_INT_EQ(parse_absolute_time("2000010", &t),
+ SSH_ERR_INVALID_FORMAT);
+ ASSERT_INT_EQ(parse_absolute_time("200001010", &t),
+ SSH_ERR_INVALID_FORMAT);
+ /* Bad day, hour, minute, second */
+ ASSERT_INT_EQ(parse_absolute_time("20000199", &t),
+ SSH_ERR_INVALID_FORMAT);
+ ASSERT_INT_EQ(parse_absolute_time("200001019900", &t),
+ SSH_ERR_INVALID_FORMAT);
+ ASSERT_INT_EQ(parse_absolute_time("200001010099", &t),
+ SSH_ERR_INVALID_FORMAT);
+ ASSERT_INT_EQ(parse_absolute_time("20000101000099", &t),
+ SSH_ERR_INVALID_FORMAT);
+ /* Invalid TZ specifier */
+ ASSERT_INT_EQ(parse_absolute_time("20000101ZZ", &t),
+ SSH_ERR_INVALID_FORMAT);
+ ASSERT_INT_EQ(parse_absolute_time("20000101PDT", &t),
+ SSH_ERR_INVALID_FORMAT);
+ ASSERT_INT_EQ(parse_absolute_time("20000101U", &t),
+ SSH_ERR_INVALID_FORMAT);
+ ASSERT_INT_EQ(parse_absolute_time("20000101UTCUTC", &t),
+ SSH_ERR_INVALID_FORMAT);
+
+ TEST_DONE();
}
diff --git a/sandbox-capsicum.c b/sandbox-capsicum.c
index 883be185815a..11045251c885 100644
--- a/sandbox-capsicum.c
+++ b/sandbox-capsicum.c
@@ -1,121 +1,128 @@
/*
* Copyright (c) 2011 Dag-Erling Smorgrav
*
* 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 SANDBOX_CAPSICUM
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/capsicum.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#ifdef HAVE_CAPSICUM_HELPERS_H
+#include <capsicum_helpers.h>
+#endif
#include "log.h"
#include "monitor.h"
#include "ssh-sandbox.h"
#include "xmalloc.h"
/*
* Capsicum sandbox that sets zero nfiles, nprocs and filesize rlimits,
* limits rights on stdout, stdin, stderr, monitor and switches to
* capability mode.
*/
struct ssh_sandbox {
struct monitor *monitor;
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 capsicum sandbox", __func__);
box = xcalloc(1, sizeof(*box));
box->monitor = monitor;
box->child_pid = 0;
return box;
}
void
ssh_sandbox_child(struct ssh_sandbox *box)
{
struct rlimit rl_zero;
cap_rights_t rights;
+#ifdef HAVE_CAPH_CACHE_TZDATA
+ caph_cache_tzdata();
+#endif
+
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));
#ifndef SANDBOX_SKIP_RLIMIT_NOFILE
if (setrlimit(RLIMIT_NOFILE, &rl_zero) == -1)
fatal("%s: setrlimit(RLIMIT_NOFILE, { 0, 0 }): %s",
__func__, strerror(errno));
#endif
if (setrlimit(RLIMIT_NPROC, &rl_zero) == -1)
fatal("%s: setrlimit(RLIMIT_NPROC, { 0, 0 }): %s",
__func__, strerror(errno));
cap_rights_init(&rights);
if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS)
fatal("can't limit stdin: %m");
if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS)
fatal("can't limit stdout: %m");
if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS)
fatal("can't limit stderr: %m");
cap_rights_init(&rights, CAP_READ, CAP_WRITE);
if (cap_rights_limit(box->monitor->m_recvfd, &rights) < 0 &&
errno != ENOSYS)
fatal("%s: failed to limit the network socket", __func__);
cap_rights_init(&rights, CAP_WRITE);
if (cap_rights_limit(box->monitor->m_log_sendfd, &rights) < 0 &&
errno != ENOSYS)
fatal("%s: failed to limit the logging socket", __func__);
if (cap_enter() < 0 && errno != ENOSYS)
fatal("%s: failed to enter capability mode", __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_CAPSICUM */
diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c
index 4ce80cb2a739..9929bdb68513 100644
--- a/sandbox-seccomp-filter.c
+++ b/sandbox-seccomp-filter.c
@@ -1,454 +1,457 @@
/*
* 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 */
+#define SANDBOX_SECCOMP_FILTER_DEBUG 1
+#if 0
+/*
+ * For older toolchains, it may be necessary to use the kernel
+ * headers directly.
+ */
#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 */
+#endif
#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_gettid
SC_ALLOW(__NR_gettid),
#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_ppoll
SC_ALLOW(__NR_ppoll),
#endif
#ifdef __NR_ppoll_time64
SC_ALLOW(__NR_ppoll_time64),
#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);
+void mm_log_handler(LogLevel level, int forced, 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);
+ mm_log_handler(SYSLOG_LEVEL_FATAL, 0, 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));
}
#endif /* SANDBOX_SECCOMP_FILTER_DEBUG */
void
ssh_sandbox_child(struct ssh_sandbox *box)
{
struct rlimit rl_zero, rl_one = {.rlim_cur = 1, .rlim_max = 1};
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));
/*
* Cannot use zero for nfds, because poll(2) will fail with
* errno=EINVAL if npfds>RLIMIT_NOFILE.
*/
if (setrlimit(RLIMIT_NOFILE, &rl_one) == -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));
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));
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 2057b5e70af0..67aca9020495 100644
--- a/scp.0
+++ b/scp.0
@@ -1,215 +1,216 @@
SCP(1) General Commands Manual SCP(1)
NAME
scp M-bM-^@M-^S OpenSSH secure file copy
SYNOPSIS
scp [-346ABCOpqRrsTv] [-c cipher] [-D sftp_server_path] [-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.
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
cannot be specified on the target if the -R 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, when using the legacy SCP
protocol (via the -O flag), this option selects batch mode for
the second host as scp cannot ask for passwords or passphrases
for both hosts. This mode is the default.
-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).
-D sftp_server_path
When using the SFTP protocol support via -M, connect directly to
a local SFTP server program rather than a remote one 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.
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 Use the legacy SCP protocol for file transfers instead of the
SFTP protocol. Forcing the use of the SCP protocol may be
necessary for servers that do not implement SFTP, for backwards-
compatibility for particular filename wildcard patterns and for
expanding paths with a M-bM-^@M-^X~M-bM-^@M-^Y prefix for older SFTP servers.
-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
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
+ RequiredRSASize
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 mode bits of the file.
-p Preserves modification times, access times, and file mode bits
from the source file.
-q Quiet mode: disables the progress meter as well as warning and
diagnostic messages from ssh(1).
-R Copies between two remote hosts are performed by connecting to
the origin host and executing scp there. This requires that scp
running on the origin host can authenticate to the destination
host without requiring a password.
-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),
sftp-server(8), sshd(8)
HISTORY
scp is based on the rcp program in BSD source code from the Regents of
the University of California.
- Since OpenSSH 8.8, scp has use the SFTP protocol for transfers by
+ Since OpenSSH 9.0, scp has used the SFTP protocol for transfers by
default.
AUTHORS
Timo Rinne <tri@iki.fi>
Tatu Ylonen <ylo@cs.hut.fi>
CAVEATS
The legacy SCP protocol (selected by the -O flag) requires execution of
the remote user's shell to perform glob(3) pattern matching. This
requires careful quoting of any characters that have special meaning to
the remote shell, such as quote characters.
-OpenBSD 7.0 February 23, 2022 OpenBSD 7.0
+OpenBSD 7.1 September 19, 2022 OpenBSD 7.1
diff --git a/scp.1 b/scp.1
index 3af6ece1e7a1..cd23f97952e9 100644
--- a/scp.1
+++ b/scp.1
@@ -1,311 +1,312 @@
.\"
.\" scp.1
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\"
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
.\" All rights reserved
.\"
.\" Created: Sun May 7 00:14:37 1995 ylo
.\"
-.\" $OpenBSD: scp.1,v 1.108 2022/02/23 21:21:16 djm Exp $
+.\" $OpenBSD: scp.1,v 1.110 2022/09/19 21:39:16 djm Exp $
.\"
-.Dd $Mdocdate: February 23 2022 $
+.Dd $Mdocdate: September 19 2022 $
.Dt SCP 1
.Os
.Sh NAME
.Nm scp
.Nd OpenSSH secure file copy
.Sh SYNOPSIS
.Nm scp
.Op Fl 346ABCOpqRrsTv
.Op Fl c Ar cipher
.Op Fl D Ar sftp_server_path
.Op Fl F Ar ssh_config
.Op Fl i Ar identity_file
.Op Fl J Ar destination
.Op Fl l Ar limit
.Op Fl o Ar ssh_option
.Op Fl P Ar port
.Op Fl S Ar program
.Ar source ... target
.Sh DESCRIPTION
.Nm
copies files between hosts on a network.
.Pp
It uses
.Xr ssh 1
for data transfer, and uses the same authentication and provides the
same security as a login session.
.Pp
.Nm
will ask for passwords or passphrases if they are needed for
authentication.
.Pp
The
.Ar source
and
.Ar target
may be specified as a local pathname, a remote host with optional path
in the form
.Sm off
.Oo user @ Oc host : Op path ,
.Sm on
or a URI in the form
.Sm off
.No scp:// Oo user @ Oc host Oo : port Oc Op / path .
.Sm on
Local file names can be made explicit using absolute or relative pathnames
to avoid
.Nm
treating file names containing
.Sq :\&
as host specifiers.
.Pp
When copying between two remote hosts, if the URI format is used, a
.Ar port
cannot be specified on the
.Ar target
if the
.Fl R
option is used.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl 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, when using the legacy SCP protocol (via the
.Fl O
flag), this option
selects batch mode for the second host as
.Nm
cannot ask for passwords or passphrases for both hosts.
This mode is the default.
.It Fl 4
Forces
.Nm
to use IPv4 addresses only.
.It Fl 6
Forces
.Nm
to use IPv6 addresses only.
.It Fl A
Allows forwarding of
.Xr ssh-agent 1
to the remote system.
The default is not to forward an authentication agent.
.It Fl B
Selects batch mode (prevents asking for passwords or passphrases).
.It Fl C
Compression enable.
Passes the
.Fl C
flag to
.Xr ssh 1
to enable compression.
.It Fl c Ar cipher
Selects the cipher to use for encrypting the data transfer.
This option is directly passed to
.Xr ssh 1 .
.It Fl D Ar sftp_server_path
When using the SFTP protocol support via
.Fl M ,
connect directly to a local SFTP server program rather than a
remote one via
.Xr ssh 1 .
This option may be useful in debugging the client and server.
.It Fl F Ar ssh_config
Specifies an alternative
per-user configuration file for
.Nm ssh .
This option is directly passed to
.Xr ssh 1 .
.It Fl i Ar identity_file
Selects the file from which the identity (private key) for public key
authentication is read.
This option is directly passed to
.Xr ssh 1 .
.It Fl J Ar destination
Connect to the target host by first making an
.Nm
connection to the jump host described by
.Ar 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
.Cm ProxyJump
configuration directive.
This option is directly passed to
.Xr ssh 1 .
.It Fl l Ar limit
Limits the used bandwidth, specified in Kbit/s.
.It Fl O
Use the legacy SCP protocol for file transfers instead of the SFTP protocol.
Forcing the use of the SCP protocol may be necessary for servers that do
not implement SFTP, for backwards-compatibility for particular filename
wildcard patterns and for expanding paths with a
.Sq ~
prefix for older SFTP servers.
.It Fl o Ar ssh_option
Can be used to pass options to
.Nm ssh
in the format used in
.Xr ssh_config 5 .
This is useful for specifying options
for which there is no separate
.Nm scp
command-line flag.
For full details of the options listed below, and their possible values, see
.Xr ssh_config 5 .
.Pp
.Bl -tag -width Ds -offset indent -compact
.It AddressFamily
.It BatchMode
.It BindAddress
.It BindInterface
.It CanonicalDomains
.It CanonicalizeFallbackLocal
.It CanonicalizeHostname
.It CanonicalizeMaxDots
.It CanonicalizePermittedCNAMEs
.It CASignatureAlgorithms
.It CertificateFile
.It CheckHostIP
.It Ciphers
.It Compression
.It ConnectionAttempts
.It ConnectTimeout
.It ControlMaster
.It ControlPath
.It ControlPersist
.It GlobalKnownHostsFile
.It GSSAPIAuthentication
.It GSSAPIDelegateCredentials
.It HashKnownHosts
.It Host
.It HostbasedAcceptedAlgorithms
.It HostbasedAuthentication
.It HostKeyAlgorithms
.It HostKeyAlias
.It Hostname
.It IdentitiesOnly
.It IdentityAgent
.It IdentityFile
.It IPQoS
.It KbdInteractiveAuthentication
.It KbdInteractiveDevices
.It KexAlgorithms
.It KnownHostsCommand
.It LogLevel
.It MACs
.It NoHostAuthenticationForLocalhost
.It NumberOfPasswordPrompts
.It PasswordAuthentication
.It PKCS11Provider
.It Port
.It PreferredAuthentications
.It ProxyCommand
.It ProxyJump
.It PubkeyAcceptedAlgorithms
.It PubkeyAuthentication
.It RekeyLimit
+.It RequiredRSASize
.It SendEnv
.It ServerAliveInterval
.It ServerAliveCountMax
.It SetEnv
.It StrictHostKeyChecking
.It TCPKeepAlive
.It UpdateHostKeys
.It User
.It UserKnownHostsFile
.It VerifyHostKeyDNS
.El
.It Fl P Ar port
Specifies the port to connect to on the remote host.
Note that this option is written with a capital
.Sq P ,
because
.Fl p
is already reserved for preserving the times and mode bits of the file.
.It Fl p
Preserves modification times, access times, and file mode bits from the
source file.
.It Fl q
Quiet mode: disables the progress meter as well as warning and diagnostic
messages from
.Xr ssh 1 .
.It Fl R
Copies between two remote hosts are performed by connecting to the origin
host and executing
.Nm
there.
This requires that
.Nm
running on the origin host can authenticate to the destination host without
requiring a password.
.It Fl r
Recursively copy entire directories.
Note that
.Nm
follows symbolic links encountered in the tree traversal.
.It Fl S Ar program
Name of
.Ar program
to use for the encrypted connection.
The program must understand
.Xr ssh 1
options.
.It Fl T
Disable strict filename checking.
By default when copying files from a remote host to a local directory
.Nm
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.
.It Fl v
Verbose mode.
Causes
.Nm
and
.Xr ssh 1
to print debugging messages about their progress.
This is helpful in
debugging connection, authentication, and configuration problems.
.El
.Sh EXIT STATUS
.Ex -std scp
.Sh SEE ALSO
.Xr sftp 1 ,
.Xr ssh 1 ,
.Xr ssh-add 1 ,
.Xr ssh-agent 1 ,
.Xr ssh-keygen 1 ,
.Xr ssh_config 5 ,
.Xr sftp-server 8 ,
.Xr sshd 8
.Sh HISTORY
.Nm
is based on the rcp program in
.Bx
source code from the Regents of the University of California.
.Pp
-Since OpenSSH 8.8,
+Since OpenSSH 9.0,
.Nm
-has use the SFTP protocol for transfers by default.
+has used the SFTP protocol for transfers by default.
.Sh AUTHORS
.An Timo Rinne Aq Mt tri@iki.fi
.An Tatu Ylonen Aq Mt ylo@cs.hut.fi
.Sh CAVEATS
The legacy SCP protocol (selected by the
.Fl O
flag) requires execution of the remote user's shell to perform
.Xr glob 3
pattern matching.
This requires careful quoting of any characters that have special meaning to
the remote shell, such as quote characters.
diff --git a/scp.c b/scp.c
index c36d66aa5941..f9ca5d393294 100644
--- a/scp.c
+++ b/scp.c
@@ -1,2175 +1,2173 @@
-/* $OpenBSD: scp.c,v 1.247 2022/03/20 08:52:17 djm Exp $ */
+/* $OpenBSD: scp.c,v 1.248 2022/05/13 06:31:50 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
#ifdef USE_SYSTEM_GLOB
# include <glob.h>
#else
# include "openbsd-compat/glob.h"
#endif
#ifdef HAVE_LIBGEN_H
#include <libgen.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"
#include "sftp.h"
#include "sftp-common.h"
#include "sftp-client.h"
extern char *__progname;
#define COPY_BUFLEN 16384
int do_cmd(char *, char *, char *, int, int, char *, int *, int *, pid_t *);
int do_cmd2(char *, char *, int, char *, int, int);
/* 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;
LogLevel log_level = SYSLOG_LEVEL_INFO;
/* 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 = 1;
/* 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;
pid_t do_cmd_pid2 = -1;
/* Needed for sftp */
volatile sig_atomic_t interrupted = 0;
int remote_glob(struct sftp_conn *, const char *, int,
int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
static void
killchild(int signo)
{
if (do_cmd_pid > 1) {
kill(do_cmd_pid, signo ? signo : SIGTERM);
waitpid(do_cmd_pid, NULL, 0);
}
if (do_cmd_pid2 > 1) {
kill(do_cmd_pid2, signo ? signo : SIGTERM);
waitpid(do_cmd_pid2, NULL, 0);
}
if (signo)
_exit(1);
exit(1);
}
static void
suspone(int pid, int signo)
{
int status;
if (pid > 1) {
kill(pid, signo);
while (waitpid(pid, &status, WUNTRACED) == -1 &&
errno == EINTR)
;
}
}
static void
suspchild(int signo)
{
suspone(do_cmd_pid, signo);
suspone(do_cmd_pid2, signo);
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 *program, char *host, char *remuser, int port, int subsystem,
char *cmd, int *fdin, int *fdout, pid_t *pid)
{
int pin[2], pout[2], reserved[2];
if (verbose_mode)
fmprintf(stderr,
"Executing: program %s host %s, user %s, command %s\n",
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. */
*pid = fork();
if (*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", program);
if (port != -1) {
addargs(&args, "-p");
addargs(&args, "%d", port);
}
if (remuser != NULL) {
addargs(&args, "-l");
addargs(&args, "%s", remuser);
}
if (subsystem)
addargs(&args, "-s");
addargs(&args, "--");
addargs(&args, "%s", host);
addargs(&args, "%s", cmd);
execvp(program, args.list);
perror(program);
exit(1);
} else if (*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)
{
int status;
pid_t pid;
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, remin2, remout2;
int Tflag, pflag, iamremote, iamrecursive, targetshouldbedirectory;
#define CMDNEEDS 64
char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
enum scp_mode_e {
MODE_SCP,
MODE_SFTP
};
int response(void);
void rsource(char *, struct stat *);
void sink(int, char *[], const char *);
void source(int, char *[]);
void tolocal(int, char *[], enum scp_mode_e, char *sftp_direct);
void toremote(int, char *[], enum scp_mode_e, char *sftp_direct);
void usage(void);
void source_sftp(int, char *, char *, struct sftp_conn *);
void sink_sftp(int, char *, const char *, struct sftp_conn *);
void throughlocal_sftp(struct sftp_conn *, struct sftp_conn *,
char *, char *);
int
main(int argc, char **argv)
{
int ch, fflag, tflag, status, n;
char **newargv, *argv0;
const char *errstr;
extern char *optarg;
extern int optind;
enum scp_mode_e mode = MODE_SFTP;
char *sftp_direct = NULL;
/* 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 */
argv0 = argv[0];
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]);
log_init(argv0, log_level, SYSLOG_FACILITY_USER, 2);
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,
"12346ABCTdfOpqRrstvD:F:J:M: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 'D':
sftp_direct = optarg;
break;
case '3':
throughlocal = 1;
break;
case 'R':
throughlocal = 0;
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 'O':
mode = MODE_SCP;
break;
case 's':
mode = MODE_SFTP;
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");
if (verbose_mode == 0)
log_level = SYSLOG_LEVEL_DEBUG1;
else if (log_level < SYSLOG_LEVEL_DEBUG3)
log_level++;
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;
log_init(argv0, log_level, SYSLOG_FACILITY_USER, 2);
/* Do this last because we want the user to be able to override it */
addargs(&args, "-oForwardAgent=no");
if (iamremote)
mode = MODE_SCP;
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, mode, sftp_direct);
else {
if (targetshouldbedirectory)
verifydir(argv[argc - 1]);
tolocal(argc, argv, mode, sftp_direct); /* 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 && (mode == MODE_SFTP || 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)
{
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;
}
static struct sftp_conn *
do_sftp_connect(char *host, char *user, int port, char *sftp_direct,
int *reminp, int *remoutp, int *pidp)
{
if (sftp_direct == NULL) {
if (do_cmd(ssh_program, host, user, port, 1, "sftp",
reminp, remoutp, pidp) < 0)
return NULL;
} else {
freeargs(&args);
addargs(&args, "sftp-server");
if (do_cmd(sftp_direct, host, NULL, -1, 0, "sftp",
reminp, remoutp, pidp) < 0)
return NULL;
}
return do_init(*reminp, *remoutp, 32768, 64, limit_kbps);
}
void
toremote(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct)
{
char *suser = NULL, *host = NULL, *src = NULL;
char *bp, *tuser, *thost, *targ;
int sport = -1, tport = -1;
struct sftp_conn *conn = NULL, *conn2 = NULL;
arglist alist;
int i, r, status;
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;
}
}
/* 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 */
if (mode == MODE_SFTP) {
if (remin == -1) {
/* Connect to dest now */
conn = do_sftp_connect(thost, tuser,
tport, sftp_direct,
&remin, &remout, &do_cmd_pid);
if (conn == NULL) {
fatal("Unable to open "
"destination connection");
}
debug3_f("origin in %d out %d pid %ld",
remin, remout, (long)do_cmd_pid);
}
/*
* XXX remember suser/host/sport and only
* reconnect if they change between arguments.
* would save reconnections for cases like
* scp -3 hosta:/foo hosta:/bar hostb:
*/
/* Connect to origin now */
conn2 = do_sftp_connect(host, suser,
sport, sftp_direct,
&remin2, &remout2, &do_cmd_pid2);
if (conn2 == NULL) {
fatal("Unable to open "
"source connection");
}
debug3_f("destination in %d out %d pid %ld",
remin2, remout2, (long)do_cmd_pid2);
throughlocal_sftp(conn2, conn, src, targ);
(void) close(remin2);
(void) close(remout2);
remin2 = remout2 = -1;
if (waitpid(do_cmd_pid2, &status, 0) == -1)
++errs;
else if (!WIFEXITED(status) ||
WEXITSTATUS(status) != 0)
++errs;
do_cmd_pid2 = -1;
continue;
} else {
xasprintf(&bp, "%s -f %s%s", cmd,
*src == '-' ? "-- " : "", src);
if (do_cmd(ssh_program, host, suser, sport, 0,
bp, &remin, &remout, &do_cmd_pid) < 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 */
/*
* Second remote user is passed to first remote side
* via scp command-line. Ensure it contains no obvious
* shell characters.
*/
if (tuser != NULL && !okname(tuser)) {
++errs;
continue;
}
if (tport != -1 && tport != SSH_DEFAULT_PORT) {
/* This would require the remote support URIs */
fatal("target port not supported with two "
"remote hosts and the -R 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 (mode == MODE_SFTP) {
if (remin == -1) {
/* Connect to remote now */
conn = do_sftp_connect(thost, tuser,
tport, sftp_direct,
&remin, &remout, &do_cmd_pid);
if (conn == NULL) {
fatal("Unable to open sftp "
"connection");
}
}
/* The protocol */
source_sftp(1, argv[i], targ, conn);
continue;
}
/* SCP */
if (remin == -1) {
xasprintf(&bp, "%s -t %s%s", cmd,
*targ == '-' ? "-- " : "", targ);
if (do_cmd(ssh_program, thost, tuser, tport, 0,
bp, &remin, &remout, &do_cmd_pid) < 0)
exit(1);
if (response() < 0)
exit(1);
free(bp);
}
source(1, argv + i);
}
}
out:
if (mode == MODE_SFTP)
free(conn);
free(tuser);
free(thost);
free(targ);
free(suser);
free(host);
free(src);
}
void
tolocal(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct)
{
char *bp, *host = NULL, *src = NULL, *suser = NULL;
arglist alist;
struct sftp_conn *conn = NULL;
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. */
if (mode == MODE_SFTP) {
conn = do_sftp_connect(host, suser, sport,
sftp_direct, &remin, &remout, &do_cmd_pid);
if (conn == NULL) {
error("sftp connection failed");
++errs;
continue;
}
/* The protocol */
sink_sftp(1, argv[argc - 1], src, conn);
free(conn);
(void) close(remin);
(void) close(remout);
remin = remout = -1;
continue;
}
/* SCP */
xasprintf(&bp, "%s -f %s%s",
cmd, *src == '-' ? "-- " : "", src);
if (do_cmd(ssh_program, host, suser, sport, 0, bp,
&remin, &remout, &do_cmd_pid) < 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);
}
/* Prepare remote path, handling ~ by assuming cwd is the homedir */
static char *
prepare_remote_path(struct sftp_conn *conn, const char *path)
{
size_t nslash;
/* Handle ~ prefixed paths */
if (*path == '\0' || strcmp(path, "~") == 0)
return xstrdup(".");
if (*path != '~')
return xstrdup(path);
if (strncmp(path, "~/", 2) == 0) {
if ((nslash = strspn(path + 2, "/")) == strlen(path + 2))
return xstrdup(".");
return xstrdup(path + 2 + nslash);
}
if (can_expand_path(conn))
return do_expand_path(conn, path);
/* No protocol extension */
error("server expand-path extension is required "
"for ~user paths in SFTP mode");
return NULL;
}
void
source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn)
{
char *target = NULL, *filename = NULL, *abs_dst = NULL;
int src_is_dir, target_is_dir;
Attrib a;
struct stat st;
memset(&a, '\0', sizeof(a));
if (stat(src, &st) != 0)
fatal("stat local \"%s\": %s", src, strerror(errno));
src_is_dir = S_ISDIR(st.st_mode);
if ((filename = basename(src)) == NULL)
fatal("basename \"%s\": %s", src, strerror(errno));
/*
* No need to glob here - the local shell already took care of
* the expansions
*/
if ((target = prepare_remote_path(conn, targ)) == NULL)
cleanup_exit(255);
target_is_dir = remote_is_dir(conn, target);
if (targetshouldbedirectory && !target_is_dir) {
debug("target directory \"%s\" does not exist", target);
a.flags = SSH2_FILEXFER_ATTR_PERMISSIONS;
a.perm = st.st_mode | 0700; /* ensure writable */
if (do_mkdir(conn, target, &a, 1) != 0)
cleanup_exit(255); /* error already logged */
target_is_dir = 1;
}
if (target_is_dir)
abs_dst = path_append(target, filename);
else {
abs_dst = target;
target = NULL;
}
debug3_f("copying local %s to remote %s", src, abs_dst);
if (src_is_dir && iamrecursive) {
if (upload_dir(conn, src, abs_dst, pflag,
- SFTP_PROGRESS_ONLY, 0, 0, 1) != 0) {
+ SFTP_PROGRESS_ONLY, 0, 0, 1, 1) != 0) {
error("failed to upload directory %s to %s", src, targ);
errs = 1;
}
- } else if (do_upload(conn, src, abs_dst, pflag, 0, 0) != 0) {
+ } else if (do_upload(conn, src, abs_dst, pflag, 0, 0, 1) != 0) {
error("failed to upload file %s to %s", src, targ);
errs = 1;
}
free(abs_dst);
free(target);
}
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)) == -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();
}
void
sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
{
char *abs_src = NULL;
char *abs_dst = NULL;
glob_t g;
char *filename, *tmp = NULL;
int i, r, err = 0, dst_is_dir;
struct stat st;
memset(&g, 0, sizeof(g));
/*
* Here, we need remote glob as SFTP can not depend on remote shell
* expansions
*/
if ((abs_src = prepare_remote_path(conn, src)) == NULL) {
err = -1;
goto out;
}
debug3_f("copying remote %s to local %s", abs_src, dst);
if ((r = remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) != 0) {
if (r == GLOB_NOSPACE)
error("%s: too many glob matches", src);
else
error("%s: %s", src, strerror(ENOENT));
err = -1;
goto out;
}
if ((r = stat(dst, &st)) != 0)
debug2_f("stat local \"%s\": %s", dst, strerror(errno));
dst_is_dir = r == 0 && S_ISDIR(st.st_mode);
if (g.gl_matchc > 1 && !dst_is_dir) {
if (r == 0) {
error("Multiple files match pattern, but destination "
"\"%s\" is not a directory", dst);
err = -1;
goto out;
}
debug2_f("creating destination \"%s\"", dst);
if (mkdir(dst, 0777) != 0) {
error("local mkdir \"%s\": %s", dst, strerror(errno));
err = -1;
goto out;
}
dst_is_dir = 1;
}
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));
err = -1;
goto out;
}
if (dst_is_dir)
abs_dst = path_append(dst, filename);
else
abs_dst = xstrdup(dst);
debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
- pflag, SFTP_PROGRESS_ONLY, 0, 0, 1) == -1)
+ pflag, SFTP_PROGRESS_ONLY, 0, 0, 1, 1) == -1)
err = -1;
} else {
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
- pflag, 0, 0) == -1)
+ pflag, 0, 0, 1) == -1)
err = -1;
}
free(abs_dst);
abs_dst = NULL;
free(tmp);
tmp = NULL;
}
out:
free(abs_src);
free(tmp);
globfree(&g);
if (err == -1)
errs = 1;
}
#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 */
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);
}
void
throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to,
char *src, char *targ)
{
char *target = NULL, *filename = NULL, *abs_dst = NULL;
char *abs_src = NULL, *tmp = NULL;
glob_t g;
int i, r, targetisdir, err = 0;
if ((filename = basename(src)) == NULL)
fatal("basename %s: %s", src, strerror(errno));
if ((abs_src = prepare_remote_path(from, src)) == NULL ||
(target = prepare_remote_path(to, targ)) == NULL)
cleanup_exit(255);
memset(&g, 0, sizeof(g));
targetisdir = remote_is_dir(to, target);
if (!targetisdir && targetshouldbedirectory) {
error("%s: destination is not a directory", targ);
err = -1;
goto out;
}
debug3_f("copying remote %s to remote %s", abs_src, target);
if ((r = remote_glob(from, abs_src, GLOB_MARK, NULL, &g)) != 0) {
if (r == GLOB_NOSPACE)
error("%s: too many glob matches", src);
else
error("%s: %s", src, strerror(ENOENT));
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));
err = -1;
goto out;
}
if (targetisdir)
abs_dst = path_append(target, filename);
else
abs_dst = xstrdup(target);
debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
if (crossload_dir(from, to, g.gl_pathv[i], abs_dst,
NULL, pflag, SFTP_PROGRESS_ONLY, 1) == -1)
err = -1;
} else {
if (do_crossload(from, to, g.gl_pathv[i], abs_dst, NULL,
pflag) == -1)
err = -1;
}
free(abs_dst);
abs_dst = NULL;
free(tmp);
tmp = NULL;
}
out:
free(abs_src);
free(abs_dst);
free(target);
free(tmp);
globfree(&g);
if (err == -1)
errs = 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 [-346ABCOpqRrsTv] [-c cipher] [-D sftp_server_path] [-F ssh_config]\n"
" [-i identity_file] [-J destination] [-l limit]\n"
" [-o ssh_option] [-P port] [-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);
}
void
cleanup_exit(int i)
{
if (remin > 0)
close(remin);
if (remout > 0)
close(remout);
if (remin2 > 0)
close(remin2);
if (remout2 > 0)
close(remout2);
if (do_cmd_pid > 0)
waitpid(do_cmd_pid, NULL, 0);
if (do_cmd_pid2 > 0)
waitpid(do_cmd_pid2, NULL, 0);
exit(i);
}
diff --git a/servconf.c b/servconf.c
index 9d9681f15acf..423772b158e4 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,3032 +1,3049 @@
-/* $OpenBSD: servconf.c,v 1.384 2022/03/18 04:04:11 djm Exp $ */
+/* $OpenBSD: servconf.c,v 1.386 2022/09/17 10:34:29 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->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;
+ options->required_rsa_size = -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 = 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");
+ if (options->required_rsa_size == -1)
+ options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
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,
sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
sKerberosGetAFSToken, 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, 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,
+ sRequiredRSASize,
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", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
{ "skeyauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
{ "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 },
+ { "requiredrsasize", sRequiredRSASize, SSHCFG_ALL },
{ 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;
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]);
host = hpdelim(&arg);
if (host == NULL)
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') {
/* Terminate on comment */
if (*attrib == '#') {
cp = NULL; /* mark all arguments consumed */
break;
}
arg = NULL;
attributes++;
/* Criterion "all" has no argument and must appear alone */
if (strcasecmp(attrib, "all") == 0) {
if (attributes > 1 || ((arg = strdelim(&cp)) != NULL &&
*arg != '\0' && *arg != '#')) {
error("'all' cannot be combined with other "
"Match attributes");
return -1;
}
if (arg != NULL && *arg == '#')
cp = NULL; /* mark all arguments consumed */
*condition = cp;
return 1;
}
/* All other criteria require an argument */
if ((arg = strdelim(&cp)) == NULL ||
*arg == '\0' || *arg == '#') {
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 *str, ***chararrayptr, **charptr, *arg, *arg2, *p, *keyword;
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;
char **oav = NULL, **av;
int oac = 0, ac;
int ret = -1;
/* 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';
}
str = line;
if ((keyword = strdelim(&str)) == NULL)
return 0;
/* Ignore leading whitespace */
if (*keyword == '\0')
keyword = strdelim(&str);
if (!keyword || !*keyword || *keyword == '#')
return 0;
if (str == NULL || *str == '\0') {
error("%s line %d: no argument after keyword \"%s\"",
filename, linenum, keyword);
return -1;
}
intptr = NULL;
charptr = NULL;
opcode = parse_token(keyword, filename, linenum, &flags);
if (argv_split(str, &oac, &oav, 1) != 0) {
error("%s line %d: invalid quotes", filename, linenum);
return -1;
}
ac = oac;
av = oav;
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, keyword, str);
if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
if (connectinfo == NULL) {
fatal("%s line %d: Directive '%s' is not allowed "
"within a Match block", filename, linenum, keyword);
} else { /* this is a directive we have already processed */
ret = 0;
goto out;
}
}
switch (opcode) {
/* Portable-specific options */
case sUsePAM:
intptr = &options->use_pam;
goto parse_flag;
/* Standard Options */
case sBadOption:
goto out;
case sPort:
/* ignore ports from configfile if cmdline specifies ports */
if (options->ports_from_cmdline) {
argv_consume(&ac);
break;
}
if (options->num_ports >= MAX_PORTS)
fatal("%s line %d: too many ports.",
filename, linenum);
arg = argv_next(&ac, &av);
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 = argv_next(&ac, &av);
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 = argv_next(&ac, &av);
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;
p = hpdelim(&arg);
if (p == NULL)
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 = argv_next(&ac, &av)) != NULL) {
if (strcmp(arg, "rdomain") != 0 ||
(arg2 = argv_next(&ac, &av)) == 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 = argv_next(&ac, &av);
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 = argv_next(&ac, &av);
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 = argv_next(&ac, &av);
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 = argv_next(&ac, &av);
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 = argv_next(&ac, &av);
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 = argv_next(&ac, &av);
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 = argv_next(&ac, &av)) != NULL) {
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 {
error("%s line %d: unsupported %s option %s",
filename, linenum, keyword, arg);
goto out;
}
}
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 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 = argv_next(&ac, &av);
if ((errstr = atoi_err(arg, &value)) != NULL)
fatal("%s line %d: %s integer value %s.",
filename, linenum, keyword, 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 = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
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 = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
if (strcmp(arg, "default") == 0) {
val64 = 0;
} else {
if (scan_scaled(arg, &val64) == -1)
fatal("%.200s line %d: Bad %s number '%s': %s",
filename, linenum, keyword,
arg, strerror(errno));
if (val64 != 0 && val64 < 16)
fatal("%.200s line %d: %s too small",
filename, linenum, keyword);
}
if (*activep && options->rekey_limit == -1)
options->rekey_limit = val64;
if (ac != 0) { /* optional rekey interval present */
if (strcmp(av[0], "none") == 0) {
(void)argv_next(&ac, &av); /* 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 = argv_next(&ac, &av);
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 = argv_next(&ac, &av);
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:
found = options->num_log_verbose == 0;
i = 0;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0') {
error("%s line %d: keyword %s empty argument",
filename, linenum, keyword);
goto out;
}
/* Allow "none" only in first position */
if (strcasecmp(arg, "none") == 0) {
if (i > 0 || ac > 0) {
error("%s line %d: keyword %s \"none\" "
"argument must appear alone.",
filename, linenum, keyword);
goto out;
}
}
i++;
if (!found || !*activep)
continue;
opt_array_append(filename, linenum, keyword,
&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:
chararrayptr = &options->allow_users;
uintptr = &options->num_allow_users;
parse_allowdenyusers:
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0' ||
match_user(NULL, NULL, NULL, arg) == -1)
fatal("%s line %d: invalid %s pattern: \"%s\"",
filename, linenum, keyword, arg);
if (!*activep)
continue;
opt_array_append(filename, linenum, keyword,
chararrayptr, uintptr, arg);
}
break;
case sDenyUsers:
chararrayptr = &options->deny_users;
uintptr = &options->num_deny_users;
goto parse_allowdenyusers;
case sAllowGroups:
chararrayptr = &options->allow_groups;
uintptr = &options->num_allow_groups;
parse_allowdenygroups:
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0')
fatal("%s line %d: empty %s pattern",
filename, linenum, keyword);
if (!*activep)
continue;
opt_array_append(filename, linenum, keyword,
chararrayptr, uintptr, arg);
}
break;
case sDenyGroups:
chararrayptr = &options->deny_groups;
uintptr = &options->num_deny_groups;
goto parse_allowdenygroups;
case sCiphers:
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
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 = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
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 = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
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 = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
if (!*activep) {
arg = argv_next(&ac, &av);
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 = argv_next(&ac, &av);
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 = argv_next(&ac, &av)) != NULL) {
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 = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
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: Invalid %s spec.",
filename, linenum, keyword);
} else if (n != 1)
fatal("%s line %d: Invalid %s spec.",
filename, linenum, keyword);
else
options->max_startups = options->max_startups_begin;
break;
case sPerSourceNetBlockSize:
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
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 %s spec.",
filename, linenum, keyword);
if (*activep) {
options->per_source_masklen_ipv4 = value;
options->per_source_masklen_ipv6 = value2;
}
break;
case sPerSourceMaxStartups:
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
if (strcmp(arg, "none") == 0) { /* no limit */
value = INT_MAX;
} else {
if ((errstr = atoi_err(arg, &value)) != NULL)
fatal("%s line %d: %s integer value %s.",
filename, linenum, keyword, 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:
uvalue = options->num_authkeys_files;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0') {
error("%s line %d: keyword %s empty argument",
filename, linenum, keyword);
goto out;
}
arg2 = tilde_expand_filename(arg, getuid());
if (*activep && uvalue == 0) {
opt_array_append(filename, linenum, keyword,
&options->authorized_keys_files,
&options->num_authkeys_files, arg2);
}
free(arg2);
}
break;
case sAuthorizedPrincipalsFile:
charptr = &options->authorized_principals_file;
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
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 = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0' || strchr(arg, '=') != NULL)
fatal("%s line %d: Invalid environment name.",
filename, linenum);
if (!*activep)
continue;
opt_array_append(filename, linenum, keyword,
&options->accept_env, &options->num_accept_env,
arg);
}
break;
case sSetEnv:
uvalue = options->num_setenv;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0' || strchr(arg, '=') == NULL)
fatal("%s line %d: Invalid environment.",
filename, linenum);
if (!*activep || uvalue != 0)
continue;
+ if (lookup_setenv_in_list(arg, options->setenv,
+ options->num_setenv) != NULL) {
+ debug2("%s line %d: ignoring duplicate env "
+ "name \"%.64s\"", filename, linenum, arg);
+ continue;
+ }
opt_array_append(filename, linenum, keyword,
&options->setenv, &options->num_setenv, arg);
}
break;
case sPermitTunnel:
intptr = &options->permit_tun;
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
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 %s argument %s",
filename, linenum, keyword, 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 = argv_next(&ac, &av)) != NULL) {
if (*arg2 == '\0') {
error("%s line %d: keyword %s empty argument",
filename, linenum, keyword);
goto out;
}
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: %s missing filename argument",
filename, linenum, keyword);
}
break;
case sMatch:
if (cmdline)
fatal("Match directive not supported as a command-line "
"option");
value = match_cfg_line(&str, 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 flag is applicable only until the first
* match block.
*/
*inc_flags &= ~SSHCFG_MATCH_ONLY;
/*
* If match_cfg_line() didn't consume all its arguments then
* arrange for the extra arguments check below to fail.
*/
if (str == NULL || *str == '\0')
argv_consume(&ac);
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 = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
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 = argv_next(&ac, &av)) {
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);
p = hpdelim(&arg);
if (p == NULL) {
fatal("%s line %d: %s missing host",
filename, linenum, keyword);
}
p = cleanhostname(p);
}
if (arg == NULL ||
((port = permitopen_port(arg)) < 0)) {
fatal("%s line %d: %s bad port number",
filename, linenum, keyword);
}
if (*activep && uvalue == 0) {
opt_array_append(filename, linenum, keyword,
chararrayptr, uintptr, arg2);
}
free(arg2);
}
break;
case sForceCommand:
if (str == NULL || *str == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
len = strspn(str, WHITESPACE);
if (*activep && options->adm_forced_command == NULL)
options->adm_forced_command = xstrdup(str + len);
argv_consume(&ac);
break;
case sChrootDirectory:
charptr = &options->chroot_directory;
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
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 = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
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 = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
if ((value = parse_ipqos(arg)) == -1)
fatal("%s line %d: Bad %s value: %s",
filename, linenum, keyword, arg);
arg = argv_next(&ac, &av);
if (arg == NULL)
value2 = value;
else if ((value2 = parse_ipqos(arg)) == -1)
fatal("%s line %d: Bad %s value: %s",
filename, linenum, keyword, arg);
if (*activep) {
options->ip_qos_interactive = value;
options->ip_qos_bulk = value2;
}
break;
case sVersionAddendum:
if (str == NULL || *str == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
len = strspn(str, WHITESPACE);
if (strchr(str + len, '\r') != NULL) {
fatal("%.200s line %d: Invalid %s argument",
filename, linenum, keyword);
}
if ((arg = strchr(line, '#')) != NULL) {
*arg = '\0';
rtrim(line);
}
if (*activep && options->version_addendum == NULL) {
if (strcasecmp(str + len, "none") == 0)
options->version_addendum = xstrdup("");
else
options->version_addendum = xstrdup(str + len);
}
argv_consume(&ac);
break;
case sAuthorizedKeysCommand:
charptr = &options->authorized_keys_command;
parse_command:
len = strspn(str, WHITESPACE);
if (str[len] != '/' && strcasecmp(str + len, "none") != 0) {
fatal("%.200s line %d: %s must be an absolute path",
filename, linenum, keyword);
}
if (*activep && options->authorized_keys_command == NULL)
*charptr = xstrdup(str + len);
argv_consume(&ac);
break;
case sAuthorizedKeysCommandUser:
charptr = &options->authorized_keys_command_user;
parse_localuser:
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0') {
fatal("%s line %d: missing %s argument.",
filename, linenum, keyword);
}
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
break;
case sAuthorizedPrincipalsCommand:
charptr = &options->authorized_principals_command;
goto parse_command;
case sAuthorizedPrincipalsCommandUser:
charptr = &options->authorized_principals_command_user;
goto parse_localuser;
case sAuthenticationMethods:
found = options->num_auth_methods == 0;
value = 0; /* seen "any" pseudo-method */
value2 = 0; /* successfully parsed any method */
while ((arg = argv_next(&ac, &av)) != NULL) {
if (strcmp(arg, "any") == 0) {
if (options->num_auth_methods > 0) {
fatal("%s line %d: \"any\" must "
"appear alone in %s",
filename, linenum, keyword);
}
value = 1;
} else if (value) {
fatal("%s line %d: \"any\" must appear "
"alone in %s", filename, linenum, keyword);
} else if (auth2_methods_valid(arg, 0) != 0) {
fatal("%s line %d: invalid %s method list.",
filename, linenum, keyword);
}
value2 = 1;
if (!found || !*activep)
continue;
opt_array_append(filename, linenum, keyword,
&options->auth_methods,
&options->num_auth_methods, arg);
}
if (value2 == 0) {
fatal("%s line %d: no %s specified",
filename, linenum, keyword);
}
break;
case sStreamLocalBindMask:
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
/* Parse mode in octal format */
value = strtol(arg, &p, 8);
if (arg == p || value < 0 || value > 0777)
fatal("%s line %d: Invalid %s.",
filename, linenum, keyword);
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 = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
if ((value = ssh_digest_alg_by_name(arg)) == -1)
fatal("%.200s line %d: Invalid %s algorithm \"%s\".",
filename, linenum, keyword, 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 = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
if (strcasecmp(arg, "none") != 0 && strcmp(arg, "%D") != 0 &&
!valid_rdomain(arg))
fatal("%s line %d: invalid routing domain",
filename, linenum);
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
break;
+ case sRequiredRSASize:
+ intptr = &options->required_rsa_size;
+ goto parse_int;
+
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",
keyword);
argv_consume(&ac);
break;
default:
fatal("%s line %d: Missing handler for opcode %s (%d)",
filename, linenum, keyword, opcode);
}
/* Check that there is no garbage at end of line. */
if (ac > 0) {
error("%.200s line %d: keyword %s extra arguments "
"at end of line", filename, linenum, keyword);
goto out;
}
/* success */
ret = 0;
out:
argv_free(oav, oac);
return ret;
}
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)
fatal_fr(r, "allocate");
while (getline(&line, &linesize, f) != -1) {
lineno++;
/*
* Strip whitespace
* NB - preserve newlines, they are needed to reproduce
* line numbers later for error messages
*/
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, 0);
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);
return -1;
}
} else {
fprintf(stderr, "Invalid test mode specification %s\n",
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);
+ M_CP_INTOPT(required_rsa_size);
/*
* 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 reexec)
{
int active = connectinfo ? 0 : 1;
parse_server_config_depth(options, filename, conf, includes,
connectinfo, (connectinfo ? SSHCFG_MATCH_ONLY : 0), &active, 0);
if (!reexec)
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_int(sRequiredRSASize, o->required_rsa_size);
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(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);
dump_cfg_strarray(sHostCertificate, o->num_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 8a04463e0b79..9346155ce5bc 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,313 +1,314 @@
-/* $OpenBSD: servconf.h,v 1.156 2022/03/18 04:04:11 djm Exp $ */
+/* $OpenBSD: servconf.h,v 1.157 2022/09/17 10:34:29 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 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;
+ int required_rsa_size; /* minimum size of RSA keys */
} 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 *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);
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 *, int);
void parse_server_match_config(ServerOptions *,
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 0541f028a650..b4c0d82b242d 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -1,936 +1,935 @@
-/* $OpenBSD: serverloop.c,v 1.231 2022/01/22 00:49:34 djm Exp $ */
+/* $OpenBSD: serverloop.c,v 1.232 2022/04/20 04:19:11 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>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#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. */
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;
}
/*ARGSUSED*/
static void
sigchld_handler(int sig)
{
child_terminated = 1;
}
/*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 ppoll() until we can do something.
* 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, struct pollfd **pfdp,
u_int *npfd_allocp, u_int *npfd_activep, u_int64_t max_time_ms,
sigset_t *sigsetp, int *conn_in_readyp, int *conn_out_readyp)
{
struct timespec ts, *tsp;
int ret;
time_t minwait_secs = 0;
int client_alive_scheduled = 0;
u_int p;
/* time we last heard from the client OR sent a keepalive */
static time_t last_client_time;
*conn_in_readyp = *conn_out_readyp = 0;
/* Prepare channel poll. First two pollfd entries are reserved */
channel_prepare_poll(ssh, pfdp, npfd_allocp, npfd_activep,
2, &minwait_secs);
if (*npfd_activep < 2)
fatal_f("bad npfd %u", *npfd_activep); /* shouldn't happen */
/* 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
/* Monitor client connection on reserved pollfd entries */
(*pfdp)[0].fd = connection_in;
(*pfdp)[0].events = POLLIN;
(*pfdp)[1].fd = connection_out;
(*pfdp)[1].events = ssh_packet_have_data_to_write(ssh) ? POLLOUT : 0;
/*
* 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)
tsp = NULL;
else {
ts.tv_sec = max_time_ms / 1000;
ts.tv_nsec = 1000000 * (max_time_ms % 1000);
tsp = &ts;
}
/* Wait for something to happen, or the timeout to expire. */
ret = ppoll(*pfdp, *npfd_activep, tsp, sigsetp);
if (ret == -1) {
for (p = 0; p < *npfd_activep; p++)
(*pfdp)[p].revents = 0;
if (errno != EINTR)
fatal_f("ppoll: %.100s", strerror(errno));
return;
}
*conn_in_readyp = (*pfdp)[0].revents != 0;
*conn_out_readyp = (*pfdp)[1].revents != 0;
if (client_alive_scheduled) {
time_t now = monotime();
/*
* If the ppoll 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 (*conn_in_readyp)
last_client_time = now;
}
}
/*
* Processes input from the client and the program. Input data is stored
* in buffers and processed later.
*/
static int
process_input(struct ssh *ssh, int connection_in)
{
int r;
if ((r = ssh_packet_process_read(ssh, connection_in)) == 0)
return 0; /* success */
if (r == SSH_ERR_SYSTEM_ERROR) {
if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)
return 0;
if (errno == EPIPE) {
verbose("Connection closed by %.100s port %d",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
return -1;
}
verbose("Read error from remote host %s port %d: %s",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
strerror(errno));
cleanup_exit(255);
}
return -1;
}
/*
* Sends data from internal buffers to client program stdin.
*/
static void
process_output(struct ssh *ssh, int connection_out)
{
int r;
/* Send any buffered packet data to the client. */
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;
int status;
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;
}
}
void
server_loop2(struct ssh *ssh, Authctxt *authctxt)
{
struct pollfd *pfd = NULL;
u_int npfd_alloc = 0, npfd_active = 0;
int r, conn_in_ready, conn_out_ready;
u_int connection_in, connection_out;
u_int64_t rekey_timeout_ms = 0;
sigset_t bsigset, osigset;
debug("Entering interactive session for SSH2.");
if (sigemptyset(&bsigset) == -1 || sigaddset(&bsigset, SIGCHLD) == -1)
error_f("bsigset setup: %s", strerror(errno));
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);
}
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;
}
/*
* Block SIGCHLD while we check for dead children, then pass
* the old signal mask through to ppoll() so that it'll wake
* up immediately if a child exits after we've called waitpid().
*/
if (sigprocmask(SIG_BLOCK, &bsigset, &osigset) == -1)
error_f("bsigset sigprocmask: %s", strerror(errno));
collect_children(ssh);
wait_until_can_do_something(ssh, connection_in, connection_out,
&pfd, &npfd_alloc, &npfd_active, rekey_timeout_ms, &osigset,
&conn_in_ready, &conn_out_ready);
if (sigprocmask(SIG_UNBLOCK, &bsigset, &osigset) == -1)
error_f("osigset sigprocmask: %s", strerror(errno));
if (received_sigterm) {
logit("Exiting on signal %d", (int)received_sigterm);
/* Clean up sessions, utmp, etc. */
cleanup_exit(255);
}
- if (!ssh_packet_is_rekeying(ssh))
- channel_after_poll(ssh, pfd, npfd_active);
+ channel_after_poll(ssh, pfd, npfd_active);
if (conn_in_ready &&
process_input(ssh, connection_in) < 0)
break;
/* A timeout may have triggered rekeying */
if ((r = ssh_packet_check_rekey(ssh)) != 0)
fatal_fr(r, "cannot start rekeying");
if (conn_out_ready)
process_output(ssh, connection_out);
}
collect_children(ssh);
free(pfd);
/* 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, success = 0;
const u_char *blob;
const char *sigalg, *kex_rsa_sigalg = NULL;
u_char *sig = 0;
size_t blen, slen;
if ((resp = sshbuf_new()) == NULL || (sigbuf = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if (sshkey_type_plain(sshkey_type_from_name(
ssh->kex->hostkey_alg)) == KEY_RSA)
kex_rsa_sigalg = 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).
*/
sigalg = NULL;
if (sshkey_type_plain(key->type) == KEY_RSA) {
if (kex_rsa_sigalg != NULL)
sigalg = kex_rsa_sigalg;
else if (ssh->kex->flags & KEX_RSA_SHA2_512_SUPPORTED)
sigalg = "rsa-sha2-512";
else if (ssh->kex->flags & KEX_RSA_SHA2_256_SUPPORTED)
sigalg = "rsa-sha2-256";
}
debug3_f("sign %s key (index %d) using sigalg %s",
sshkey_type(key), ndx, sigalg == NULL ? "default" : sigalg);
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), sigalg)) != 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))) {
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/sftp-client.c b/sftp-client.c
index 1b8ce6d78826..35be53d697b6 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -1,2795 +1,2938 @@
-/* $OpenBSD: sftp-client.c,v 1.162 2022/03/31 03:07:03 djm Exp $ */
+/* $OpenBSD: sftp-client.c,v 1.165 2022/09/19 10:43:12 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>
#ifdef HAVE_POLL_H
#include <poll.h>
#else
# ifdef HAVE_SYS_POLL_H
# include <sys/poll.h>
# endif
#endif
#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 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
-#define SFTP_EXT_PATH_EXPAND 0x00000080
-#define SFTP_EXT_COPY_DATA 0x00000100
+#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
+#define SFTP_EXT_PATH_EXPAND 0x00000080
+#define SFTP_EXT_COPY_DATA 0x00000100
+#define SFTP_EXT_GETUSERSGROUPS_BY_ID 0x00000200
u_int exts;
u_int64_t limit_kbps;
struct bwlimit bwlimit_in, bwlimit_out;
};
/* Tracks in-progress requests during file transfers */
struct request {
u_int id;
size_t len;
u_int64_t offset;
TAILQ_ENTRY(request) tq;
};
TAILQ_HEAD(requests, request);
static u_char *
get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len,
const char *errfmt, ...) __attribute__((format(printf, 4, 5)));
static struct request *
request_enqueue(struct requests *requests, u_int id, size_t len,
uint64_t offset)
{
struct request *req;
req = xcalloc(1, sizeof(*req));
req->id = id;
req->len = len;
req->offset = offset;
TAILQ_INSERT_TAIL(requests, req, tq);
return req;
}
static struct request *
request_find(struct requests *requests, u_int id)
{
struct request *req;
for (req = TAILQ_FIRST(requests);
req != NULL && req->id != id;
req = TAILQ_NEXT(req, tq))
;
return req;
}
/* 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;
sshbuf_reset(m);
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 F:0x%04x M:%05o",
conn->fd_out, code, id, a->flags, a->perm);
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;
}
/* XXX returning &static is error-prone. Refactor to fill *Attrib argument */
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");
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("stat remote: %s", fx2txt(status));
else
error("stat remote: %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;
}
debug3("Received stat reply T:%u I:%u F:0x%04x M:%05o",
type, id, a.flags, a.perm);
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("remote statvfs: %s", fx2txt(status));
else
error("remote 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->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);
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;
} else if (strcmp(name, "expand-path@openssh.com") == 0 &&
strcmp((char *)value, "1") == 0) {
ret->exts |= SFTP_EXT_PATH_EXPAND;
known = 1;
} else if (strcmp(name, "copy-data") == 0 &&
strcmp((char *)value, "1") == 0) {
ret->exts |= SFTP_EXT_COPY_DATA;
known = 1;
+ } else if (strcmp(name,
+ "users-groups-by-id@openssh.com") == 0 &&
+ strcmp((char *)value, "1") == 0) {
+ ret->exts |= SFTP_EXT_GETUSERSGROUPS_BY_ID;
+ 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->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->download_buflen);
bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps,
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) {
debug_f("expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
SSH2_FXP_EXTENDED_REPLY, type);
/* Disable the limits extension */
conn->exts &= ~SFTP_EXT_LIMITS;
sshbuf_free(msg);
return 0;
}
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("close remote: %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("remote delete %s: %s", path, 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;
debug2("Sending SSH2_FXP_MKDIR \"%s\"", path);
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("remote mkdir \"%s\": %s", path, fx2txt(status));
return status == SSH2_FX_OK ? 0 : -1;
}
int
do_rmdir(struct sftp_conn *conn, const char *path)
{
u_int status, id;
debug2("Sending SSH2_FXP_RMDIR \"%s\"", path);
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("remote rmdir \"%s\": %s", path, fx2txt(status));
return status == SSH2_FX_OK ? 0 : -1;
}
Attrib *
do_stat(struct sftp_conn *conn, const char *path, int quiet)
{
u_int id;
debug2("Sending SSH2_FXP_STAT \"%s\"", path);
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;
debug2("Sending SSH2_FXP_FSTAT \"%s\"");
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;
debug2("Sending SSH2_FXP_SETSTAT \"%s\"", path);
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("remote setstat \"%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;
debug2("Sending SSH2_FXP_FSETSTAT");
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("remote fsetstat: %s", fx2txt(status));
return status == SSH2_FX_OK ? 0 : -1;
}
/* Implements both the realpath and expand-path operations */
static char *
do_realpath_expand(struct sftp_conn *conn, const char *path, int expand)
{
struct sshbuf *msg;
u_int expected_id, count, id;
char *filename, *longname;
Attrib a;
u_char type;
int r;
const char *what = "SSH2_FXP_REALPATH";
if (expand)
what = "expand-path@openssh.com";
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
expected_id = id = conn->msg_id++;
if (expand) {
debug2("Sending SSH2_FXP_EXTENDED(expand-path@openssh.com) "
"\"%s\"", path);
if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
(r = sshbuf_put_u32(msg, id)) != 0 ||
(r = sshbuf_put_cstring(msg,
"expand-path@openssh.com")) != 0 ||
(r = sshbuf_put_cstring(msg, path)) != 0)
fatal_fr(r, "compose %s", what);
send_msg(conn, msg);
} else {
debug2("Sending SSH2_FXP_REALPATH \"%s\"", path);
send_string_request(conn, id, SSH2_FXP_REALPATH,
path, strlen(path));
}
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;
char *errmsg;
if ((r = sshbuf_get_u32(msg, &status)) != 0 ||
(r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0)
fatal_fr(r, "parse status");
error("%s %s: %s", expand ? "expand" : "realpath",
path, *errmsg == '\0' ? fx2txt(status) : errmsg);
free(errmsg);
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 %s", count, what);
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("%s %s -> %s", what, path, filename);
free(longname);
sshbuf_free(msg);
return(filename);
}
char *
do_realpath(struct sftp_conn *conn, const char *path)
{
return do_realpath_expand(conn, path, 0);
}
int
can_expand_path(struct sftp_conn *conn)
{
return (conn->exts & SFTP_EXT_PATH_EXPAND) != 0;
}
char *
do_expand_path(struct sftp_conn *conn, const char *path)
{
if (!can_expand_path(conn)) {
debug3_f("no server support, fallback to realpath");
return do_realpath_expand(conn, path, 0);
}
return do_realpath_expand(conn, path, 1);
}
int
do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath)
{
Attrib junk, *a;
struct sshbuf *msg;
u_char *old_handle, *new_handle;
u_int mode, status, id;
size_t old_handle_len, new_handle_len;
int r;
/* Return if the extension is not supported */
if ((conn->exts & SFTP_EXT_COPY_DATA) == 0) {
error("Server does not support copy-data extension");
return -1;
}
/* Make sure the file exists, and we can copy its perms */
if ((a = do_stat(conn, oldpath, 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;
if (!S_ISREG(a->perm)) {
error("Cannot copy non-regular file: %s", oldpath);
return -1;
}
} else {
/* NB: The user's umask will apply to this */
mode = 0666;
}
/* Set up the new perms for the new file */
attrib_clear(a);
a->perm = mode;
a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
if ((msg = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
attrib_clear(&junk); /* Send empty attributes */
/* Open the old file for reading */
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, oldpath)) != 0 ||
(r = sshbuf_put_u32(msg, SSH2_FXF_READ)) != 0 ||
(r = encode_attrib(msg, &junk)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
send_msg(conn, msg);
debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, oldpath);
sshbuf_reset(msg);
old_handle = get_handle(conn, id, &old_handle_len,
"remote open(\"%s\")", oldpath);
if (old_handle == NULL) {
sshbuf_free(msg);
return -1;
}
/* Open the new file for writing */
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, newpath)) != 0 ||
(r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|
SSH2_FXF_TRUNC)) != 0 ||
(r = encode_attrib(msg, a)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
send_msg(conn, msg);
debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, newpath);
sshbuf_reset(msg);
new_handle = get_handle(conn, id, &new_handle_len,
"remote open(\"%s\")", newpath);
if (new_handle == NULL) {
sshbuf_free(msg);
free(old_handle);
return -1;
}
/* Copy the file data */
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, "copy-data")) != 0 ||
(r = sshbuf_put_string(msg, old_handle, old_handle_len)) != 0 ||
(r = sshbuf_put_u64(msg, 0)) != 0 ||
(r = sshbuf_put_u64(msg, 0)) != 0 ||
(r = sshbuf_put_string(msg, new_handle, new_handle_len)) != 0 ||
(r = sshbuf_put_u64(msg, 0)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
send_msg(conn, msg);
debug3("Sent message copy-data \"%s\" 0 0 -> \"%s\" 0",
oldpath, newpath);
status = get_status(conn, id);
if (status != SSH2_FX_OK)
error("Couldn't copy file \"%s\" to \"%s\": %s", oldpath,
newpath, fx2txt(status));
/* Clean up everything */
sshbuf_free(msg);
do_close(conn, old_handle, old_handle_len);
do_close(conn, new_handle, new_handle_len);
free(old_handle);
free(new_handle);
return status == SSH2_FX_OK ? 0 : -1;
}
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) {
debug2("Sending SSH2_FXP_EXTENDED(posix-rename@openssh.com) "
"\"%s\" to \"%s\"", oldpath, newpath);
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 {
debug2("Sending SSH2_FXP_RENAME \"%s\" to \"%s\"",
oldpath, newpath);
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("remote rename \"%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;
}
debug2("Sending SSH2_FXP_EXTENDED(hardlink@openssh.com) "
"\"%s\" to \"%s\"", oldpath, newpath);
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);
sshbuf_free(msg);
status = get_status(conn, id);
if (status != SSH2_FX_OK)
error("remote link \"%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);
}
debug2("Sending SSH2_FXP_SYMLINK \"%s\" to \"%s\"", oldpath, newpath);
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("remote 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;
debug2("Sending SSH2_FXP_EXTENDED(fsync@openssh.com)");
/* 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("remote fsync: %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;
debug2("Sending SSH2_FXP_READLINK \"%s\"", path);
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;
}
debug2("Sending SSH2_FXP_EXTENDED(statvfs@openssh.com) \"%s\"", path);
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;
}
debug2("Sending SSH2_FXP_EXTENDED(fstatvfs@openssh.com)");
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;
}
debug2("Sending SSH2_FXP_EXTENDED(lsetstat@openssh.com) \"%s\"", path);
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("remote lsetstat \"%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);
}
static int
send_open(struct sftp_conn *conn, const char *path, const char *tag,
u_int openmode, Attrib *a, u_char **handlep, size_t *handle_lenp)
{
Attrib junk;
u_char *handle;
size_t handle_len;
struct sshbuf *msg;
int r;
u_int id;
debug2("Sending SSH2_FXP_OPEN \"%s\"", path);
*handlep = NULL;
*handle_lenp = 0;
if (a == NULL) {
attrib_clear(&junk); /* Send empty attributes */
a = &junk;
}
/* Send open request */
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
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, path)) != 0 ||
(r = sshbuf_put_u32(msg, openmode)) != 0 ||
(r = encode_attrib(msg, a)) != 0)
fatal_fr(r, "compose %s open", tag);
send_msg(conn, msg);
sshbuf_free(msg);
debug3("Sent %s message SSH2_FXP_OPEN I:%u P:%s M:0x%04x",
tag, id, path, openmode);
if ((handle = get_handle(conn, id, &handle_len,
"%s open \"%s\"", tag, path)) == NULL)
return -1;
/* success */
*handlep = handle;
*handle_lenp = handle_len;
return 0;
}
static const char *
progress_meter_path(const char *path)
{
const char *progresspath;
if ((progresspath = strrchr(path, '/')) == NULL)
return path;
progresspath++;
if (*progresspath == '\0')
return path;
return progresspath;
}
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)
+ int fsync_flag, int inplace_flag)
{
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 requests requests;
struct request *req;
u_char type;
debug2_f("download remote \"%s\" to local \"%s\"",
remote_path, local_path);
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("download %s: not a regular file", remote_path);
return(-1);
}
if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
size = a->size;
else
size = 0;
buflen = conn->download_buflen;
/* Send open request */
if (send_open(conn, remote_path, "remote", SSH2_FXF_READ, NULL,
&handle, &handle_len) != 0)
return -1;
- local_fd = open(local_path,
- O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR);
+ local_fd = open(local_path, O_WRONLY | O_CREAT |
+ ((resume_flag || inplace_flag) ? 0 : O_TRUNC), mode | S_IWUSR);
if (local_fd == -1) {
error("open local \"%s\": %s", local_path, strerror(errno));
goto fail;
}
offset = highwater = 0;
if (resume_flag) {
if (fstat(local_fd, &st) == -1) {
error("stat local \"%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);
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(progress_meter_path(remote_path),
size, &progress_counter);
}
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
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 = request_enqueue(&requests, conn->msg_id++,
buflen, offset);
offset += buflen;
num_req++;
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 */
if ((req = request_find(&requests, id)) == 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) {
+ /*
+ * Truncate at highest contiguous point to avoid holes on interrupt,
+ * or unconditionally if writing in place.
+ */
+ if (inplace_flag || 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("local ftruncate \"%s\": %s", local_path,
strerror(errno));
}
if (read_error) {
error("read remote \"%s\" : %s", remote_path, fx2txt(status));
status = -1;
do_close(conn, handle, handle_len);
} else if (write_error) {
error("write local \"%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("local chmod \"%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("local set times \"%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("local sync \"%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 follow_link_flag)
+ int resume_flag, int fsync_flag, int follow_link_flag, int inplace_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;
}
debug2_f("download dir remote \"%s\" to local \"%s\"", src, dst);
if (dirattrib == NULL &&
(dirattrib = do_stat(conn, src, 1)) == NULL) {
error("stat remote \"%s\" directory failed", src);
return -1;
}
if (!S_ISDIR(dirattrib->perm)) {
error("\"%s\" is not a directory", src);
return -1;
}
if (print_flag && print_flag != SFTP_PROGRESS_ONLY)
mprintf("Retrieving %s\n", src);
if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
mode = dirattrib->perm & 01777;
tmpmode = mode | (S_IWUSR|S_IXUSR);
} else {
debug("download remote \"%s\": server "
"did not send permissions", 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("remote readdir \"%s\" failed", 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, follow_link_flag) == -1)
+ fsync_flag, follow_link_flag, inplace_flag) == -1)
ret = -1;
} else if (S_ISREG(dir_entries[i]->a.perm) ||
(follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) {
/*
* If this is a symlink then don't send the link's
* Attrib. do_download() will do a FXP_STAT operation
* and get the link target's attributes.
*/
if (do_download(conn, new_src, new_dst,
S_ISLNK(dir_entries[i]->a.perm) ? NULL :
&(dir_entries[i]->a),
- preserve_flag, resume_flag, fsync_flag) == -1) {
+ preserve_flag, resume_flag, fsync_flag,
+ inplace_flag) == -1) {
error("Download of file %s to %s failed",
new_src, new_dst);
ret = -1;
}
} else
logit("download \"%s\": not a regular file", 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("local 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("local chmod directory \"%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, int follow_link_flag)
+ int fsync_flag, int follow_link_flag, int inplace_flag)
{
char *src_canon;
int ret;
if ((src_canon = do_realpath(conn, src)) == NULL) {
error("download \"%s\": path canonicalization failed", src);
return -1;
}
ret = download_dir_internal(conn, src_canon, dst, 0,
dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag,
- follow_link_flag);
+ follow_link_flag, inplace_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)
+ const char *remote_path, int preserve_flag, int resume,
+ int fsync_flag, int inplace_flag)
{
int r, local_fd;
- u_int status = SSH2_FX_OK;
- u_int id;
- u_char type;
+ u_int openmode, id, status = SSH2_FX_OK, reordered = 0;
off_t offset, progress_counter;
- u_char *handle, *data;
+ u_char type, *handle, *data;
struct sshbuf *msg;
struct stat sb;
- Attrib a, *c = NULL;
- u_int32_t startid;
- u_int32_t ackid;
+ Attrib a, t, *c = NULL;
+ u_int32_t startid, ackid;
+ u_int64_t highwater = 0;
struct request *ack = NULL;
struct requests acks;
size_t handle_len;
debug2_f("upload local \"%s\" to remote \"%s\"",
local_path, remote_path);
TAILQ_INIT(&acks);
if ((local_fd = open(local_path, O_RDONLY)) == -1) {
error("open local \"%s\": %s", local_path, strerror(errno));
return(-1);
}
if (fstat(local_fd, &sb) == -1) {
error("fstat local \"%s\": %s", local_path, strerror(errno));
close(local_fd);
return(-1);
}
if (!S_ISREG(sb.st_mode)) {
error("local \"%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("resume \"%s\": destination file "
"same size or larger", local_path);
close(local_fd);
return -1;
}
if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) {
close(local_fd);
return -1;
}
}
+ openmode = SSH2_FXF_WRITE|SSH2_FXF_CREAT;
+ if (resume)
+ openmode |= SSH2_FXF_APPEND;
+ else if (!inplace_flag)
+ openmode |= SSH2_FXF_TRUNC;
+
/* Send open request */
- if (send_open(conn, remote_path, "dest", SSH2_FXF_WRITE|SSH2_FXF_CREAT|
- (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC),
- &a, &handle, &handle_len) != 0) {
+ if (send_open(conn, remote_path, "dest", openmode, &a,
+ &handle, &handle_len) != 0) {
close(local_fd);
return -1;
}
id = conn->msg_id;
startid = ackid = id + 1;
data = xmalloc(conn->upload_buflen);
/* Read from local and write to remote */
offset = progress_counter = (resume ? c->size : 0);
if (showprogress) {
start_progress_meter(progress_meter_path(local_path),
sb.st_size, &progress_counter);
}
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
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->upload_buflen);
while ((len == -1) &&
(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
if (len == -1) {
fatal("read local \"%s\": %s",
local_path, strerror(errno));
} else if (len != 0) {
ack = request_enqueue(&acks, ++id, len, offset);
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 */
if ((ack = request_find(&acks, rid)) == NULL)
fatal("Can't find request for ID %u", rid);
TAILQ_REMOVE(&acks, ack, tq);
debug3("In write loop, ack for %u %zu bytes at %lld",
ack->id, ack->len, (unsigned long long)ack->offset);
++ackid;
progress_counter += ack->len;
+ if (!reordered && ack->offset <= highwater)
+ highwater = ack->offset + ack->len;
+ else if (!reordered && ack->offset > highwater) {
+ debug3_f("server reordered ACKs");
+ reordered = 1;
+ }
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("write remote \"%s\": %s", remote_path, fx2txt(status));
status = SSH2_FX_FAILURE;
}
+ if (inplace_flag || (resume && (status != SSH2_FX_OK || interrupted))) {
+ debug("truncating at %llu", (unsigned long long)highwater);
+ attrib_clear(&t);
+ t.flags = SSH2_FILEXFER_ATTR_SIZE;
+ t.size = highwater;
+ do_fsetstat(conn, handle, handle_len, &t);
+ }
+
if (close(local_fd) == -1) {
error("close local \"%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 follow_link_flag)
+ int follow_link_flag, int inplace_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;
debug2_f("upload local dir \"%s\" to remote \"%s\"", src, dst);
if (depth >= MAX_DIR_DEPTH) {
error("Maximum directory depth exceeded: %d levels", depth);
return -1;
}
if (stat(src, &sb) == -1) {
error("stat local \"%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 && print_flag != SFTP_PROGRESS_ONLY)
mprintf("Entering %s\n", src);
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("local opendir \"%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("local lstat \"%s\": %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, follow_link_flag) == -1)
+ fsync_flag, follow_link_flag, inplace_flag) == -1)
ret = -1;
} else if (S_ISREG(sb.st_mode) ||
(follow_link_flag && S_ISLNK(sb.st_mode))) {
if (do_upload(conn, new_src, new_dst,
- preserve_flag, resume, fsync_flag) == -1) {
+ preserve_flag, resume, fsync_flag,
+ inplace_flag) == -1) {
error("upload \"%s\" to \"%s\" failed",
new_src, new_dst);
ret = -1;
}
} else
logit("%s: not a regular file", 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,
- int follow_link_flag)
+ int follow_link_flag, int inplace_flag)
{
char *dst_canon;
int ret;
if ((dst_canon = do_realpath(conn, dst)) == NULL) {
error("upload \"%s\": path canonicalization failed", dst);
return -1;
}
ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
- print_flag, resume, fsync_flag, follow_link_flag);
+ print_flag, resume, fsync_flag, follow_link_flag, inplace_flag);
free(dst_canon);
return ret;
}
static void
handle_dest_replies(struct sftp_conn *to, const char *to_path, int synchronous,
u_int *nreqsp, u_int *write_errorp)
{
struct sshbuf *msg;
u_char type;
u_int id, status;
int r;
struct pollfd pfd;
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
/* Try to eat replies from the upload side */
while (*nreqsp > 0) {
debug3_f("%u outstanding replies", *nreqsp);
if (!synchronous) {
/* Bail out if no data is ready to be read */
pfd.fd = to->fd_in;
pfd.events = POLLIN;
if ((r = poll(&pfd, 1, 0)) == -1) {
if (errno == EINTR)
break;
fatal_f("poll: %s", strerror(errno));
} else if (r == 0)
break; /* fd not ready */
}
sshbuf_reset(msg);
get_msg(to, msg);
if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
(r = sshbuf_get_u32(msg, &id)) != 0)
fatal_fr(r, "dest parse");
debug3("Received dest reply T:%u I:%u R:%u", type, id, *nreqsp);
if (type != SSH2_FXP_STATUS) {
fatal_f("Expected SSH2_FXP_STATUS(%d) packet, got %d",
SSH2_FXP_STATUS, type);
}
if ((r = sshbuf_get_u32(msg, &status)) != 0)
fatal_fr(r, "parse dest status");
debug3("dest SSH2_FXP_STATUS %u", status);
if (status != SSH2_FX_OK) {
/* record first error */
if (*write_errorp == 0)
*write_errorp = status;
}
/*
* XXX this doesn't do full reply matching like do_upload and
* so cannot gracefully truncate terminated uploads at a
* high-water mark. ATM the only caller of this function (scp)
* doesn't support transfer resumption, so this doesn't matter
* a whole lot.
*
* To be safe, do_crossload truncates the destination file to
* zero length on upload failure, since we can't trust the
* server not to have reordered replies that could have
* inserted holes where none existed in the source file.
*
* XXX we could get a more accutate progress bar if we updated
* the counter based on the reply from the destination...
*/
(*nreqsp)--;
}
debug3_f("done: %u outstanding replies", *nreqsp);
sshbuf_free(msg);
}
int
do_crossload(struct sftp_conn *from, struct sftp_conn *to,
const char *from_path, const char *to_path,
Attrib *a, int preserve_flag)
{
struct sshbuf *msg;
int write_error, read_error, r;
u_int64_t offset = 0, size;
u_int id, buflen, num_req, max_req, status = SSH2_FX_OK;
u_int num_upload_req;
off_t progress_counter;
u_char *from_handle, *to_handle;
size_t from_handle_len, to_handle_len;
struct requests requests;
struct request *req;
u_char type;
debug2_f("crossload src \"%s\" to dst \"%s\"", from_path, to_path);
TAILQ_INIT(&requests);
if (a == NULL && (a = do_stat(from, from_path, 0)) == NULL)
return -1;
if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
(!S_ISREG(a->perm))) {
error("download \"%s\": not a regular file", from_path);
return(-1);
}
if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
size = a->size;
else
size = 0;
buflen = from->download_buflen;
if (buflen > to->upload_buflen)
buflen = to->upload_buflen;
/* Send open request to read side */
if (send_open(from, from_path, "origin", SSH2_FXF_READ, NULL,
&from_handle, &from_handle_len) != 0)
return -1;
/* Send open request to write side */
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 (send_open(to, to_path, "dest",
SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a,
&to_handle, &to_handle_len) != 0) {
do_close(from, from_handle, from_handle_len);
return -1;
}
/* Read from remote "from" and write to remote "to" */
offset = 0;
write_error = read_error = num_req = num_upload_req = 0;
max_req = 1;
progress_counter = 0;
if (showprogress && size != 0) {
start_progress_meter(progress_meter_path(from_path),
size, &progress_counter);
}
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
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 = request_enqueue(&requests, from->msg_id++,
buflen, offset);
offset += buflen;
num_req++;
send_read_request(from, req->id, req->offset,
req->len, from_handle, from_handle_len);
}
/* Try to eat replies from the upload side (nonblocking) */
handle_dest_replies(to, to_path, 0,
&num_upload_req, &write_error);
sshbuf_reset(msg);
get_msg(from, msg);
if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
(r = sshbuf_get_u32(msg, &id)) != 0)
fatal_fr(r, "parse");
debug3("Received origin reply T:%u I:%u R:%d",
type, id, max_req);
/* Find the request in our queue */
if ((req = request_find(&requests, id)) == 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);
/* Write this chunk out to the destination */
sshbuf_reset(msg);
if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 ||
(r = sshbuf_put_u32(msg, to->msg_id++)) != 0 ||
(r = sshbuf_put_string(msg, to_handle,
to_handle_len)) != 0 ||
(r = sshbuf_put_u64(msg, req->offset)) != 0 ||
(r = sshbuf_put_string(msg, data, len)) != 0)
fatal_fr(r, "compose write");
send_msg(to, msg);
debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%zu",
id, (unsigned long long)offset, len);
num_upload_req++;
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 = from->msg_id++;
req->len -= len;
req->offset += len;
send_read_request(from, req->id,
req->offset, req->len,
from_handle, from_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 < from->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();
/* Drain replies from the server (blocking) */
debug3_f("waiting for %u replies from destination", num_upload_req);
handle_dest_replies(to, to_path, 1, &num_upload_req, &write_error);
/* Sanity check */
if (TAILQ_FIRST(&requests) != NULL)
fatal("Transfer complete, but requests still in queue");
/* Truncate at 0 length on interrupt or error to avoid holes at dest */
if (read_error || write_error || interrupted) {
debug("truncating \"%s\" at 0", to_path);
do_close(to, to_handle, to_handle_len);
free(to_handle);
if (send_open(to, to_path, "dest",
SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a,
&to_handle, &to_handle_len) != 0) {
error("dest truncate \"%s\" failed", to_path);
to_handle = NULL;
}
}
if (read_error) {
error("read origin \"%s\": %s", from_path, fx2txt(status));
status = -1;
do_close(from, from_handle, from_handle_len);
if (to_handle != NULL)
do_close(to, to_handle, to_handle_len);
} else if (write_error) {
error("write dest \"%s\": %s", to_path, fx2txt(write_error));
status = SSH2_FX_FAILURE;
do_close(from, from_handle, from_handle_len);
if (to_handle != NULL)
do_close(to, to_handle, to_handle_len);
} else {
if (do_close(from, from_handle, from_handle_len) != 0 ||
interrupted)
status = -1;
else
status = SSH2_FX_OK;
if (to_handle != NULL) {
/* Need to resend utimes after write */
if (preserve_flag)
do_fsetstat(to, to_handle, to_handle_len, a);
do_close(to, to_handle, to_handle_len);
}
}
sshbuf_free(msg);
free(from_handle);
free(to_handle);
return status == SSH2_FX_OK ? 0 : -1;
}
static int
crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to,
const char *from_path, const char *to_path,
int depth, Attrib *dirattrib, int preserve_flag, int print_flag,
int follow_link_flag)
{
int i, ret = 0;
SFTP_DIRENT **dir_entries;
char *filename, *new_from_path = NULL, *new_to_path = NULL;
mode_t mode = 0777;
Attrib curdir;
debug2_f("crossload dir src \"%s\" to dst \"%s\"", from_path, to_path);
if (depth >= MAX_DIR_DEPTH) {
error("Maximum directory depth exceeded: %d levels", depth);
return -1;
}
if (dirattrib == NULL &&
(dirattrib = do_stat(from, from_path, 1)) == NULL) {
error("stat remote \"%s\" failed", from_path);
return -1;
}
if (!S_ISDIR(dirattrib->perm)) {
error("\"%s\" is not a directory", from_path);
return -1;
}
if (print_flag && print_flag != SFTP_PROGRESS_ONLY)
mprintf("Retrieving %s\n", from_path);
curdir = *dirattrib; /* dirattrib will be clobbered */
curdir.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
curdir.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
if ((curdir.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) == 0) {
debug("Origin did not send permissions for "
"directory \"%s\"", to_path);
curdir.perm = S_IWUSR|S_IXUSR;
curdir.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
}
/* We need to be able to write to the directory while we transfer it */
mode = curdir.perm & 01777;
curdir.perm = mode | (S_IWUSR|S_IXUSR);
/*
* 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.
*/
if (do_mkdir(to, to_path, &curdir, 0) != 0) {
if ((dirattrib = do_stat(to, to_path, 0)) == NULL)
return -1;
if (!S_ISDIR(dirattrib->perm)) {
error("\"%s\" exists but is not a directory", to_path);
return -1;
}
}
curdir.perm = mode;
if (do_readdir(from, from_path, &dir_entries) == -1) {
error("origin readdir \"%s\" failed", from_path);
return -1;
}
for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
free(new_from_path);
free(new_to_path);
filename = dir_entries[i]->filename;
new_from_path = path_append(from_path, filename);
new_to_path = path_append(to_path, filename);
if (S_ISDIR(dir_entries[i]->a.perm)) {
if (strcmp(filename, ".") == 0 ||
strcmp(filename, "..") == 0)
continue;
if (crossload_dir_internal(from, to,
new_from_path, new_to_path,
depth + 1, &(dir_entries[i]->a), preserve_flag,
print_flag, follow_link_flag) == -1)
ret = -1;
} else if (S_ISREG(dir_entries[i]->a.perm) ||
(follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) {
/*
* If this is a symlink then don't send the link's
* Attrib. do_download() will do a FXP_STAT operation
* and get the link target's attributes.
*/
if (do_crossload(from, to, new_from_path, new_to_path,
S_ISLNK(dir_entries[i]->a.perm) ? NULL :
&(dir_entries[i]->a), preserve_flag) == -1) {
error("crossload \"%s\" to \"%s\" failed",
new_from_path, new_to_path);
ret = -1;
}
} else {
logit("origin \"%s\": not a regular file",
new_from_path);
}
}
free(new_to_path);
free(new_from_path);
do_setstat(to, to_path, &curdir);
free_sftp_dirents(dir_entries);
return ret;
}
int
crossload_dir(struct sftp_conn *from, struct sftp_conn *to,
const char *from_path, const char *to_path,
Attrib *dirattrib, int preserve_flag, int print_flag, int follow_link_flag)
{
char *from_path_canon;
int ret;
if ((from_path_canon = do_realpath(from, from_path)) == NULL) {
error("crossload \"%s\": path canonicalization failed",
from_path);
return -1;
}
ret = crossload_dir_internal(from, to, from_path_canon, to_path, 0,
dirattrib, preserve_flag, print_flag, follow_link_flag);
free(from_path_canon);
return ret;
}
+int
+can_get_users_groups_by_id(struct sftp_conn *conn)
+{
+ return (conn->exts & SFTP_EXT_GETUSERSGROUPS_BY_ID) != 0;
+}
+
+int
+do_get_users_groups_by_id(struct sftp_conn *conn,
+ const u_int *uids, u_int nuids,
+ const u_int *gids, u_int ngids,
+ char ***usernamesp, char ***groupnamesp)
+{
+ struct sshbuf *msg, *uidbuf, *gidbuf;
+ u_int i, expected_id, id;
+ char *name, **usernames = NULL, **groupnames = NULL;
+ u_char type;
+ int r;
+
+ *usernamesp = *groupnamesp = NULL;
+ if (!can_get_users_groups_by_id(conn))
+ return SSH_ERR_FEATURE_UNSUPPORTED;
+
+ if ((msg = sshbuf_new()) == NULL ||
+ (uidbuf = sshbuf_new()) == NULL ||
+ (gidbuf = sshbuf_new()) == NULL)
+ fatal_f("sshbuf_new failed");
+ expected_id = id = conn->msg_id++;
+ debug2("Sending SSH2_FXP_EXTENDED(users-groups-by-id@openssh.com)");
+ for (i = 0; i < nuids; i++) {
+ if ((r = sshbuf_put_u32(uidbuf, uids[i])) != 0)
+ fatal_fr(r, "compose uids");
+ }
+ for (i = 0; i < ngids; i++) {
+ if ((r = sshbuf_put_u32(gidbuf, gids[i])) != 0)
+ fatal_fr(r, "compose gids");
+ }
+ if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
+ (r = sshbuf_put_u32(msg, id)) != 0 ||
+ (r = sshbuf_put_cstring(msg,
+ "users-groups-by-id@openssh.com")) != 0 ||
+ (r = sshbuf_put_stringb(msg, uidbuf)) != 0 ||
+ (r = sshbuf_put_stringb(msg, gidbuf)) != 0)
+ fatal_fr(r, "compose");
+ send_msg(conn, msg);
+ 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;
+ char *errmsg;
+
+ if ((r = sshbuf_get_u32(msg, &status)) != 0 ||
+ (r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0)
+ fatal_fr(r, "parse status");
+ error("users-groups-by-id %s",
+ *errmsg == '\0' ? fx2txt(status) : errmsg);
+ free(errmsg);
+ sshbuf_free(msg);
+ sshbuf_free(uidbuf);
+ sshbuf_free(gidbuf);
+ return -1;
+ } else if (type != SSH2_FXP_EXTENDED_REPLY)
+ fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
+ SSH2_FXP_EXTENDED_REPLY, type);
+
+ /* reuse */
+ sshbuf_free(uidbuf);
+ sshbuf_free(gidbuf);
+ uidbuf = gidbuf = NULL;
+ if ((r = sshbuf_froms(msg, &uidbuf)) != 0 ||
+ (r = sshbuf_froms(msg, &gidbuf)) != 0)
+ fatal_fr(r, "parse response");
+ if (nuids > 0) {
+ usernames = xcalloc(nuids, sizeof(*usernames));
+ for (i = 0; i < nuids; i++) {
+ if ((r = sshbuf_get_cstring(uidbuf, &name, NULL)) != 0)
+ fatal_fr(r, "parse user name");
+ /* Handle unresolved names */
+ if (*name == '\0') {
+ free(name);
+ name = NULL;
+ }
+ usernames[i] = name;
+ }
+ }
+ if (ngids > 0) {
+ groupnames = xcalloc(ngids, sizeof(*groupnames));
+ for (i = 0; i < ngids; i++) {
+ if ((r = sshbuf_get_cstring(gidbuf, &name, NULL)) != 0)
+ fatal_fr(r, "parse user name");
+ /* Handle unresolved names */
+ if (*name == '\0') {
+ free(name);
+ name = NULL;
+ }
+ groupnames[i] = name;
+ }
+ }
+ if (sshbuf_len(uidbuf) != 0)
+ fatal_f("unexpected extra username data");
+ if (sshbuf_len(gidbuf) != 0)
+ fatal_f("unexpected extra groupname data");
+ sshbuf_free(uidbuf);
+ sshbuf_free(gidbuf);
+ sshbuf_free(msg);
+ /* success */
+ *usernamesp = usernames;
+ *groupnamesp = groupnames;
+ return 0;
+}
+
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 282a4c70037d..d7deab17e4cb 100644
--- a/sftp-client.h
+++ b/sftp-client.h
@@ -1,201 +1,211 @@
-/* $OpenBSD: sftp-client.h,v 1.36 2022/03/31 03:07:03 djm Exp $ */
+/* $OpenBSD: sftp-client.h,v 1.38 2022/09/19 10:43:12 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;
};
/* print flag values */
#define SFTP_QUIET 0 /* be quiet during transfers */
#define SFTP_PRINT 1 /* list files and show progress bar */
#define SFTP_PROGRESS_ONLY 2 /* progress bar only */
/*
* 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 *);
/* Canonicalisation with tilde expansion (requires server extension) */
char *do_expand_path(struct sftp_conn *, const char *);
/* Returns non-zero if server can tilde-expand paths */
int can_expand_path(struct sftp_conn *);
/* 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);
/* Copy 'oldpath' to 'newpath' */
int do_copy(struct sftp_conn *, const char *, const char *);
/* 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);
+int do_download(struct sftp_conn *, const char *, const char *, Attrib *,
+ int, 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, int);
+int download_dir(struct sftp_conn *, const char *, const char *, Attrib *,
+ int, int, 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);
+int do_upload(struct sftp_conn *, const char *, const char *,
+ int, 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, int);
+int upload_dir(struct sftp_conn *, const char *, const char *,
+ int, int, int, int, int, int);
/*
* Download a 'from_path' from the 'from' connection and upload it to
* to 'to' connection at 'to_path'.
*/
int
do_crossload(struct sftp_conn *from, struct sftp_conn *to,
const char *from_path, const char *to_path,
Attrib *a, int preserve_flag);
/*
* Recursively download a directory from 'from_path' from the 'from'
* connection and upload it to 'to' connection at 'to_path'.
*/
int crossload_dir(struct sftp_conn *from, struct sftp_conn *to,
const char *from_path, const char *to_path,
Attrib *dirattrib, int preserve_flag, int print_flag,
int follow_link_flag);
+/*
+ * User/group ID to name translation.
+ */
+int can_get_users_groups_by_id(struct sftp_conn *conn);
+int do_get_users_groups_by_id(struct sftp_conn *conn,
+ const u_int *uids, u_int nuids,
+ const u_int *gids, u_int ngids,
+ char ***usernamesp, char ***groupnamesp);
+
/* 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 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-common.c b/sftp-common.c
index 3ad57673d41e..50f1bbafb4bc 100644
--- a/sftp-common.c
+++ b/sftp-common.c
@@ -1,259 +1,263 @@
-/* $OpenBSD: sftp-common.c,v 1.32 2020/10/18 11:32:02 djm Exp $ */
+/* $OpenBSD: sftp-common.c,v 1.33 2022/09/19 10:41:58 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 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/stat.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>
#include <unistd.h>
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
#include "xmalloc.h"
#include "ssherr.h"
#include "sshbuf.h"
#include "log.h"
#include "misc.h"
#include "sftp.h"
#include "sftp-common.h"
/* Clear contents of attributes structure */
void
attrib_clear(Attrib *a)
{
a->flags = 0;
a->size = 0;
a->uid = 0;
a->gid = 0;
a->perm = 0;
a->atime = 0;
a->mtime = 0;
}
/* Convert from struct stat to filexfer attribs */
void
stat_to_attrib(const struct stat *st, Attrib *a)
{
attrib_clear(a);
a->flags = 0;
a->flags |= SSH2_FILEXFER_ATTR_SIZE;
a->size = st->st_size;
a->flags |= SSH2_FILEXFER_ATTR_UIDGID;
a->uid = st->st_uid;
a->gid = st->st_gid;
a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
a->perm = st->st_mode;
a->flags |= SSH2_FILEXFER_ATTR_ACMODTIME;
a->atime = st->st_atime;
a->mtime = st->st_mtime;
}
/* Convert from filexfer attribs to struct stat */
void
attrib_to_stat(const Attrib *a, struct stat *st)
{
memset(st, 0, sizeof(*st));
if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
st->st_size = a->size;
if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
st->st_uid = a->uid;
st->st_gid = a->gid;
}
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
st->st_mode = a->perm;
if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
st->st_atime = a->atime;
st->st_mtime = a->mtime;
}
}
/* Decode attributes in buffer */
int
decode_attrib(struct sshbuf *b, Attrib *a)
{
int r;
attrib_clear(a);
if ((r = sshbuf_get_u32(b, &a->flags)) != 0)
return r;
if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
if ((r = sshbuf_get_u64(b, &a->size)) != 0)
return r;
}
if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
if ((r = sshbuf_get_u32(b, &a->uid)) != 0 ||
(r = sshbuf_get_u32(b, &a->gid)) != 0)
return r;
}
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
if ((r = sshbuf_get_u32(b, &a->perm)) != 0)
return r;
}
if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
if ((r = sshbuf_get_u32(b, &a->atime)) != 0 ||
(r = sshbuf_get_u32(b, &a->mtime)) != 0)
return r;
}
/* vendor-specific extensions */
if (a->flags & SSH2_FILEXFER_ATTR_EXTENDED) {
char *type;
u_char *data;
size_t dlen;
u_int i, count;
if ((r = sshbuf_get_u32(b, &count)) != 0)
return r;
for (i = 0; i < count; i++) {
if ((r = sshbuf_get_cstring(b, &type, NULL)) != 0 ||
(r = sshbuf_get_string(b, &data, &dlen)) != 0)
return r;
debug3("Got file attribute \"%.100s\" len %zu",
type, dlen);
free(type);
free(data);
}
}
return 0;
}
/* Encode attributes to buffer */
int
encode_attrib(struct sshbuf *b, const Attrib *a)
{
int r;
if ((r = sshbuf_put_u32(b, a->flags)) != 0)
return r;
if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
if ((r = sshbuf_put_u64(b, a->size)) != 0)
return r;
}
if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
if ((r = sshbuf_put_u32(b, a->uid)) != 0 ||
(r = sshbuf_put_u32(b, a->gid)) != 0)
return r;
}
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
if ((r = sshbuf_put_u32(b, a->perm)) != 0)
return r;
}
if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
if ((r = sshbuf_put_u32(b, a->atime)) != 0 ||
(r = sshbuf_put_u32(b, a->mtime)) != 0)
return r;
}
return 0;
}
/* Convert from SSH2_FX_ status to text error message */
const char *
fx2txt(int status)
{
switch (status) {
case SSH2_FX_OK:
return("No error");
case SSH2_FX_EOF:
return("End of file");
case SSH2_FX_NO_SUCH_FILE:
return("No such file or directory");
case SSH2_FX_PERMISSION_DENIED:
return("Permission denied");
case SSH2_FX_FAILURE:
return("Failure");
case SSH2_FX_BAD_MESSAGE:
return("Bad message");
case SSH2_FX_NO_CONNECTION:
return("No connection");
case SSH2_FX_CONNECTION_LOST:
return("Connection lost");
case SSH2_FX_OP_UNSUPPORTED:
return("Operation unsupported");
default:
return("Unknown status");
}
/* NOTREACHED */
}
/*
* drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh
*/
char *
-ls_file(const char *name, const struct stat *st, int remote, int si_units)
+ls_file(const char *name, const struct stat *st, int remote, int si_units,
+ const char *user, const char *group)
{
int ulen, glen, sz = 0;
struct tm *ltime = localtime(&st->st_mtime);
- const char *user, *group;
char buf[1024], lc[8], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1];
char sbuf[FMT_SCALED_STRSIZE];
time_t now;
strmode(st->st_mode, mode);
if (remote) {
- snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid);
- user = ubuf;
- snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid);
- group = gbuf;
+ if (user == NULL) {
+ snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid);
+ user = ubuf;
+ }
+ if (group == NULL) {
+ snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid);
+ group = gbuf;
+ }
strlcpy(lc, "?", sizeof(lc));
} else {
user = user_from_uid(st->st_uid, 0);
group = group_from_gid(st->st_gid, 0);
snprintf(lc, sizeof(lc), "%u", (u_int)st->st_nlink);
}
if (ltime != NULL) {
now = time(NULL);
if (now - (365*24*60*60)/2 < st->st_mtime &&
now >= st->st_mtime)
sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime);
else
sz = strftime(tbuf, sizeof tbuf, "%b %e %Y", ltime);
}
if (sz == 0)
tbuf[0] = '\0';
ulen = MAXIMUM(strlen(user), 8);
glen = MAXIMUM(strlen(group), 8);
if (si_units) {
fmt_scaled((long long)st->st_size, sbuf);
snprintf(buf, sizeof buf, "%s %3s %-*s %-*s %8s %s %s",
mode, lc, ulen, user, glen, group,
sbuf, tbuf, name);
} else {
snprintf(buf, sizeof buf, "%s %3s %-*s %-*s %8llu %s %s",
mode, lc, ulen, user, glen, group,
(unsigned long long)st->st_size, tbuf, name);
}
return xstrdup(buf);
}
diff --git a/sftp-common.h b/sftp-common.h
index 2e778a9ca0ba..421a78f78822 100644
--- a/sftp-common.h
+++ b/sftp-common.h
@@ -1,52 +1,53 @@
-/* $OpenBSD: sftp-common.h,v 1.12 2015/01/14 13:54:13 djm Exp $ */
+/* $OpenBSD: sftp-common.h,v 1.13 2022/09/19 10:41:58 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 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.
*/
/* Maximum packet that we are willing to send/accept */
#define SFTP_MAX_MSG_LENGTH (256 * 1024)
struct sshbuf;
typedef struct Attrib Attrib;
/* File attributes */
struct Attrib {
u_int32_t flags;
u_int64_t size;
u_int32_t uid;
u_int32_t gid;
u_int32_t perm;
u_int32_t atime;
u_int32_t mtime;
};
void attrib_clear(Attrib *);
void stat_to_attrib(const struct stat *, Attrib *);
void attrib_to_stat(const Attrib *, struct stat *);
int decode_attrib(struct sshbuf *, Attrib *);
int encode_attrib(struct sshbuf *, const Attrib *);
-char *ls_file(const char *, const struct stat *, int, int);
+char *ls_file(const char *, const struct stat *, int, int,
+ const char *, const char *);
const char *fx2txt(int);
diff --git a/sftp-server-main.c b/sftp-server-main.c
index 06566d36ed84..2c70f89bc70b 100644
--- a/sftp-server-main.c
+++ b/sftp-server-main.c
@@ -1,54 +1,52 @@
/* $OpenBSD: sftp-server-main.c,v 1.6 2019/06/06 05:13:13 otto Exp $ */
/*
* Copyright (c) 2008 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 <pwd.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include "log.h"
#include "sftp.h"
#include "misc.h"
#include "xmalloc.h"
void
cleanup_exit(int i)
{
sftp_server_cleanup_exit(i);
}
int
main(int argc, char **argv)
{
struct passwd *user_pw;
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
sanitise_stdfd();
- seed_rng();
-
if ((user_pw = getpwuid(getuid())) == NULL) {
fprintf(stderr, "No user found for uid %lu\n",
(u_long)getuid());
return 1;
}
return (sftp_server_main(argc, argv, user_pw));
}
diff --git a/sftp-server.0 b/sftp-server.0
index d362040d8ae7..7c5113d3faf3 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
Specifies 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
Specifies 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
Queries 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 7.0 July 27, 2021 OpenBSD 7.0
+OpenBSD 7.1 July 27, 2021 OpenBSD 7.1
diff --git a/sftp-server.c b/sftp-server.c
index 3dd19d4c81db..25f953489759 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -1,2018 +1,2108 @@
-/* $OpenBSD: sftp-server.c,v 1.140 2022/03/31 03:05:49 djm Exp $ */
+/* $OpenBSD: sftp-server.c,v 1.144 2022/09/19 10:41:58 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>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#include <pwd.h>
+#include <grp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <stdarg.h>
#include "atomicio.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 (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_expand(u_int32_t id);
static void process_extended_copy_data(u_int32_t id);
+static void process_extended_home_directory(u_int32_t id);
+static void process_extended_get_users_groups_by_id(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 },
{ "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, 0 },
{ "expand-path", "expand-path@openssh.com", 0,
process_extended_expand, 0 },
{ "copy-data", "copy-data", 0, process_extended_copy_data, 1 },
+ { "home-directory", "home-directory", 0,
+ process_extended_home_directory, 0 },
+ { "users-groups-by-id", "users-groups-by-id@openssh.com", 0,
+ process_extended_get_users_groups_by_id, 0 },
{ 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)
{
static const char * const 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_errmsg(u_int32_t id, u_int32_t status, const char *errmsg)
{
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, errmsg == NULL ?
status_to_message(status) : errmsg)) != 0 ||
(r = sshbuf_put_cstring(msg, "")) != 0)
fatal_fr(r, "compose message");
}
send_msg(msg);
sshbuf_free(msg);
}
static void
send_status(u_int32_t id, u_int32_t status)
{
send_status_errmsg(id, status, NULL);
}
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 advertisement.
*/
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)
fatal_fr(r, "compose");
/* extension advertisements */
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");
compose_extension(msg, "expand-path@openssh.com", "1");
compose_extension(msg, "copy-data", "1");
+ compose_extension(msg, "home-directory", "1");
+ compose_extension(msg, "users-groups-by-id@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)
{
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 %u",
id, handle_to_name(handle), handle, (unsigned long long)off, 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;
}
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) {
status = errno_to_portable(errno);
error_f("seek \"%.100s\": %s", handle_to_name(handle),
strerror(errno));
} else {
/* XXX ATOMICIO ? */
ret = write(fd, data, len);
if (ret == -1) {
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);
+ stats[count].long_name = ls_file(dp->d_name, &st,
+ 0, 0, NULL, NULL);
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);
}
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;
#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
struct rlimit rlim;
#endif
debug("request %u: limits", id);
#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
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_expand(u_int32_t id)
{
char cwd[PATH_MAX], resolvedname[PATH_MAX];
char *path, *npath;
int r;
Stat s;
if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0)
fatal_fr(r, "parse");
if (getcwd(cwd, sizeof(cwd)) == NULL) {
send_status(id, errno_to_portable(errno));
goto out;
}
debug3("request %u: expand, original \"%s\"", id, path);
if (path[0] == '\0') {
/* empty path */
free(path);
path = xstrdup(".");
} else if (*path == '~') {
/* ~ expand path */
/* Special-case for "~" and "~/" to respect homedir flag */
if (strcmp(path, "~") == 0) {
free(path);
path = xstrdup(cwd);
} else if (strncmp(path, "~/", 2) == 0) {
npath = xstrdup(path + 2);
free(path);
xasprintf(&path, "%s/%s", cwd, npath);
free(npath);
} else {
/* ~user expansions */
if (tilde_expand(path, pw->pw_uid, &npath) != 0) {
send_status_errmsg(id,
errno_to_portable(ENOENT), "no such user");
goto out;
}
free(path);
path = npath;
}
} else if (*path != '/') {
/* relative path */
xasprintf(&npath, "%s/%s", cwd, path);
free(path);
path = npath;
}
verbose("expand \"%s\"", path);
if (sftp_realpath(path, resolvedname) == NULL) {
send_status(id, errno_to_portable(errno));
goto out;
}
attrib_clear(&s.attrib);
s.name = s.long_name = resolvedname;
send_names(id, 1, &s);
out:
free(path);
}
static void
process_extended_copy_data(u_int32_t id)
{
u_char buf[64*1024];
int read_handle, read_fd, write_handle, write_fd;
u_int64_t len, read_off, read_len, write_off;
int r, copy_until_eof, status = SSH2_FX_OP_UNSUPPORTED;
size_t ret;
if ((r = get_handle(iqueue, &read_handle)) != 0 ||
(r = sshbuf_get_u64(iqueue, &read_off)) != 0 ||
(r = sshbuf_get_u64(iqueue, &read_len)) != 0 ||
(r = get_handle(iqueue, &write_handle)) != 0 ||
(r = sshbuf_get_u64(iqueue, &write_off)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
debug("request %u: copy-data from \"%s\" (handle %d) off %llu len %llu "
"to \"%s\" (handle %d) off %llu",
id, handle_to_name(read_handle), read_handle,
(unsigned long long)read_off, (unsigned long long)read_len,
handle_to_name(write_handle), write_handle,
(unsigned long long)write_off);
/* For read length of 0, we read until EOF. */
if (read_len == 0) {
read_len = (u_int64_t)-1 - read_off;
copy_until_eof = 1;
} else
copy_until_eof = 0;
read_fd = handle_to_fd(read_handle);
write_fd = handle_to_fd(write_handle);
/* Disallow reading & writing to the same handle or same path or dirs */
if (read_handle == write_handle || read_fd < 0 || write_fd < 0 ||
!strcmp(handle_to_name(read_handle), handle_to_name(write_handle))) {
status = SSH2_FX_FAILURE;
goto out;
}
if (lseek(read_fd, read_off, SEEK_SET) < 0) {
status = errno_to_portable(errno);
error("%s: read_seek failed", __func__);
goto out;
}
if ((handle_to_flags(write_handle) & O_APPEND) == 0 &&
lseek(write_fd, write_off, SEEK_SET) < 0) {
status = errno_to_portable(errno);
error("%s: write_seek failed", __func__);
goto out;
}
/* Process the request in chunks. */
while (read_len > 0 || copy_until_eof) {
len = MINIMUM(sizeof(buf), read_len);
read_len -= len;
ret = atomicio(read, read_fd, buf, len);
if (ret == 0 && errno == EPIPE) {
status = copy_until_eof ? SSH2_FX_OK : SSH2_FX_EOF;
break;
} else if (ret == 0) {
status = errno_to_portable(errno);
error("%s: read failed: %s", __func__, strerror(errno));
break;
}
len = ret;
handle_update_read(read_handle, len);
ret = atomicio(vwrite, write_fd, buf, len);
if (ret != len) {
status = errno_to_portable(errno);
error("%s: write failed: %llu != %llu: %s", __func__,
(unsigned long long)ret, (unsigned long long)len,
strerror(errno));
break;
}
handle_update_write(write_handle, len);
}
if (read_len == 0)
status = SSH2_FX_OK;
out:
send_status(id, status);
}
+static void
+process_extended_home_directory(u_int32_t id)
+{
+ char *username;
+ struct passwd *user_pw;
+ int r;
+ Stat s;
+
+ if ((r = sshbuf_get_cstring(iqueue, &username, NULL)) != 0)
+ fatal_fr(r, "parse");
+
+ debug3("request %u: home-directory \"%s\"", id, username);
+ if ((user_pw = getpwnam(username)) == NULL) {
+ send_status(id, SSH2_FX_FAILURE);
+ goto out;
+ }
+
+ verbose("home-directory \"%s\"", pw->pw_dir);
+ attrib_clear(&s.attrib);
+ s.name = s.long_name = pw->pw_dir;
+ send_names(id, 1, &s);
+ out:
+ free(username);
+}
+
+static void
+process_extended_get_users_groups_by_id(u_int32_t id)
+{
+ struct passwd *user_pw;
+ struct group *gr;
+ struct sshbuf *uids, *gids, *usernames, *groupnames, *msg;
+ int r;
+ u_int n, nusers = 0, ngroups = 0;
+ const char *name;
+
+ if ((usernames = sshbuf_new()) == NULL ||
+ (groupnames = sshbuf_new()) == NULL ||
+ (msg = sshbuf_new()) == NULL)
+ fatal_f("sshbuf_new failed");
+ if ((r = sshbuf_froms(iqueue, &uids)) != 0 ||
+ (r = sshbuf_froms(iqueue, &gids)) != 0)
+ fatal_fr(r, "parse");
+ debug_f("uids len = %zu, gids len = %zu",
+ sshbuf_len(uids), sshbuf_len(gids));
+ while (sshbuf_len(uids) != 0) {
+ if ((r = sshbuf_get_u32(uids, &n)) != 0)
+ fatal_fr(r, "parse inner uid");
+ user_pw = getpwuid((uid_t)n);
+ name = user_pw == NULL ? "" : user_pw->pw_name;
+ debug3_f("uid %u => \"%s\"", n, name);
+ if ((r = sshbuf_put_cstring(usernames, name)) != 0)
+ fatal_fr(r, "assemble gid reply");
+ nusers++;
+ }
+ while (sshbuf_len(gids) != 0) {
+ if ((r = sshbuf_get_u32(gids, &n)) != 0)
+ fatal_fr(r, "parse inner gid");
+ gr = getgrgid((gid_t)n);
+ name = gr == NULL ? "" : gr->gr_name;
+ debug3_f("gid %u => \"%s\"", n, name);
+ if ((r = sshbuf_put_cstring(groupnames, name)) != 0)
+ fatal_fr(r, "assemble gid reply");
+ nusers++;
+ }
+ verbose("users-groups-by-id: %u users, %u groups", nusers, ngroups);
+
+ if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED_REPLY)) != 0 ||
+ (r = sshbuf_put_u32(msg, id)) != 0 ||
+ (r = sshbuf_put_stringb(msg, usernames)) != 0 ||
+ (r = sshbuf_put_stringb(msg, groupnames)) != 0)
+ fatal_fr(r, "compose");
+ send_msg(msg);
+
+ sshbuf_free(uids);
+ sshbuf_free(gids);
+ sshbuf_free(usernames);
+ sshbuf_free(groupnames);
+ sshbuf_free(msg);
+}
+
static void
process_extended(u_int32_t id)
{
char *request;
int r;
const struct sftp_handler *exthand;
if ((r = sshbuf_get_cstring(iqueue, &request, NULL)) != 0)
fatal_fr(r, "parse");
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)
{
int i, r, in, out, ch, skipargs = 0, log_stderr = 0;
ssize_t len, olen;
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
if ((iqueue = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if ((oqueue = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
if (homedir != NULL) {
if (chdir(homedir) != 0) {
error("chdir to \"%s\" failed: %s", homedir,
strerror(errno));
}
}
for (;;) {
struct pollfd pfd[2];
memset(pfd, 0, sizeof pfd);
pfd[0].fd = pfd[1].fd = -1;
/*
* 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) {
pfd[0].fd = in;
pfd[0].events = POLLIN;
}
else if (r != SSH_ERR_NO_BUFFER_SPACE)
fatal_fr(r, "reserve");
olen = sshbuf_len(oqueue);
if (olen > 0) {
pfd[1].fd = out;
pfd[1].events = POLLOUT;
}
if (poll(pfd, 2, -1) == -1) {
if (errno == EINTR)
continue;
error("poll: %s", strerror(errno));
sftp_server_cleanup_exit(2);
}
/* copy stdin to iqueue */
if (pfd[0].revents & (POLLIN|POLLHUP)) {
len = read(in, buf, sizeof buf);
if (len == 0) {
debug("read eof");
sftp_server_cleanup_exit(0);
} else if (len == -1) {
if (errno != EAGAIN && errno != EINTR) {
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 (pfd[1].revents & (POLLOUT|POLLHUP)) {
len = write(out, sshbuf_ptr(oqueue), olen);
if (len == 0 || (len == -1 && errno == EPIPE)) {
debug("write eof");
sftp_server_cleanup_exit(0);
} else if (len == -1) {
sftp_server_cleanup_exit(1);
if (errno != EAGAIN && errno != EINTR) {
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-usergroup.c b/sftp-usergroup.c
new file mode 100644
index 000000000000..083930a4a327
--- /dev/null
+++ b/sftp-usergroup.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2022 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.
+ */
+
+/* sftp client user/group lookup and caching */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <openbsd-compat/sys-tree.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "log.h"
+#include "xmalloc.h"
+
+#include "sftp-common.h"
+#include "sftp-client.h"
+#include "sftp-usergroup.h"
+
+/* Tree of id, name */
+struct idname {
+ u_int id;
+ char *name;
+ RB_ENTRY(idname) entry;
+ /* XXX implement bounded cache as TAILQ */
+};
+static int
+idname_cmp(struct idname *a, struct idname *b)
+{
+ if (a->id == b->id)
+ return 0;
+ return a->id > b->id ? 1 : -1;
+}
+RB_HEAD(idname_tree, idname);
+RB_GENERATE_STATIC(idname_tree, idname, entry, idname_cmp)
+
+static struct idname_tree user_idname = RB_INITIALIZER(&user_idname);
+static struct idname_tree group_idname = RB_INITIALIZER(&group_idname);
+
+static void
+idname_free(struct idname *idname)
+{
+ if (idname == NULL)
+ return;
+ free(idname->name);
+ free(idname);
+}
+
+static void
+idname_enter(struct idname_tree *tree, u_int id, const char *name)
+{
+ struct idname *idname;
+
+ if ((idname = xcalloc(1, sizeof(*idname))) == NULL)
+ fatal_f("alloc");
+ idname->id = id;
+ idname->name = xstrdup(name);
+ if (RB_INSERT(idname_tree, tree, idname) != NULL)
+ idname_free(idname);
+}
+
+static const char *
+idname_lookup(struct idname_tree *tree, u_int id)
+{
+ struct idname idname, *found;
+
+ memset(&idname, 0, sizeof(idname));
+ idname.id = id;
+ if ((found = RB_FIND(idname_tree, tree, &idname)) != NULL)
+ return found->name;
+ return NULL;
+}
+
+static void
+freenames(char **names, u_int nnames)
+{
+ u_int i;
+
+ if (names == NULL)
+ return;
+ for (i = 0; i < nnames; i++)
+ free(names[i]);
+ free(names);
+}
+
+static void
+lookup_and_record(struct sftp_conn *conn,
+ u_int *uids, u_int nuids, u_int *gids, u_int ngids)
+{
+ int r;
+ u_int i;
+ char **usernames = NULL, **groupnames = NULL;
+
+ if ((r = do_get_users_groups_by_id(conn, uids, nuids, gids, ngids,
+ &usernames, &groupnames)) != 0) {
+ debug_fr(r, "do_get_users_groups_by_id");
+ return;
+ }
+ for (i = 0; i < nuids; i++) {
+ if (usernames[i] == NULL) {
+ debug3_f("uid %u not resolved", uids[i]);
+ continue;
+ }
+ debug3_f("record uid %u => \"%s\"", uids[i], usernames[i]);
+ idname_enter(&user_idname, uids[i], usernames[i]);
+ }
+ for (i = 0; i < ngids; i++) {
+ if (groupnames[i] == NULL) {
+ debug3_f("gid %u not resolved", gids[i]);
+ continue;
+ }
+ debug3_f("record gid %u => \"%s\"", gids[i], groupnames[i]);
+ idname_enter(&group_idname, gids[i], groupnames[i]);
+ }
+ freenames(usernames, nuids);
+ freenames(groupnames, ngids);
+}
+
+static int
+has_id(u_int id, u_int *ids, u_int nids)
+{
+ u_int i;
+
+ if (nids == 0)
+ return 0;
+
+ /* XXX O(N^2) */
+ for (i = 0; i < nids; i++) {
+ if (ids[i] == id)
+ break;
+ }
+ return i < nids;
+}
+
+static void
+collect_ids_from_glob(glob_t *g, int user, u_int **idsp, u_int *nidsp)
+{
+ u_int id, i, n = 0, *ids = NULL;
+
+ for (i = 0; g->gl_pathv[i] != NULL; i++) {
+ if (user) {
+ if (ruser_name(g->gl_statv[i]->st_uid) != NULL)
+ continue; /* Already seen */
+ id = (u_int)g->gl_statv[i]->st_uid;
+ } else {
+ if (rgroup_name(g->gl_statv[i]->st_gid) != NULL)
+ continue; /* Already seen */
+ id = (u_int)g->gl_statv[i]->st_gid;
+ }
+ if (has_id(id, ids, n))
+ continue;
+ ids = xrecallocarray(ids, n, n + 1, sizeof(*ids));
+ ids[n++] = id;
+ }
+ *idsp = ids;
+ *nidsp = n;
+}
+
+void
+get_remote_user_groups_from_glob(struct sftp_conn *conn, glob_t *g)
+{
+ u_int *uids = NULL, nuids = 0, *gids = NULL, ngids = 0;
+
+ if (!can_get_users_groups_by_id(conn))
+ return;
+
+ collect_ids_from_glob(g, 1, &uids, &nuids);
+ collect_ids_from_glob(g, 0, &gids, &ngids);
+ lookup_and_record(conn, uids, nuids, gids, ngids);
+ free(uids);
+ free(gids);
+}
+
+static void
+collect_ids_from_dirents(SFTP_DIRENT **d, int user, u_int **idsp, u_int *nidsp)
+{
+ u_int id, i, n = 0, *ids = NULL;
+
+ for (i = 0; d[i] != NULL; i++) {
+ if (user) {
+ if (ruser_name((uid_t)(d[i]->a.uid)) != NULL)
+ continue; /* Already seen */
+ id = d[i]->a.uid;
+ } else {
+ if (rgroup_name((gid_t)(d[i]->a.gid)) != NULL)
+ continue; /* Already seen */
+ id = d[i]->a.gid;
+ }
+ if (has_id(id, ids, n))
+ continue;
+ ids = xrecallocarray(ids, n, n + 1, sizeof(*ids));
+ ids[n++] = id;
+ }
+ *idsp = ids;
+ *nidsp = n;
+}
+
+void
+get_remote_user_groups_from_dirents(struct sftp_conn *conn, SFTP_DIRENT **d)
+{
+ u_int *uids = NULL, nuids = 0, *gids = NULL, ngids = 0;
+
+ if (!can_get_users_groups_by_id(conn))
+ return;
+
+ collect_ids_from_dirents(d, 1, &uids, &nuids);
+ collect_ids_from_dirents(d, 0, &gids, &ngids);
+ lookup_and_record(conn, uids, nuids, gids, ngids);
+ free(uids);
+ free(gids);
+}
+
+const char *
+ruser_name(uid_t uid)
+{
+ return idname_lookup(&user_idname, (u_int)uid);
+}
+
+const char *
+rgroup_name(uid_t gid)
+{
+ return idname_lookup(&group_idname, (u_int)gid);
+}
+
diff --git a/sftp-server-main.c b/sftp-usergroup.h
similarity index 50%
copy from sftp-server-main.c
copy to sftp-usergroup.h
index 06566d36ed84..2711faf3a881 100644
--- a/sftp-server-main.c
+++ b/sftp-usergroup.h
@@ -1,54 +1,25 @@
-/* $OpenBSD: sftp-server-main.c,v 1.6 2019/06/06 05:13:13 otto Exp $ */
/*
- * Copyright (c) 2008 Markus Friedl. All rights reserved.
+ * Copyright (c) 2022 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"
+/* sftp client user/group lookup and caching */
-#include <sys/types.h>
-#include <pwd.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <unistd.h>
+/* Lookup uids/gids and populate cache */
+void get_remote_user_groups_from_glob(struct sftp_conn *conn, glob_t *g);
+void get_remote_user_groups_from_dirents(struct sftp_conn *conn, SFTP_DIRENT **d);
-#include "log.h"
-#include "sftp.h"
-#include "misc.h"
-#include "xmalloc.h"
-
-void
-cleanup_exit(int i)
-{
- sftp_server_cleanup_exit(i);
-}
-
-int
-main(int argc, char **argv)
-{
- struct passwd *user_pw;
-
- /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
- sanitise_stdfd();
-
- seed_rng();
-
- if ((user_pw = getpwuid(getuid())) == NULL) {
- fprintf(stderr, "No user found for uid %lu\n",
- (u_long)getuid());
- return 1;
- }
-
- return (sftp_server_main(argc, argv, user_pw));
-}
+/* Return user/group name from cache or NULL if not found */
+const char *ruser_name(uid_t uid);
+const char *rgroup_name(uid_t gid);
diff --git a/sftp.0 b/sftp.0
index 2e042261e59d..23aaa3af93fc 100644
--- a/sftp.0
+++ b/sftp.0
@@ -1,420 +1,423 @@
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]
+ [-D sftp_server_command] [-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, copy, cp,
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
+ -D sftp_server_command
Connect directly to a local sftp server (rather than via ssh(1)).
- This option may be useful in debugging the client and server.
+ A command and arguments may be specified, for example
+ "/path/sftp-server -el debug3". 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
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
+ RequiredRSASize
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.
copy oldpath newpath
Copy remote file from oldpath to newpath.
Note that this is only supported by servers that implement the
"copy-data" extension.
cp oldpath newpath
Alias to copy command.
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 7.0 March 31, 2022 OpenBSD 7.0
+OpenBSD 7.1 September 19, 2022 OpenBSD 7.1
diff --git a/sftp.1 b/sftp.1
index 39e7d6ed68a8..3b3f2c5a7917 100644
--- a/sftp.1
+++ b/sftp.1
@@ -1,711 +1,714 @@
-.\" $OpenBSD: sftp.1,v 1.140 2022/03/31 17:27:27 naddy Exp $
+.\" $OpenBSD: sftp.1,v 1.142 2022/09/19 21:39:16 djm Exp $
.\"
.\" Copyright (c) 2001 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.
.\"
-.Dd $Mdocdate: March 31 2022 $
+.Dd $Mdocdate: September 19 2022 $
.Dt SFTP 1
.Os
.Sh NAME
.Nm sftp
.Nd OpenSSH secure file transfer
.Sh SYNOPSIS
.Nm sftp
.Op Fl 46AaCfNpqrv
.Op Fl B Ar buffer_size
.Op Fl b Ar batchfile
.Op Fl c Ar cipher
-.Op Fl D Ar sftp_server_path
+.Op Fl D Ar sftp_server_command
.Op Fl F Ar ssh_config
.Op Fl i Ar identity_file
.Op Fl J Ar destination
.Op Fl l Ar limit
.Op Fl o Ar ssh_option
.Op Fl P Ar port
.Op Fl R Ar num_requests
.Op Fl S Ar program
.Op Fl s Ar subsystem | sftp_server
.Ar destination
.Sh DESCRIPTION
.Nm
is a file transfer program, similar to
.Xr ftp 1 ,
which performs all operations over an encrypted
.Xr ssh 1
transport.
It may also use many features of ssh, such as public key authentication and
compression.
.Pp
The
.Ar destination
may be specified either as
.Sm off
.Oo user @ Oc host Op : path
.Sm on
or as a URI in the form
.Sm off
.No sftp:// Oo user @ Oc host Oo : port Oc Op / path .
.Sm on
.Pp
If the
.Ar destination
includes a
.Ar path
and it is not a directory,
.Nm
will retrieve files automatically if a non-interactive
authentication method is used; otherwise it will do so after
successful interactive authentication.
.Pp
If no
.Ar path
is specified, or if the
.Ar path
is a directory,
.Nm
will log in to the specified
.Ar 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
.Ar path
to be interpreted as a directory.
.Pp
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.
.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 A
Allows forwarding of
.Xr ssh-agent 1
to the remote system.
The default is not to forward an authentication agent.
.It Fl 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.
.It Fl B Ar buffer_size
Specify the size of the buffer that
.Nm
uses when transferring files.
Larger buffers require fewer round trips at the cost of higher
memory consumption.
The default is 32768 bytes.
.It Fl b Ar batchfile
Batch mode reads a series of commands from an input
.Ar batchfile
instead of
.Em 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
.Xr sshd 8
and
.Xr ssh-keygen 1
for details).
.Pp
A
.Ar batchfile
of
.Sq \-
may be used to indicate standard input.
.Nm
will abort if any of the following
commands fail:
.Ic get , put , reget , reput , rename , ln ,
.Ic rm , mkdir , chdir , ls ,
.Ic lchdir , copy , cp , chmod , chown ,
.Ic chgrp , lpwd , df , symlink ,
and
.Ic lmkdir .
.Pp
Termination on error can be suppressed on a command by command basis by
prefixing the command with a
.Sq \-
character (for example,
.Ic -rm /tmp/blah* ) .
Echo of the command may be suppressed by prefixing the command with a
.Sq @
character.
These two prefixes may be combined in any order, for example
.Ic -@ls /bsd .
.It Fl C
Enables compression (via ssh's
.Fl C
flag).
.It Fl c Ar cipher
Selects the cipher to use for encrypting the data transfers.
This option is directly passed to
.Xr ssh 1 .
-.It Fl D Ar sftp_server_path
+.It Fl D Ar sftp_server_command
Connect directly to a local sftp server
(rather than via
.Xr ssh 1 ) .
+A command and arguments may be specified, for example
+.Qq /path/sftp-server -el debug3 .
This option may be useful in debugging the client and server.
.It Fl F Ar ssh_config
Specifies an alternative
per-user configuration file for
.Xr ssh 1 .
This option is directly passed to
.Xr ssh 1 .
.It Fl 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.
.It Fl i Ar identity_file
Selects the file from which the identity (private key) for public key
authentication is read.
This option is directly passed to
.Xr ssh 1 .
.It Fl J Ar destination
Connect to the target host by first making an
.Nm
connection to the jump host described by
.Ar 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
.Cm ProxyJump
configuration directive.
This option is directly passed to
.Xr ssh 1 .
.It Fl l Ar limit
Limits the used bandwidth, specified in Kbit/s.
.It Fl N
Disables quiet mode, e.g. to override the implicit quiet mode set by the
.Fl b
flag.
.It Fl o Ar ssh_option
Can be used to pass options to
.Nm ssh
in the format used in
.Xr ssh_config 5 .
This is useful for specifying options
for which there is no separate
.Nm sftp
command-line flag.
For example, to specify an alternate port use:
.Ic sftp -oPort=24 .
For full details of the options listed below, and their possible values, see
.Xr ssh_config 5 .
.Pp
.Bl -tag -width Ds -offset indent -compact
.It AddressFamily
.It BatchMode
.It BindAddress
.It BindInterface
.It CanonicalDomains
.It CanonicalizeFallbackLocal
.It CanonicalizeHostname
.It CanonicalizeMaxDots
.It CanonicalizePermittedCNAMEs
.It CASignatureAlgorithms
.It CertificateFile
.It CheckHostIP
.It Ciphers
.It Compression
.It ConnectionAttempts
.It ConnectTimeout
.It ControlMaster
.It ControlPath
.It ControlPersist
.It GlobalKnownHostsFile
.It GSSAPIAuthentication
.It GSSAPIDelegateCredentials
.It HashKnownHosts
.It Host
.It HostbasedAcceptedAlgorithms
.It HostbasedAuthentication
.It HostKeyAlgorithms
.It HostKeyAlias
.It Hostname
.It IdentitiesOnly
.It IdentityAgent
.It IdentityFile
.It IPQoS
.It KbdInteractiveAuthentication
.It KbdInteractiveDevices
.It KexAlgorithms
.It KnownHostsCommand
.It LogLevel
.It MACs
.It NoHostAuthenticationForLocalhost
.It NumberOfPasswordPrompts
.It PasswordAuthentication
.It PKCS11Provider
.It Port
.It PreferredAuthentications
.It ProxyCommand
.It ProxyJump
.It PubkeyAcceptedAlgorithms
.It PubkeyAuthentication
.It RekeyLimit
+.It RequiredRSASize
.It SendEnv
.It ServerAliveInterval
.It ServerAliveCountMax
.It SetEnv
.It StrictHostKeyChecking
.It TCPKeepAlive
.It UpdateHostKeys
.It User
.It UserKnownHostsFile
.It VerifyHostKeyDNS
.El
.It Fl P Ar port
Specifies the port to connect to on the remote host.
.It Fl p
Preserves modification times, access times, and modes from the
original files transferred.
.It Fl q
Quiet mode: disables the progress meter as well as warning and
diagnostic messages from
.Xr ssh 1 .
.It Fl R Ar 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.
.It Fl r
Recursively copy entire directories when uploading and downloading.
Note that
.Nm
does not follow symbolic links encountered in the tree traversal.
.It Fl S Ar program
Name of the
.Ar program
to use for the encrypted connection.
The program must understand
.Xr ssh 1
options.
.It Fl s Ar 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
.Xr sshd 8
does not have an sftp subsystem configured.
.It Fl v
Raise logging level.
This option is also passed to ssh.
.El
.Sh INTERACTIVE COMMANDS
Once in interactive mode,
.Nm
understands a set of commands similar to those of
.Xr 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
.Xr glob 3
must be escaped with backslashes
.Pq Sq \e .
.Bl -tag -width Ds
.It Ic bye
Quit
.Nm sftp .
.It Ic cd Op Ar path
Change remote directory to
.Ar path .
If
.Ar path
is not specified, then change directory to the one the session started in.
.It Xo Ic chgrp
.Op Fl h
.Ar grp
.Ar path
.Xc
Change group of file
.Ar path
to
.Ar grp .
.Ar path
may contain
.Xr glob 7
characters and may match multiple files.
.Ar grp
must be a numeric GID.
.Pp
If the
.Fl 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.
.It Xo Ic chmod
.Op Fl h
.Ar mode
.Ar path
.Xc
Change permissions of file
.Ar path
to
.Ar mode .
.Ar path
may contain
.Xr glob 7
characters and may match multiple files.
.Pp
If the
.Fl 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.
.It Xo Ic chown
.Op Fl h
.Ar own
.Ar path
.Xc
Change owner of file
.Ar path
to
.Ar own .
.Ar path
may contain
.Xr glob 7
characters and may match multiple files.
.Ar own
must be a numeric UID.
.Pp
If the
.Fl 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.
.It Ic copy Ar oldpath Ar newpath
Copy remote file from
.Ar oldpath
to
.Ar newpath .
.Pp
Note that this is only supported by servers that implement the "copy-data"
extension.
.It Ic cp Ar oldpath Ar newpath
Alias to
.Ic copy
command.
.It Xo Ic df
.Op Fl hi
.Op Ar path
.Xc
Display usage information for the filesystem holding the current directory
(or
.Ar path
if specified).
If the
.Fl h
flag is specified, the capacity information will be displayed using
"human-readable" suffixes.
The
.Fl i
flag requests display of inode information in addition to capacity information.
This command is only supported on servers that implement the
.Dq statvfs@openssh.com
extension.
.It Ic exit
Quit
.Nm sftp .
.It Xo Ic get
.Op Fl afpR
.Ar remote-path
.Op Ar local-path
.Xc
Retrieve the
.Ar 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.
.Ar remote-path
may contain
.Xr glob 7
characters and may match multiple files.
If it does and
.Ar local-path
is specified, then
.Ar local-path
must specify a directory.
.Pp
If the
.Fl 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.
.Pp
If the
.Fl f
flag is specified, then
.Xr fsync 2
will be called after the file transfer has completed to flush the file
to disk.
.Pp
If the
.Fl p
.\" undocumented redundant alias
.\" or
.\" .Fl P
flag is specified, then full file permissions and access times are
copied too.
.Pp
If the
.Fl R
.\" undocumented redundant alias
.\" or
.\" .Fl r
flag is specified then directories will be copied recursively.
Note that
.Nm
does not follow symbolic links when performing recursive transfers.
.It Ic help
Display help text.
.It Ic lcd Op Ar path
Change local directory to
.Ar path .
If
.Ar path
is not specified, then change directory to the local user's home directory.
.It Ic lls Op Ar ls-options Op Ar path
Display local directory listing of either
.Ar path
or current directory if
.Ar path
is not specified.
.Ar ls-options
may contain any flags supported by the local system's
.Xr ls 1
command.
.Ar path
may contain
.Xr glob 7
characters and may match multiple files.
.It Ic lmkdir Ar path
Create local directory specified by
.Ar path .
.It Xo Ic ln
.Op Fl s
.Ar oldpath
.Ar newpath
.Xc
Create a link from
.Ar oldpath
to
.Ar newpath .
If the
.Fl s
flag is specified the created link is a symbolic link, otherwise it is
a hard link.
.It Ic lpwd
Print local working directory.
.It Xo Ic ls
.Op Fl 1afhlnrSt
.Op Ar path
.Xc
Display a remote directory listing of either
.Ar path
or the current directory if
.Ar path
is not specified.
.Ar path
may contain
.Xr glob 7
characters and may match multiple files.
.Pp
The following flags are recognized and alter the behaviour of
.Ic ls
accordingly:
.Bl -tag -width Ds
.It Fl 1
Produce single columnar output.
.It Fl a
List files beginning with a dot
.Pq Sq \&. .
.It Fl f
Do not sort the listing.
The default sort order is lexicographical.
.It Fl 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.).
.It Fl l
Display additional details including permissions
and ownership information.
.It Fl n
Produce a long listing with user and group information presented
numerically.
.It Fl r
Reverse the sort order of the listing.
.It Fl S
Sort the listing by file size.
.It Fl t
Sort the listing by last modification time.
.El
.It Ic lumask Ar umask
Set local umask to
.Ar umask .
.It Ic mkdir Ar path
Create remote directory specified by
.Ar path .
.It Ic progress
Toggle display of progress meter.
.It Xo Ic put
.Op Fl afpR
.Ar local-path
.Op Ar remote-path
.Xc
Upload
.Ar 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.
.Ar local-path
may contain
.Xr glob 7
characters and may match multiple files.
If it does and
.Ar remote-path
is specified, then
.Ar remote-path
must specify a directory.
.Pp
If the
.Fl 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.
.Pp
If the
.Fl f
flag is specified, then a request will be sent to the server to call
.Xr fsync 2
after the file has been transferred.
Note that this is only supported by servers that implement
the "fsync@openssh.com" extension.
.Pp
If the
.Fl p
.\" undocumented redundant alias
.\" or
.\" .Fl P
flag is specified, then full file permissions and access times are
copied too.
.Pp
If the
.Fl R
.\" undocumented redundant alias
.\" or
.\" .Fl r
flag is specified then directories will be copied recursively.
Note that
.Nm
does not follow symbolic links when performing recursive transfers.
.It Ic pwd
Display remote working directory.
.It Ic quit
Quit
.Nm sftp .
.It Xo Ic reget
.Op Fl fpR
.Ar remote-path
.Op Ar local-path
.Xc
Resume download of
.Ar remote-path .
Equivalent to
.Ic get
with the
.Fl a
flag set.
.It Xo Ic reput
.Op Fl fpR
.Ar local-path
.Op Ar remote-path
.Xc
Resume upload of
.Ar local-path .
Equivalent to
.Ic put
with the
.Fl a
flag set.
.It Ic rename Ar oldpath newpath
Rename remote file from
.Ar oldpath
to
.Ar newpath .
.It Ic rm Ar path
Delete remote file specified by
.Ar path .
.It Ic rmdir Ar path
Remove remote directory specified by
.Ar path .
.It Ic symlink Ar oldpath newpath
Create a symbolic link from
.Ar oldpath
to
.Ar newpath .
.It Ic version
Display the
.Nm
protocol version.
.It Ic \&! Ns Ar command
Execute
.Ar command
in local shell.
.It Ic \&!
Escape to local shell.
.It Ic \&?
Synonym for help.
.El
.Sh SEE ALSO
.Xr ftp 1 ,
.Xr ls 1 ,
.Xr scp 1 ,
.Xr ssh 1 ,
.Xr ssh-add 1 ,
.Xr ssh-keygen 1 ,
.Xr ssh_config 5 ,
.Xr glob 7 ,
.Xr sftp-server 8 ,
.Xr sshd 8
.Rs
.%A T. Ylonen
.%A S. Lehtinen
.%T "SSH File Transfer Protocol"
.%N draft-ietf-secsh-filexfer-00.txt
.%D January 2001
.%O work in progress material
.Re
diff --git a/sftp.c b/sftp.c
index 4efc025a504c..c3c347e087e4 100644
--- a/sftp.c
+++ b/sftp.c
@@ -1,2598 +1,2656 @@
-/* $OpenBSD: sftp.c,v 1.214 2022/03/31 03:07:03 djm Exp $ */
+/* $OpenBSD: sftp.c,v 1.222 2022/09/19 10:46:00 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/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"
+#include "sftp-usergroup.h"
/* 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 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_COPY,
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;
+ const int t; /* Completion type for the first argument */
+ const int t2; /* completion type for the optional second argument */
};
/* 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 },
- { "copy", I_COPY, REMOTE },
- { "cp", I_COPY, 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 }
+ { "bye", I_QUIT, NOARGS, NOARGS },
+ { "cd", I_CHDIR, REMOTE, NOARGS },
+ { "chdir", I_CHDIR, REMOTE, NOARGS },
+ { "chgrp", I_CHGRP, REMOTE, NOARGS },
+ { "chmod", I_CHMOD, REMOTE, NOARGS },
+ { "chown", I_CHOWN, REMOTE, NOARGS },
+ { "copy", I_COPY, REMOTE, LOCAL },
+ { "cp", I_COPY, REMOTE, LOCAL },
+ { "df", I_DF, REMOTE, NOARGS },
+ { "dir", I_LS, REMOTE, NOARGS },
+ { "exit", I_QUIT, NOARGS, NOARGS },
+ { "get", I_GET, REMOTE, LOCAL },
+ { "help", I_HELP, NOARGS, NOARGS },
+ { "lcd", I_LCHDIR, LOCAL, NOARGS },
+ { "lchdir", I_LCHDIR, LOCAL, NOARGS },
+ { "lls", I_LLS, LOCAL, NOARGS },
+ { "lmkdir", I_LMKDIR, LOCAL, NOARGS },
+ { "ln", I_LINK, REMOTE, REMOTE },
+ { "lpwd", I_LPWD, LOCAL, NOARGS },
+ { "ls", I_LS, REMOTE, NOARGS },
+ { "lumask", I_LUMASK, NOARGS, NOARGS },
+ { "mkdir", I_MKDIR, REMOTE, NOARGS },
+ { "mget", I_GET, REMOTE, LOCAL },
+ { "mput", I_PUT, LOCAL, REMOTE },
+ { "progress", I_PROGRESS, NOARGS, NOARGS },
+ { "put", I_PUT, LOCAL, REMOTE },
+ { "pwd", I_PWD, REMOTE, NOARGS },
+ { "quit", I_QUIT, NOARGS, NOARGS },
+ { "reget", I_REGET, REMOTE, LOCAL },
+ { "rename", I_RENAME, REMOTE, REMOTE },
+ { "reput", I_REPUT, LOCAL, REMOTE },
+ { "rm", I_RM, REMOTE, NOARGS },
+ { "rmdir", I_RMDIR, REMOTE, NOARGS },
+ { "symlink", I_SYMLINK, REMOTE, REMOTE },
+ { "version", I_VERSION, NOARGS, NOARGS },
+ { "!", I_SHELL, NOARGS, NOARGS },
+ { "?", I_HELP, NOARGS, NOARGS },
+ { NULL, -1, -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
read_interrupt(int signo)
{
interrupted = 1;
}
/*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"
"copy oldpath newpath Copy remote file\n"
"cp oldpath newpath Copy remote file\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 char *
+escape_glob(const char *s)
+{
+ size_t i, o, len;
+ char *ret;
+
+ len = strlen(s);
+ ret = xcalloc(2, len + 1);
+ for (i = o = 0; i < len; i++) {
+ if (strchr("[]?*\\", s[i]) != NULL)
+ ret[o++] = '\\';
+ ret[o++] = s[i];
+ }
+ ret[o++] = '\0';
+ return ret;
+}
+
+static char *
+make_absolute_pwd_glob(const char *p, const char *pwd)
+{
+ char *ret, *escpwd;
+
+ escpwd = escape_glob(pwd);
+ if (p == NULL)
+ return escpwd;
+ ret = make_absolute(xstrdup(p), escpwd);
+ free(escpwd);
+ return ret;
+}
+
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;
+ char *filename, *abs_src = NULL, *abs_dst = NULL, *tmp = NULL;
glob_t g;
- char *filename, *tmp=NULL;
int i, r, err = 0;
- abs_src = xstrdup(src);
- abs_src = make_absolute(abs_src, pwd);
+ abs_src = make_absolute_pwd_glob(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);
/* XXX follow link flag */
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, 0) == -1)
+ fflag || global_fflag, 0, 0) == -1)
err = -1;
} else {
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
pflag || global_pflag, resume,
- fflag || global_fflag) == -1)
+ fflag || global_fflag, 0) == -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;
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);
/* XXX follow_link_flag */
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, 0) == -1)
+ fflag || global_fflag, 0, 0) == -1)
err = -1;
} else {
if (do_upload(conn, g.gl_pathv[i], abs_dst,
pflag || global_pflag, resume,
- fflag || global_fflag) == -1)
+ fflag || global_fflag, 0) == -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);
}
+ get_remote_user_groups_from_dirents(conn, d);
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)) {
+ if ((lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) != 0 ||
+ can_get_users_groups_by_id(conn)) {
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));
+ (lflag & LS_SI_UNITS),
+ ruser_name(sb.st_uid),
+ rgroup_name(sb.st_gid));
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;
}
+ get_remote_user_groups_from_glob(conn, &g);
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));
+ (lflag & LS_SI_UNITS),
+ ruser_name(g.gl_statv[i]->st_uid),
+ rgroup_name(g.gl_statv[i]->st_gid));
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_COPY:
if ((optidx = parse_no_flags(cmd, argv, argc)) == -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_COPY:
path1 = make_absolute(path1, *pwd);
path2 = make_absolute(path2, *pwd);
err = do_copy(conn, path1, path2);
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);
+ path1 = make_absolute_pwd_glob(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);
+ path1 = make_absolute_pwd_glob(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);
+ path1 = make_absolute_pwd_glob(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);
+ path1 = make_absolute_pwd_glob(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.
+ * Determine whether a particular sftp command's arguments (if any) represent
+ * local or remote files. The "cmdarg" argument specifies the actual argument
+ * and accepts values 1 or 2.
*/
static int
-complete_is_remote(char *cmd) {
+complete_is_remote(char *cmd, int cmdarg) {
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;
+ if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c))) {
+ if (cmdarg == 1)
+ return cmds[i].t;
+ else if (cmdarg == 2)
+ return cmds[i].t2;
+ break;
+ }
}
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);
+ tmp = make_absolute_pwd_glob(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]);
+ int remote = 0;
+ int i = 0, cmdarg = 0;
char *filematch = NULL;
if (carg > 1 && line[cursor-1] != ' ')
filematch = argv[carg - 1];
- if (remote != 0 &&
+ for (i = 1; i < carg; i++) {
+ /* Skip flags */
+ if (argv[i][0] != '-')
+ cmdarg++;
+ }
+
+ /*
+ * If previous argument is complete, then offer completion
+ * on the next one.
+ */
+ if (line[cursor - 1] == ' ')
+ cmdarg++;
+
+ remote = complete_is_remote(argv[0], cmdarg);
+
+ if ((remote == REMOTE || remote == LOCAL) &&
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 (;;) {
struct sigaction sa;
interrupted = 0;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = interactive ? read_interrupt : killchild;
if (sigaction(SIGINT, &sa, NULL) == -1) {
debug3("sigaction(%s): %s", strsignal(SIGINT),
strerror(errno));
break;
}
if (el == NULL) {
if (interactive)
printf("sftp> ");
if (fgets(cmd, sizeof(cmd), infile) == NULL) {
if (interactive)
printf("\n");
if (interrupted)
continue;
break;
}
} else {
#ifdef USE_LIBEDIT
const char *line;
int count = 0;
if ((line = el_gets(el, &count)) == NULL ||
count <= 0) {
printf("\n");
if (interrupted)
continue;
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"
+ " [-D sftp_server_command] [-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 r, in, out, ch, err, tmp, port = -1, noisy = 0;
+ char *host = NULL, *user, *cp, **cpp, *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 = 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);
+ if ((r = argv_split(sftp_direct, &tmp, &cpp, 1)) != 0)
+ fatal_r(r, "Parse -D arguments");
+ if (cpp[0] == 0)
+ fatal("No sftp server specified via -D");
+ connect_to_server(cpp[0], cpp, &in, &out);
+ argv_free(cpp, tmp);
}
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/sk-api.h b/sk-api.h
index 34e110b4e320..08f567a9e271 100644
--- a/sk-api.h
+++ b/sk-api.h
@@ -1,101 +1,103 @@
-/* $OpenBSD: sk-api.h,v 1.14 2021/11/02 22:56:40 djm Exp $ */
+/* $OpenBSD: sk-api.h,v 1.15 2022/07/20 03:29:14 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.
*/
#ifndef _SK_API_H
#define _SK_API_H 1
#include <stddef.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
/* Flags */
#define SSH_SK_USER_PRESENCE_REQD 0x01
#define SSH_SK_USER_VERIFICATION_REQD 0x04
+#define SSH_SK_FORCE_OPERATION 0x10
#define SSH_SK_RESIDENT_KEY 0x20
/* Algs */
#define SSH_SK_ECDSA 0x00
#define SSH_SK_ED25519 0x01
/* Error codes */
#define SSH_SK_ERR_GENERAL -1
#define SSH_SK_ERR_UNSUPPORTED -2
#define SSH_SK_ERR_PIN_REQUIRED -3
#define SSH_SK_ERR_DEVICE_NOT_FOUND -4
+#define SSH_SK_ERR_CREDENTIAL_EXISTS -5
struct sk_enroll_response {
uint8_t flags;
uint8_t *public_key;
size_t public_key_len;
uint8_t *key_handle;
size_t key_handle_len;
uint8_t *signature;
size_t signature_len;
uint8_t *attestation_cert;
size_t attestation_cert_len;
uint8_t *authdata;
size_t authdata_len;
};
struct sk_sign_response {
uint8_t flags;
uint32_t counter;
uint8_t *sig_r;
size_t sig_r_len;
uint8_t *sig_s;
size_t sig_s_len;
};
struct sk_resident_key {
uint32_t alg;
size_t slot;
char *application;
struct sk_enroll_response key;
uint8_t flags;
uint8_t *user_id;
size_t user_id_len;
};
struct sk_option {
char *name;
char *value;
uint8_t required;
};
-#define SSH_SK_VERSION_MAJOR 0x00090000 /* current API version */
+#define SSH_SK_VERSION_MAJOR 0x000a0000 /* current API version */
#define SSH_SK_VERSION_MAJOR_MASK 0xffff0000
/* Return the version of the middleware API */
uint32_t sk_api_version(void);
/* Enroll a U2F key (private key generation) */
int sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
const char *application, uint8_t flags, const char *pin,
struct sk_option **options, struct sk_enroll_response **enroll_response);
/* Sign a challenge */
int sk_sign(uint32_t alg, const uint8_t *data, size_t data_len,
const char *application, const uint8_t *key_handle, size_t key_handle_len,
uint8_t flags, const char *pin, struct sk_option **options,
struct sk_sign_response **sign_response);
/* Enumerate all resident keys */
int sk_load_resident_keys(const char *pin, struct sk_option **options,
struct sk_resident_key ***rks, size_t *nrks);
#endif /* _SK_API_H */
diff --git a/sk-usbhid.c b/sk-usbhid.c
index 2d36ac337ffa..46e09c26cc2b 100644
--- a/sk-usbhid.c
+++ b/sk-usbhid.c
@@ -1,1400 +1,1485 @@
-/* $OpenBSD: sk-usbhid.c,v 1.38 2022/02/07 01:25:12 djm Exp $ */
+/* $OpenBSD: sk-usbhid.c,v 1.45 2022/09/14 00:14:37 djm Exp $ */
/*
* Copyright (c) 2019 Markus Friedl
* Copyright (c) 2020 Pedro Martelletto
*
* 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 ENABLE_SK_INTERNAL
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
#include <time.h>
#ifdef HAVE_SHA2_H
#include <sha2.h>
#endif
/*
* Almost every use of OpenSSL in this file is for ECDSA-NISTP256.
* This is strictly a larger hammer than necessary, but it reduces changes
* with upstream.
*/
#ifndef OPENSSL_HAS_ECC
# undef WITH_OPENSSL
#endif
#ifdef WITH_OPENSSL
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#endif /* WITH_OPENSSL */
#include <fido.h>
#include <fido/credman.h>
/* backwards compat for libfido2 */
#ifndef HAVE_FIDO_CRED_PROT
#define fido_cred_prot(x) (0)
#endif
#ifndef HAVE_FIDO_CRED_SET_PROT
#define fido_cred_set_prot(x, y) (FIDO_ERR_UNSUPPORTED_OPTION)
#endif
#ifndef HAVE_FIDO_DEV_SUPPORTS_CRED_PROT
#define fido_dev_supports_cred_prot(x) (0)
#endif
#ifndef HAVE_FIDO_DEV_GET_TOUCH_BEGIN
#define fido_dev_get_touch_begin(x) (FIDO_ERR_UNSUPPORTED_OPTION)
#endif
#ifndef HAVE_FIDO_DEV_GET_TOUCH_STATUS
#define fido_dev_get_touch_status(x, y, z) (FIDO_ERR_UNSUPPORTED_OPTION)
#endif
#ifndef FIDO_CRED_PROT_UV_REQUIRED
#define FIDO_CRED_PROT_UV_REQUIRED 0
#endif
#ifndef FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID
#define FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID 0
#endif
#ifndef SK_STANDALONE
# include "log.h"
# include "xmalloc.h"
# include "misc.h"
/*
* If building as part of OpenSSH, then rename exported functions.
* This must be done before including sk-api.h.
*/
# define sk_api_version ssh_sk_api_version
# define sk_enroll ssh_sk_enroll
# define sk_sign ssh_sk_sign
# define sk_load_resident_keys ssh_sk_load_resident_keys
#endif /* !SK_STANDALONE */
#include "sk-api.h"
/* #define SK_DEBUG 1 */
#ifdef SK_DEBUG
#define SSH_FIDO_INIT_ARG FIDO_DEBUG
#else
#define SSH_FIDO_INIT_ARG 0
#endif
#define MAX_FIDO_DEVICES 8
#define FIDO_POLL_MS 50
#define SELECT_MS 15000
#define POLL_SLEEP_NS 200000000
/* Compatibility with OpenSSH 1.0.x */
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
#define ECDSA_SIG_get0(sig, pr, ps) \
do { \
(*pr) = sig->r; \
(*ps) = sig->s; \
} while (0)
#endif
#ifndef FIDO_ERR_OPERATION_DENIED
#define FIDO_ERR_OPERATION_DENIED 0x27
#endif
struct sk_usbhid {
fido_dev_t *dev;
char *path;
};
/* Return the version of the middleware API */
uint32_t sk_api_version(void);
/* Enroll a U2F key (private key generation) */
int sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
const char *application, uint8_t flags, const char *pin,
struct sk_option **options, struct sk_enroll_response **enroll_response);
/* Sign a challenge */
int sk_sign(uint32_t alg, const uint8_t *data, size_t data_len,
const char *application, const uint8_t *key_handle, size_t key_handle_len,
uint8_t flags, const char *pin, struct sk_option **options,
struct sk_sign_response **sign_response);
/* Load resident keys */
int sk_load_resident_keys(const char *pin, struct sk_option **options,
struct sk_resident_key ***rks, size_t *nrks);
static void skdebug(const char *func, const char *fmt, ...)
__attribute__((__format__ (printf, 2, 3)));
static void
skdebug(const char *func, const char *fmt, ...)
{
#if !defined(SK_STANDALONE)
char *msg;
va_list ap;
va_start(ap, fmt);
xvasprintf(&msg, fmt, ap);
va_end(ap);
debug("%s: %s", func, msg);
free(msg);
#elif defined(SK_DEBUG)
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s: ", func);
vfprintf(stderr, fmt, ap);
fputc('\n', stderr);
va_end(ap);
#else
(void)func; /* XXX */
(void)fmt; /* XXX */
#endif
}
uint32_t
sk_api_version(void)
{
return SSH_SK_VERSION_MAJOR;
}
static struct sk_usbhid *
sk_open(const char *path)
{
struct sk_usbhid *sk;
int r;
if (path == NULL) {
skdebug(__func__, "path == NULL");
return NULL;
}
if ((sk = calloc(1, sizeof(*sk))) == NULL) {
skdebug(__func__, "calloc sk failed");
return NULL;
}
if ((sk->path = strdup(path)) == NULL) {
skdebug(__func__, "strdup path failed");
free(sk);
return NULL;
}
if ((sk->dev = fido_dev_new()) == NULL) {
skdebug(__func__, "fido_dev_new failed");
free(sk->path);
free(sk);
return NULL;
}
if ((r = fido_dev_open(sk->dev, sk->path)) != FIDO_OK) {
skdebug(__func__, "fido_dev_open %s failed: %s", sk->path,
fido_strerr(r));
fido_dev_free(&sk->dev);
free(sk->path);
free(sk);
return NULL;
}
return sk;
}
static void
sk_close(struct sk_usbhid *sk)
{
if (sk == NULL)
return;
fido_dev_cancel(sk->dev); /* cancel any pending operation */
fido_dev_close(sk->dev);
fido_dev_free(&sk->dev);
free(sk->path);
free(sk);
}
static struct sk_usbhid **
sk_openv(const fido_dev_info_t *devlist, size_t ndevs, size_t *nopen)
{
const fido_dev_info_t *di;
struct sk_usbhid **skv;
size_t i;
*nopen = 0;
if ((skv = calloc(ndevs, sizeof(*skv))) == NULL) {
skdebug(__func__, "calloc skv failed");
return NULL;
}
for (i = 0; i < ndevs; i++) {
if ((di = fido_dev_info_ptr(devlist, i)) == NULL)
skdebug(__func__, "fido_dev_info_ptr failed");
else if ((skv[*nopen] = sk_open(fido_dev_info_path(di))) == NULL)
skdebug(__func__, "sk_open failed");
else
(*nopen)++;
}
if (*nopen == 0) {
for (i = 0; i < ndevs; i++)
sk_close(skv[i]);
free(skv);
skv = NULL;
}
return skv;
}
static void
sk_closev(struct sk_usbhid **skv, size_t nsk)
{
size_t i;
for (i = 0; i < nsk; i++)
sk_close(skv[i]);
free(skv);
}
static int
sk_touch_begin(struct sk_usbhid **skv, size_t nsk)
{
size_t i, ok = 0;
int r;
for (i = 0; i < nsk; i++)
if ((r = fido_dev_get_touch_begin(skv[i]->dev)) != FIDO_OK)
skdebug(__func__, "fido_dev_get_touch_begin %s failed:"
" %s", skv[i]->path, fido_strerr(r));
else
ok++;
return ok ? 0 : -1;
}
static int
sk_touch_poll(struct sk_usbhid **skv, size_t nsk, int *touch, size_t *idx)
{
struct timespec ts_pause;
size_t npoll, i;
int r;
ts_pause.tv_sec = 0;
ts_pause.tv_nsec = POLL_SLEEP_NS;
nanosleep(&ts_pause, NULL);
npoll = nsk;
for (i = 0; i < nsk; i++) {
if (skv[i] == NULL)
continue; /* device discarded */
skdebug(__func__, "polling %s", skv[i]->path);
if ((r = fido_dev_get_touch_status(skv[i]->dev, touch,
FIDO_POLL_MS)) != FIDO_OK) {
skdebug(__func__, "fido_dev_get_touch_status %s: %s",
skv[i]->path, fido_strerr(r));
sk_close(skv[i]); /* discard device */
skv[i] = NULL;
if (--npoll == 0) {
skdebug(__func__, "no device left to poll");
return -1;
}
} else if (*touch) {
*idx = i;
return 0;
}
}
*touch = 0;
return 0;
}
#if !defined(HAVE_FIDO_ASSERT_SET_CLIENTDATA) || \
!defined(HAVE_FIDO_CRED_SET_CLIENTDATA)
/* Calculate SHA256(m) */
static int
sha256_mem(const void *m, size_t mlen, u_char *d, size_t dlen)
{
#ifdef WITH_OPENSSL
u_int mdlen;
#else
SHA2_CTX ctx;
#endif
if (dlen != 32)
return -1;
#ifdef WITH_OPENSSL
mdlen = dlen;
if (!EVP_Digest(m, mlen, d, &mdlen, EVP_sha256(), NULL))
return -1;
#else
SHA256Init(&ctx);
SHA256Update(&ctx, (const uint8_t *)m, mlen);
SHA256Final(d, &ctx);
#endif
return 0;
}
#endif /* !HAVE_FIDO_ASSERT_SET_CLIENTDATA || !HAVE_FIDO_CRED_SET_CLIENTDATA */
#ifndef HAVE_FIDO_CRED_SET_CLIENTDATA
static int
fido_cred_set_clientdata(fido_cred_t *cred, const u_char *ptr, size_t len)
{
uint8_t d[32];
int r;
if (sha256_mem(ptr, len, d, sizeof(d)) != 0) {
skdebug(__func__, "hash challenge failed");
return FIDO_ERR_INTERNAL;
}
r = fido_cred_set_clientdata_hash(cred, d, sizeof(d));
explicit_bzero(d, sizeof(d));
if (r != FIDO_OK) {
skdebug(__func__, "fido_cred_set_clientdata_hash failed: %s",
fido_strerr(r));
}
return r;
}
#endif /* HAVE_FIDO_CRED_SET_CLIENTDATA */
#ifndef HAVE_FIDO_ASSERT_SET_CLIENTDATA
static int
fido_assert_set_clientdata(fido_assert_t *assert, const u_char *ptr, size_t len)
{
uint8_t d[32];
int r;
if (sha256_mem(ptr, len, d, sizeof(d)) != 0) {
skdebug(__func__, "hash challenge failed");
return FIDO_ERR_INTERNAL;
}
r = fido_assert_set_clientdata_hash(assert, d, sizeof(d));
explicit_bzero(d, sizeof(d));
if (r != FIDO_OK) {
skdebug(__func__, "fido_assert_set_clientdata_hash failed: %s",
fido_strerr(r));
}
return r;
}
#endif /* HAVE_FIDO_ASSERT_SET_CLIENTDATA */
+#ifndef HAVE_FIDO_DEV_IS_WINHELLO
+static bool
+fido_dev_is_winhello(const fido_dev_t *fdev)
+{
+ return 0;
+}
+#endif /* HAVE_FIDO_DEV_IS_WINHELLO */
+
/* Check if the specified key handle exists on a given sk. */
static int
sk_try(const struct sk_usbhid *sk, const char *application,
const uint8_t *key_handle, size_t key_handle_len)
{
fido_assert_t *assert = NULL;
int r = FIDO_ERR_INTERNAL;
uint8_t message[32];
memset(message, '\0', sizeof(message));
if ((assert = fido_assert_new()) == NULL) {
skdebug(__func__, "fido_assert_new failed");
goto out;
}
/* generate an invalid signature on FIDO2 tokens */
if ((r = fido_assert_set_clientdata(assert, message,
sizeof(message))) != FIDO_OK) {
- skdebug(__func__, "fido_assert_set_clientdata_hash: %s",
+ skdebug(__func__, "fido_assert_set_clientdata: %s",
fido_strerr(r));
goto out;
}
if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) {
skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r));
goto out;
}
if ((r = fido_assert_allow_cred(assert, key_handle,
key_handle_len)) != FIDO_OK) {
skdebug(__func__, "fido_assert_allow_cred: %s", fido_strerr(r));
goto out;
}
if ((r = fido_assert_set_up(assert, FIDO_OPT_FALSE)) != FIDO_OK) {
skdebug(__func__, "fido_assert_up: %s", fido_strerr(r));
goto out;
}
r = fido_dev_get_assert(sk->dev, assert, NULL);
skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) {
/* U2F tokens may return this */
r = FIDO_OK;
}
out:
fido_assert_free(&assert);
return r != FIDO_OK ? -1 : 0;
}
static int
check_sk_options(fido_dev_t *dev, const char *opt, int *ret)
{
fido_cbor_info_t *info;
char * const *name;
const bool *value;
size_t len, i;
int r;
*ret = -1;
if (!fido_dev_is_fido2(dev)) {
skdebug(__func__, "device is not fido2");
return 0;
}
if ((info = fido_cbor_info_new()) == NULL) {
skdebug(__func__, "fido_cbor_info_new failed");
return -1;
}
if ((r = fido_dev_get_cbor_info(dev, info)) != FIDO_OK) {
skdebug(__func__, "fido_dev_get_cbor_info: %s", fido_strerr(r));
fido_cbor_info_free(&info);
return -1;
}
name = fido_cbor_info_options_name_ptr(info);
value = fido_cbor_info_options_value_ptr(info);
len = fido_cbor_info_options_len(info);
for (i = 0; i < len; i++) {
if (!strcmp(name[i], opt)) {
*ret = value[i];
break;
}
}
fido_cbor_info_free(&info);
if (*ret == -1)
skdebug(__func__, "option %s is unknown", opt);
else
skdebug(__func__, "option %s is %s", opt, *ret ? "on" : "off");
return 0;
}
static struct sk_usbhid *
sk_select_by_cred(const fido_dev_info_t *devlist, size_t ndevs,
const char *application, const uint8_t *key_handle, size_t key_handle_len)
{
struct sk_usbhid **skv, *sk;
size_t skvcnt, i;
int internal_uv;
if ((skv = sk_openv(devlist, ndevs, &skvcnt)) == NULL) {
skdebug(__func__, "sk_openv failed");
return NULL;
}
if (skvcnt == 1 && check_sk_options(skv[0]->dev, "uv",
&internal_uv) == 0 && internal_uv != -1) {
sk = skv[0];
skv[0] = NULL;
goto out;
}
sk = NULL;
for (i = 0; i < skvcnt; i++) {
if (sk_try(skv[i], application, key_handle,
key_handle_len) == 0) {
sk = skv[i];
skv[i] = NULL;
skdebug(__func__, "found key in %s", sk->path);
break;
}
}
out:
sk_closev(skv, skvcnt);
return sk;
}
static struct sk_usbhid *
sk_select_by_touch(const fido_dev_info_t *devlist, size_t ndevs)
{
struct sk_usbhid **skv, *sk;
struct timeval tv_start, tv_now, tv_delta;
size_t skvcnt, idx;
int touch, ms_remain;
if ((skv = sk_openv(devlist, ndevs, &skvcnt)) == NULL) {
skdebug(__func__, "sk_openv failed");
return NULL;
}
sk = NULL;
if (skvcnt < 2) {
if (skvcnt == 1) {
/* single candidate */
sk = skv[0];
skv[0] = NULL;
}
goto out;
}
#ifndef HAVE_FIDO_DEV_GET_TOUCH_STATUS
skdebug(__func__, "libfido2 version does not support a feature needed for multiple tokens. Please upgrade to >=1.5.0");
goto out;
#endif
if (sk_touch_begin(skv, skvcnt) == -1) {
skdebug(__func__, "sk_touch_begin failed");
goto out;
}
monotime_tv(&tv_start);
do {
if (sk_touch_poll(skv, skvcnt, &touch, &idx) == -1) {
skdebug(__func__, "sk_touch_poll failed");
goto out;
}
if (touch) {
sk = skv[idx];
skv[idx] = NULL;
goto out;
}
monotime_tv(&tv_now);
timersub(&tv_now, &tv_start, &tv_delta);
ms_remain = SELECT_MS - tv_delta.tv_sec * 1000 -
tv_delta.tv_usec / 1000;
} while (ms_remain >= FIDO_POLL_MS);
skdebug(__func__, "timeout");
out:
sk_closev(skv, skvcnt);
return sk;
}
static struct sk_usbhid *
sk_probe(const char *application, const uint8_t *key_handle,
- size_t key_handle_len)
+ size_t key_handle_len, int probe_resident)
{
struct sk_usbhid *sk;
fido_dev_info_t *devlist;
size_t ndevs;
int r;
+#ifdef HAVE_CYGWIN
+ if (!probe_resident && (sk = sk_open("windows://hello")) != NULL)
+ return sk;
+#endif /* HAVE_CYGWIN */
if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) {
skdebug(__func__, "fido_dev_info_new failed");
return NULL;
}
if ((r = fido_dev_info_manifest(devlist, MAX_FIDO_DEVICES,
&ndevs)) != FIDO_OK) {
skdebug(__func__, "fido_dev_info_manifest failed: %s",
fido_strerr(r));
fido_dev_info_free(&devlist, MAX_FIDO_DEVICES);
return NULL;
}
skdebug(__func__, "%zu device(s) detected", ndevs);
if (ndevs == 0) {
sk = NULL;
} else if (application != NULL && key_handle != NULL) {
skdebug(__func__, "selecting sk by cred");
sk = sk_select_by_cred(devlist, ndevs, application, key_handle,
key_handle_len);
} else {
skdebug(__func__, "selecting sk by touch");
sk = sk_select_by_touch(devlist, ndevs);
}
fido_dev_info_free(&devlist, MAX_FIDO_DEVICES);
return sk;
}
#ifdef WITH_OPENSSL
/*
* The key returned via fido_cred_pubkey_ptr() is in affine coordinates,
* but the API expects a SEC1 octet string.
*/
static int
pack_public_key_ecdsa(const fido_cred_t *cred,
struct sk_enroll_response *response)
{
const uint8_t *ptr;
BIGNUM *x = NULL, *y = NULL;
EC_POINT *q = NULL;
EC_GROUP *g = NULL;
int ret = -1;
response->public_key = NULL;
response->public_key_len = 0;
if ((x = BN_new()) == NULL ||
(y = BN_new()) == NULL ||
(g = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)) == NULL ||
(q = EC_POINT_new(g)) == NULL) {
skdebug(__func__, "libcrypto setup failed");
goto out;
}
if ((ptr = fido_cred_pubkey_ptr(cred)) == NULL) {
skdebug(__func__, "fido_cred_pubkey_ptr failed");
goto out;
}
if (fido_cred_pubkey_len(cred) != 64) {
skdebug(__func__, "bad fido_cred_pubkey_len %zu",
fido_cred_pubkey_len(cred));
goto out;
}
if (BN_bin2bn(ptr, 32, x) == NULL ||
BN_bin2bn(ptr + 32, 32, y) == NULL) {
skdebug(__func__, "BN_bin2bn failed");
goto out;
}
if (EC_POINT_set_affine_coordinates_GFp(g, q, x, y, NULL) != 1) {
skdebug(__func__, "EC_POINT_set_affine_coordinates_GFp failed");
goto out;
}
response->public_key_len = EC_POINT_point2oct(g, q,
POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
if (response->public_key_len == 0 || response->public_key_len > 2048) {
skdebug(__func__, "bad pubkey length %zu",
response->public_key_len);
goto out;
}
if ((response->public_key = malloc(response->public_key_len)) == NULL) {
skdebug(__func__, "malloc pubkey failed");
goto out;
}
if (EC_POINT_point2oct(g, q, POINT_CONVERSION_UNCOMPRESSED,
response->public_key, response->public_key_len, NULL) == 0) {
skdebug(__func__, "EC_POINT_point2oct failed");
goto out;
}
/* success */
ret = 0;
out:
if (ret != 0 && response->public_key != NULL) {
memset(response->public_key, 0, response->public_key_len);
free(response->public_key);
response->public_key = NULL;
}
EC_POINT_free(q);
EC_GROUP_free(g);
BN_clear_free(x);
BN_clear_free(y);
return ret;
}
#endif /* WITH_OPENSSL */
static int
pack_public_key_ed25519(const fido_cred_t *cred,
struct sk_enroll_response *response)
{
const uint8_t *ptr;
size_t len;
int ret = -1;
response->public_key = NULL;
response->public_key_len = 0;
if ((len = fido_cred_pubkey_len(cred)) != 32) {
skdebug(__func__, "bad fido_cred_pubkey_len len %zu", len);
goto out;
}
if ((ptr = fido_cred_pubkey_ptr(cred)) == NULL) {
skdebug(__func__, "fido_cred_pubkey_ptr failed");
goto out;
}
response->public_key_len = len;
if ((response->public_key = malloc(response->public_key_len)) == NULL) {
skdebug(__func__, "malloc pubkey failed");
goto out;
}
memcpy(response->public_key, ptr, len);
ret = 0;
out:
if (ret != 0)
free(response->public_key);
return ret;
}
static int
pack_public_key(uint32_t alg, const fido_cred_t *cred,
struct sk_enroll_response *response)
{
switch(alg) {
#ifdef WITH_OPENSSL
case SSH_SK_ECDSA:
return pack_public_key_ecdsa(cred, response);
#endif /* WITH_OPENSSL */
case SSH_SK_ED25519:
return pack_public_key_ed25519(cred, response);
default:
return -1;
}
}
static int
fidoerr_to_skerr(int fidoerr)
{
switch (fidoerr) {
case FIDO_ERR_UNSUPPORTED_OPTION:
case FIDO_ERR_UNSUPPORTED_ALGORITHM:
return SSH_SK_ERR_UNSUPPORTED;
case FIDO_ERR_PIN_REQUIRED:
case FIDO_ERR_PIN_INVALID:
case FIDO_ERR_OPERATION_DENIED:
return SSH_SK_ERR_PIN_REQUIRED;
default:
return -1;
}
}
static int
check_enroll_options(struct sk_option **options, char **devicep,
uint8_t *user_id, size_t user_id_len)
{
size_t i;
if (options == NULL)
return 0;
for (i = 0; options[i] != NULL; i++) {
if (strcmp(options[i]->name, "device") == 0) {
if ((*devicep = strdup(options[i]->value)) == NULL) {
skdebug(__func__, "strdup device failed");
return -1;
}
skdebug(__func__, "requested device %s", *devicep);
} else if (strcmp(options[i]->name, "user") == 0) {
if (strlcpy(user_id, options[i]->value, user_id_len) >=
user_id_len) {
skdebug(__func__, "user too long");
return -1;
}
skdebug(__func__, "requested user %s",
(char *)user_id);
} else {
skdebug(__func__, "requested unsupported option %s",
options[i]->name);
if (options[i]->required) {
skdebug(__func__, "unknown required option");
return -1;
}
}
}
return 0;
}
+static int
+key_lookup(fido_dev_t *dev, const char *application, const uint8_t *user_id,
+ size_t user_id_len, const char *pin)
+{
+ fido_assert_t *assert = NULL;
+ uint8_t message[32];
+ int r = FIDO_ERR_INTERNAL;
+ int sk_supports_uv, uv;
+ size_t i;
+
+ memset(message, '\0', sizeof(message));
+ if ((assert = fido_assert_new()) == NULL) {
+ skdebug(__func__, "fido_assert_new failed");
+ goto out;
+ }
+ /* generate an invalid signature on FIDO2 tokens */
+ if ((r = fido_assert_set_clientdata(assert, message,
+ sizeof(message))) != FIDO_OK) {
+ skdebug(__func__, "fido_assert_set_clientdata: %s",
+ fido_strerr(r));
+ goto out;
+ }
+ if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) {
+ skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r));
+ goto out;
+ }
+ if ((r = fido_assert_set_up(assert, FIDO_OPT_FALSE)) != FIDO_OK) {
+ skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r));
+ goto out;
+ }
+ uv = FIDO_OPT_OMIT;
+ if (pin == NULL && check_sk_options(dev, "uv", &sk_supports_uv) == 0 &&
+ sk_supports_uv != -1)
+ uv = FIDO_OPT_TRUE;
+ if ((r = fido_assert_set_uv(assert, uv)) != FIDO_OK) {
+ skdebug(__func__, "fido_assert_set_uv: %s", fido_strerr(r));
+ goto out;
+ }
+ if ((r = fido_dev_get_assert(dev, assert, pin)) != FIDO_OK) {
+ skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
+ goto out;
+ }
+ r = FIDO_ERR_NO_CREDENTIALS;
+ skdebug(__func__, "%zu signatures returned", fido_assert_count(assert));
+ for (i = 0; i < fido_assert_count(assert); i++) {
+ if (fido_assert_user_id_len(assert, i) == user_id_len &&
+ memcmp(fido_assert_user_id_ptr(assert, i), user_id,
+ user_id_len) == 0) {
+ skdebug(__func__, "credential exists");
+ r = FIDO_OK;
+ goto out;
+ }
+ }
+ out:
+ fido_assert_free(&assert);
+
+ return r;
+}
+
int
sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
const char *application, uint8_t flags, const char *pin,
struct sk_option **options, struct sk_enroll_response **enroll_response)
{
fido_cred_t *cred = NULL;
const uint8_t *ptr;
uint8_t user_id[32];
struct sk_usbhid *sk = NULL;
struct sk_enroll_response *response = NULL;
size_t len;
int credprot;
- int internal_uv;
int cose_alg;
int ret = SSH_SK_ERR_GENERAL;
int r;
char *device = NULL;
fido_init(SSH_FIDO_INIT_ARG);
if (enroll_response == NULL) {
skdebug(__func__, "enroll_response == NULL");
goto out;
}
*enroll_response = NULL;
memset(user_id, 0, sizeof(user_id));
if (check_enroll_options(options, &device, user_id,
sizeof(user_id)) != 0)
goto out; /* error already logged */
switch(alg) {
#ifdef WITH_OPENSSL
case SSH_SK_ECDSA:
cose_alg = COSE_ES256;
break;
#endif /* WITH_OPENSSL */
case SSH_SK_ED25519:
cose_alg = COSE_EDDSA;
break;
default:
skdebug(__func__, "unsupported key type %d", alg);
goto out;
}
if (device != NULL)
sk = sk_open(device);
else
- sk = sk_probe(NULL, NULL, 0);
+ sk = sk_probe(NULL, NULL, 0, 0);
if (sk == NULL) {
ret = SSH_SK_ERR_DEVICE_NOT_FOUND;
skdebug(__func__, "failed to find sk");
goto out;
}
skdebug(__func__, "using device %s", sk->path);
+ if ((flags & SSH_SK_RESIDENT_KEY) != 0 &&
+ (flags & SSH_SK_FORCE_OPERATION) == 0 &&
+ (r = key_lookup(sk->dev, application, user_id, sizeof(user_id),
+ pin)) != FIDO_ERR_NO_CREDENTIALS) {
+ if (r != FIDO_OK) {
+ ret = fidoerr_to_skerr(r);
+ skdebug(__func__, "key_lookup failed");
+ } else {
+ ret = SSH_SK_ERR_CREDENTIAL_EXISTS;
+ skdebug(__func__, "key exists");
+ }
+ goto out;
+ }
if ((cred = fido_cred_new()) == NULL) {
skdebug(__func__, "fido_cred_new failed");
goto out;
}
if ((r = fido_cred_set_type(cred, cose_alg)) != FIDO_OK) {
skdebug(__func__, "fido_cred_set_type: %s", fido_strerr(r));
goto out;
}
if ((r = fido_cred_set_clientdata(cred,
challenge, challenge_len)) != FIDO_OK) {
skdebug(__func__, "fido_cred_set_clientdata: %s",
fido_strerr(r));
goto out;
}
if ((r = fido_cred_set_rk(cred, (flags & SSH_SK_RESIDENT_KEY) != 0 ?
FIDO_OPT_TRUE : FIDO_OPT_OMIT)) != FIDO_OK) {
skdebug(__func__, "fido_cred_set_rk: %s", fido_strerr(r));
goto out;
}
if ((r = fido_cred_set_user(cred, user_id, sizeof(user_id),
"openssh", "openssh", NULL)) != FIDO_OK) {
skdebug(__func__, "fido_cred_set_user: %s", fido_strerr(r));
goto out;
}
if ((r = fido_cred_set_rp(cred, application, NULL)) != FIDO_OK) {
skdebug(__func__, "fido_cred_set_rp: %s", fido_strerr(r));
goto out;
}
if ((flags & (SSH_SK_RESIDENT_KEY|SSH_SK_USER_VERIFICATION_REQD)) != 0) {
#if !defined(HAVE_FIDO_DEV_SUPPORTS_CRED_PROT) || \
!defined(HAVE_FIDO_CRED_SET_PROT)
skdebug(__func__, "libfido2 version does not support a feature required for this operation. Please upgrade to >=1.5.0");
ret = SSH_SK_ERR_UNSUPPORTED;
goto out;
credprot = 0; (void)credprot; /* avoid warning */
#endif
if (!fido_dev_supports_cred_prot(sk->dev)) {
skdebug(__func__, "%s does not support credprot, "
"refusing to create unprotected "
"resident/verify-required key", sk->path);
ret = SSH_SK_ERR_UNSUPPORTED;
goto out;
}
if ((flags & SSH_SK_USER_VERIFICATION_REQD))
credprot = FIDO_CRED_PROT_UV_REQUIRED;
else
credprot = FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID;
if ((r = fido_cred_set_prot(cred, credprot)) != FIDO_OK) {
skdebug(__func__, "fido_cred_set_prot: %s",
fido_strerr(r));
ret = fidoerr_to_skerr(r);
goto out;
}
}
if ((r = fido_dev_make_cred(sk->dev, cred, pin)) != FIDO_OK) {
skdebug(__func__, "fido_dev_make_cred: %s", fido_strerr(r));
ret = fidoerr_to_skerr(r);
goto out;
}
if (fido_cred_x5c_ptr(cred) != NULL) {
if ((r = fido_cred_verify(cred)) != FIDO_OK) {
skdebug(__func__, "fido_cred_verify: %s",
fido_strerr(r));
goto out;
}
} else {
skdebug(__func__, "self-attested credential");
if ((r = fido_cred_verify_self(cred)) != FIDO_OK) {
skdebug(__func__, "fido_cred_verify_self: %s",
fido_strerr(r));
goto out;
}
}
if ((response = calloc(1, sizeof(*response))) == NULL) {
skdebug(__func__, "calloc response failed");
goto out;
}
response->flags = flags;
- if ((flags & SSH_SK_USER_VERIFICATION_REQD)) {
- if (check_sk_options(sk->dev, "uv", &internal_uv) == 0 &&
- internal_uv != -1) {
- /* user verification handled by token */
- response->flags &= ~SSH_SK_USER_VERIFICATION_REQD;
- }
- }
if (pack_public_key(alg, cred, response) != 0) {
skdebug(__func__, "pack_public_key failed");
goto out;
}
if ((ptr = fido_cred_id_ptr(cred)) != NULL) {
len = fido_cred_id_len(cred);
if ((response->key_handle = calloc(1, len)) == NULL) {
skdebug(__func__, "calloc key handle failed");
goto out;
}
memcpy(response->key_handle, ptr, len);
response->key_handle_len = len;
}
if ((ptr = fido_cred_sig_ptr(cred)) != NULL) {
len = fido_cred_sig_len(cred);
if ((response->signature = calloc(1, len)) == NULL) {
skdebug(__func__, "calloc signature failed");
goto out;
}
memcpy(response->signature, ptr, len);
response->signature_len = len;
}
if ((ptr = fido_cred_x5c_ptr(cred)) != NULL) {
len = fido_cred_x5c_len(cred);
skdebug(__func__, "attestation cert len=%zu", len);
if ((response->attestation_cert = calloc(1, len)) == NULL) {
skdebug(__func__, "calloc attestation cert failed");
goto out;
}
memcpy(response->attestation_cert, ptr, len);
response->attestation_cert_len = len;
}
if ((ptr = fido_cred_authdata_ptr(cred)) != NULL) {
len = fido_cred_authdata_len(cred);
skdebug(__func__, "authdata len=%zu", len);
if ((response->authdata = calloc(1, len)) == NULL) {
skdebug(__func__, "calloc authdata failed");
goto out;
}
memcpy(response->authdata, ptr, len);
response->authdata_len = len;
}
*enroll_response = response;
response = NULL;
ret = 0;
out:
free(device);
if (response != NULL) {
free(response->public_key);
free(response->key_handle);
free(response->signature);
free(response->attestation_cert);
free(response->authdata);
free(response);
}
sk_close(sk);
fido_cred_free(&cred);
return ret;
}
#ifdef WITH_OPENSSL
static int
pack_sig_ecdsa(fido_assert_t *assert, struct sk_sign_response *response)
{
ECDSA_SIG *sig = NULL;
const BIGNUM *sig_r, *sig_s;
const unsigned char *cp;
size_t sig_len;
int ret = -1;
cp = fido_assert_sig_ptr(assert, 0);
sig_len = fido_assert_sig_len(assert, 0);
if ((sig = d2i_ECDSA_SIG(NULL, &cp, sig_len)) == NULL) {
skdebug(__func__, "d2i_ECDSA_SIG failed");
goto out;
}
ECDSA_SIG_get0(sig, &sig_r, &sig_s);
response->sig_r_len = BN_num_bytes(sig_r);
response->sig_s_len = BN_num_bytes(sig_s);
if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL ||
(response->sig_s = calloc(1, response->sig_s_len)) == NULL) {
skdebug(__func__, "calloc signature failed");
goto out;
}
BN_bn2bin(sig_r, response->sig_r);
BN_bn2bin(sig_s, response->sig_s);
ret = 0;
out:
ECDSA_SIG_free(sig);
if (ret != 0) {
free(response->sig_r);
free(response->sig_s);
response->sig_r = NULL;
response->sig_s = NULL;
}
return ret;
}
#endif /* WITH_OPENSSL */
static int
pack_sig_ed25519(fido_assert_t *assert, struct sk_sign_response *response)
{
const unsigned char *ptr;
size_t len;
int ret = -1;
ptr = fido_assert_sig_ptr(assert, 0);
len = fido_assert_sig_len(assert, 0);
if (len != 64) {
skdebug(__func__, "bad length %zu", len);
goto out;
}
response->sig_r_len = len;
if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL) {
skdebug(__func__, "calloc signature failed");
goto out;
}
memcpy(response->sig_r, ptr, len);
ret = 0;
out:
if (ret != 0) {
free(response->sig_r);
response->sig_r = NULL;
}
return ret;
}
static int
pack_sig(uint32_t alg, fido_assert_t *assert,
struct sk_sign_response *response)
{
switch(alg) {
#ifdef WITH_OPENSSL
case SSH_SK_ECDSA:
return pack_sig_ecdsa(assert, response);
#endif /* WITH_OPENSSL */
case SSH_SK_ED25519:
return pack_sig_ed25519(assert, response);
default:
return -1;
}
}
/* Checks sk_options for sk_sign() and sk_load_resident_keys() */
static int
check_sign_load_resident_options(struct sk_option **options, char **devicep)
{
size_t i;
if (options == NULL)
return 0;
for (i = 0; options[i] != NULL; i++) {
if (strcmp(options[i]->name, "device") == 0) {
if ((*devicep = strdup(options[i]->value)) == NULL) {
skdebug(__func__, "strdup device failed");
return -1;
}
skdebug(__func__, "requested device %s", *devicep);
} else {
skdebug(__func__, "requested unsupported option %s",
options[i]->name);
if (options[i]->required) {
skdebug(__func__, "unknown required option");
return -1;
}
}
}
return 0;
}
int
sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
const char *application,
const uint8_t *key_handle, size_t key_handle_len,
uint8_t flags, const char *pin, struct sk_option **options,
struct sk_sign_response **sign_response)
{
fido_assert_t *assert = NULL;
char *device = NULL;
struct sk_usbhid *sk = NULL;
struct sk_sign_response *response = NULL;
int ret = SSH_SK_ERR_GENERAL, internal_uv;
int r;
fido_init(SSH_FIDO_INIT_ARG);
if (sign_response == NULL) {
skdebug(__func__, "sign_response == NULL");
goto out;
}
*sign_response = NULL;
if (check_sign_load_resident_options(options, &device) != 0)
goto out; /* error already logged */
if (device != NULL)
sk = sk_open(device);
else if (pin != NULL || (flags & SSH_SK_USER_VERIFICATION_REQD))
- sk = sk_probe(NULL, NULL, 0);
+ sk = sk_probe(NULL, NULL, 0, 0);
else
- sk = sk_probe(application, key_handle, key_handle_len);
+ sk = sk_probe(application, key_handle, key_handle_len, 0);
if (sk == NULL) {
ret = SSH_SK_ERR_DEVICE_NOT_FOUND;
skdebug(__func__, "failed to find sk");
goto out;
}
if ((assert = fido_assert_new()) == NULL) {
skdebug(__func__, "fido_assert_new failed");
goto out;
}
if ((r = fido_assert_set_clientdata(assert,
data, datalen)) != FIDO_OK) {
skdebug(__func__, "fido_assert_set_clientdata: %s",
fido_strerr(r));
goto out;
}
if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) {
skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r));
goto out;
}
if ((r = fido_assert_allow_cred(assert, key_handle,
key_handle_len)) != FIDO_OK) {
skdebug(__func__, "fido_assert_allow_cred: %s", fido_strerr(r));
goto out;
}
if ((r = fido_assert_set_up(assert,
(flags & SSH_SK_USER_PRESENCE_REQD) ?
FIDO_OPT_TRUE : FIDO_OPT_FALSE)) != FIDO_OK) {
skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r));
goto out;
}
+ /*
+ * WinHello requests the PIN by default. Make "uv" request explicit
+ * to allow keys with and without -O verify-required to make sense.
+ */
+ if (pin == NULL && fido_dev_is_winhello (sk->dev) &&
+ (r = fido_assert_set_uv(assert, FIDO_OPT_FALSE)) != FIDO_OK) {
+ skdebug(__func__, "fido_assert_set_uv: %s", fido_strerr(r));
+ }
if (pin == NULL && (flags & SSH_SK_USER_VERIFICATION_REQD)) {
if (check_sk_options(sk->dev, "uv", &internal_uv) < 0 ||
internal_uv != 1) {
skdebug(__func__, "check_sk_options uv");
ret = SSH_SK_ERR_PIN_REQUIRED;
goto out;
}
if ((r = fido_assert_set_uv(assert,
FIDO_OPT_TRUE)) != FIDO_OK) {
skdebug(__func__, "fido_assert_set_uv: %s",
fido_strerr(r));
ret = fidoerr_to_skerr(r);
goto out;
}
}
if ((r = fido_dev_get_assert(sk->dev, assert, pin)) != FIDO_OK) {
skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
ret = fidoerr_to_skerr(r);
goto out;
}
if ((response = calloc(1, sizeof(*response))) == NULL) {
skdebug(__func__, "calloc response failed");
goto out;
}
response->flags = fido_assert_flags(assert, 0);
response->counter = fido_assert_sigcount(assert, 0);
if (pack_sig(alg, assert, response) != 0) {
skdebug(__func__, "pack_sig failed");
goto out;
}
*sign_response = response;
response = NULL;
ret = 0;
out:
free(device);
if (response != NULL) {
free(response->sig_r);
free(response->sig_s);
free(response);
}
sk_close(sk);
fido_assert_free(&assert);
return ret;
}
static int
read_rks(struct sk_usbhid *sk, const char *pin,
struct sk_resident_key ***rksp, size_t *nrksp)
{
int ret = SSH_SK_ERR_GENERAL, r = -1, internal_uv;
fido_credman_metadata_t *metadata = NULL;
fido_credman_rp_t *rp = NULL;
fido_credman_rk_t *rk = NULL;
size_t i, j, nrp, nrk, user_id_len;
const fido_cred_t *cred;
const char *rp_id, *rp_name, *user_name;
struct sk_resident_key *srk = NULL, **tmp;
const u_char *user_id;
if (pin == NULL) {
skdebug(__func__, "no PIN specified");
ret = SSH_SK_ERR_PIN_REQUIRED;
goto out;
}
if ((metadata = fido_credman_metadata_new()) == NULL) {
skdebug(__func__, "alloc failed");
goto out;
}
if (check_sk_options(sk->dev, "uv", &internal_uv) != 0) {
skdebug(__func__, "check_sk_options failed");
goto out;
}
if ((r = fido_credman_get_dev_metadata(sk->dev, metadata, pin)) != 0) {
if (r == FIDO_ERR_INVALID_COMMAND) {
skdebug(__func__, "device %s does not support "
"resident keys", sk->path);
ret = 0;
goto out;
}
skdebug(__func__, "get metadata for %s failed: %s",
sk->path, fido_strerr(r));
ret = fidoerr_to_skerr(r);
goto out;
}
skdebug(__func__, "existing %llu, remaining %llu",
(unsigned long long)fido_credman_rk_existing(metadata),
(unsigned long long)fido_credman_rk_remaining(metadata));
if ((rp = fido_credman_rp_new()) == NULL) {
skdebug(__func__, "alloc rp failed");
goto out;
}
if ((r = fido_credman_get_dev_rp(sk->dev, rp, pin)) != 0) {
skdebug(__func__, "get RPs for %s failed: %s",
sk->path, fido_strerr(r));
goto out;
}
nrp = fido_credman_rp_count(rp);
skdebug(__func__, "Device %s has resident keys for %zu RPs",
sk->path, nrp);
/* Iterate over RP IDs that have resident keys */
for (i = 0; i < nrp; i++) {
rp_id = fido_credman_rp_id(rp, i);
rp_name = fido_credman_rp_name(rp, i);
skdebug(__func__, "rp %zu: name=\"%s\" id=\"%s\" hashlen=%zu",
i, rp_name == NULL ? "(none)" : rp_name,
rp_id == NULL ? "(none)" : rp_id,
fido_credman_rp_id_hash_len(rp, i));
/* Skip non-SSH RP IDs */
if (rp_id == NULL ||
strncasecmp(fido_credman_rp_id(rp, i), "ssh:", 4) != 0)
continue;
fido_credman_rk_free(&rk);
if ((rk = fido_credman_rk_new()) == NULL) {
skdebug(__func__, "alloc rk failed");
goto out;
}
if ((r = fido_credman_get_dev_rk(sk->dev,
fido_credman_rp_id(rp, i), rk, pin)) != 0) {
skdebug(__func__, "get RKs for %s slot %zu failed: %s",
sk->path, i, fido_strerr(r));
goto out;
}
nrk = fido_credman_rk_count(rk);
skdebug(__func__, "RP \"%s\" has %zu resident keys",
fido_credman_rp_id(rp, i), nrk);
/* Iterate over resident keys for this RP ID */
for (j = 0; j < nrk; j++) {
if ((cred = fido_credman_rk(rk, j)) == NULL) {
skdebug(__func__, "no RK in slot %zu", j);
continue;
}
if ((user_name = fido_cred_user_name(cred)) == NULL)
user_name = "";
user_id = fido_cred_user_id_ptr(cred);
user_id_len = fido_cred_user_id_len(cred);
skdebug(__func__, "Device %s RP \"%s\" user \"%s\" "
"uidlen %zu slot %zu: type %d flags 0x%02x "
"prot 0x%02x", sk->path, rp_id, user_name,
user_id_len, j, fido_cred_type(cred),
fido_cred_flags(cred), fido_cred_prot(cred));
/* build response entry */
if ((srk = calloc(1, sizeof(*srk))) == NULL ||
(srk->key.key_handle = calloc(1,
fido_cred_id_len(cred))) == NULL ||
(srk->application = strdup(rp_id)) == NULL ||
(user_id_len > 0 &&
(srk->user_id = calloc(1, user_id_len)) == NULL)) {
skdebug(__func__, "alloc sk_resident_key");
goto out;
}
srk->key.key_handle_len = fido_cred_id_len(cred);
memcpy(srk->key.key_handle, fido_cred_id_ptr(cred),
srk->key.key_handle_len);
srk->user_id_len = user_id_len;
if (srk->user_id_len != 0)
memcpy(srk->user_id, user_id, srk->user_id_len);
switch (fido_cred_type(cred)) {
case COSE_ES256:
srk->alg = SSH_SK_ECDSA;
break;
case COSE_EDDSA:
srk->alg = SSH_SK_ED25519;
break;
default:
skdebug(__func__, "unsupported key type %d",
fido_cred_type(cred));
goto out; /* XXX free rk and continue */
}
if (fido_cred_prot(cred) == FIDO_CRED_PROT_UV_REQUIRED
&& internal_uv == -1)
srk->flags |= SSH_SK_USER_VERIFICATION_REQD;
if ((r = pack_public_key(srk->alg, cred,
&srk->key)) != 0) {
skdebug(__func__, "pack public key failed");
goto out;
}
/* append */
if ((tmp = recallocarray(*rksp, *nrksp, (*nrksp) + 1,
sizeof(**rksp))) == NULL) {
skdebug(__func__, "alloc rksp");
goto out;
}
*rksp = tmp;
(*rksp)[(*nrksp)++] = srk;
srk = NULL;
}
}
/* Success */
ret = 0;
out:
if (srk != NULL) {
free(srk->application);
freezero(srk->key.public_key, srk->key.public_key_len);
freezero(srk->key.key_handle, srk->key.key_handle_len);
freezero(srk->user_id, srk->user_id_len);
freezero(srk, sizeof(*srk));
}
fido_credman_rp_free(&rp);
fido_credman_rk_free(&rk);
fido_credman_metadata_free(&metadata);
return ret;
}
int
sk_load_resident_keys(const char *pin, struct sk_option **options,
struct sk_resident_key ***rksp, size_t *nrksp)
{
int ret = SSH_SK_ERR_GENERAL, r = -1;
size_t i, nrks = 0;
struct sk_resident_key **rks = NULL;
struct sk_usbhid *sk = NULL;
char *device = NULL;
*rksp = NULL;
*nrksp = 0;
fido_init(SSH_FIDO_INIT_ARG);
if (check_sign_load_resident_options(options, &device) != 0)
goto out; /* error already logged */
if (device != NULL)
sk = sk_open(device);
else
- sk = sk_probe(NULL, NULL, 0);
+ sk = sk_probe(NULL, NULL, 0, 1);
if (sk == NULL) {
ret = SSH_SK_ERR_DEVICE_NOT_FOUND;
skdebug(__func__, "failed to find sk");
goto out;
}
skdebug(__func__, "trying %s", sk->path);
if ((r = read_rks(sk, pin, &rks, &nrks)) != 0) {
skdebug(__func__, "read_rks failed for %s", sk->path);
ret = r;
goto out;
}
/* success, unless we have no keys but a specific error */
if (nrks > 0 || ret == SSH_SK_ERR_GENERAL)
ret = 0;
*rksp = rks;
*nrksp = nrks;
rks = NULL;
nrks = 0;
out:
sk_close(sk);
for (i = 0; i < nrks; i++) {
free(rks[i]->application);
freezero(rks[i]->key.public_key, rks[i]->key.public_key_len);
freezero(rks[i]->key.key_handle, rks[i]->key.key_handle_len);
freezero(rks[i]->user_id, rks[i]->user_id_len);
freezero(rks[i], sizeof(*rks[i]));
}
+ free(device);
free(rks);
return ret;
}
#endif /* ENABLE_SK_INTERNAL */
diff --git a/ssh-add.0 b/ssh-add.0
index fc2836b93d0c..583aa6fd0b04 100644
--- a/ssh-add.0
+++ b/ssh-add.0
@@ -1,203 +1,203 @@
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] [-H hostkey_file]
[-h destination_constraint] [-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_ecdsa, ~/.ssh/id_ecdsa_sk, ~/.ssh/id_ed25519,
~/.ssh/id_ed25519_sk, and ~/.ssh/id_dsa. 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.
-H hostkey_file
Specifies a known hosts file to look up hostkeys when using
destination-constrained keys via the -h flag. This option may be
specified multiple times to allow multiple files to be searched.
If no files are specified, ssh-add will use the default
ssh_config(5) known hosts files: ~/.ssh/known_hosts,
~/.ssh/known_hosts2, /etc/ssh/ssh_known_hosts, and
/etc/ssh/ssh_known_hosts2.
-h destination_constraint
When adding keys, constrain them to be usable only through
specific hosts or to specific destinations.
Destination constraints of the form M-bM-^@M-^X[user@]dest-hostnameM-bM-^@M-^Y permit
use of the key only from the origin host (the one running
ssh-agent(1)) to the listed destination host, with optional user
name.
Constraints of the form M-bM-^@M-^Xsrc-hostname>[user@]dst-hostnameM-bM-^@M-^Y allow
a key available on a forwarded ssh-agent(1) to be used through a
particular host (as specified by M-bM-^@M-^Xsrc-hostnameM-bM-^@M-^Y) to authenticate
to a further host, specified by M-bM-^@M-^Xdst-hostnameM-bM-^@M-^Y.
Multiple destination constraints may be added when loading keys.
When attempting authentication with a key that has destination
constraints, the whole connection path, including ssh-agent(1)
forwarding, is tested against those constraints and each hop must
be permitted for the attempt to succeed. For example, if key is
forwarded to a remote host, M-bM-^@M-^Xhost-bM-bM-^@M-^Y, and is attempting
authentication to another host, M-bM-^@M-^Xhost-cM-bM-^@M-^Y, then the operation will
be successful only if M-bM-^@M-^Xhost-bM-bM-^@M-^Y was permitted from the origin host
and the subsequent M-bM-^@M-^Xhost-b>host-cM-bM-^@M-^Y hop is also permitted by
destination constraints.
Hosts are identified by their host keys, and are looked up from
known hosts files by ssh-add. Wildcards patterns may be used for
hostnames and certificate host keys are supported. By default,
keys added by ssh-add are not destination constrained.
Destination constraints were added in OpenSSH release 8.9.
Support in both the remote SSH client and server is required when
using destination-constrained keys over a forwarded ssh-agent(1)
channel.
It is also important to note that destination constraints can
only be enforced by ssh-agent(1) when a key is used, or when it
is forwarded by a cooperating ssh(1). Specifically, it does not
prevent an attacker with access to a remote SSH_AUTH_SOCK from
forwarding it again and using it on a different host (but only to
a permitted destination).
-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 7.0 February 4, 2022 OpenBSD 7.0
+OpenBSD 7.1 February 4, 2022 OpenBSD 7.1
diff --git a/ssh-add.c b/ssh-add.c
index 755547748276..777f21e26b01 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -1,1014 +1,1014 @@
-/* $OpenBSD: ssh-add.c,v 1.165 2022/02/04 02:49:17 dtucker Exp $ */
+/* $OpenBSD: ssh-add.c,v 1.166 2022/06/18 02:17:16 dtucker 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"
#include "hostfile.h"
/* argv0 */
extern char *__progname;
/* Default files to add */
static char *default_files[] = {
#ifdef WITH_OPENSSL
_PATH_SSH_CLIENT_ID_RSA,
#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,
_PATH_SSH_CLIENT_ID_DSA,
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);
+ sshkey_type(key), comment ? comment : "no 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 dest_constraint **dest_constraints,
size_t ndest_constraints)
{
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);
} else {
fprintf(stderr,
"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;
}
} 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,
dest_constraints, ndest_constraints)) == 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,
dest_constraints, ndest_constraints)) != 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,
struct dest_constraint **dest_constraints, size_t ndest_constraints)
{
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, dest_constraints, ndest_constraints)) == 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 dest_constraint **dest_constraints, size_t ndest_constraints)
{
struct sshsk_resident_key **srks;
size_t nsrks, i;
struct sshkey *key;
int r, ok = 0;
char *fp;
pass = read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN);
if ((r = sshsk_load_resident(skprovider, NULL, pass, 0,
&srks, &nsrks)) != 0) {
error_r(r, "Unable to load resident keys");
return r;
}
for (i = 0; i < nsrks; i++) {
key = srks[i]->key;
if ((fp = sshkey_fingerprint(key,
fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
fatal_f("sshkey_fingerprint failed");
if ((r = ssh_add_identity_constrained(agent_fd, key, "",
lifetime, confirm, maxsign, skprovider,
dest_constraints, ndest_constraints)) != 0) {
error("Unable to add key %s %s",
sshkey_type(key), fp);
free(fp);
ok = r;
continue;
}
if (ok == 0)
ok = 1;
if (!qflag) {
fprintf(stderr, "Resident identity added: %s %s\n",
sshkey_type(key), 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);
}
sshsk_free_resident_keys(srks, nsrks);
if (nsrks == 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, struct dest_constraint **dest_constraints,
size_t ndest_constraints)
{
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,
dest_constraints, ndest_constraints) == -1)
return -1;
}
return 0;
}
/* Append string 's' to a NULL-terminated array of strings */
static void
stringlist_append(char ***listp, const char *s)
{
size_t i = 0;
if (*listp == NULL)
*listp = xcalloc(2, sizeof(**listp));
else {
for (i = 0; (*listp)[i] != NULL; i++)
; /* count */
*listp = xrecallocarray(*listp, i + 1, i + 2, sizeof(**listp));
}
(*listp)[i] = xstrdup(s);
}
static void
parse_dest_constraint_hop(const char *s, struct dest_constraint_hop *dch,
char **hostkey_files)
{
char *user = NULL, *host, *os, *path;
size_t i;
struct hostkeys *hostkeys;
const struct hostkey_entry *hke;
int r, want_ca;
memset(dch, '\0', sizeof(*dch));
os = xstrdup(s);
if ((host = strchr(os, '@')) == NULL)
host = os;
else {
*host++ = '\0';
user = os;
}
cleanhostname(host);
/* Trivial case: username@ (all hosts) */
if (*host == '\0') {
if (user == NULL) {
fatal("Invalid key destination constraint \"%s\": "
"does not specify user or host", s);
}
dch->user = xstrdup(user);
/* other fields left blank */
free(os);
return;
}
if (hostkey_files == NULL)
fatal_f("no hostkey files");
/* Otherwise we need to look up the keys for this hostname */
hostkeys = init_hostkeys();
for (i = 0; hostkey_files[i]; i++) {
path = tilde_expand_filename(hostkey_files[i], getuid());
debug2_f("looking up host keys for \"%s\" in %s", host, path);
load_hostkeys(hostkeys, host, path, 0);
free(path);
}
dch->user = user == NULL ? NULL : xstrdup(user);
dch->hostname = xstrdup(host);
for (i = 0; i < hostkeys->num_entries; i++) {
hke = hostkeys->entries + i;
want_ca = hke->marker == MRK_CA;
if (hke->marker != MRK_NONE && !want_ca)
continue;
debug3_f("%s%s%s: adding %s %skey from %s:%lu as key %u",
user == NULL ? "": user, user == NULL ? "" : "@",
host, sshkey_type(hke->key), want_ca ? "CA " : "",
hke->file, hke->line, dch->nkeys);
dch->keys = xrecallocarray(dch->keys, dch->nkeys,
dch->nkeys + 1, sizeof(*dch->keys));
dch->key_is_ca = xrecallocarray(dch->key_is_ca, dch->nkeys,
dch->nkeys + 1, sizeof(*dch->key_is_ca));
if ((r = sshkey_from_private(hke->key,
&(dch->keys[dch->nkeys]))) != 0)
fatal_fr(r, "sshkey_from_private");
dch->key_is_ca[dch->nkeys] = want_ca;
dch->nkeys++;
}
if (dch->nkeys == 0)
fatal("No host keys found for destination \"%s\"", host);
free_hostkeys(hostkeys);
free(os);
return;
}
static void
parse_dest_constraint(const char *s, struct dest_constraint ***dcp,
size_t *ndcp, char **hostkey_files)
{
struct dest_constraint *dc;
char *os, *cp;
dc = xcalloc(1, sizeof(*dc));
os = xstrdup(s);
if ((cp = strchr(os, '>')) == NULL) {
/* initial hop; no 'from' hop specified */
parse_dest_constraint_hop(os, &dc->to, hostkey_files);
} else {
/* two hops specified */
*(cp++) = '\0';
parse_dest_constraint_hop(os, &dc->from, hostkey_files);
parse_dest_constraint_hop(cp, &dc->to, hostkey_files);
if (dc->from.user != NULL) {
fatal("Invalid key constraint %s: cannot specify "
"user on 'from' host", os);
}
}
/* XXX eliminate or error on duplicates */
debug2_f("constraint %zu: %s%s%s (%u keys) > %s%s%s (%u keys)", *ndcp,
dc->from.user ? dc->from.user : "", dc->from.user ? "@" : "",
dc->from.hostname ? dc->from.hostname : "(ORIGIN)", dc->from.nkeys,
dc->to.user ? dc->to.user : "", dc->to.user ? "@" : "",
dc->to.hostname ? dc->to.hostname : "(ANY)", dc->to.nkeys);
*dcp = xrecallocarray(*dcp, *ndcp, *ndcp + 1, sizeof(**dcp));
(*dcp)[(*ndcp)++] = dc;
free(os);
}
static void
usage(void)
{
fprintf(stderr,
"usage: ssh-add [-cDdKkLlqvXx] [-E fingerprint_hash] [-H hostkey_file]\n"
" [-h destination_constraint] [-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;
char **dest_constraint_strings = NULL, **hostkey_files = 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;
struct dest_constraint **dest_constraints = NULL;
size_t ndest_constraints = 0;
/* 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:h:H: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 'H':
stringlist_append(&hostkey_files, optarg);
break;
case 'h':
stringlist_append(&dest_constraint_strings, 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
if (hostkey_files == NULL) {
/* use defaults from readconf.c */
stringlist_append(&hostkey_files, _PATH_SSH_USER_HOSTFILE);
stringlist_append(&hostkey_files, _PATH_SSH_USER_HOSTFILE2);
stringlist_append(&hostkey_files, _PATH_SSH_SYSTEM_HOSTFILE);
stringlist_append(&hostkey_files, _PATH_SSH_SYSTEM_HOSTFILE2);
}
if (dest_constraint_strings != NULL) {
for (i = 0; dest_constraint_strings[i] != NULL; i++) {
parse_dest_constraint(dest_constraint_strings[i],
&dest_constraints, &ndest_constraints, hostkey_files);
}
}
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, dest_constraints, ndest_constraints) == -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,
dest_constraints, ndest_constraints) != 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,
dest_constraints, ndest_constraints) == -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,
dest_constraints, ndest_constraints) == -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 80bb9d890dbf..80665b7220d8 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 7.0 March 31, 2022 OpenBSD 7.0
+OpenBSD 7.1 March 31, 2022 OpenBSD 7.1
diff --git a/ssh-agent.c b/ssh-agent.c
index 03ae2b022eed..006ddad94ae1 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,2281 +1,2273 @@
-/* $OpenBSD: ssh-agent.c,v 1.287 2022/01/14 03:43:48 djm Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.292 2022/09/17 10:11:29 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/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"
#include "myproposal.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)
/* Maximum number of recorded session IDs/hostkeys per connection */
#define AGENT_MAX_SESSION_IDS 16
/* Maximum size of session ID */
#define AGENT_MAX_SID_LEN 128
/* Maximum number of destination constraints to accept on a key */
#define AGENT_MAX_DEST_CONSTRAINTS 1024
/* XXX store hostkey_sid in a refcounted tree */
typedef enum {
AUTH_UNUSED = 0,
AUTH_SOCKET = 1,
AUTH_CONNECTION = 2,
} sock_type;
struct hostkey_sid {
struct sshkey *key;
struct sshbuf *sid;
int forwarded;
};
typedef struct socket_entry {
int fd;
sock_type type;
struct sshbuf *input;
struct sshbuf *output;
struct sshbuf *request;
size_t nsession_ids;
struct hostkey_sid *session_ids;
} 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;
struct dest_constraint *dest_constraints;
size_t ndest_constraints;
} 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)
{
size_t i;
close(e->fd);
sshbuf_free(e->input);
sshbuf_free(e->output);
sshbuf_free(e->request);
for (i = 0; i < e->nsession_ids; i++) {
sshkey_free(e->session_ids[i].key);
sshbuf_free(e->session_ids[i].sid);
}
free(e->session_ids);
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_dest_constraint_hop(struct dest_constraint_hop *dch)
{
u_int i;
if (dch == NULL)
return;
free(dch->user);
free(dch->hostname);
for (i = 0; i < dch->nkeys; i++)
sshkey_free(dch->keys[i]);
free(dch->keys);
free(dch->key_is_ca);
}
static void
free_dest_constraints(struct dest_constraint *dcs, size_t ndcs)
{
size_t i;
for (i = 0; i < ndcs; i++) {
free_dest_constraint_hop(&dcs[i].from);
free_dest_constraint_hop(&dcs[i].to);
}
free(dcs);
}
static void
free_identity(Identity *id)
{
sshkey_free(id->key);
free(id->provider);
free(id->comment);
free(id->sk_provider);
free_dest_constraints(id->dest_constraints, id->ndest_constraints);
free(id);
}
/*
* Match 'key' against the key/CA list in a destination constraint hop
* Returns 0 on success or -1 otherwise.
*/
static int
match_key_hop(const char *tag, const struct sshkey *key,
const struct dest_constraint_hop *dch)
{
const char *reason = NULL;
const char *hostname = dch->hostname ? dch->hostname : "(ORIGIN)";
u_int i;
char *fp;
if (key == NULL)
return -1;
/* XXX logspam */
if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
SSH_FP_DEFAULT)) == NULL)
fatal_f("fingerprint failed");
debug3_f("%s: entering hostname %s, requested key %s %s, %u keys avail",
tag, hostname, sshkey_type(key), fp, dch->nkeys);
free(fp);
for (i = 0; i < dch->nkeys; i++) {
if (dch->keys[i] == NULL)
return -1;
/* XXX logspam */
if ((fp = sshkey_fingerprint(dch->keys[i], SSH_FP_HASH_DEFAULT,
SSH_FP_DEFAULT)) == NULL)
fatal_f("fingerprint failed");
debug3_f("%s: key %u: %s%s %s", tag, i,
dch->key_is_ca[i] ? "CA " : "",
sshkey_type(dch->keys[i]), fp);
free(fp);
if (!sshkey_is_cert(key)) {
/* plain key */
if (dch->key_is_ca[i] ||
!sshkey_equal(key, dch->keys[i]))
continue;
return 0;
}
/* certificate */
if (!dch->key_is_ca[i])
continue;
if (key->cert == NULL || key->cert->signature_key == NULL)
return -1; /* shouldn't happen */
if (!sshkey_equal(key->cert->signature_key, dch->keys[i]))
continue;
if (sshkey_cert_check_host(key, hostname, 1,
SSH_ALLOWED_CA_SIGALGS, &reason) != 0) {
debug_f("cert %s / hostname %s rejected: %s",
key->cert->key_id, hostname, reason);
continue;
}
return 0;
}
return -1;
}
/* Check destination constraints on an identity against the hostkey/user */
static int
permitted_by_dest_constraints(const struct sshkey *fromkey,
const struct sshkey *tokey, Identity *id, const char *user,
const char **hostnamep)
{
size_t i;
struct dest_constraint *d;
if (hostnamep != NULL)
*hostnamep = NULL;
for (i = 0; i < id->ndest_constraints; i++) {
d = id->dest_constraints + i;
/* XXX remove logspam */
debug2_f("constraint %zu %s%s%s (%u keys) > %s%s%s (%u keys)",
i, d->from.user ? d->from.user : "",
d->from.user ? "@" : "",
d->from.hostname ? d->from.hostname : "(ORIGIN)",
d->from.nkeys,
d->to.user ? d->to.user : "", d->to.user ? "@" : "",
d->to.hostname ? d->to.hostname : "(ANY)", d->to.nkeys);
/* Match 'from' key */
if (fromkey == NULL) {
/* We are matching the first hop */
if (d->from.hostname != NULL || d->from.nkeys != 0)
continue;
} else if (match_key_hop("from", fromkey, &d->from) != 0)
continue;
/* Match 'to' key */
if (tokey != NULL && match_key_hop("to", tokey, &d->to) != 0)
continue;
/* Match user if specified */
if (d->to.user != NULL && user != NULL &&
!match_pattern(user, d->to.user))
continue;
/* successfully matched this constraint */
if (hostnamep != NULL)
*hostnamep = d->to.hostname;
debug2_f("allowed for hostname %s",
d->to.hostname == NULL ? "*" : d->to.hostname);
return 0;
}
/* no match */
debug2_f("%s identity \"%s\" not permitted for this destination",
sshkey_type(id->key), id->comment);
return -1;
}
/*
* Check whether hostkeys on a SocketEntry and the optionally specified user
* are permitted by the destination constraints on the Identity.
* Returns 0 on success or -1 otherwise.
*/
static int
identity_permitted(Identity *id, SocketEntry *e, char *user,
const char **forward_hostnamep, const char **last_hostnamep)
{
size_t i;
const char **hp;
struct hostkey_sid *hks;
const struct sshkey *fromkey = NULL;
const char *test_user;
char *fp1, *fp2;
/* XXX remove logspam */
debug3_f("entering: key %s comment \"%s\", %zu socket bindings, "
"%zu constraints", sshkey_type(id->key), id->comment,
e->nsession_ids, id->ndest_constraints);
if (id->ndest_constraints == 0)
return 0; /* unconstrained */
if (e->nsession_ids == 0)
return 0; /* local use */
/*
* Walk through the hops recorded by session_id and try to find a
* constraint that satisfies each.
*/
for (i = 0; i < e->nsession_ids; i++) {
hks = e->session_ids + i;
if (hks->key == NULL)
fatal_f("internal error: no bound key");
/* XXX remove logspam */
fp1 = fp2 = NULL;
if (fromkey != NULL &&
(fp1 = sshkey_fingerprint(fromkey, SSH_FP_HASH_DEFAULT,
SSH_FP_DEFAULT)) == NULL)
fatal_f("fingerprint failed");
if ((fp2 = sshkey_fingerprint(hks->key, SSH_FP_HASH_DEFAULT,
SSH_FP_DEFAULT)) == NULL)
fatal_f("fingerprint failed");
debug3_f("socketentry fd=%d, entry %zu %s, "
"from hostkey %s %s to user %s hostkey %s %s",
e->fd, i, hks->forwarded ? "FORWARD" : "AUTH",
fromkey ? sshkey_type(fromkey) : "(ORIGIN)",
fromkey ? fp1 : "", user ? user : "(ANY)",
sshkey_type(hks->key), fp2);
free(fp1);
free(fp2);
/*
* Record the hostnames for the initial forwarding and
* the final destination.
*/
hp = NULL;
if (i == e->nsession_ids - 1)
hp = last_hostnamep;
else if (i == 0)
hp = forward_hostnamep;
/* Special handling for final recorded binding */
test_user = NULL;
if (i == e->nsession_ids - 1) {
/* Can only check user at final hop */
test_user = user;
/*
* user is only presented for signature requests.
* If this is the case, make sure last binding is not
* for a forwarding.
*/
if (hks->forwarded && user != NULL) {
error_f("tried to sign on forwarding hop");
return -1;
}
} else if (!hks->forwarded) {
error_f("tried to forward though signing bind");
return -1;
}
if (permitted_by_dest_constraints(fromkey, hks->key, id,
test_user, hp) != 0)
return -1;
fromkey = hks->key;
}
/*
* Another special case: if the last bound session ID was for a
* forwarding, and this function is not being called to check a sign
* request (i.e. no 'user' supplied), then only permit the key if
* there is a permission that would allow it to be used at another
* destination. This hides keys that are allowed to be used to
* authenticate *to* a host but not permitted for *use* beyond it.
*/
hks = &e->session_ids[e->nsession_ids - 1];
if (hks->forwarded && user == NULL &&
permitted_by_dest_constraints(hks->key, NULL, id,
NULL, NULL) != 0) {
debug3_f("key permitted at host but not after");
return -1;
}
/* success */
return 0;
}
/* 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, *keys;
int r;
u_int nentries = 0;
debug2_f("entering");
if ((msg = sshbuf_new()) == NULL || (keys = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
TAILQ_FOREACH(id, &idtab->idlist, next) {
/* identity not visible, don't include in response */
if (identity_permitted(id, e, NULL, NULL, NULL) != 0)
continue;
if ((r = sshkey_puts_opts(id->key, keys,
SSHKEY_SERIALIZE_INFO)) != 0 ||
(r = sshbuf_put_cstring(keys, id->comment)) != 0) {
error_fr(r, "compose key/comment");
continue;
}
nentries++;
}
debug2_f("replying with %u allowed of %u available keys",
nentries, idtab->nentries);
if ((r = sshbuf_put_u8(msg, SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
(r = sshbuf_put_u32(msg, nentries)) != 0 ||
(r = sshbuf_putb(msg, keys)) != 0)
fatal_fr(r, "compose");
if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
fatal_fr(r, "enqueue");
sshbuf_free(msg);
sshbuf_free(keys);
}
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, session ID and/or hostkey from the request.
*/
static int
parse_userauth_request(struct sshbuf *msg, const struct sshkey *expected_key,
char **userp, struct sshbuf **sess_idp, struct sshkey **hostkeyp)
{
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, *hostkey = NULL;
if (userp != NULL)
*userp = NULL;
if (sess_idp != NULL)
*sess_idp = NULL;
if (hostkeyp != NULL)
*hostkeyp = 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-hostbound-v00@openssh.com") == 0) {
if ((r = sshkey_froms(b, &hostkey)) != 0)
goto out;
} else 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;
}
if (hostkeyp != NULL) {
*hostkeyp = hostkey;
hostkey = NULL;
}
out:
sshbuf_free(b);
sshbuf_free(sess_id);
free(user);
free(service);
free(method);
free(pkalg);
sshkey_free(mkey);
sshkey_free(hostkey);
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, 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;
}
static int
buf_equal(const struct sshbuf *a, const struct sshbuf *b)
{
if (sshbuf_ptr(a) == NULL || sshbuf_ptr(b) == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if (sshbuf_len(a) != sshbuf_len(b))
return SSH_ERR_INVALID_FORMAT;
if (timingsafe_bcmp(sshbuf_ptr(a), sshbuf_ptr(b), sshbuf_len(a)) != 0)
return SSH_ERR_INVALID_FORMAT;
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, retried = 0;
char *fp = NULL, *pin = NULL, *prompt = NULL;
char *user = NULL, *sig_dest = NULL;
const char *fwd_host = NULL, *dest_host = NULL;
struct sshbuf *msg = NULL, *data = NULL, *sid = NULL;
struct sshkey *key = NULL, *hostkey = 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 ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
SSH_FP_DEFAULT)) == NULL)
fatal_f("fingerprint failed");
if (id->ndest_constraints != 0) {
if (e->nsession_ids == 0) {
logit_f("refusing use of destination-constrained key "
"to sign on unbound connection");
goto send;
}
if (parse_userauth_request(data, key, &user, &sid,
&hostkey) != 0) {
logit_f("refusing use of destination-constrained key "
"to sign an unidentified signature");
goto send;
}
/* XXX logspam */
debug_f("user=%s", user);
if (identity_permitted(id, e, user, &fwd_host, &dest_host) != 0)
goto send;
/* XXX display fwd_host/dest_host in askpass UI */
/*
* Ensure that the session ID is the most recent one
* registered on the socket - it should have been bound by
* ssh immediately before userauth.
*/
if (buf_equal(sid,
e->session_ids[e->nsession_ids - 1].sid) != 0) {
error_f("unexpected session ID (%zu listed) on "
"signature request for target user %s with "
"key %s %s", e->nsession_ids, user,
sshkey_type(id->key), fp);
goto send;
}
/*
* Ensure that the hostkey embedded in the signature matches
* the one most recently bound to the socket. An exception is
* made for the initial forwarding hop.
*/
if (e->nsession_ids > 1 && hostkey == NULL) {
error_f("refusing use of destination-constrained key: "
"no hostkey recorded in signature for forwarded "
"connection");
goto send;
}
if (hostkey != NULL && !sshkey_equal(hostkey,
e->session_ids[e->nsession_ids - 1].key)) {
error_f("refusing use of destination-constrained key: "
"mismatch between hostkey in request and most "
"recently bound session");
goto send;
}
xasprintf(&sig_dest, "public key authentication request for "
"user \"%s\" to listed host", user);
}
if (id->confirm && confirm_key(id, sig_dest) != 0) {
verbose_f("user refused key");
goto send;
}
if (sshkey_is_sk(id->key)) {
- if (strncmp(id->key->sk_application, "ssh:", 4) != 0 &&
+ if (restrict_websafe &&
+ 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_VERIFICATION_REQD)) {
- /* XXX include sig_dest */
- xasprintf(&prompt, "Enter PIN%sfor %s key %s: ",
- (id->key->sk_flags & SSH_SK_USER_PRESENCE_REQD) ?
- " and confirm user presence " : " ",
- sshkey_type(id->key), fp);
- pin = read_passphrase(prompt, RP_USE_ASKPASS);
- free(prompt);
- prompt = NULL;
- } else if ((id->key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
+ if (id->key->sk_flags & SSH_SK_USER_PRESENCE_REQD) {
notifier = notify_start(0,
"Confirm user presence for key %s %s%s%s",
sshkey_type(id->key), fp,
sig_dest == NULL ? "" : "\n",
sig_dest == NULL ? "" : sig_dest);
}
}
retry_pin:
if ((r = sshkey_sign(id->key, &signature, &slen,
sshbuf_ptr(data), sshbuf_len(data), agent_decode_alg(key, flags),
id->sk_provider, pin, compat)) != 0) {
debug_fr(r, "sshkey_sign");
if (pin == NULL && !retried && sshkey_is_sk(id->key) &&
r == SSH_ERR_KEY_WRONG_PASSPHRASE) {
- if (notifier) {
- notify_complete(notifier, NULL);
- notifier = NULL;
- }
+ notify_complete(notifier, NULL);
+ notifier = NULL;
/* XXX include sig_dest */
xasprintf(&prompt, "Enter PIN%sfor %s key %s: ",
(id->key->sk_flags & SSH_SK_USER_PRESENCE_REQD) ?
" and confirm user presence " : " ",
sshkey_type(id->key), fp);
pin = read_passphrase(prompt, RP_USE_ASKPASS);
retried = 1;
goto retry_pin;
}
error_fr(r, "sshkey_sign");
goto send;
}
/* Success */
ok = 0;
send:
+ debug_f("good signature");
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(sid);
sshbuf_free(data);
sshbuf_free(msg);
sshkey_free(key);
sshkey_free(hostkey);
free(fp);
free(signature);
free(sig_dest);
free(user);
free(prompt);
if (pin != NULL)
freezero(pin, strlen(pin));
}
/* 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;
}
/* identity not visible, cannot be removed */
if (identity_permitted(id, e, NULL, NULL, NULL) != 0)
goto done; /* error already logged */
/* 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_dest_constraint_hop(struct sshbuf *b, struct dest_constraint_hop *dch)
{
u_char key_is_ca;
size_t elen = 0;
int r;
struct sshkey *k = NULL;
char *fp;
memset(dch, '\0', sizeof(*dch));
if ((r = sshbuf_get_cstring(b, &dch->user, NULL)) != 0 ||
(r = sshbuf_get_cstring(b, &dch->hostname, NULL)) != 0 ||
(r = sshbuf_get_string_direct(b, NULL, &elen)) != 0) {
error_fr(r, "parse");
goto out;
}
if (elen != 0) {
error_f("unsupported extensions (len %zu)", elen);
r = SSH_ERR_FEATURE_UNSUPPORTED;
goto out;
}
if (*dch->hostname == '\0') {
free(dch->hostname);
dch->hostname = NULL;
}
if (*dch->user == '\0') {
free(dch->user);
dch->user = NULL;
}
while (sshbuf_len(b) != 0) {
dch->keys = xrecallocarray(dch->keys, dch->nkeys,
dch->nkeys + 1, sizeof(*dch->keys));
dch->key_is_ca = xrecallocarray(dch->key_is_ca, dch->nkeys,
dch->nkeys + 1, sizeof(*dch->key_is_ca));
if ((r = sshkey_froms(b, &k)) != 0 ||
(r = sshbuf_get_u8(b, &key_is_ca)) != 0)
goto out;
if ((fp = sshkey_fingerprint(k, SSH_FP_HASH_DEFAULT,
SSH_FP_DEFAULT)) == NULL)
fatal_f("fingerprint failed");
debug3_f("%s%s%s: adding %skey %s %s",
dch->user == NULL ? "" : dch->user,
dch->user == NULL ? "" : "@",
dch->hostname, key_is_ca ? "CA " : "", sshkey_type(k), fp);
free(fp);
dch->keys[dch->nkeys] = k;
dch->key_is_ca[dch->nkeys] = key_is_ca != 0;
dch->nkeys++;
k = NULL; /* transferred */
}
/* success */
r = 0;
out:
sshkey_free(k);
return r;
}
static int
parse_dest_constraint(struct sshbuf *m, struct dest_constraint *dc)
{
struct sshbuf *b = NULL, *frombuf = NULL, *tobuf = NULL;
int r;
size_t elen = 0;
debug3_f("entering");
memset(dc, '\0', sizeof(*dc));
if ((r = sshbuf_froms(m, &b)) != 0 ||
(r = sshbuf_froms(b, &frombuf)) != 0 ||
(r = sshbuf_froms(b, &tobuf)) != 0 ||
(r = sshbuf_get_string_direct(b, NULL, &elen)) != 0) {
error_fr(r, "parse");
goto out;
}
if ((r = parse_dest_constraint_hop(frombuf, &dc->from) != 0) ||
(r = parse_dest_constraint_hop(tobuf, &dc->to) != 0))
goto out; /* already logged */
if (elen != 0) {
error_f("unsupported extensions (len %zu)", elen);
r = SSH_ERR_FEATURE_UNSUPPORTED;
goto out;
}
debug2_f("parsed %s (%u keys) > %s%s%s (%u keys)",
dc->from.hostname ? dc->from.hostname : "(ORIGIN)", dc->from.nkeys,
dc->to.user ? dc->to.user : "", dc->to.user ? "@" : "",
dc->to.hostname ? dc->to.hostname : "(ANY)", dc->to.nkeys);
/* check consistency */
if ((dc->from.hostname == NULL) != (dc->from.nkeys == 0) ||
dc->from.user != NULL) {
error_f("inconsistent \"from\" specification");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (dc->to.hostname == NULL || dc->to.nkeys == 0) {
error_f("incomplete \"to\" specification");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* success */
r = 0;
out:
sshbuf_free(b);
sshbuf_free(frombuf);
sshbuf_free(tobuf);
return r;
}
static int
parse_key_constraint_extension(struct sshbuf *m, char **sk_providerp,
struct dest_constraint **dcsp, size_t *ndcsp)
{
char *ext_name = NULL;
int r;
struct sshbuf *b = NULL;
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 if (strcmp(ext_name,
"restrict-destination-v00@openssh.com") == 0) {
if (*dcsp != NULL) {
error_f("%s already set", ext_name);
goto out;
}
if ((r = sshbuf_froms(m, &b)) != 0) {
error_fr(r, "parse %s outer", ext_name);
goto out;
}
while (sshbuf_len(b) != 0) {
if (*ndcsp >= AGENT_MAX_DEST_CONSTRAINTS) {
error_f("too many %s constraints", ext_name);
goto out;
}
*dcsp = xrecallocarray(*dcsp, *ndcsp, *ndcsp + 1,
sizeof(**dcsp));
if ((r = parse_dest_constraint(b,
*dcsp + (*ndcsp)++)) != 0)
goto out; /* error already logged */
}
} else {
error_f("unsupported constraint \"%s\"", ext_name);
r = SSH_ERR_FEATURE_UNSUPPORTED;
goto out;
}
/* success */
r = 0;
out:
free(ext_name);
sshbuf_free(b);
return r;
}
static int
parse_key_constraints(struct sshbuf *m, struct sshkey *k, time_t *deathp,
u_int *secondsp, int *confirmp, char **sk_providerp,
struct dest_constraint **dcsp, size_t *ndcsp)
{
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, dcsp, ndcsp)) != 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 dest_constraint *dest_constraints = NULL;
size_t ndest_constraints = 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, &dest_constraints, &ndest_constraints) != 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 {
/* identity not visible, do not update */
if (identity_permitted(id, e, NULL, NULL, NULL) != 0)
goto out; /* error already logged */
/* key state might have been updated */
sshkey_free(id->key);
free(id->comment);
free(id->sk_provider);
free_dest_constraints(id->dest_constraints,
id->ndest_constraints);
}
/* success */
id->key = k;
id->comment = comment;
id->death = death;
id->confirm = confirm;
id->sk_provider = sk_provider;
id->dest_constraints = dest_constraints;
id->ndest_constraints = ndest_constraints;
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) (destination constraints: %zu)",
sshkey_ssh_name(k), fp, comment, seconds, confirm,
sk_provider == NULL ? "none" : sk_provider, ndest_constraints);
free(fp);
/* transferred */
k = NULL;
comment = NULL;
sk_provider = NULL;
dest_constraints = NULL;
ndest_constraints = 0;
success = 1;
out:
free(sk_provider);
free(comment);
sshkey_free(k);
free_dest_constraints(dest_constraints, ndest_constraints);
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;
struct dest_constraint *dest_constraints = NULL;
size_t ndest_constraints = 0;
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, &dest_constraints, &ndest_constraints) != 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;
id->dest_constraints = dest_constraints;
id->ndest_constraints = ndest_constraints;
dest_constraints = NULL; /* transferred */
ndest_constraints = 0;
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);
free_dest_constraints(dest_constraints, ndest_constraints);
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 */
static int
process_ext_session_bind(SocketEntry *e)
{
int r, sid_match, key_match;
struct sshkey *key = NULL;
struct sshbuf *sid = NULL, *sig = NULL;
char *fp = NULL;
size_t i;
u_char fwd = 0;
debug2_f("entering");
if ((r = sshkey_froms(e->request, &key)) != 0 ||
(r = sshbuf_froms(e->request, &sid)) != 0 ||
(r = sshbuf_froms(e->request, &sig)) != 0 ||
(r = sshbuf_get_u8(e->request, &fwd)) != 0) {
error_fr(r, "parse");
goto out;
}
if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
SSH_FP_DEFAULT)) == NULL)
fatal_f("fingerprint failed");
/* check signature with hostkey on session ID */
if ((r = sshkey_verify(key, sshbuf_ptr(sig), sshbuf_len(sig),
sshbuf_ptr(sid), sshbuf_len(sid), NULL, 0, NULL)) != 0) {
error_fr(r, "sshkey_verify for %s %s", sshkey_type(key), fp);
goto out;
}
/* check whether sid/key already recorded */
for (i = 0; i < e->nsession_ids; i++) {
if (!e->session_ids[i].forwarded) {
error_f("attempt to bind session ID to socket "
"previously bound for authentication attempt");
r = -1;
goto out;
}
sid_match = buf_equal(sid, e->session_ids[i].sid) == 0;
key_match = sshkey_equal(key, e->session_ids[i].key);
if (sid_match && key_match) {
debug_f("session ID already recorded for %s %s",
sshkey_type(key), fp);
r = 0;
goto out;
} else if (sid_match) {
error_f("session ID recorded against different key "
"for %s %s", sshkey_type(key), fp);
r = -1;
goto out;
}
/*
* new sid with previously-seen key can happen, e.g. multiple
* connections to the same host.
*/
}
/* record new key/sid */
if (e->nsession_ids >= AGENT_MAX_SESSION_IDS) {
error_f("too many session IDs recorded");
goto out;
}
e->session_ids = xrecallocarray(e->session_ids, e->nsession_ids,
e->nsession_ids + 1, sizeof(*e->session_ids));
i = e->nsession_ids++;
debug_f("recorded %s %s (slot %zu of %d)", sshkey_type(key), fp, i,
AGENT_MAX_SESSION_IDS);
e->session_ids[i].key = key;
e->session_ids[i].forwarded = fwd != 0;
key = NULL; /* transferred */
/* can't transfer sid; it's refcounted and scoped to request's life */
if ((e->session_ids[i].sid = sshbuf_new()) == NULL)
fatal_f("sshbuf_new");
if ((r = sshbuf_putb(e->session_ids[i].sid, sid)) != 0)
fatal_fr(r, "sshbuf_putb session ID");
/* success */
r = 0;
out:
+ free(fp);
sshkey_free(key);
sshbuf_free(sid);
sshbuf_free(sig);
return r == 0 ? 1 : 0;
}
static void
process_extension(SocketEntry *e)
{
int r, success = 0;
char *name;
debug2_f("entering");
if ((r = sshbuf_get_cstring(e->request, &name, NULL)) != 0) {
error_fr(r, "parse");
goto send;
}
if (strcmp(name, "session-bind@openssh.com") == 0)
success = process_ext_session_bind(e);
else
debug_f("unsupported extension \"%s\"", name);
free(name);
send:
send_status(e, success);
}
/*
* 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 */
case SSH_AGENTC_EXTENSION:
process_extension(e);
break;
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|POLLHUP|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)
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-ed25519.c b/ssh-ed25519.c
index 23419f3c884a..4861628cb524 100644
--- a/ssh-ed25519.c
+++ b/ssh-ed25519.c
@@ -1,160 +1,160 @@
-/* $OpenBSD: ssh-ed25519.c,v 1.9 2020/10/18 11:32:02 djm Exp $ */
+/* $OpenBSD: ssh-ed25519.c,v 1.10 2022/08/26 08:12:56 djm Exp $ */
/*
* Copyright (c) 2013 Markus Friedl <markus@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 <limits.h>
#include "crypto_api.h"
#include <string.h>
#include <stdarg.h>
#include "log.h"
#include "sshbuf.h"
#define SSHKEY_INTERNAL
#include "sshkey.h"
#include "ssherr.h"
#include "ssh.h"
int
ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, u_int compat)
{
u_char *sig = NULL;
size_t slen = 0, len;
unsigned long long smlen;
int r, ret;
struct sshbuf *b = NULL;
if (lenp != NULL)
*lenp = 0;
if (sigp != NULL)
*sigp = NULL;
if (key == NULL ||
sshkey_type_plain(key->type) != KEY_ED25519 ||
key->ed25519_sk == NULL ||
datalen >= INT_MAX - crypto_sign_ed25519_BYTES)
return SSH_ERR_INVALID_ARGUMENT;
smlen = slen = datalen + crypto_sign_ed25519_BYTES;
if ((sig = malloc(slen)) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen,
key->ed25519_sk)) != 0 || smlen <= datalen) {
r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */
goto out;
}
/* encode signature */
if ((b = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_put_cstring(b, "ssh-ed25519")) != 0 ||
(r = sshbuf_put_string(b, sig, smlen - datalen)) != 0)
goto out;
len = sshbuf_len(b);
if (sigp != NULL) {
if ((*sigp = malloc(len)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(*sigp, sshbuf_ptr(b), len);
}
if (lenp != NULL)
*lenp = len;
/* success */
r = 0;
out:
sshbuf_free(b);
- if (sig != NULL)
+ if (sig != NULL)
freezero(sig, slen);
return r;
}
int
ssh_ed25519_verify(const struct sshkey *key,
const u_char *signature, size_t signaturelen,
const u_char *data, size_t datalen, u_int compat)
{
struct sshbuf *b = NULL;
char *ktype = NULL;
const u_char *sigblob;
u_char *sm = NULL, *m = NULL;
size_t len;
unsigned long long smlen = 0, mlen = 0;
int r, ret;
if (key == NULL ||
sshkey_type_plain(key->type) != KEY_ED25519 ||
key->ed25519_pk == NULL ||
datalen >= INT_MAX - crypto_sign_ed25519_BYTES ||
signature == NULL || signaturelen == 0)
return SSH_ERR_INVALID_ARGUMENT;
if ((b = sshbuf_from(signature, signaturelen)) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 ||
(r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0)
goto out;
if (strcmp("ssh-ed25519", ktype) != 0) {
r = SSH_ERR_KEY_TYPE_MISMATCH;
goto out;
}
if (sshbuf_len(b) != 0) {
r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
goto out;
}
if (len > crypto_sign_ed25519_BYTES) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (datalen >= SIZE_MAX - len) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
smlen = len + datalen;
mlen = smlen;
if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(sm, sigblob, len);
memcpy(sm+len, data, datalen);
if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen,
key->ed25519_pk)) != 0) {
debug2_f("crypto_sign_ed25519_open failed: %d", ret);
}
if (ret != 0 || mlen != datalen) {
r = SSH_ERR_SIGNATURE_INVALID;
goto out;
}
/* XXX compare 'm' and 'data' ? */
/* success */
r = 0;
out:
- if (sm != NULL)
+ if (sm != NULL)
freezero(sm, smlen);
- if (m != NULL)
+ if (m != NULL)
freezero(m, smlen); /* NB mlen may be invalid if r != 0 */
sshbuf_free(b);
free(ktype);
return r;
}
diff --git a/ssh-keygen.0 b/ssh-keygen.0
index f81493770585..d171715234a6 100644
--- a/ssh-keygen.0
+++ b/ssh-keygen.0
@@ -1,849 +1,902 @@
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 [-O option] -s signature_file
-f allowed_signers_file
ssh-keygen -Y match-principals -I signer_identity -f allowed_signers_file
ssh-keygen -Y check-novalidate [-O option] -n namespace -s signature_file
ssh-keygen -Y sign [-O option] -f key_file -n namespace file ...
ssh-keygen -Y verify [-O option] -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 Generate host keys of all default key types (rsa, ecdsa, and
+ ed25519) if they do not already exist. The host keys are
+ generated 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. See the CERTIFICATES section for details.
-I certificate_identity
Specify the key identity when signing a public key. 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.
+ authenticator. See the FIDO AUTHENTICATOR section for more
+ information.
-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. 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. This information is potentially sensitive.
- By default, this information is discarded.
+ When generating FIDO authenticator-backed keys, the options
+ listed in the FIDO AUTHENTICATOR section may be specified.
When performing signature-related options using the -Y flag, the
following options are accepted:
hashalg=algorithm
Selects the hash algorithm to use for hashing the message
to be signed. Valid algorithms are M-bM-^@M-^\sha256M-bM-^@M-^] and
M-bM-^@M-^\sha512.M-bM-^@M-^] The default is M-bM-^@M-^\sha512.M-bM-^@M-^]
print-pubkey
Print the full public key to standard output after
signature verification.
verify-time=timestamp
Specifies a time to use when validating signatures
instead of the current time. The time may be specified
- as a date in YYYYMMDD format or a time in
- YYYYMMDDHHMM[SS] format.
+ as a date or time in the YYYYMMDD[Z] or in
+ YYYYMMDDHHMM[SS][Z] formats. Dates and times will be
+ interpreted in the current system time zone unless
+ suffixed with a Z character, which causes them to be
+ interpreted in the UTC time zone.
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. 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 When used in combination with -s or -Y sign, 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).
+ The start time may be specified as:
+ M-bM-^@M-M-bM-^@M-" The string M-bM-^@M-^\alwaysM-bM-^@M-^] to indicate the certificate has no
+ specified start time.
+ M-bM-^@M-M-bM-^@M-" A date or time in the system time zone formatted as YYYYMMDD
+ or YYYYMMDDHHMM[SS].
+ M-bM-^@M-M-bM-^@M-" A date or time in the UTC time zone as YYYYMMDDZ or
+ YYYYMMDDHHMM[SS]Z.
+ M-bM-^@M-M-bM-^@M-" A relative time before the current system time consisting of
+ a minus sign followed by an interval in the format described
+ in the TIME FORMATS section of sshd_config(5).
+ M-bM-^@M-M-bM-^@M-" A raw seconds since epoch (Jan 1 1970 00:00:00 UTC) as a
+ hexadecimal number beginning with M-bM-^@M-^\0xM-bM-^@M-^].
+
+ The end time may be specified similarly to the start time:
+ M-bM-^@M-M-bM-^@M-" The string M-bM-^@M-^\foreverM-bM-^@M-^] to indicate the certificate has no
+ specified end time.
+ M-bM-^@M-M-bM-^@M-" A date or time in the system time zone formatted as YYYYMMDD
+ or YYYYMMDDHHMM[SS].
+ M-bM-^@M-M-bM-^@M-" A date or time in the UTC time zone as YYYYMMDDZ or
+ YYYYMMDDHHMM[SS]Z.
+ M-bM-^@M-M-bM-^@M-" A relative time after the current system time consisting of a
+ plus sign followed by an interval in the format described in
+ the TIME FORMATS section of sshd_config(5).
+ M-bM-^@M-M-bM-^@M-" A raw seconds since epoch (Jan 1 1970 00:00:00 UTC) as a
+ hexadecimal number beginning with M-bM-^@M-^\0xM-bM-^@M-^].
+
+ For example:
+
+ +52w1d Valid from now to 52 weeks and one day from now.
+
+ -4w:+4w
+ Valid from four weeks ago to four weeks from now.
+
+ 20100101123000:20110101123000
+ Valid from 12:30 PM, January 1st, 2010 to 12:30 PM,
+ January 1st, 2011.
+
+ 20100101123000Z:20110101123000Z
+ Similar, but interpreted in the UTC time zone rather than
+ the system time zone.
+
+ -1d:20110101
+ Valid from yesterday to midnight, January 1st, 2011.
+
+ 0x1:0x2000000000
+ Valid from roughly early 1970 to May 2033.
+
+ -1m:forever
+ 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 match-principals
Find principal matching the principal name provided using the -I
flag in the authorized signers file specified using the -f flag.
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.
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). Refer to those manual
pages for details.
+FIDO AUTHENTICATOR
+ ssh-keygen is able to generate FIDO authenticator-backed keys, after
+ which they may be used much like any other key type supported by OpenSSH,
+ so long as the hardware authenticator is attached when the keys are used.
+ FIDO authenticators generally require the user to explicitly authorise
+ operations by touching or tapping them. FIDO keys consist of two parts:
+ a key handle part stored in the private key file on disk, and a per-
+ device private key that is unique to each FIDO authenticator and that
+ cannot be exported from the authenticator hardware. These are combined
+ by the hardware at authentication time to derive the real key that is
+ used to sign authentication challenges. Supported key types are ecdsa-sk
+ and ed25519-sk.
+
+ The options that are valid for FIDO keys 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 authenticator 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 authenticator 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 handle should be stored on the FIDO
+ authenticator itself. This makes it easier to use the
+ authenticator on multiple computers. Resident keys may be
+ supported on FIDO2 authenticators and typically require that a
+ PIN be set on the authenticator prior to generation. Resident
+ keys may be loaded off the authenticator using ssh-add(1).
+ Storing both parts of a key on a FIDO authenticator increases the
+ likelihood of an attacker being able to use a stolen
+ authenticator device.
+
+ 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 authenticators 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 authenticators during key generation. This
+ information is potentially sensitive. By default, this
+ information is discarded.
+
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.
valid-after=timestamp
Indicates that the key is valid for use at or after the specified
- timestamp, which may be a date in YYYYMMDD format or a time in
- YYYYMMDDHHMM[SS] format.
+ timestamp, which may be a date or time in the YYYYMMDD[Z] or
+ YYYYMMDDHHMM[SS][Z] formats. Dates and times will be interpreted
+ in the current system time zone unless suffixed with a Z
+ character, which causes them to be interpreted in the UTC time
+ zone.
valid-before=timestamp
Indicates that the key is valid for use at or before the
specified timestamp.
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 7.0 February 6, 2022 OpenBSD 7.0
+OpenBSD 7.1 September 10, 2022 OpenBSD 7.1
diff --git a/ssh-keygen.1 b/ssh-keygen.1
index 59b7f23a1fa5..8b1f617d2377 100644
--- a/ssh-keygen.1
+++ b/ssh-keygen.1
@@ -1,1264 +1,1334 @@
-.\" $OpenBSD: ssh-keygen.1,v 1.220 2022/02/06 00:29:03 jsg Exp $
+.\" $OpenBSD: ssh-keygen.1,v 1.226 2022/09/10 08:50:53 jsg 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 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.
.\"
-.Dd $Mdocdate: February 6 2022 $
+.Dd $Mdocdate: September 10 2022 $
.Dt SSH-KEYGEN 1
.Os
.Sh NAME
.Nm ssh-keygen
.Nd OpenSSH authentication key utility
.Sh SYNOPSIS
.Nm ssh-keygen
.Op Fl q
.Op Fl a Ar rounds
.Op Fl b Ar bits
.Op Fl C Ar comment
.Op Fl f Ar output_keyfile
.Op Fl m Ar format
.Op Fl N Ar new_passphrase
.Op Fl O Ar option
.Op Fl t Cm dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa
.Op Fl w Ar provider
.Op Fl Z Ar cipher
.Nm ssh-keygen
.Fl p
.Op Fl a Ar rounds
.Op Fl f Ar keyfile
.Op Fl m Ar format
.Op Fl N Ar new_passphrase
.Op Fl P Ar old_passphrase
.Op Fl Z Ar cipher
.Nm ssh-keygen
.Fl i
.Op Fl f Ar input_keyfile
.Op Fl m Ar key_format
.Nm ssh-keygen
.Fl e
.Op Fl f Ar input_keyfile
.Op Fl m Ar key_format
.Nm ssh-keygen
.Fl y
.Op Fl f Ar input_keyfile
.Nm ssh-keygen
.Fl c
.Op Fl a Ar rounds
.Op Fl C Ar comment
.Op Fl f Ar keyfile
.Op Fl P Ar passphrase
.Nm ssh-keygen
.Fl l
.Op Fl v
.Op Fl E Ar fingerprint_hash
.Op Fl f Ar input_keyfile
.Nm ssh-keygen
.Fl B
.Op Fl f Ar input_keyfile
.Nm ssh-keygen
.Fl D Ar pkcs11
.Nm ssh-keygen
.Fl F Ar hostname
.Op Fl lv
.Op Fl f Ar known_hosts_file
.Nm ssh-keygen
.Fl H
.Op Fl f Ar known_hosts_file
.Nm ssh-keygen
.Fl K
.Op Fl a Ar rounds
.Op Fl w Ar provider
.Nm ssh-keygen
.Fl R Ar hostname
.Op Fl f Ar known_hosts_file
.Nm ssh-keygen
.Fl r Ar hostname
.Op Fl g
.Op Fl f Ar input_keyfile
.Nm ssh-keygen
.Fl M Cm generate
.Op Fl O Ar option
.Ar output_file
.Nm ssh-keygen
.Fl M Cm screen
.Op Fl f Ar input_file
.Op Fl O Ar option
.Ar output_file
.Nm ssh-keygen
.Fl I Ar certificate_identity
.Fl s Ar ca_key
.Op Fl hU
.Op Fl D Ar pkcs11_provider
.Op Fl n Ar principals
.Op Fl O Ar option
.Op Fl V Ar validity_interval
.Op Fl z Ar serial_number
.Ar
.Nm ssh-keygen
.Fl L
.Op Fl f Ar input_keyfile
.Nm ssh-keygen
.Fl A
.Op Fl a Ar rounds
.Op Fl f Ar prefix_path
.Nm ssh-keygen
.Fl k
.Fl f Ar krl_file
.Op Fl u
.Op Fl s Ar ca_public
.Op Fl z Ar version_number
.Ar
.Nm ssh-keygen
.Fl Q
.Op Fl l
.Fl f Ar krl_file
.Ar
.Nm ssh-keygen
.Fl Y Cm find-principals
.Op Fl O Ar option
.Fl s Ar signature_file
.Fl f Ar allowed_signers_file
.Nm ssh-keygen
.Fl Y Cm match-principals
.Fl I Ar signer_identity
.Fl f Ar allowed_signers_file
.Nm ssh-keygen
.Fl Y Cm check-novalidate
.Op Fl O Ar option
.Fl n Ar namespace
.Fl s Ar signature_file
.Nm ssh-keygen
.Fl Y Cm sign
.Op Fl O Ar option
.Fl f Ar key_file
.Fl n Ar namespace
.Ar
.Nm ssh-keygen
.Fl Y Cm verify
.Op Fl O Ar option
.Fl f Ar allowed_signers_file
.Fl I Ar signer_identity
.Fl n Ar namespace
.Fl s Ar signature_file
.Op Fl r Ar revocation_file
.Sh DESCRIPTION
.Nm
generates, manages and converts authentication keys for
.Xr ssh 1 .
.Nm
can create keys for use by SSH protocol version 2.
.Pp
The type of key to be generated is specified with the
.Fl t
option.
If invoked without any arguments,
.Nm
will generate an RSA key.
.Pp
.Nm
is also used to generate groups for use in Diffie-Hellman group
exchange (DH-GEX).
See the
.Sx MODULI GENERATION
section for details.
.Pp
Finally,
.Nm
can be used to generate and update Key Revocation Lists, and to test whether
given keys have been revoked by one.
See the
.Sx KEY REVOCATION LISTS
section for details.
.Pp
Normally each user wishing to use SSH
with public key authentication runs this once to create the authentication
key in
.Pa ~/.ssh/id_dsa ,
.Pa ~/.ssh/id_ecdsa ,
.Pa ~/.ssh/id_ecdsa_sk ,
.Pa ~/.ssh/id_ed25519 ,
.Pa ~/.ssh/id_ed25519_sk
or
.Pa ~/.ssh/id_rsa .
Additionally, the system administrator may use this to generate host keys,
as seen in
.Pa /etc/rc .
.Pp
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
.Dq .pub
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
.Fl p
option.
.Pp
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.
.Pp
.Nm
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
.Dq user@host
when the key is created, but can be changed using the
.Fl c
option.
.Pp
It is still possible for
.Nm
to write the previously-used PEM format private keys using the
.Fl 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
.Fl p
(change passphrase) flag.
.Pp
After a key is generated,
.Nm
will ask where the keys
should be placed to be activated.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl 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,
+Generate host keys of all default key types (rsa, ecdsa, and
+ed25519) if they do not already exist.
+The host keys are generated with the default key file path,
an empty passphrase, default bits for the key type, and default comment.
If
.Fl 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
.Pa /etc/rc
to generate new host keys.
.It Fl a Ar rounds
When saving a private key, this option specifies the number of KDF
(key derivation function, currently
.Xr 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.
.It Fl B
Show the bubblebabble digest of specified private or public key file.
.It Fl b Ar 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
.Fl 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
.Fl b
flag will be ignored.
.It Fl C Ar comment
Provides a new comment.
.It Fl 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.
.It Fl D Ar pkcs11
Download the public keys provided by the PKCS#11 shared library
.Ar pkcs11 .
When used in combination with
.Fl s ,
this option indicates that a CA key resides in a PKCS#11 token (see the
.Sx CERTIFICATES
section for details).
.It Fl E Ar fingerprint_hash
Specifies the hash algorithm used when displaying key fingerprints.
Valid options are:
.Dq md5
and
.Dq sha256 .
The default is
.Dq sha256 .
.It Fl 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
.Fl m
option.
The default export format is
.Dq RFC4716 .
This option allows exporting OpenSSH keys for use by other programs, including
several commercial SSH implementations.
.It Fl F Ar hostname | [hostname]:port
Search for the specified
.Ar hostname
(with optional port number)
in a
.Pa 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
.Fl H
option to print found keys in a hashed format.
.It Fl f Ar filename
Specifies the filename of the key file.
.It Fl g
Use generic DNS format when printing fingerprint resource records using the
.Fl r
command.
.It Fl H
Hash a
.Pa 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
.Nm ssh
and
.Nm 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.
.It Fl h
When signing a key, create a host certificate instead of a user
certificate.
See the
.Sx CERTIFICATES
section for details.
.It Fl I Ar certificate_identity
Specify the key identity when signing a public key.
See the
.Sx CERTIFICATES
section for details.
.It Fl i
This option will read an unencrypted private (or public) key file
in the format specified by the
.Fl 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
.Dq RFC4716 .
.It Fl 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.
+See the
+.Sx FIDO AUTHENTICATOR
+section for more information.
.It Fl k
Generate a KRL file.
In this mode,
.Nm
will generate a KRL file at the location specified via the
.Fl 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
.Sx KEY REVOCATION LISTS
section.
.It Fl L
Prints the contents of one or more certificates.
.It Fl l
Show fingerprint of specified public key file.
For RSA and DSA keys
.Nm
tries to find the matching public key file and prints its fingerprint.
If combined with
.Fl v ,
a visual ASCII art representation of the key is supplied with the
fingerprint.
.It Fl M Cm generate
Generate candidate Diffie-Hellman Group Exchange (DH-GEX) parameters for
eventual use by the
.Sq diffie-hellman-group-exchange-*
key exchange methods.
The numbers generated by this operation must be further screened before
use.
See the
.Sx MODULI GENERATION
section for more information.
.It Fl M Cm 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
.Pa /etc/moduli
file.
See the
.Sx MODULI GENERATION
section for more information.
.It Fl m Ar key_format
Specify a key format for key generation, the
.Fl i
(import),
.Fl e
(export) conversion options, and the
.Fl 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:
.Dq RFC4716
(RFC 4716/SSH2 public or private key),
.Dq PKCS8
(PKCS8 public or private key)
or
.Dq PEM
(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
.Dq RFC4716 .
Setting a format of
.Dq PEM
when generating or updating a supported private key type will cause the
key to be stored in the legacy PEM private key format.
.It Fl N Ar new_passphrase
Provides the new passphrase.
.It Fl n Ar 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.
See the
.Sx CERTIFICATES
section for details.
.It Fl O Ar option
Specify a key/value option.
These are specific to the operation that
.Nm
has been requested to perform.
.Pp
When signing certificates, one of the options listed in the
.Sx CERTIFICATES
section may be specified here.
.Pp
When performing moduli generation or screening, one of the options
listed in the
.Sx MODULI GENERATION
section may be specified.
.Pp
-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:
-.Bl -tag -width Ds
-.It Cm application
-Override the default FIDO application/origin string of
-.Dq ssh: .
-This may be useful when generating host or domain-specific resident keys.
-The specified application string must begin with
-.Dq ssh: .
-.It Cm challenge Ns = Ns Ar 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).
-.It Cm device
-Explicitly specify a
-.Xr fido 4
-device to use, rather than letting the token middleware select one.
-.It Cm no-touch-required
-Indicate that the generated private key should not require touch
-events (user presence) when making signatures.
-Note that
-.Xr sshd 8
-will refuse such signatures by default, unless overridden via
-an authorized_keys option.
-.It Cm 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
-.Xr ssh-add 1 .
-.It Cm 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.
-.It Cm 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.
-.It Cm write-attestation Ns = Ns Ar path
-May be used at key generation time to record the attestation data
-returned from FIDO tokens during key generation.
-This information is potentially sensitive.
-By default, this information is discarded.
-.El
+When generating FIDO authenticator-backed keys, the options listed in the
+.Sx FIDO AUTHENTICATOR
+section may be specified.
.Pp
When performing signature-related options using the
.Fl Y
flag, the following options are accepted:
.Bl -tag -width Ds
.It Cm hashalg Ns = Ns Ar algorithm
Selects the hash algorithm to use for hashing the message to be signed.
Valid algorithms are
.Dq sha256
and
.Dq sha512.
The default is
.Dq sha512.
.It Cm print-pubkey
Print the full public key to standard output after signature verification.
.It Cm verify-time Ns = Ns Ar timestamp
Specifies a time to use when validating signatures instead of the current
time.
-The time may be specified as a date in YYYYMMDD format or a time
-in YYYYMMDDHHMM[SS] format.
+The time may be specified as a date or time in the YYYYMMDD[Z] or
+in YYYYMMDDHHMM[SS][Z] formats.
+Dates and times will be interpreted in the current system time zone unless
+suffixed with a Z character, which causes them to be interpreted in the
+UTC time zone.
.El
.Pp
The
.Fl O
option may be specified multiple times.
.It Fl P Ar passphrase
Provides the (old) passphrase.
.It Fl 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.
.It Fl Q
Test whether keys have been revoked in a KRL.
If the
.Fl l
option is also specified then the contents of the KRL will be printed.
.It Fl q
Silence
.Nm ssh-keygen .
.It Fl R Ar hostname | [hostname]:port
Removes all keys belonging to the specified
.Ar hostname
(with optional port number)
from a
.Pa known_hosts
file.
This option is useful to delete hashed hosts (see the
.Fl H
option above).
.It Fl r Ar hostname
Print the SSHFP fingerprint resource record named
.Ar hostname
for the specified public key file.
.It Fl s Ar ca_key
Certify (sign) a public key using the specified CA key.
See the
.Sx CERTIFICATES
section for details.
.Pp
When generating a KRL,
.Fl s
specifies a path to a CA public key file used to revoke certificates directly
by key ID or serial number.
See the
.Sx KEY REVOCATION LISTS
section for details.
.It Fl t Cm dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa
Specifies the type of key to create.
The possible values are
.Dq dsa ,
.Dq ecdsa ,
.Dq ecdsa-sk ,
.Dq ed25519 ,
.Dq ed25519-sk ,
or
.Dq rsa .
.Pp
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
.Dq ssh-rsa
(SHA1 signatures, not recommended),
.Dq rsa-sha2-256 ,
and
.Dq rsa-sha2-512
(the default).
.It Fl U
When used in combination with
-.Fl s ,
+.Fl s
+or
+.Fl Y Cm sign ,
this option indicates that a CA key resides in a
.Xr ssh-agent 1 .
See the
.Sx CERTIFICATES
section for more information.
.It Fl u
Update a KRL.
When specified with
.Fl k ,
keys listed via the command line are added to the existing KRL rather than
a new KRL being created.
.It Fl V Ar 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.
.Pp
-The start time may be specified as the string
+The start time may be specified as:
+.Bl -bullet -compact
+.It
+The string
.Dq always
-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
+to indicate the certificate has no specified start time.
+.It
+A date or time in the system time zone formatted as YYYYMMDD or
+YYYYMMDDHHMM[SS].
+.It
+A date or time in the UTC time zone as YYYYMMDDZ or YYYYMMDDHHMM[SS]Z.
+.It
+A relative time before the current system time consisting of a minus sign
+followed by an interval in the format described in the
TIME FORMATS section of
.Xr sshd_config 5 .
+.It
+A raw seconds since epoch (Jan 1 1970 00:00:00 UTC) as a hexadecimal
+number beginning with
+.Dq 0x .
+.El
.Pp
-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
+The end time may be specified similarly to the start time:
+.Bl -bullet -compact
+.It
+The string
.Dq forever
-to indicate that the certificate has no expiry date.
+to indicate the certificate has no specified end time.
+.It
+A date or time in the system time zone formatted as YYYYMMDD or
+YYYYMMDDHHMM[SS].
+.It
+A date or time in the UTC time zone as YYYYMMDDZ or YYYYMMDDHHMM[SS]Z.
+.It
+A relative time after the current system time consisting of a plus sign
+followed by an interval in the format described in the
+TIME FORMATS section of
+.Xr sshd_config 5 .
+.It
+A raw seconds since epoch (Jan 1 1970 00:00:00 UTC) as a hexadecimal
+number beginning with
+.Dq 0x .
+.El
.Pp
For example:
-.Dq +52w1d
-(valid from now to 52 weeks and one day from now),
-.Dq -4w:+4w
-(valid from four weeks ago to four weeks from now),
-.Dq 20100101123000:20110101123000
-(valid from 12:30 PM, January 1st, 2010 to 12:30 PM, January 1st, 2011),
-.Dq -1d:20110101
-(valid from yesterday to midnight, January 1st, 2011),
-.Dq -1m:forever
-(valid from one minute ago and never expiring).
+.Bl -tag -width Ds
+.It +52w1d
+Valid from now to 52 weeks and one day from now.
+.It -4w:+4w
+Valid from four weeks ago to four weeks from now.
+.It 20100101123000:20110101123000
+Valid from 12:30 PM, January 1st, 2010 to 12:30 PM, January 1st, 2011.
+.It 20100101123000Z:20110101123000Z
+Similar, but interpreted in the UTC time zone rather than the system time zone.
+.It -1d:20110101
+Valid from yesterday to midnight, January 1st, 2011.
+.It 0x1:0x2000000000
+Valid from roughly early 1970 to May 2033.
+.It -1m:forever
+Valid from one minute ago and never expiring.
+.El
.It Fl v
Verbose mode.
Causes
.Nm
to print debugging messages about its progress.
This is helpful for debugging moduli generation.
Multiple
.Fl v
options increase the verbosity.
The maximum is 3.
.It Fl w Ar 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.
.It Fl Y Cm find-principals
Find the principal(s) associated with the public key of a signature,
provided using the
.Fl s
flag in an authorized signers file provided using the
.Fl f
flag.
The format of the allowed signers file is documented in the
.Sx ALLOWED SIGNERS
section below.
If one or more matching principals are found, they are returned on
standard output.
.It Fl Y Cm match-principals
Find principal matching the principal name provided using the
.Fl I
flag in the authorized signers file specified using the
.Fl f
flag.
If one or more matching principals are found, they are returned on
standard output.
.It Fl Y Cm check-novalidate
Checks that a signature generated using
.Nm
.Fl Y Cm sign
has a valid structure.
This does not validate if a signature comes from an authorized signer.
When testing a signature,
.Nm
accepts a message on standard input and a signature namespace using
.Fl n .
A file containing the corresponding signature must also be supplied using the
.Fl s
flag.
Successful testing of the signature is signalled by
.Nm
returning a zero exit status.
.It Fl Y Cm sign
Cryptographically sign a file or some data using a SSH key.
When signing,
.Nm
accepts zero or more files to sign on the command-line - if no files
are specified then
.Nm
will sign data presented on standard input.
Signatures are written to the path of the input file with
.Dq .sig
appended, or to standard output if the message to be signed was read from
standard input.
.Pp
The key used for signing is specified using the
.Fl f
option and may refer to either a private key, or a public key with the private
half available via
.Xr 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
.Fl n
flag.
Namespaces are arbitrary strings, and may include:
.Dq file
for file signing,
.Dq email
for email signing.
For custom uses, it is recommended to use names following a
NAMESPACE@YOUR.DOMAIN pattern to generate unambiguous namespaces.
.It Fl Y Cm verify
Request to verify a signature generated using
.Nm
.Fl Y Cm sign
as described above.
When verifying a signature,
.Nm
accepts a message on standard input and a signature namespace using
.Fl n .
A file containing the corresponding signature must also be supplied using the
.Fl s
flag, along with the identity of the signer using
.Fl I
and a list of allowed signers via the
.Fl f
flag.
The format of the allowed signers file is documented in the
.Sx ALLOWED SIGNERS
section below.
A file containing revoked keys can be passed using the
.Fl 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
.Nm
returning a zero exit status.
.It Fl y
This option will read a private
OpenSSH format file and print an OpenSSH public key to stdout.
.It Fl Z Ar 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
.Qq ssh -Q cipher .
The default is
.Dq aes256-ctr .
.It Fl z Ar serial_number
Specifies a serial number to be embedded in the certificate to distinguish
this certificate from others from the same CA.
If the
.Ar serial_number
is prefixed with a
.Sq +
character, then the serial number will be incremented for each certificate
signed on a single command-line.
The default serial number is zero.
.Pp
When generating a KRL, the
.Fl z
flag is used to specify a KRL version number.
.El
.Sh MODULI GENERATION
.Nm
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).
.Pp
Generation of primes is performed using the
.Fl M Cm generate
option.
The desired length of the primes may be specified by the
.Fl O Cm bits
option.
For example:
.Pp
.Dl # ssh-keygen -M generate -O bits=2048 moduli-2048.candidates
.Pp
By default, the search for primes begins at a random point in the
desired length range.
This may be overridden using the
.Fl O Cm start
option, which specifies a different start point (in hex).
.Pp
Once a set of candidates have been generated, they must be screened for
suitability.
This may be performed using the
.Fl M Cm screen
option.
In this mode
.Nm
will read candidates from standard input (or a file specified using the
.Fl f
option).
For example:
.Pp
.Dl # ssh-keygen -M screen -f moduli-2048.candidates moduli-2048
.Pp
By default, each candidate will be subjected to 100 primality tests.
This may be overridden using the
.Fl O Cm 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
.Fl O Cm generator
option.
Valid generator values are 2, 3, and 5.
.Pp
Screened DH groups may be installed in
.Pa /etc/moduli .
It is important that this file contains moduli of a range of bit lengths.
.Pp
A number of options are available for moduli generation and screening via the
.Fl O
flag:
.Bl -tag -width Ds
.It Ic lines Ns = Ns Ar number
Exit after screening the specified number of lines while performing DH
candidate screening.
.It Ic start-line Ns = Ns Ar line-number
Start screening at the specified line number while performing DH candidate
screening.
.It Ic checkpoint Ns = Ns Ar 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.
.It Ic memory Ns = Ns Ar mbytes
Specify the amount of memory to use (in megabytes) when generating
candidate moduli for DH-GEX.
.It Ic start Ns = Ns Ar hex-value
Specify start point (in hex) when generating candidate moduli for DH-GEX.
.It Ic generator Ns = Ns Ar value
Specify desired generator (in decimal) when testing candidate moduli for DH-GEX.
.El
.Sh CERTIFICATES
.Nm
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
.Xr ssl 8 .
.Pp
.Nm
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:
.Pp
.Dl $ ssh-keygen -s /path/to/ca_key -I key_id /path/to/user_key.pub
.Pp
The resultant certificate will be placed in
.Pa /path/to/user_key-cert.pub .
A host certificate requires the
.Fl h
option:
.Pp
.Dl $ ssh-keygen -s /path/to/ca_key -I key_id -h /path/to/host_key.pub
.Pp
The host certificate will be output to
.Pa /path/to/host_key-cert.pub .
.Pp
It is possible to sign using a CA key stored in a PKCS#11 token by
providing the token library using
.Fl D
and identifying the CA key by providing its public half as an argument
to
.Fl s :
.Pp
.Dl $ ssh-keygen -s ca_key.pub -D libpkcs11.so -I key_id user_key.pub
.Pp
Similarly, it is possible for the CA key to be hosted in a
.Xr ssh-agent 1 .
This is indicated by the
.Fl U
flag and, again, the CA key must be identified by its public half.
.Pp
.Dl $ ssh-keygen -Us ca_key.pub -I key_id user_key.pub
.Pp
In all cases,
.Ar key_id
is a "key identifier" that is logged by the server when the certificate
is used for authentication.
.Pp
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:
.Pp
.Dl $ ssh-keygen -s ca_key -I key_id -n user1,user2 user_key.pub
.Dl "$ ssh-keygen -s ca_key -I key_id -h -n host.domain host_key.pub"
.Pp
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.
.Pp
The options that are valid for user certificates are:
.Pp
.Bl -tag -width Ds -compact
.It Ic clear
Clear all enabled permissions.
This is useful for clearing the default set of permissions so permissions may
be added individually.
.Pp
.It Ic critical : Ns Ar name Ns Op Ns = Ns Ar contents
.It Ic extension : Ns Ar name Ns Op Ns = Ns Ar contents
Includes an arbitrary certificate critical option or extension.
The specified
.Ar name
should include a domain suffix, e.g.\&
.Dq name@example.com .
If
.Ar 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.
.Pp
.It Ic force-command Ns = Ns Ar command
Forces the execution of
.Ar command
instead of any shell or command specified by the user when
the certificate is used for authentication.
.Pp
.It Ic no-agent-forwarding
Disable
.Xr ssh-agent 1
forwarding (permitted by default).
.Pp
.It Ic no-port-forwarding
Disable port forwarding (permitted by default).
.Pp
.It Ic no-pty
Disable PTY allocation (permitted by default).
.Pp
.It Ic no-user-rc
Disable execution of
.Pa ~/.ssh/rc
by
.Xr sshd 8
(permitted by default).
.Pp
.It Ic no-x11-forwarding
Disable X11 forwarding (permitted by default).
.Pp
.It Ic permit-agent-forwarding
Allows
.Xr ssh-agent 1
forwarding.
.Pp
.It Ic permit-port-forwarding
Allows port forwarding.
.Pp
.It Ic permit-pty
Allows PTY allocation.
.Pp
.It Ic permit-user-rc
Allows execution of
.Pa ~/.ssh/rc
by
.Xr sshd 8 .
.Pp
.It Ic permit-X11-forwarding
Allows X11 forwarding.
.Pp
.It Ic 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
.Cm ecdsa-sk
and
.Cm ed25519-sk .
.Pp
.It Ic source-address Ns = Ns Ar address_list
Restrict the source addresses from which the certificate is considered valid.
The
.Ar address_list
is a comma-separated list of one or more address/netmask pairs in CIDR
format.
.Pp
.It Ic 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
.Cm ecdsa-sk
and
.Cm ed25519-sk .
Currently PIN authentication is the only supported verification method,
but other methods may be supported in the future.
.El
.Pp
At present, no standard options are valid for host keys.
.Pp
Finally, certificates may be defined with a validity lifetime.
The
.Fl 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
.Ux
Epoch to the distant future.
.Pp
For certificates to be used for user or host authentication, the CA
public key must be trusted by
.Xr sshd 8
or
.Xr ssh 1 .
Refer to those manual pages for details.
+.Sh FIDO AUTHENTICATOR
+.Nm
+is able to generate FIDO authenticator-backed keys, after which
+they may be used much like any other key type supported by OpenSSH, so
+long as the hardware authenticator is attached when the keys are used.
+FIDO authenticators generally require the user to explicitly authorise
+operations by touching or tapping them.
+FIDO keys consist of two parts: a key handle part stored in the
+private key file on disk, and a per-device private key that is unique
+to each FIDO authenticator and that cannot be exported from the
+authenticator hardware.
+These are combined by the hardware at authentication time to derive
+the real key that is used to sign authentication challenges.
+Supported key types are
+.Cm ecdsa-sk
+and
+.Cm ed25519-sk .
+.Pp
+The options that are valid for FIDO keys are:
+.Bl -tag -width Ds
+.It Cm application
+Override the default FIDO application/origin string of
+.Dq ssh: .
+This may be useful when generating host or domain-specific resident keys.
+The specified application string must begin with
+.Dq ssh: .
+.It Cm challenge Ns = Ns Ar path
+Specifies a path to a challenge string that will be passed to the
+FIDO authenticator 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).
+.It Cm device
+Explicitly specify a
+.Xr fido 4
+device to use, rather than letting the authenticator middleware select one.
+.It Cm no-touch-required
+Indicate that the generated private key should not require touch
+events (user presence) when making signatures.
+Note that
+.Xr sshd 8
+will refuse such signatures by default, unless overridden via
+an authorized_keys option.
+.It Cm resident
+Indicate that the key handle should be stored on the FIDO
+authenticator itself.
+This makes it easier to use the authenticator on multiple computers.
+Resident keys may be supported on FIDO2 authenticators and typically
+require that a PIN be set on the authenticator prior to generation.
+Resident keys may be loaded off the authenticator using
+.Xr ssh-add 1 .
+Storing both parts of a key on a FIDO authenticator increases the likelihood
+of an attacker being able to use a stolen authenticator device.
+.It Cm 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.
+.It Cm verify-required
+Indicate that this private key should require user verification for
+each signature.
+Not all FIDO authenticators support this option.
+Currently PIN authentication is the only supported verification method,
+but other methods may be supported in the future.
+.It Cm write-attestation Ns = Ns Ar path
+May be used at key generation time to record the attestation data
+returned from FIDO authenticators during key generation.
+This information is potentially sensitive.
+By default, this information is discarded.
+.El
.Sh KEY REVOCATION LISTS
.Nm
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.
.Pp
KRLs may be generated using the
.Fl 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).
.Pp
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.
.Bl -tag -width Ds
.It Cm serial : Ar serial_number Ns Op - Ns Ar 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
.Nm
command line using the
.Fl s
option.
.It Cm id : Ar key_id
Revokes a certificate with the specified key ID string.
The CA key must have been specified on the
.Nm
command line using the
.Fl s
option.
.It Cm key : Ar public_key
Revokes the specified key.
If a certificate is listed, then it is revoked as a plain public key.
.It Cm sha1 : Ar public_key
Revokes the specified key by including its SHA1 hash in the KRL.
.It Cm sha256 : Ar 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.
.It Cm hash : Ar fingerprint
Revokes a key using a fingerprint hash, as obtained from a
.Xr sshd 8
authentication log message or the
.Nm
.Fl l
flag.
Only SHA256 fingerprints are supported here and resultant KRLs are
not supported by OpenSSH versions prior to 7.9.
.El
.Pp
KRLs may be updated using the
.Fl u
flag in addition to
.Fl k .
When this option is specified, keys listed via the command line are merged into
the KRL, adding to those already there.
.Pp
It is also possible, given a KRL, to test whether it revokes a particular key
(or keys).
The
.Fl 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
.Nm
will exit with a non-zero exit status.
A zero exit status will only be returned if no key was revoked.
.Sh ALLOWED SIGNERS
When verifying signatures,
.Nm
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
.Xr 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
.Ql #
are ignored as comments.
.Pp
The principals field is a pattern-list (see PATTERNS in
.Xr 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
.Fl I
option must match a principals pattern in order for the corresponding key to be
considered acceptable for verification.
.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 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.
.It Cm namespaces Ns = Ns "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.
.It Cm valid-after Ns = Ns "timestamp"
Indicates that the key is valid for use at or after the specified timestamp,
-which may be a date in YYYYMMDD format or a time in YYYYMMDDHHMM[SS] format.
+which may be a date or time in the YYYYMMDD[Z] or YYYYMMDDHHMM[SS][Z] formats.
+Dates and times will be interpreted in the current system time zone unless
+suffixed with a Z character, which causes them to be interpreted in the UTC
+time zone.
.It Cm valid-before Ns = Ns "timestamp"
Indicates that the key is valid for use at or before the specified timestamp.
.El
.Pp
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.
.Pp
An example allowed signers file:
.Bd -literal -offset 3n
# 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...
.Ed
.Sh ENVIRONMENT
.Bl -tag -width Ds
.It Ev 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.
.El
.Sh FILES
.Bl -tag -width Ds -compact
.It Pa ~/.ssh/id_dsa
.It Pa ~/.ssh/id_ecdsa
.It Pa ~/.ssh/id_ecdsa_sk
.It Pa ~/.ssh/id_ed25519
.It Pa ~/.ssh/id_ed25519_sk
.It Pa ~/.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
.Nm
but it is offered as the default file for the private key.
.Xr ssh 1
will read this file when a login attempt is made.
.Pp
.It Pa ~/.ssh/id_dsa.pub
.It Pa ~/.ssh/id_ecdsa.pub
.It Pa ~/.ssh/id_ecdsa_sk.pub
.It Pa ~/.ssh/id_ed25519.pub
.It Pa ~/.ssh/id_ed25519_sk.pub
.It Pa ~/.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
.Pa ~/.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.
.Pp
.It Pa /etc/moduli
Contains Diffie-Hellman groups used for DH-GEX.
The file format is described in
.Xr moduli 5 .
.El
.Sh SEE ALSO
.Xr ssh 1 ,
.Xr ssh-add 1 ,
.Xr ssh-agent 1 ,
.Xr moduli 5 ,
.Xr sshd 8
.Rs
.%R RFC 4716
.%T "The Secure Shell (SSH) Public Key File Format"
.%D 2006
.Re
.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.
diff --git a/ssh-keygen.c b/ssh-keygen.c
index d62fab3e818a..9b2beda05f0c 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,3868 +1,3932 @@
-/* $OpenBSD: ssh-keygen.c,v 1.450 2022/03/18 02:32:22 djm Exp $ */
+/* $OpenBSD: ssh-keygen.c,v 1.459 2022/08/11 01:56:51 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_REQUIRE_VERIFY (1<<6)
#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) {
+ if ((r = sshkey_sign(key, &sig, &slen, data, sizeof(data),
+ NULL, NULL, NULL, 0)) != 0)
+ error_fr(r, "signing with converted key failed");
+ else if ((r = sshkey_verify(key, sig, slen, data, sizeof(data),
+ NULL, 0, NULL)) != 0)
+ error_fr(r, "verification with converted key failed");
+ if (r != 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);
free(hashed);
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);
+ if ((certflags_flags & CERTOPT_REQUIRE_VERIFY) != 0)
+ cert_ext_add("verify-required", NULL, 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_hex_u64(const char *s, uint64_t *up)
+{
+ char *ep;
+ unsigned long long ull;
+
+ errno = 0;
+ ull = strtoull(s, &ep, 16);
+ if (*s == '\0' || *ep != '\0')
+ fatal("Invalid certificate time: not a number");
+ if (errno == ERANGE && ull == ULONG_MAX)
+ fatal_fr(SSH_ERR_SYSTEM_ERROR, "Invalid certificate time");
+ *up = (uint64_t)ull;
+}
+
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 := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | 0x... | "always"
+ * to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | 0x... | "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 (strncmp(from, "0x", 2) == 0)
+ parse_hex_u64(from, &cert_valid_from);
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 (strncmp(from, "0x", 2) == 0)
+ parse_hex_u64(to, &cert_valid_to);
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 (strcasecmp(opt, "no-verify-required") == 0)
+ certflags_flags &= ~CERTOPT_REQUIRE_VERIFY;
+ else if (strcasecmp(opt, "verify-required") == 0)
+ certflags_flags |= CERTOPT_REQUIRE_VERIFY;
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))) {
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 (in_critical &&
+ strcmp(name, "verify-required") == 0) {
+ printf("\n");
} 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);
static const char * const suffixes[] = { "-cert.pub", ".pub", NULL };
struct sshkey *ret = NULL, *privkey = NULL;
- int r;
+ int r, waspub = 0;
+ struct stat st;
/*
* 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);
+ waspub = 1;
}
- if ((privkey = load_identity(privpath, NULL)) == NULL) {
- error("Couldn't load identity %s", keypath);
- goto done;
- }
+ if (waspub && stat(privpath, &st) != 0 && errno == ENOENT)
+ fatal("No private key found for public key \"%s\"", keypath);
+ if ((r = sshkey_load_private(privpath, "", &privkey, NULL)) != 0 &&
+ (r != SSH_ERR_KEY_WRONG_PASSPHRASE)) {
+ debug_fr(r, "load private key \"%s\"", privpath);
+ fatal("No private key found for \"%s\"", privpath);
+ } else if (privkey == NULL)
+ privkey = load_identity(privpath, NULL);
+
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, const char *hashalg, 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, hashalg, 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_process_opts(char * const *opts, size_t nopts, char **hashalgp,
uint64_t *verify_timep, int *print_pubkey)
{
size_t i;
time_t now;
if (verify_timep != NULL)
*verify_timep = 0;
if (print_pubkey != NULL)
*print_pubkey = 0;
if (hashalgp != NULL)
*hashalgp = NULL;
for (i = 0; i < nopts; i++) {
if (hashalgp != NULL &&
strncasecmp(opts[i], "hashalg=", 8) == 0) {
*hashalgp = xstrdup(opts[i] + 8);
} else if (verify_timep &&
strncasecmp(opts[i], "verify-time=", 12) == 0) {
if (parse_absolute_time(opts[i] + 12,
verify_timep) != 0 || *verify_timep == 0) {
error("Invalid \"verify-time\" option");
return SSH_ERR_INVALID_ARGUMENT;
}
} else if (print_pubkey &&
strcasecmp(opts[i], "print-pubkey") == 0) {
*print_pubkey = 1;
} else {
error("Invalid option \"%s\"", opts[i]);
return SSH_ERR_INVALID_ARGUMENT;
}
}
if (verify_timep && *verify_timep == 0) {
if ((now = time(NULL)) < 0) {
error("Time is before epoch");
return SSH_ERR_INVALID_ARGUMENT;
}
*verify_timep = (uint64_t)now;
}
return 0;
}
static int
-sig_sign(const char *keypath, const char *sig_namespace, int argc, char **argv,
- char * const *opts, size_t nopts)
+sig_sign(const char *keypath, const char *sig_namespace, int require_agent,
+ int argc, char **argv, char * const *opts, size_t nopts)
{
int i, fd = -1, r, ret = -1;
int agent_fd = -1;
struct sshkey *pubkey = NULL, *privkey = NULL, *signkey = NULL;
sshsig_signer *signer = NULL;
char *hashalg = 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 (sig_process_opts(opts, nopts, &hashalg, NULL, NULL) != 0)
goto done; /* error already logged */
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)
+ if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) {
+ if (require_agent)
+ fatal("Couldn't get agent socket");
debug_r(r, "Couldn't get agent socket");
- else {
+ } else {
if ((r = ssh_agent_has_key(agent_fd, pubkey)) == 0)
signer = agent_signer;
- else
+ else {
+ if (require_agent)
+ fatal("Couldn't find key in agent");
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, hashalg, 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,
hashalg, 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);
free(hashalg);
return ret;
}
static int
sig_verify(const char *signature, const char *sig_namespace,
const char *principal, const char *allowed_keys, const char *revoked_keys,
char * const *opts, size_t nopts)
{
int r, ret = -1;
int print_pubkey = 0;
struct sshbuf *sigbuf = NULL, *abuf = NULL;
struct sshkey *sign_key = NULL;
char *fp = NULL;
struct sshkey_sig_details *sig_details = NULL;
uint64_t verify_time = 0;
if (sig_process_opts(opts, nopts, NULL, &verify_time,
&print_pubkey) != 0)
goto done; /* error already logged */
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, verify_time)) != 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);
} else {
printf("Good \"%s\" signature for %s with %s key %s\n",
sig_namespace, principal,
sshkey_type(sign_key), fp);
}
} else {
printf("Could not verify signature.\n");
}
}
/* Print the signature key if requested */
if (ret == 0 && print_pubkey && sign_key != NULL) {
if ((r = sshkey_write(sign_key, stdout)) == 0)
fputc('\n', stdout);
else {
error_r(r, "Could not print public key.\n");
ret = -1;
}
}
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,
char * const *opts, size_t nopts)
{
int r, ret = -1;
struct sshbuf *sigbuf = NULL, *abuf = NULL;
struct sshkey *sign_key = NULL;
char *principals = NULL, *cp, *tmp;
uint64_t verify_time = 0;
if (sig_process_opts(opts, nopts, NULL, &verify_time, NULL) != 0)
goto done; /* error already logged */
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,
verify_time, &principals)) != 0) {
if (r != SSH_ERR_KEY_NOT_FOUND)
error_fr(r, "sshsig_find_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 int
sig_match_principals(const char *allowed_keys, char *principal,
char * const *opts, size_t nopts)
{
int r;
char **principals = NULL;
size_t i, nprincipals = 0;
if ((r = sig_process_opts(opts, nopts, NULL, NULL, NULL)) != 0)
return r; /* error already logged */
if ((r = sshsig_match_principals(allowed_keys, principal,
&principals, &nprincipals)) != 0) {
debug_f("match: %s", ssh_err(r));
fprintf(stderr, "No principal matched.\n");
return r;
}
for (i = 0; i < nprincipals; i++) {
printf("%s\n", principals[i]);
free(principals[i]);
}
free(principals);
return 0;
}
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 */
}
+/* Read and confirm a passphrase */
static char *
-private_key_passphrase(void)
+read_check_passphrase(const char *prompt1, const char *prompt2,
+ const char *retry_prompt)
{
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));
+ for (;;) {
+ passphrase1 = read_passphrase(prompt1, RP_ALLOW_STDIN);
+ passphrase2 = read_passphrase(prompt2, RP_ALLOW_STDIN);
+ if (strcmp(passphrase1, passphrase2) == 0) {
freezero(passphrase2, strlen(passphrase2));
- printf("Passphrases do not match. Try again.\n");
- goto passphrase_again;
+ return passphrase1;
}
- /* Clear the other copy of the passphrase. */
+ /* The passphrases do not match. Clear them and retry. */
+ freezero(passphrase1, strlen(passphrase1));
freezero(passphrase2, strlen(passphrase2));
+ fputs(retry_prompt, stdout);
+ fputc('\n', stdout);
+ fflush(stdout);
}
- return passphrase1;
+ /* NOTREACHED */
+ return NULL;
+}
+
+static char *
+private_key_passphrase(void)
+{
+ if (identity_passphrase)
+ return xstrdup(identity_passphrase);
+ if (identity_new_passphrase)
+ return xstrdup(identity_new_passphrase);
+
+ return read_check_passphrase(
+ "Enter passphrase (empty for no passphrase): ",
+ "Enter same passphrase again: ",
+ "Passphrases do not match. Try again.");
}
static char *
sk_suffix(const char *application, const uint8_t *user, size_t userlen)
{
char *ret, *cp;
size_t slen, i;
/* Trim off URL-like preamble */
if (strncmp(application, "ssh://", 6) == 0)
ret = xstrdup(application + 6);
else if (strncmp(application, "ssh:", 4) == 0)
ret = xstrdup(application + 4);
else
ret = xstrdup(application);
/* Count trailing zeros in user */
for (i = 0; i < userlen; i++) {
if (user[userlen - i - 1] != 0)
break;
}
if (i >= userlen)
return ret; /* user-id was default all-zeros */
/* Append user-id, escaping non-UTF-8 characters */
slen = userlen - i;
if (asmprintf(&cp, INT_MAX, NULL, "%.*s", (int)slen, user) == -1)
fatal_f("asmprintf failed");
/* Don't emit a user-id that contains path or control characters */
if (strchr(cp, '/') != NULL || strstr(cp, "..") != NULL ||
strchr(cp, '\\') != NULL) {
free(cp);
cp = tohex(user, slen);
}
xextendf(&ret, "_", "%s", cp);
free(cp);
return ret;
}
static int
do_download_sk(const char *skprovider, const char *device)
{
struct sshsk_resident_key **srks;
size_t nsrks, i;
int r, ret = -1;
char *fp, *pin = NULL, *pass = NULL, *path, *pubpath;
const char *ext;
struct sshkey *key;
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, 0,
&srks, &nsrks)) != 0) {
if (pin != NULL)
freezero(pin, strlen(pin));
error_r(r, "Unable to load resident keys");
return -1;
}
if (nsrks == 0)
logit("No keys to download");
if (pin != NULL)
freezero(pin, strlen(pin));
for (i = 0; i < nsrks; i++) {
key = srks[i]->key;
if (key->type != KEY_ECDSA_SK && key->type != KEY_ED25519_SK) {
error("Unsupported key type %s (%d)",
sshkey_type(key), key->type);
continue;
}
if ((fp = sshkey_fingerprint(key, fingerprint_hash,
SSH_FP_DEFAULT)) == NULL)
fatal_f("sshkey_fingerprint failed");
debug_f("key %zu: %s %s %s (flags 0x%02x)", i,
sshkey_type(key), fp, key->sk_application, key->sk_flags);
ext = sk_suffix(key->sk_application,
srks[i]->user_id, srks[i]->user_id_len);
xasprintf(&path, "id_%s_rk%s%s",
key->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(key, path, pass,
key->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(key),
*ext != '\0' ? " " : "",
*ext != '\0' ? key->sk_application : "",
path);
}
/* Save public key too */
xasprintf(&pubpath, "%s.pub", path);
free(path);
if ((r = sshkey_save_public(key, pubpath,
key->sk_application)) != 0) {
error_r(r, "Saving public key \"%s\" failed", pubpath);
free(pubpath);
break;
}
free(pubpath);
}
if (i >= nsrks)
ret = 0; /* success */
if (pass != NULL)
freezero(pass, strlen(pass));
sshsk_free_resident_keys(srks, nsrks);
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 int
+confirm_sk_overwrite(const char *application, const char *user)
+{
+ char yesno[3];
+
+ printf("A resident key scoped to '%s' with user id '%s' already "
+ "exists.\n", application == NULL ? "ssh:" : application,
+ user == NULL ? "null" : user);
+ printf("Overwrite key in token (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
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"
#ifdef WITH_OPENSSL
" ssh-keygen -i [-f input_keyfile] [-m key_format]\n"
" ssh-keygen -e [-f input_keyfile] [-m key_format]\n"
#endif
" 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 match-principals -I signer_identity -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 [-O option] ...\n"
" ssh-keygen -Y verify -f allowed_signers_file -I signer_identity\n"
" -n namespace -s signature_file [-r krl_file] [-O option]\n");
exit(1);
}
/*
* Main program for key management.
*/
int
main(int argc, char **argv)
{
- char comment[1024], *passphrase;
+ char comment[1024], *passphrase = NULL;
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");
exit(1);
}
if (!have_identity) {
error("Too few arguments for find-principals:"
"missing allowed keys file");
exit(1);
}
return sig_find_principals(ca_key_path, identity_file,
opts, nopts);
} else if (strncmp(sign_op, "match-principals", 16) == 0) {
if (!have_identity) {
error("Too few arguments for match-principals:"
"missing allowed keys file");
exit(1);
}
if (cert_key_id == NULL) {
error("Too few arguments for match-principals: "
"missing principal ID");
exit(1);
}
return sig_match_principals(identity_file, cert_key_id,
opts, nopts);
} else if (strncmp(sign_op, "sign", 4) == 0) {
/* NB. cert_principals is actually namespace, via -n */
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, opts, nopts);
+ prefer_agent, argc, argv, opts, nopts);
} else if (strncmp(sign_op, "check-novalidate", 16) == 0) {
/* NB. cert_principals is actually namespace, via -n */
if (cert_principals == NULL ||
*cert_principals == '\0') {
error("Too few arguments for check-novalidate: "
"missing namespace");
exit(1);
}
if (ca_key_path == NULL) {
error("Too few arguments for check-novalidate: "
"missing signature file");
exit(1);
}
return sig_verify(ca_key_path, cert_principals,
NULL, NULL, NULL, opts, nopts);
} else if (strncmp(sign_op, "verify", 6) == 0) {
/* NB. cert_principals is actually namespace, via -n */
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 identity");
exit(1);
}
return sig_verify(ca_key_path, cert_principals,
cert_key_id, identity_file, rr_hostname,
opts, nopts);
}
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++) {
+ r = 0;
+ for (i = 0 ;;) {
+ if (!quiet) {
+ printf("You may need to touch your "
+ "authenticator%s to authorize key "
+ "generation.\n",
+ r == 0 ? "" : " again");
+ }
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_BAD_PERMISSIONS &&
+ (sk_flags & SSH_SK_RESIDENT_KEY) != 0 &&
+ (sk_flags & SSH_SK_FORCE_OPERATION) == 0 &&
+ confirm_sk_overwrite(sk_application, sk_user)) {
+ sk_flags |= SSH_SK_FORCE_OPERATION;
+ continue;
+ }
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)
+ 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 7e41755b5375..b3b2a207598e 100644
--- a/ssh-keyscan.0
+++ b/ssh-keyscan.0
@@ -1,96 +1,97 @@
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.
+ possible values are M-bM-^@M-^\dsaM-bM-^@M-^], M-bM-^@M-^\ecdsaM-bM-^@M-^], M-bM-^@M-^\ed25519M-bM-^@M-^], M-bM-^@M-^\ecdsa-skM-bM-^@M-^],
+ M-bM-^@M-^\ed25519-skM-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-^], M-bM-^@M-^\ed25519M-bM-^@M-^], M-bM-^@M-^\ecdsa-skM-bM-^@M-^], and M-bM-^@M-^\ed25519-skM-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 7.0 November 30, 2019 OpenBSD 7.0
+OpenBSD 7.1 June 3, 2022 OpenBSD 7.1
diff --git a/ssh-keyscan.1 b/ssh-keyscan.1
index f9df75d42f1a..4eb0bea09168 100644
--- a/ssh-keyscan.1
+++ b/ssh-keyscan.1
@@ -1,158 +1,162 @@
-.\" $OpenBSD: ssh-keyscan.1,v 1.45 2019/11/30 07:07:59 jmc Exp $
+.\" $OpenBSD: ssh-keyscan.1,v 1.46 2022/06/03 04:00:15 dtucker Exp $
.\"
.\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
.\"
.\" Modification and redistribution in source and binary forms is
.\" permitted provided that due credit is given to the author and the
.\" OpenBSD project by leaving this copyright notice intact.
.\"
-.Dd $Mdocdate: November 30 2019 $
+.Dd $Mdocdate: June 3 2022 $
.Dt SSH-KEYSCAN 1
.Os
.Sh NAME
.Nm ssh-keyscan
.Nd gather SSH public keys from servers
.Sh SYNOPSIS
.Nm ssh-keyscan
.Op Fl 46cDHv
.Op Fl f Ar file
.Op Fl p Ar port
.Op Fl T Ar timeout
.Op Fl t Ar type
.Op Ar host | addrlist namelist
.Sh DESCRIPTION
.Nm
is a utility for gathering the public SSH host keys of a number of
hosts.
It was designed to aid in building and verifying
.Pa ssh_known_hosts
files,
the format of which is documented in
.Xr sshd 8 .
.Nm
provides a minimal interface suitable for use by shell and perl
scripts.
.Pp
.Nm
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
.Xr 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.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl 4
Force
.Nm
to use IPv4 addresses only.
.It Fl 6
Force
.Nm
to use IPv6 addresses only.
.It Fl c
Request certificates from target hosts instead of plain keys.
.It Fl D
Print keys found as SSHFP DNS records.
The default is to print keys in a format usable as a
.Xr ssh 1
.Pa known_hosts
file.
.It Fl f Ar file
Read hosts or
.Dq addrlist namelist
pairs from
.Ar file ,
one per line.
If
.Sq -
is supplied instead of a filename,
.Nm
will read from the standard input.
Input is expected in the format:
.Bd -literal
1.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4
.Ed
.It Fl H
Hash all hostnames and addresses in the output.
Hashed names may be used normally by
.Xr ssh 1
and
.Xr sshd 8 ,
but they do not reveal identifying information should the file's contents
be disclosed.
.It Fl p Ar port
Connect to
.Ar port
on the remote host.
.It Fl T Ar timeout
Set the timeout for connection attempts.
If
.Ar 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.
.It Fl t Ar type
Specify the type of the key to fetch from the scanned hosts.
The possible values are
.Dq dsa ,
.Dq ecdsa ,
.Dq ed25519 ,
+.Dq ecdsa-sk ,
+.Dq ed25519-sk ,
or
.Dq rsa .
Multiple values may be specified by separating them with commas.
The default is to fetch
.Dq rsa ,
.Dq ecdsa ,
+.Dq ed25519 ,
+.Dq ecdsa-sk ,
and
-.Dq ed25519
+.Dq ed25519-sk
keys.
.It Fl v
Verbose mode:
print debugging messages about progress.
.El
.Pp
If an ssh_known_hosts file is constructed using
.Nm
without verifying the keys, users will be vulnerable to
.Em man in the middle
attacks.
On the other hand, if the security model allows such a risk,
.Nm
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.
.Sh FILES
.Pa /etc/ssh/ssh_known_hosts
.Sh EXAMPLES
Print the RSA host key for machine
.Ar hostname :
.Pp
.Dl $ ssh-keyscan -t rsa hostname
.Pp
Find all hosts from the file
.Pa ssh_hosts
which have new or different keys from those in the sorted file
.Pa ssh_known_hosts :
.Bd -literal -offset indent
$ ssh-keyscan -t rsa,dsa,ecdsa,ed25519 -f ssh_hosts | \e
sort -u - ssh_known_hosts | diff ssh_known_hosts -
.Ed
.Sh SEE ALSO
.Xr ssh 1 ,
.Xr sshd 8
.Rs
.%D 2006
.%R RFC 4255
.%T Using DNS to Securely Publish Secure Shell (SSH) Key Fingerprints
.Re
.Sh AUTHORS
.An -nosplit
.An David Mazieres Aq Mt dm@lcs.mit.edu
wrote the initial version, and
.An Wayne Davison Aq Mt wayned@users.sourceforge.net
added support for protocol version 2.
diff --git a/ssh-keyscan.c b/ssh-keyscan.c
index d29a03b4e68a..d7283136c7d2 100644
--- a/ssh-keyscan.c
+++ b/ssh-keyscan.c
@@ -1,822 +1,836 @@
-/* $OpenBSD: ssh-keyscan.c,v 1.145 2022/01/21 00:53:40 deraadt Exp $ */
+/* $OpenBSD: ssh-keyscan.c,v 1.146 2022/08/19 04:02:46 dtucker Exp $ */
/*
* Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
*
* Modification and redistribution in source and binary forms is
* permitted provided that due credit is given to the author and the
* OpenBSD project by leaving this copyright notice intact.
*/
#include "includes.h"
#include <sys/types.h>
#include "openbsd-compat/sys-queue.h"
#include <sys/resource.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef WITH_OPENSSL
#include <openssl/bn.h>
#endif
#include <netdb.h>
#include <errno.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include "xmalloc.h"
#include "ssh.h"
#include "sshbuf.h"
#include "sshkey.h"
#include "cipher.h"
#include "kex.h"
#include "compat.h"
#include "myproposal.h"
#include "packet.h"
#include "dispatch.h"
#include "log.h"
#include "atomicio.h"
#include "misc.h"
#include "hostfile.h"
#include "ssherr.h"
#include "ssh_api.h"
#include "dns.h"
/* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
Default value is AF_UNSPEC means both IPv4 and IPv6. */
int IPv4or6 = AF_UNSPEC;
int ssh_port = SSH_DEFAULT_PORT;
#define KT_DSA (1)
#define KT_RSA (1<<1)
#define KT_ECDSA (1<<2)
#define KT_ED25519 (1<<3)
#define KT_XMSS (1<<4)
#define KT_ECDSA_SK (1<<5)
#define KT_ED25519_SK (1<<6)
#define KT_MIN KT_DSA
#define KT_MAX KT_ED25519_SK
int get_cert = 0;
int get_keytypes = KT_RSA|KT_ECDSA|KT_ED25519|KT_ECDSA_SK|KT_ED25519_SK;
int hash_hosts = 0; /* Hash hostname on output */
int print_sshfp = 0; /* Print SSHFP records instead of known_hosts */
int found_one = 0; /* Successfully found a key */
#define MAXMAXFD 256
/* The number of seconds after which to give up on a TCP connection */
int timeout = 5;
int maxfd;
#define MAXCON (maxfd - 10)
extern char *__progname;
struct pollfd *read_wait;
int ncon;
/*
* Keep a connection structure for each file descriptor. The state
* associated with file descriptor n is held in fdcon[n].
*/
typedef struct Connection {
u_char c_status; /* State of connection on this file desc. */
#define CS_UNUSED 0 /* File descriptor unused */
#define CS_CON 1 /* Waiting to connect/read greeting */
#define CS_SIZE 2 /* Waiting to read initial packet size */
#define CS_KEYS 3 /* Waiting to read public key packet */
int c_fd; /* Quick lookup: c->c_fd == c - fdcon */
int c_plen; /* Packet length field for ssh packet */
int c_len; /* Total bytes which must be read. */
int c_off; /* Length of data read so far. */
int c_keytype; /* Only one of KT_* */
sig_atomic_t c_done; /* SSH2 done */
char *c_namebase; /* Address to free for c_name and c_namelist */
char *c_name; /* Hostname of connection for errors */
char *c_namelist; /* Pointer to other possible addresses */
char *c_output_name; /* Hostname of connection for output */
char *c_data; /* Data read from this fd */
struct ssh *c_ssh; /* SSH-connection */
struct timespec c_ts; /* Time at which connection gets aborted */
TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */
} con;
TAILQ_HEAD(conlist, Connection) tq; /* Timeout Queue */
con *fdcon;
static void keyprint(con *c, struct sshkey *key);
static int
fdlim_get(int hard)
{
#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
struct rlimit rlfd;
if (getrlimit(RLIMIT_NOFILE, &rlfd) == -1)
return (-1);
if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY)
return SSH_SYSFDMAX;
else
return hard ? rlfd.rlim_max : rlfd.rlim_cur;
#else
return SSH_SYSFDMAX;
#endif
}
static int
fdlim_set(int lim)
{
#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
struct rlimit rlfd;
#endif
if (lim <= 0)
return (-1);
#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
if (getrlimit(RLIMIT_NOFILE, &rlfd) == -1)
return (-1);
rlfd.rlim_cur = lim;
if (setrlimit(RLIMIT_NOFILE, &rlfd) == -1)
return (-1);
#elif defined (HAVE_SETDTABLESIZE)
setdtablesize(lim);
#endif
return (0);
}
/*
* This is an strsep function that returns a null field for adjacent
* separators. This is the same as the 4.4BSD strsep, but different from the
* one in the GNU libc.
*/
static char *
xstrsep(char **str, const char *delim)
{
char *s, *e;
if (!**str)
return (NULL);
s = *str;
e = s + strcspn(s, delim);
if (*e != '\0')
*e++ = '\0';
*str = e;
return (s);
}
/*
* Get the next non-null token (like GNU strsep). Strsep() will return a
* null token for two adjacent separators, so we may have to loop.
*/
static char *
strnnsep(char **stringp, char *delim)
{
char *tok;
do {
tok = xstrsep(stringp, delim);
} while (tok && *tok == '\0');
return (tok);
}
static int
key_print_wrapper(struct sshkey *hostkey, struct ssh *ssh)
{
con *c;
if ((c = ssh_get_app_data(ssh)) != NULL)
keyprint(c, hostkey);
/* always abort key exchange */
return -1;
}
static int
ssh2_capable(int remote_major, int remote_minor)
{
switch (remote_major) {
case 1:
if (remote_minor == 99)
return 1;
break;
case 2:
return 1;
default:
break;
}
return 0;
}
static void
keygrab_ssh2(con *c)
{
char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
int r;
switch (c->c_keytype) {
case KT_DSA:
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
"ssh-dss-cert-v01@openssh.com" : "ssh-dss";
break;
case KT_RSA:
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
"rsa-sha2-512-cert-v01@openssh.com,"
"rsa-sha2-256-cert-v01@openssh.com,"
"ssh-rsa-cert-v01@openssh.com" :
"rsa-sha2-512,"
"rsa-sha2-256,"
"ssh-rsa";
break;
case KT_ED25519:
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
"ssh-ed25519-cert-v01@openssh.com" : "ssh-ed25519";
break;
case KT_XMSS:
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
"ssh-xmss-cert-v01@openssh.com" : "ssh-xmss@openssh.com";
break;
case KT_ECDSA:
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
"ecdsa-sha2-nistp256-cert-v01@openssh.com,"
"ecdsa-sha2-nistp384-cert-v01@openssh.com,"
"ecdsa-sha2-nistp521-cert-v01@openssh.com" :
"ecdsa-sha2-nistp256,"
"ecdsa-sha2-nistp384,"
"ecdsa-sha2-nistp521";
break;
case KT_ECDSA_SK:
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
"sk-ecdsa-sha2-nistp256-cert-v01@openssh.com" :
"sk-ecdsa-sha2-nistp256@openssh.com";
break;
case KT_ED25519_SK:
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
"sk-ssh-ed25519-cert-v01@openssh.com" :
"sk-ssh-ed25519@openssh.com";
break;
default:
fatal("unknown key type %d", c->c_keytype);
break;
}
if ((r = kex_setup(c->c_ssh, myproposal)) != 0) {
free(c->c_ssh);
fprintf(stderr, "kex_setup: %s\n", ssh_err(r));
exit(1);
}
#ifdef WITH_OPENSSL
c->c_ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_client;
c->c_ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_client;
c->c_ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_client;
c->c_ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_client;
c->c_ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_client;
c->c_ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
c->c_ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
# ifdef OPENSSL_HAS_ECC
c->c_ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client;
# endif
#endif
c->c_ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
c->c_ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client;
ssh_set_verify_host_key_callback(c->c_ssh, key_print_wrapper);
/*
* do the key-exchange until an error occurs or until
* the key_print_wrapper() callback sets c_done.
*/
ssh_dispatch_run(c->c_ssh, DISPATCH_BLOCK, &c->c_done);
}
static void
keyprint_one(const char *host, struct sshkey *key)
{
char *hostport = NULL, *hashed = NULL;
const char *known_host;
found_one = 1;
if (print_sshfp) {
export_dns_rr(host, key, stdout, 0);
return;
}
hostport = put_host_port(host, ssh_port);
lowercase(hostport);
if (hash_hosts && (hashed = host_hash(hostport, NULL, 0)) == NULL)
fatal("host_hash failed");
known_host = hash_hosts ? hashed : hostport;
if (!get_cert)
fprintf(stdout, "%s ", known_host);
sshkey_write(key, stdout);
fputs("\n", stdout);
free(hashed);
free(hostport);
}
static void
keyprint(con *c, struct sshkey *key)
{
char *hosts = c->c_output_name ? c->c_output_name : c->c_name;
char *host, *ohosts;
if (key == NULL)
return;
if (get_cert || (!hash_hosts && ssh_port == SSH_DEFAULT_PORT)) {
keyprint_one(hosts, key);
return;
}
ohosts = hosts = xstrdup(hosts);
while ((host = strsep(&hosts, ",")) != NULL)
keyprint_one(host, key);
free(ohosts);
}
static int
tcpconnect(char *host)
{
struct addrinfo hints, *ai, *aitop;
char strport[NI_MAXSERV];
int gaierr, s = -1;
snprintf(strport, sizeof strport, "%d", ssh_port);
memset(&hints, 0, sizeof(hints));
hints.ai_family = IPv4or6;
hints.ai_socktype = SOCK_STREAM;
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {
error("getaddrinfo %s: %s", host, ssh_gai_strerror(gaierr));
return -1;
}
for (ai = aitop; ai; ai = ai->ai_next) {
s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (s == -1) {
error("socket: %s", strerror(errno));
continue;
}
if (set_nonblock(s) == -1)
fatal_f("set_nonblock(%d)", s);
if (connect(s, ai->ai_addr, ai->ai_addrlen) == -1 &&
errno != EINPROGRESS)
error("connect (`%s'): %s", host, strerror(errno));
else
break;
close(s);
s = -1;
}
freeaddrinfo(aitop);
return s;
}
static int
conalloc(char *iname, char *oname, int keytype)
{
char *namebase, *name, *namelist;
int s;
namebase = namelist = xstrdup(iname);
do {
name = xstrsep(&namelist, ",");
if (!name) {
free(namebase);
return (-1);
}
} while ((s = tcpconnect(name)) < 0);
if (s >= maxfd)
fatal("conalloc: fdno %d too high", s);
if (fdcon[s].c_status)
fatal("conalloc: attempt to reuse fdno %d", s);
debug3_f("oname %s kt %d", oname, keytype);
fdcon[s].c_fd = s;
fdcon[s].c_status = CS_CON;
fdcon[s].c_namebase = namebase;
fdcon[s].c_name = name;
fdcon[s].c_namelist = namelist;
fdcon[s].c_output_name = xstrdup(oname);
fdcon[s].c_data = (char *) &fdcon[s].c_plen;
fdcon[s].c_len = 4;
fdcon[s].c_off = 0;
fdcon[s].c_keytype = keytype;
monotime_ts(&fdcon[s].c_ts);
fdcon[s].c_ts.tv_sec += timeout;
TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
read_wait[s].fd = s;
read_wait[s].events = POLLIN;
ncon++;
return (s);
}
static void
confree(int s)
{
if (s >= maxfd || fdcon[s].c_status == CS_UNUSED)
fatal("confree: attempt to free bad fdno %d", s);
free(fdcon[s].c_namebase);
free(fdcon[s].c_output_name);
if (fdcon[s].c_status == CS_KEYS)
free(fdcon[s].c_data);
fdcon[s].c_status = CS_UNUSED;
fdcon[s].c_keytype = 0;
if (fdcon[s].c_ssh) {
ssh_packet_close(fdcon[s].c_ssh);
free(fdcon[s].c_ssh);
fdcon[s].c_ssh = NULL;
} else
close(s);
TAILQ_REMOVE(&tq, &fdcon[s], c_link);
read_wait[s].fd = -1;
read_wait[s].events = 0;
ncon--;
}
static void
contouch(int s)
{
TAILQ_REMOVE(&tq, &fdcon[s], c_link);
monotime_ts(&fdcon[s].c_ts);
fdcon[s].c_ts.tv_sec += timeout;
TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
}
static int
conrecycle(int s)
{
con *c = &fdcon[s];
int ret;
ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype);
confree(s);
return (ret);
}
static void
congreet(int s)
{
int n = 0, remote_major = 0, remote_minor = 0;
char buf[256], *cp;
char remote_version[sizeof buf];
size_t bufsiz;
con *c = &fdcon[s];
/* send client banner */
n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n",
PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2);
if (n < 0 || (size_t)n >= sizeof(buf)) {
error("snprintf: buffer too small");
confree(s);
return;
}
if (atomicio(vwrite, s, buf, n) != (size_t)n) {
error("write (%s): %s", c->c_name, strerror(errno));
confree(s);
return;
}
+ /*
+ * Read the server banner as per RFC4253 section 4.2. The "SSH-"
+ * protocol identification string may be preceeded by an arbitarily
+ * large banner which we must read and ignore. Loop while reading
+ * newline-terminated lines until we have one starting with "SSH-".
+ * The ID string cannot be longer than 255 characters although the
+ * preceeding banner lines may (in which case they'll be discarded
+ * in multiple iterations of the outer loop).
+ */
for (;;) {
memset(buf, '\0', sizeof(buf));
bufsiz = sizeof(buf);
cp = buf;
while (bufsiz-- &&
(n = atomicio(read, s, cp, 1)) == 1 && *cp != '\n') {
if (*cp == '\r')
*cp = '\n';
cp++;
}
if (n != 1 || strncmp(buf, "SSH-", 4) == 0)
break;
}
if (n == 0) {
switch (errno) {
case EPIPE:
error("%s: Connection closed by remote host", c->c_name);
break;
case ECONNREFUSED:
break;
default:
error("read (%s): %s", c->c_name, strerror(errno));
break;
}
conrecycle(s);
return;
}
+ if (cp >= buf + sizeof(buf)) {
+ error("%s: greeting exceeds allowable length", c->c_name);
+ confree(s);
+ return;
+ }
if (*cp != '\n' && *cp != '\r') {
error("%s: bad greeting", c->c_name);
confree(s);
return;
}
*cp = '\0';
if ((c->c_ssh = ssh_packet_set_connection(NULL, s, s)) == NULL)
fatal("ssh_packet_set_connection failed");
ssh_packet_set_timeout(c->c_ssh, timeout, 1);
ssh_set_app_data(c->c_ssh, c); /* back link */
c->c_ssh->compat = 0;
if (sscanf(buf, "SSH-%d.%d-%[^\n]\n",
&remote_major, &remote_minor, remote_version) == 3)
compat_banner(c->c_ssh, remote_version);
if (!ssh2_capable(remote_major, remote_minor)) {
debug("%s doesn't support ssh2", c->c_name);
confree(s);
return;
}
fprintf(stderr, "%c %s:%d %s\n", print_sshfp ? ';' : '#',
c->c_name, ssh_port, chop(buf));
keygrab_ssh2(c);
confree(s);
}
static void
conread(int s)
{
con *c = &fdcon[s];
size_t n;
if (c->c_status == CS_CON) {
congreet(s);
return;
}
n = atomicio(read, s, c->c_data + c->c_off, c->c_len - c->c_off);
if (n == 0) {
error("read (%s): %s", c->c_name, strerror(errno));
confree(s);
return;
}
c->c_off += n;
if (c->c_off == c->c_len)
switch (c->c_status) {
case CS_SIZE:
c->c_plen = htonl(c->c_plen);
c->c_len = c->c_plen + 8 - (c->c_plen & 7);
c->c_off = 0;
c->c_data = xmalloc(c->c_len);
c->c_status = CS_KEYS;
break;
default:
fatal("conread: invalid status %d", c->c_status);
break;
}
contouch(s);
}
static void
conloop(void)
{
struct timespec seltime, now;
con *c;
int i;
monotime_ts(&now);
c = TAILQ_FIRST(&tq);
if (c && timespeccmp(&c->c_ts, &now, >))
timespecsub(&c->c_ts, &now, &seltime);
else
timespecclear(&seltime);
while (ppoll(read_wait, maxfd, &seltime, NULL) == -1) {
if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)
continue;
error("poll error");
}
for (i = 0; i < maxfd; i++) {
if (read_wait[i].revents & (POLLHUP|POLLERR|POLLNVAL))
confree(i);
else if (read_wait[i].revents & (POLLIN|POLLHUP))
conread(i);
}
c = TAILQ_FIRST(&tq);
while (c && timespeccmp(&c->c_ts, &now, <)) {
int s = c->c_fd;
c = TAILQ_NEXT(c, c_link);
conrecycle(s);
}
}
static void
do_host(char *host)
{
char *name = strnnsep(&host, " \t\n");
int j;
if (name == NULL)
return;
for (j = KT_MIN; j <= KT_MAX; j *= 2) {
if (get_keytypes & j) {
while (ncon >= MAXCON)
conloop();
conalloc(name, *host ? host : name, j);
}
}
}
void
sshfatal(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);
cleanup_exit(255);
}
static void
usage(void)
{
fprintf(stderr,
"usage: %s [-46cDHv] [-f file] [-p port] [-T timeout] [-t type]\n"
"\t\t [host | addrlist namelist]\n",
__progname);
exit(1);
}
int
main(int argc, char **argv)
{
int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO;
int opt, fopt_count = 0, j;
char *tname, *cp, *line = NULL;
size_t linesize = 0;
FILE *fp;
extern int optind;
extern char *optarg;
__progname = ssh_get_progname(argv[0]);
seed_rng();
TAILQ_INIT(&tq);
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
sanitise_stdfd();
if (argc <= 1)
usage();
while ((opt = getopt(argc, argv, "cDHv46p:T:t:f:")) != -1) {
switch (opt) {
case 'H':
hash_hosts = 1;
break;
case 'c':
get_cert = 1;
break;
case 'D':
print_sshfp = 1;
break;
case 'p':
ssh_port = a2port(optarg);
if (ssh_port <= 0) {
fprintf(stderr, "Bad port '%s'\n", optarg);
exit(1);
}
break;
case 'T':
timeout = convtime(optarg);
if (timeout == -1 || timeout == 0) {
fprintf(stderr, "Bad timeout '%s'\n", optarg);
usage();
}
break;
case 'v':
if (!debug_flag) {
debug_flag = 1;
log_level = SYSLOG_LEVEL_DEBUG1;
}
else if (log_level < SYSLOG_LEVEL_DEBUG3)
log_level++;
else
fatal("Too high debugging level.");
break;
case 'f':
if (strcmp(optarg, "-") == 0)
optarg = NULL;
argv[fopt_count++] = optarg;
break;
case 't':
get_keytypes = 0;
tname = strtok(optarg, ",");
while (tname) {
int type = sshkey_type_from_name(tname);
switch (type) {
case KEY_DSA:
get_keytypes |= KT_DSA;
break;
case KEY_ECDSA:
get_keytypes |= KT_ECDSA;
break;
case KEY_RSA:
get_keytypes |= KT_RSA;
break;
case KEY_ED25519:
get_keytypes |= KT_ED25519;
break;
case KEY_XMSS:
get_keytypes |= KT_XMSS;
break;
case KEY_ED25519_SK:
get_keytypes |= KT_ED25519_SK;
break;
case KEY_ECDSA_SK:
get_keytypes |= KT_ECDSA_SK;
break;
case KEY_UNSPEC:
default:
fatal("Unknown key type \"%s\"", tname);
}
tname = strtok(NULL, ",");
}
break;
case '4':
IPv4or6 = AF_INET;
break;
case '6':
IPv4or6 = AF_INET6;
break;
case '?':
default:
usage();
}
}
if (optind == argc && !fopt_count)
usage();
log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1);
maxfd = fdlim_get(1);
if (maxfd < 0)
fatal("%s: fdlim_get: bad value", __progname);
if (maxfd > MAXMAXFD)
maxfd = MAXMAXFD;
if (MAXCON <= 0)
fatal("%s: not enough file descriptors", __progname);
if (maxfd > fdlim_get(0))
fdlim_set(maxfd);
fdcon = xcalloc(maxfd, sizeof(con));
read_wait = xcalloc(maxfd, sizeof(struct pollfd));
for (j = 0; j < maxfd; j++)
read_wait[j].fd = -1;
for (j = 0; j < fopt_count; j++) {
if (argv[j] == NULL)
fp = stdin;
else if ((fp = fopen(argv[j], "r")) == NULL)
fatal("%s: %s: %s", __progname, argv[j], strerror(errno));
while (getline(&line, &linesize, fp) != -1) {
/* Chomp off trailing whitespace and comments */
if ((cp = strchr(line, '#')) == NULL)
cp = line + strlen(line) - 1;
while (cp >= line) {
if (*cp == ' ' || *cp == '\t' ||
*cp == '\n' || *cp == '#')
*cp-- = '\0';
else
break;
}
/* Skip empty lines */
if (*line == '\0')
continue;
do_host(line);
}
if (ferror(fp))
fatal("%s: %s: %s", __progname, argv[j], strerror(errno));
fclose(fp);
}
free(line);
while (optind < argc)
do_host(argv[optind++]);
while (ncon > 0)
conloop();
return found_one ? 0 : 1;
}
diff --git a/ssh-keysign.0 b/ssh-keysign.0
index 8e109a291fe3..6937679e46a3 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 7.0 March 31, 2022 OpenBSD 7.0
+OpenBSD 7.1 March 31, 2022 OpenBSD 7.1
diff --git a/ssh-keysign.c b/ssh-keysign.c
index c52321e220e7..b989f5e941ad 100644
--- a/ssh-keysign.c
+++ b/ssh-keysign.c
@@ -1,308 +1,306 @@
-/* $OpenBSD: ssh-keysign.c,v 1.70 2022/01/06 22:00:18 djm Exp $ */
+/* $OpenBSD: ssh-keysign.c,v 1.71 2022/08/01 11:09:26 djm Exp $ */
/*
* Copyright (c) 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.
*/
#include "includes.h"
#include <fcntl.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 <errno.h>
#ifdef WITH_OPENSSL
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include "openbsd-compat/openssl-compat.h"
#endif
#include "xmalloc.h"
#include "log.h"
#include "sshkey.h"
#include "ssh.h"
#include "ssh2.h"
#include "misc.h"
#include "sshbuf.h"
#include "authfile.h"
#include "msg.h"
#include "canohost.h"
#include "pathnames.h"
#include "readconf.h"
#include "uidswap.h"
#include "ssherr.h"
extern char *__progname;
static int
valid_request(struct passwd *pw, char *host, struct sshkey **ret, char **pkalgp,
u_char *data, size_t datalen)
{
struct sshbuf *b;
struct sshkey *key = NULL;
u_char type, *pkblob;
char *p;
size_t blen, len;
char *pkalg, *luser;
int r, pktype, fail;
if (ret != NULL)
*ret = NULL;
if (pkalgp != NULL)
*pkalgp = NULL;
fail = 0;
if ((b = sshbuf_from(data, datalen)) == NULL)
fatal_f("sshbuf_from failed");
/* session id */
if ((r = sshbuf_get_string(b, NULL, &len)) != 0)
fatal_fr(r, "parse session ID");
if (len != 20 && /* SHA1 */
len != 32 && /* SHA256 */
len != 48 && /* SHA384 */
len != 64) /* SHA512 */
fail++;
if ((r = sshbuf_get_u8(b, &type)) != 0)
fatal_fr(r, "parse type");
if (type != SSH2_MSG_USERAUTH_REQUEST)
fail++;
/* server user */
if ((r = sshbuf_skip_string(b)) != 0)
fatal_fr(r, "parse user");
/* service */
if ((r = sshbuf_get_cstring(b, &p, NULL)) != 0)
fatal_fr(r, "parse service");
if (strcmp("ssh-connection", p) != 0)
fail++;
free(p);
/* method */
if ((r = sshbuf_get_cstring(b, &p, NULL)) != 0)
fatal_fr(r, "parse method");
if (strcmp("hostbased", p) != 0)
fail++;
free(p);
/* pubkey */
if ((r = sshbuf_get_cstring(b, &pkalg, NULL)) != 0 ||
(r = sshbuf_get_string(b, &pkblob, &blen)) != 0)
fatal_fr(r, "parse pk");
pktype = sshkey_type_from_name(pkalg);
if (pktype == KEY_UNSPEC)
fail++;
else if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
error_fr(r, "decode key");
fail++;
} else if (key->type != pktype)
fail++;
/* client host name, handle trailing dot */
if ((r = sshbuf_get_cstring(b, &p, &len)) != 0)
fatal_fr(r, "parse hostname");
debug2_f("check expect chost %s got %s", host, p);
if (strlen(host) != len - 1)
fail++;
else if (p[len - 1] != '.')
fail++;
else if (strncasecmp(host, p, len - 1) != 0)
fail++;
free(p);
/* local user */
if ((r = sshbuf_get_cstring(b, &luser, NULL)) != 0)
fatal_fr(r, "parse luser");
if (strcmp(pw->pw_name, luser) != 0)
fail++;
free(luser);
/* end of message */
if (sshbuf_len(b) != 0)
fail++;
sshbuf_free(b);
debug3_f("fail %d", fail);
- if (fail)
- sshkey_free(key);
- else {
+ if (!fail) {
if (ret != NULL) {
*ret = key;
key = NULL;
}
if (pkalgp != NULL) {
*pkalgp = pkalg;
pkalg = NULL;
}
}
sshkey_free(key);
free(pkalg);
free(pkblob);
return (fail ? -1 : 0);
}
int
main(int argc, char **argv)
{
struct sshbuf *b;
Options options;
#define NUM_KEYTYPES 5
struct sshkey *keys[NUM_KEYTYPES], *key = NULL;
struct passwd *pw;
int r, key_fd[NUM_KEYTYPES], i, found, version = 2, fd;
u_char *signature, *data, rver;
char *host, *fp, *pkalg;
size_t slen, dlen;
if (pledge("stdio rpath getpw dns id", NULL) != 0)
fatal("%s: pledge: %s", __progname, strerror(errno));
/* Ensure that stdin and stdout are connected */
if ((fd = open(_PATH_DEVNULL, O_RDWR)) < 2)
exit(1);
/* Leave /dev/null fd iff it is attached to stderr */
if (fd > 2)
close(fd);
i = 0;
/* XXX This really needs to read sshd_config for the paths */
key_fd[i++] = open(_PATH_HOST_DSA_KEY_FILE, O_RDONLY);
key_fd[i++] = open(_PATH_HOST_ECDSA_KEY_FILE, O_RDONLY);
key_fd[i++] = open(_PATH_HOST_ED25519_KEY_FILE, O_RDONLY);
key_fd[i++] = open(_PATH_HOST_XMSS_KEY_FILE, O_RDONLY);
key_fd[i++] = open(_PATH_HOST_RSA_KEY_FILE, O_RDONLY);
if ((pw = getpwuid(getuid())) == NULL)
fatal("getpwuid failed");
pw = pwcopy(pw);
permanently_set_uid(pw);
seed_rng();
#ifdef DEBUG_SSH_KEYSIGN
log_init("ssh-keysign", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0);
#endif
/* verify that ssh-keysign is enabled by the admin */
initialize_options(&options);
(void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, "", "",
&options, 0, NULL);
(void)fill_default_options(&options);
if (options.enable_ssh_keysign != 1)
fatal("ssh-keysign not enabled in %s",
_PATH_HOST_CONFIG_FILE);
if (pledge("stdio dns", NULL) != 0)
fatal("%s: pledge: %s", __progname, strerror(errno));
for (i = found = 0; i < NUM_KEYTYPES; i++) {
if (key_fd[i] != -1)
found = 1;
}
if (found == 0)
fatal("could not open any host key");
found = 0;
for (i = 0; i < NUM_KEYTYPES; i++) {
keys[i] = NULL;
if (key_fd[i] == -1)
continue;
r = sshkey_load_private_type_fd(key_fd[i], KEY_UNSPEC,
NULL, &key, NULL);
close(key_fd[i]);
if (r != 0)
debug_r(r, "parse key %d", i);
else if (key != NULL) {
keys[i] = key;
found = 1;
}
}
if (!found)
fatal("no hostkey found");
if ((b = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __progname);
if (ssh_msg_recv(STDIN_FILENO, b) < 0)
fatal("%s: ssh_msg_recv failed", __progname);
if ((r = sshbuf_get_u8(b, &rver)) != 0)
fatal_r(r, "%s: buffer error", __progname);
if (rver != version)
fatal("%s: bad version: received %d, expected %d",
__progname, rver, version);
if ((r = sshbuf_get_u32(b, (u_int *)&fd)) != 0)
fatal_r(r, "%s: buffer error", __progname);
if (fd < 0 || fd == STDIN_FILENO || fd == STDOUT_FILENO)
fatal("%s: bad fd = %d", __progname, fd);
if ((host = get_local_name(fd)) == NULL)
fatal("%s: cannot get local name for fd", __progname);
if ((r = sshbuf_get_string(b, &data, &dlen)) != 0)
fatal_r(r, "%s: buffer error", __progname);
if (valid_request(pw, host, &key, &pkalg, data, dlen) < 0)
fatal("%s: not a valid request", __progname);
free(host);
found = 0;
for (i = 0; i < NUM_KEYTYPES; i++) {
if (keys[i] != NULL &&
sshkey_equal_public(key, keys[i])) {
found = 1;
break;
}
}
if (!found) {
if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
SSH_FP_DEFAULT)) == NULL)
fatal("%s: sshkey_fingerprint failed", __progname);
fatal("%s: no matching hostkey found for key %s %s", __progname,
sshkey_type(key), fp ? fp : "");
}
if ((r = sshkey_sign(keys[i], &signature, &slen, data, dlen,
pkalg, NULL, NULL, 0)) != 0)
fatal_r(r, "%s: sshkey_sign failed", __progname);
free(data);
/* send reply */
sshbuf_reset(b);
if ((r = sshbuf_put_string(b, signature, slen)) != 0)
fatal_r(r, "%s: buffer error", __progname);
if (ssh_msg_send(STDOUT_FILENO, version, b) == -1)
fatal("%s: ssh_msg_send failed", __progname);
return (0);
}
diff --git a/ssh-pkcs11-helper.0 b/ssh-pkcs11-helper.0
index 5b38bb07d8ca..7f46839780a0 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 used by ssh(1), ssh-agent(1), and ssh-keygen(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).
+ ssh-pkcs11-helper is not intended to be invoked directly by the user.
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.
+ Note that ssh(1), ssh-agent(1), and ssh-keygen(1) will
+ automatically pass the -v flag to ssh-pkcs11-helper when they
+ have themselves been placed in debug mode.
SEE ALSO
- ssh(1), ssh-add(1), ssh-agent(1)
+ ssh(1), ssh-agent(1), ssh-keygen(1)
HISTORY
ssh-pkcs11-helper first appeared in OpenBSD 4.7.
AUTHORS
Markus Friedl <markus@openbsd.org>
-OpenBSD 7.0 November 30, 2019 OpenBSD 7.0
+OpenBSD 7.1 April 29, 2022 OpenBSD 7.1
diff --git a/ssh-pkcs11-helper.8 b/ssh-pkcs11-helper.8
index 6a592b1f36e3..5edc98507e0c 100644
--- a/ssh-pkcs11-helper.8
+++ b/ssh-pkcs11-helper.8
@@ -1,66 +1,71 @@
-.\" $OpenBSD: ssh-pkcs11-helper.8,v 1.6 2019/11/30 07:07:59 jmc Exp $
+.\" $OpenBSD: ssh-pkcs11-helper.8,v 1.7 2022/04/29 03:24:30 djm Exp $
.\"
.\" Copyright (c) 2010 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.
.\"
-.Dd $Mdocdate: November 30 2019 $
+.Dd $Mdocdate: April 29 2022 $
.Dt SSH-PKCS11-HELPER 8
.Os
.Sh NAME
.Nm ssh-pkcs11-helper
.Nd OpenSSH helper for PKCS#11 support
.Sh SYNOPSIS
.Nm
.Op Fl v
.Sh DESCRIPTION
.Nm
is used by
-.Xr ssh-agent 1
+.Xr ssh 1 ,
+.Xr ssh-agent 1 ,
+and
+.Xr ssh-keygen 1
to access keys provided by a PKCS#11 token.
.Pp
.Nm
-is not intended to be invoked by the user, but from
-.Xr ssh-agent 1 .
+is not intended to be invoked directly by the user.
.Pp
A single option is supported:
.Bl -tag -width Ds
.It Fl v
Verbose mode.
Causes
.Nm
to print debugging messages about its progress.
This is helpful in debugging problems.
Multiple
.Fl v
options increase the verbosity.
The maximum is 3.
.Pp
Note that
-.Xr ssh-agent 1
+.Xr ssh 1 ,
+.Xr ssh-agent 1 ,
+and
+.Xr ssh-keygen 1
will automatically pass the
.Fl v
flag to
.Nm
-when it has itself been placed in debug mode.
+when they have themselves been placed in debug mode.
.El
.Sh SEE ALSO
.Xr ssh 1 ,
-.Xr ssh-add 1 ,
-.Xr ssh-agent 1
+.Xr ssh-agent 1 ,
+.Xr ssh-keygen 1
.Sh HISTORY
.Nm
first appeared in
.Ox 4.7 .
.Sh AUTHORS
.An Markus Friedl Aq Mt markus@openbsd.org
diff --git a/ssh-sk-helper.8 b/ssh-sk-helper.8
index 3c53da1ec796..e9b2ae12b102 100644
--- a/ssh-sk-helper.8
+++ b/ssh-sk-helper.8
@@ -1,66 +1,71 @@
-.\" $OpenBSD: ssh-sk-helper.8,v 1.3 2019/12/21 20:22:34 naddy Exp $
+.\" $OpenBSD: ssh-sk-helper.8,v 1.4 2022/04/29 03:24:30 djm Exp $
.\"
.\" Copyright (c) 2010 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.
.\"
-.Dd $Mdocdate: December 21 2019 $
+.Dd $Mdocdate: April 29 2022 $
.Dt SSH-SK-HELPER 8
.Os
.Sh NAME
.Nm ssh-sk-helper
.Nd OpenSSH helper for FIDO authenticator support
.Sh SYNOPSIS
.Nm
.Op Fl v
.Sh DESCRIPTION
.Nm
is used by
-.Xr ssh-agent 1
+.Xr ssh 1 ,
+.Xr ssh-agent 1 ,
+and
+.Xr ssh-keygen 1
to access keys provided by a FIDO authenticator.
.Pp
.Nm
-is not intended to be invoked by the user, but from
-.Xr ssh-agent 1 .
+is not intended to be invoked directly by the user.
.Pp
A single option is supported:
.Bl -tag -width Ds
.It Fl v
Verbose mode.
Causes
.Nm
to print debugging messages about its progress.
This is helpful in debugging problems.
Multiple
.Fl v
options increase the verbosity.
The maximum is 3.
.Pp
Note that
-.Xr ssh-agent 1
+.Xr ssh 1 ,
+.Xr ssh-agent 1 ,
+and
+.Xr ssh-keygen 1
will automatically pass the
.Fl v
flag to
.Nm
-when it has itself been placed in debug mode.
+when they have themselves been placed in debug mode.
.El
.Sh SEE ALSO
.Xr ssh 1 ,
-.Xr ssh-add 1 ,
-.Xr ssh-agent 1
+.Xr ssh-agent 1 ,
+.Xr ssh-keygen 1
.Sh HISTORY
.Nm
first appeared in
.Ox 6.7 .
.Sh AUTHORS
.An Damien Miller Aq Mt djm@openbsd.org
diff --git a/ssh-sk-helper.c b/ssh-sk-helper.c
index b1d22631f2f6..bd9b410a6974 100644
--- a/ssh-sk-helper.c
+++ b/ssh-sk-helper.c
@@ -1,367 +1,368 @@
-/* $OpenBSD: ssh-sk-helper.c,v 1.12 2021/10/28 02:54:18 djm Exp $ */
+/* $OpenBSD: ssh-sk-helper.c,v 1.13 2022/04/29 03:16:48 dtucker 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.
*/
/*
* This is a tiny program used to isolate the address space used for
* security key middleware signing operations from ssh-agent. It is similar
* to ssh-pkcs11-helper.c but considerably simpler as the operations for
* security keys are stateless.
*
* Please crank SSH_SK_HELPER_VERSION in sshkey.h for any incompatible
* protocol changes.
*/
#include "includes.h"
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "xmalloc.h"
#include "log.h"
#include "sshkey.h"
#include "authfd.h"
#include "misc.h"
#include "sshbuf.h"
#include "msg.h"
#include "uidswap.h"
#include "sshkey.h"
#include "ssherr.h"
#include "ssh-sk.h"
#ifdef ENABLE_SK
extern char *__progname;
static struct sshbuf *reply_error(int r, char *fmt, ...)
__attribute__((__format__ (printf, 2, 3)));
static struct sshbuf *
reply_error(int r, char *fmt, ...)
{
char *msg;
va_list ap;
struct sshbuf *resp;
va_start(ap, fmt);
xvasprintf(&msg, fmt, ap);
va_end(ap);
debug("%s: %s", __progname, msg);
free(msg);
if (r >= 0)
fatal_f("invalid error code %d", r);
if ((resp = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __progname);
if (sshbuf_put_u32(resp, SSH_SK_HELPER_ERROR) != 0 ||
sshbuf_put_u32(resp, (u_int)-r) != 0)
fatal("%s: buffer error", __progname);
return resp;
}
/* If the specified string is zero length, then free it and replace with NULL */
static void
null_empty(char **s)
{
if (s == NULL || *s == NULL || **s != '\0')
return;
free(*s);
*s = NULL;
}
static struct sshbuf *
process_sign(struct sshbuf *req)
{
int r = SSH_ERR_INTERNAL_ERROR;
struct sshbuf *resp, *kbuf;
struct sshkey *key = NULL;
uint32_t compat;
const u_char *message;
u_char *sig = NULL;
size_t msglen, siglen = 0;
char *provider = NULL, *pin = NULL;
if ((r = sshbuf_froms(req, &kbuf)) != 0 ||
(r = sshbuf_get_cstring(req, &provider, NULL)) != 0 ||
(r = sshbuf_get_string_direct(req, &message, &msglen)) != 0 ||
(r = sshbuf_get_cstring(req, NULL, NULL)) != 0 || /* alg */
(r = sshbuf_get_u32(req, &compat)) != 0 ||
(r = sshbuf_get_cstring(req, &pin, NULL)) != 0)
fatal_r(r, "%s: parse", __progname);
if (sshbuf_len(req) != 0)
fatal("%s: trailing data in request", __progname);
if ((r = sshkey_private_deserialize(kbuf, &key)) != 0)
fatal_r(r, "%s: Unable to parse private key", __progname);
if (!sshkey_is_sk(key)) {
fatal("%s: Unsupported key type %s",
__progname, sshkey_ssh_name(key));
}
debug_f("ready to sign with key %s, provider %s: "
"msg len %zu, compat 0x%lx", sshkey_type(key),
provider, msglen, (u_long)compat);
null_empty(&pin);
if ((r = sshsk_sign(provider, key, &sig, &siglen,
message, msglen, compat, pin)) != 0) {
resp = reply_error(r, "Signing failed: %s", ssh_err(r));
goto out;
}
if ((resp = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __progname);
if ((r = sshbuf_put_u32(resp, SSH_SK_HELPER_SIGN)) != 0 ||
(r = sshbuf_put_string(resp, sig, siglen)) != 0)
fatal_r(r, "%s: compose", __progname);
out:
sshkey_free(key);
sshbuf_free(kbuf);
free(provider);
if (sig != NULL)
freezero(sig, siglen);
if (pin != NULL)
freezero(pin, strlen(pin));
return resp;
}
static struct sshbuf *
process_enroll(struct sshbuf *req)
{
int r;
u_int type;
char *provider, *application, *pin, *device, *userid;
uint8_t flags;
struct sshbuf *challenge, *attest, *kbuf, *resp;
struct sshkey *key;
if ((attest = sshbuf_new()) == NULL ||
(kbuf = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __progname);
if ((r = sshbuf_get_u32(req, &type)) != 0 ||
(r = sshbuf_get_cstring(req, &provider, NULL)) != 0 ||
(r = sshbuf_get_cstring(req, &device, NULL)) != 0 ||
(r = sshbuf_get_cstring(req, &application, NULL)) != 0 ||
(r = sshbuf_get_cstring(req, &userid, NULL)) != 0 ||
(r = sshbuf_get_u8(req, &flags)) != 0 ||
(r = sshbuf_get_cstring(req, &pin, NULL)) != 0 ||
(r = sshbuf_froms(req, &challenge)) != 0)
fatal_r(r, "%s: parse", __progname);
if (sshbuf_len(req) != 0)
fatal("%s: trailing data in request", __progname);
if (type > INT_MAX)
fatal("%s: bad type %u", __progname, type);
if (sshbuf_len(challenge) == 0) {
sshbuf_free(challenge);
challenge = NULL;
}
null_empty(&device);
null_empty(&userid);
null_empty(&pin);
if ((r = sshsk_enroll((int)type, provider, device, application, userid,
flags, pin, challenge, &key, attest)) != 0) {
resp = reply_error(r, "Enrollment failed: %s", ssh_err(r));
goto out;
}
if ((resp = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __progname);
if ((r = sshkey_private_serialize(key, kbuf)) != 0)
fatal_r(r, "%s: encode key", __progname);
if ((r = sshbuf_put_u32(resp, SSH_SK_HELPER_ENROLL)) != 0 ||
(r = sshbuf_put_stringb(resp, kbuf)) != 0 ||
(r = sshbuf_put_stringb(resp, attest)) != 0)
fatal_r(r, "%s: compose", __progname);
out:
sshkey_free(key);
sshbuf_free(kbuf);
sshbuf_free(attest);
sshbuf_free(challenge);
free(provider);
free(application);
if (pin != NULL)
freezero(pin, strlen(pin));
return resp;
}
static struct sshbuf *
process_load_resident(struct sshbuf *req)
{
int r;
char *provider, *pin, *device;
struct sshbuf *kbuf, *resp;
struct sshsk_resident_key **srks = NULL;
size_t nsrks = 0, i;
u_int flags;
if ((kbuf = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __progname);
if ((r = sshbuf_get_cstring(req, &provider, NULL)) != 0 ||
(r = sshbuf_get_cstring(req, &device, NULL)) != 0 ||
(r = sshbuf_get_cstring(req, &pin, NULL)) != 0 ||
(r = sshbuf_get_u32(req, &flags)) != 0)
fatal_r(r, "%s: parse", __progname);
if (sshbuf_len(req) != 0)
fatal("%s: trailing data in request", __progname);
null_empty(&device);
null_empty(&pin);
if ((r = sshsk_load_resident(provider, device, pin, flags,
&srks, &nsrks)) != 0) {
resp = reply_error(r, "sshsk_load_resident failed: %s",
ssh_err(r));
goto out;
}
if ((resp = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __progname);
if ((r = sshbuf_put_u32(resp, SSH_SK_HELPER_LOAD_RESIDENT)) != 0)
fatal_r(r, "%s: compose", __progname);
for (i = 0; i < nsrks; i++) {
debug_f("key %zu %s %s uidlen %zu", i,
sshkey_type(srks[i]->key), srks[i]->key->sk_application,
srks[i]->user_id_len);
sshbuf_reset(kbuf);
if ((r = sshkey_private_serialize(srks[i]->key, kbuf)) != 0)
fatal_r(r, "%s: encode key", __progname);
if ((r = sshbuf_put_stringb(resp, kbuf)) != 0 ||
(r = sshbuf_put_cstring(resp, "")) != 0 || /* comment */
(r = sshbuf_put_string(resp, srks[i]->user_id,
srks[i]->user_id_len)) != 0)
fatal_r(r, "%s: compose key", __progname);
}
out:
sshsk_free_resident_keys(srks, nsrks);
sshbuf_free(kbuf);
free(provider);
+ free(device);
if (pin != NULL)
freezero(pin, strlen(pin));
return resp;
}
int
main(int argc, char **argv)
{
SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
LogLevel log_level = SYSLOG_LEVEL_ERROR;
struct sshbuf *req, *resp;
int in, out, ch, r, vflag = 0;
u_int rtype, ll = 0;
uint8_t version, log_stderr = 0;
sanitise_stdfd();
log_init(__progname, log_level, log_facility, log_stderr);
while ((ch = getopt(argc, argv, "v")) != -1) {
switch (ch) {
case 'v':
vflag = 1;
if (log_level == SYSLOG_LEVEL_ERROR)
log_level = SYSLOG_LEVEL_DEBUG1;
else if (log_level < SYSLOG_LEVEL_DEBUG3)
log_level++;
break;
default:
fprintf(stderr, "usage: %s [-v]\n", __progname);
exit(1);
}
}
log_init(__progname, log_level, log_facility, vflag);
/*
* Rearrange our file descriptors a little; we don't trust the
* providers not to fiddle with stdin/out.
*/
closefrom(STDERR_FILENO + 1);
if ((in = dup(STDIN_FILENO)) == -1 || (out = dup(STDOUT_FILENO)) == -1)
fatal("%s: dup: %s", __progname, strerror(errno));
close(STDIN_FILENO);
close(STDOUT_FILENO);
sanitise_stdfd(); /* resets to /dev/null */
if ((req = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __progname);
if (ssh_msg_recv(in, req) < 0)
fatal("ssh_msg_recv failed");
close(in);
debug_f("received message len %zu", sshbuf_len(req));
if ((r = sshbuf_get_u8(req, &version)) != 0)
fatal_r(r, "%s: parse version", __progname);
if (version != SSH_SK_HELPER_VERSION) {
fatal("unsupported version: received %d, expected %d",
version, SSH_SK_HELPER_VERSION);
}
if ((r = sshbuf_get_u32(req, &rtype)) != 0 ||
(r = sshbuf_get_u8(req, &log_stderr)) != 0 ||
(r = sshbuf_get_u32(req, &ll)) != 0)
fatal_r(r, "%s: parse", __progname);
if (!vflag && log_level_name((LogLevel)ll) != NULL)
log_init(__progname, (LogLevel)ll, log_facility, log_stderr);
switch (rtype) {
case SSH_SK_HELPER_SIGN:
resp = process_sign(req);
break;
case SSH_SK_HELPER_ENROLL:
resp = process_enroll(req);
break;
case SSH_SK_HELPER_LOAD_RESIDENT:
resp = process_load_resident(req);
break;
default:
fatal("%s: unsupported request type %u", __progname, rtype);
}
sshbuf_free(req);
debug_f("reply len %zu", sshbuf_len(resp));
if (ssh_msg_send(out, SSH_SK_HELPER_VERSION, resp) == -1)
fatal("ssh_msg_send failed");
sshbuf_free(resp);
close(out);
return (0);
}
#else /* ENABLE_SK */
#include <stdio.h>
int
main(int argc, char **argv)
{
fprintf(stderr, "ssh-sk-helper: disabled at compile time\n");
return -1;
}
#endif /* ENABLE_SK */
diff --git a/ssh-sk.c b/ssh-sk.c
index a1ff5cc485e8..fbeb39320976 100644
--- a/ssh-sk.c
+++ b/ssh-sk.c
@@ -1,874 +1,877 @@
-/* $OpenBSD: ssh-sk.c,v 1.38 2022/01/14 03:35:10 djm Exp $ */
+/* $OpenBSD: ssh-sk.c,v 1.39 2022/07/20 03:29:14 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.
*/
/* #define DEBUG_SK 1 */
#include "includes.h"
#ifdef ENABLE_SK
#include <dlfcn.h>
#include <stddef.h>
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#include <string.h>
#include <stdio.h>
#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
#include <openssl/objects.h>
#include <openssl/ec.h>
#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
#include "log.h"
#include "misc.h"
#include "sshbuf.h"
#include "sshkey.h"
#include "ssherr.h"
#include "digest.h"
#include "ssh-sk.h"
#include "sk-api.h"
#include "crypto_api.h"
/*
* Almost every use of OpenSSL in this file is for ECDSA-NISTP256.
* This is strictly a larger hammer than necessary, but it reduces changes
* with upstream.
*/
#ifndef OPENSSL_HAS_ECC
# undef WITH_OPENSSL
#endif
struct sshsk_provider {
char *path;
void *dlhandle;
/* Return the version of the middleware API */
uint32_t (*sk_api_version)(void);
/* Enroll a U2F key (private key generation) */
int (*sk_enroll)(int alg, const uint8_t *challenge,
size_t challenge_len, const char *application, uint8_t flags,
const char *pin, struct sk_option **opts,
struct sk_enroll_response **enroll_response);
/* Sign a challenge */
int (*sk_sign)(int alg, const uint8_t *message, size_t message_len,
const char *application,
const uint8_t *key_handle, size_t key_handle_len,
uint8_t flags, const char *pin, struct sk_option **opts,
struct sk_sign_response **sign_response);
/* Enumerate resident keys */
int (*sk_load_resident_keys)(const char *pin, struct sk_option **opts,
struct sk_resident_key ***rks, size_t *nrks);
};
/* Built-in version */
int ssh_sk_enroll(int alg, const uint8_t *challenge,
size_t challenge_len, const char *application, uint8_t flags,
const char *pin, struct sk_option **opts,
struct sk_enroll_response **enroll_response);
int ssh_sk_sign(int alg, const uint8_t *message, size_t message_len,
const char *application,
const uint8_t *key_handle, size_t key_handle_len,
uint8_t flags, const char *pin, struct sk_option **opts,
struct sk_sign_response **sign_response);
int ssh_sk_load_resident_keys(const char *pin, struct sk_option **opts,
struct sk_resident_key ***rks, size_t *nrks);
static void
sshsk_free(struct sshsk_provider *p)
{
if (p == NULL)
return;
free(p->path);
if (p->dlhandle != NULL)
dlclose(p->dlhandle);
free(p);
}
static struct sshsk_provider *
sshsk_open(const char *path)
{
struct sshsk_provider *ret = NULL;
uint32_t version;
if (path == NULL || *path == '\0') {
error("No FIDO SecurityKeyProvider specified");
return NULL;
}
if ((ret = calloc(1, sizeof(*ret))) == NULL) {
error_f("calloc failed");
return NULL;
}
if ((ret->path = strdup(path)) == NULL) {
error_f("strdup failed");
goto fail;
}
/* Skip the rest if we're using the linked in middleware */
if (strcasecmp(ret->path, "internal") == 0) {
#ifdef ENABLE_SK_INTERNAL
ret->sk_enroll = ssh_sk_enroll;
ret->sk_sign = ssh_sk_sign;
ret->sk_load_resident_keys = ssh_sk_load_resident_keys;
+ return ret;
#else
error("internal security key support not enabled");
+ goto fail;
#endif
- return ret;
}
if ((ret->dlhandle = dlopen(path, RTLD_NOW)) == NULL) {
error("Provider \"%s\" dlopen failed: %s", path, dlerror());
goto fail;
}
if ((ret->sk_api_version = dlsym(ret->dlhandle,
"sk_api_version")) == NULL) {
error("Provider \"%s\" dlsym(sk_api_version) failed: %s",
path, dlerror());
goto fail;
}
version = ret->sk_api_version();
debug_f("provider %s implements version 0x%08lx", ret->path,
(u_long)version);
if ((version & SSH_SK_VERSION_MAJOR_MASK) != SSH_SK_VERSION_MAJOR) {
error("Provider \"%s\" implements unsupported "
"version 0x%08lx (supported: 0x%08lx)",
path, (u_long)version, (u_long)SSH_SK_VERSION_MAJOR);
goto fail;
}
if ((ret->sk_enroll = dlsym(ret->dlhandle, "sk_enroll")) == NULL) {
error("Provider %s dlsym(sk_enroll) failed: %s",
path, dlerror());
goto fail;
}
if ((ret->sk_sign = dlsym(ret->dlhandle, "sk_sign")) == NULL) {
error("Provider \"%s\" dlsym(sk_sign) failed: %s",
path, dlerror());
goto fail;
}
if ((ret->sk_load_resident_keys = dlsym(ret->dlhandle,
"sk_load_resident_keys")) == NULL) {
error("Provider \"%s\" dlsym(sk_load_resident_keys) "
"failed: %s", path, dlerror());
goto fail;
}
/* success */
return ret;
fail:
sshsk_free(ret);
return NULL;
}
static void
sshsk_free_enroll_response(struct sk_enroll_response *r)
{
if (r == NULL)
return;
freezero(r->key_handle, r->key_handle_len);
freezero(r->public_key, r->public_key_len);
freezero(r->signature, r->signature_len);
freezero(r->attestation_cert, r->attestation_cert_len);
freezero(r->authdata, r->authdata_len);
freezero(r, sizeof(*r));
}
static void
sshsk_free_sign_response(struct sk_sign_response *r)
{
if (r == NULL)
return;
freezero(r->sig_r, r->sig_r_len);
freezero(r->sig_s, r->sig_s_len);
freezero(r, sizeof(*r));
}
#ifdef WITH_OPENSSL
/* Assemble key from response */
static int
sshsk_ecdsa_assemble(struct sk_enroll_response *resp, struct sshkey **keyp)
{
struct sshkey *key = NULL;
struct sshbuf *b = NULL;
EC_POINT *q = NULL;
int r;
*keyp = NULL;
if ((key = sshkey_new(KEY_ECDSA_SK)) == NULL) {
error_f("sshkey_new failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
key->ecdsa_nid = NID_X9_62_prime256v1;
if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid)) == NULL ||
(q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL ||
(b = sshbuf_new()) == NULL) {
error_f("allocation failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_put_string(b,
resp->public_key, resp->public_key_len)) != 0) {
error_fr(r, "sshbuf_put_string");
goto out;
}
if ((r = sshbuf_get_ec(b, q, EC_KEY_get0_group(key->ecdsa))) != 0) {
error_fr(r, "parse");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa), q) != 0) {
error("Authenticator returned invalid ECDSA key");
r = 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 */
error_f("allocation failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* success */
*keyp = key;
key = NULL; /* transferred */
r = 0;
out:
EC_POINT_free(q);
sshkey_free(key);
sshbuf_free(b);
return r;
}
#endif /* WITH_OPENSSL */
static int
sshsk_ed25519_assemble(struct sk_enroll_response *resp, struct sshkey **keyp)
{
struct sshkey *key = NULL;
int r;
*keyp = NULL;
if (resp->public_key_len != ED25519_PK_SZ) {
error_f("invalid size: %zu", resp->public_key_len);
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((key = sshkey_new(KEY_ED25519_SK)) == NULL) {
error_f("sshkey_new failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((key->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) {
error_f("malloc failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(key->ed25519_pk, resp->public_key, ED25519_PK_SZ);
/* success */
*keyp = key;
key = NULL; /* transferred */
r = 0;
out:
sshkey_free(key);
return r;
}
static int
sshsk_key_from_response(int alg, const char *application, uint8_t flags,
struct sk_enroll_response *resp, struct sshkey **keyp)
{
struct sshkey *key = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
*keyp = NULL;
/* Check response validity */
if (resp->public_key == NULL || resp->key_handle == NULL) {
error_f("sk_enroll response invalid");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
switch (alg) {
#ifdef WITH_OPENSSL
case SSH_SK_ECDSA:
if ((r = sshsk_ecdsa_assemble(resp, &key)) != 0)
goto out;
break;
#endif /* WITH_OPENSSL */
case SSH_SK_ED25519:
if ((r = sshsk_ed25519_assemble(resp, &key)) != 0)
goto out;
break;
default:
error_f("unsupported algorithm %d", alg);
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
key->sk_flags = flags;
if ((key->sk_key_handle = sshbuf_new()) == NULL ||
(key->sk_reserved = sshbuf_new()) == NULL) {
error_f("allocation failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((key->sk_application = strdup(application)) == NULL) {
error_f("strdup application failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_put(key->sk_key_handle, resp->key_handle,
resp->key_handle_len)) != 0) {
error_fr(r, "put key handle");
goto out;
}
/* success */
r = 0;
*keyp = key;
key = NULL;
out:
sshkey_free(key);
return r;
}
static int
skerr_to_ssherr(int skerr)
{
switch (skerr) {
case SSH_SK_ERR_UNSUPPORTED:
return SSH_ERR_FEATURE_UNSUPPORTED;
case SSH_SK_ERR_PIN_REQUIRED:
return SSH_ERR_KEY_WRONG_PASSPHRASE;
case SSH_SK_ERR_DEVICE_NOT_FOUND:
return SSH_ERR_DEVICE_NOT_FOUND;
+ case SSH_SK_ERR_CREDENTIAL_EXISTS:
+ return SSH_ERR_KEY_BAD_PERMISSIONS;
case SSH_SK_ERR_GENERAL:
default:
return SSH_ERR_INVALID_FORMAT;
}
}
static void
sshsk_free_options(struct sk_option **opts)
{
size_t i;
if (opts == NULL)
return;
for (i = 0; opts[i] != NULL; i++) {
free(opts[i]->name);
free(opts[i]->value);
free(opts[i]);
}
free(opts);
}
static int
sshsk_add_option(struct sk_option ***optsp, size_t *noptsp,
const char *name, const char *value, uint8_t required)
{
struct sk_option **opts = *optsp;
size_t nopts = *noptsp;
if ((opts = recallocarray(opts, nopts, nopts + 2, /* extra for NULL */
sizeof(*opts))) == NULL) {
error_f("array alloc failed");
return SSH_ERR_ALLOC_FAIL;
}
*optsp = opts;
*noptsp = nopts + 1;
if ((opts[nopts] = calloc(1, sizeof(**opts))) == NULL) {
error_f("alloc failed");
return SSH_ERR_ALLOC_FAIL;
}
if ((opts[nopts]->name = strdup(name)) == NULL ||
(opts[nopts]->value = strdup(value)) == NULL) {
error_f("alloc failed");
return SSH_ERR_ALLOC_FAIL;
}
opts[nopts]->required = required;
return 0;
}
static int
make_options(const char *device, const char *user_id,
struct sk_option ***optsp)
{
struct sk_option **opts = NULL;
size_t nopts = 0;
int r, ret = SSH_ERR_INTERNAL_ERROR;
if (device != NULL &&
(r = sshsk_add_option(&opts, &nopts, "device", device, 0)) != 0) {
ret = r;
goto out;
}
if (user_id != NULL &&
(r = sshsk_add_option(&opts, &nopts, "user", user_id, 0)) != 0) {
ret = r;
goto out;
}
/* success */
*optsp = opts;
opts = NULL;
nopts = 0;
ret = 0;
out:
sshsk_free_options(opts);
return ret;
}
static int
fill_attestation_blob(const struct sk_enroll_response *resp,
struct sshbuf *attest)
{
int r;
if (attest == NULL)
return 0; /* nothing to do */
if ((r = sshbuf_put_cstring(attest, "ssh-sk-attest-v01")) != 0 ||
(r = sshbuf_put_string(attest,
resp->attestation_cert, resp->attestation_cert_len)) != 0 ||
(r = sshbuf_put_string(attest,
resp->signature, resp->signature_len)) != 0 ||
(r = sshbuf_put_string(attest,
resp->authdata, resp->authdata_len)) != 0 ||
(r = sshbuf_put_u32(attest, 0)) != 0 || /* resvd flags */
(r = sshbuf_put_string(attest, NULL, 0)) != 0 /* resvd */) {
error_fr(r, "compose");
return r;
}
/* success */
return 0;
}
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)
{
struct sshsk_provider *skp = NULL;
struct sshkey *key = NULL;
u_char randchall[32];
const u_char *challenge;
size_t challenge_len;
struct sk_enroll_response *resp = NULL;
struct sk_option **opts = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
int alg;
debug_f("provider \"%s\", device \"%s\", application \"%s\", "
"userid \"%s\", flags 0x%02x, challenge len %zu%s",
provider_path, device, application, userid, flags,
challenge_buf == NULL ? 0 : sshbuf_len(challenge_buf),
(pin != NULL && *pin != '\0') ? " with-pin" : "");
*keyp = NULL;
if (attest)
sshbuf_reset(attest);
if ((r = make_options(device, userid, &opts)) != 0)
goto out;
switch (type) {
#ifdef WITH_OPENSSL
case KEY_ECDSA_SK:
alg = SSH_SK_ECDSA;
break;
#endif /* WITH_OPENSSL */
case KEY_ED25519_SK:
alg = SSH_SK_ED25519;
break;
default:
error_f("unsupported key type");
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if (provider_path == NULL) {
error_f("missing provider");
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if (application == NULL || *application == '\0') {
error_f("missing application");
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if (challenge_buf == NULL) {
debug_f("using random challenge");
arc4random_buf(randchall, sizeof(randchall));
challenge = randchall;
challenge_len = sizeof(randchall);
} else if (sshbuf_len(challenge_buf) == 0) {
error("Missing enrollment challenge");
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
} else {
challenge = sshbuf_ptr(challenge_buf);
challenge_len = sshbuf_len(challenge_buf);
debug3_f("using explicit challenge len=%zd", challenge_len);
}
if ((skp = sshsk_open(provider_path)) == NULL) {
r = SSH_ERR_INVALID_FORMAT; /* XXX sshsk_open return code? */
goto out;
}
/* XXX validate flags? */
/* enroll key */
if ((r = skp->sk_enroll(alg, challenge, challenge_len, application,
flags, pin, opts, &resp)) != 0) {
debug_f("provider \"%s\" failure %d", provider_path, r);
r = skerr_to_ssherr(r);
goto out;
}
if ((r = sshsk_key_from_response(alg, application, resp->flags,
resp, &key)) != 0)
goto out;
/* Optionally fill in the attestation information */
if ((r = fill_attestation_blob(resp, attest)) != 0)
goto out;
/* success */
*keyp = key;
key = NULL; /* transferred */
r = 0;
out:
sshsk_free_options(opts);
sshsk_free(skp);
sshkey_free(key);
sshsk_free_enroll_response(resp);
explicit_bzero(randchall, sizeof(randchall));
return r;
}
#ifdef WITH_OPENSSL
static int
sshsk_ecdsa_sig(struct sk_sign_response *resp, struct sshbuf *sig)
{
struct sshbuf *inner_sig = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
/* Check response validity */
if (resp->sig_r == NULL || resp->sig_s == NULL) {
error_f("sk_sign response invalid");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((inner_sig = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* Prepare and append inner signature object */
if ((r = sshbuf_put_bignum2_bytes(inner_sig,
resp->sig_r, resp->sig_r_len)) != 0 ||
(r = sshbuf_put_bignum2_bytes(inner_sig,
resp->sig_s, resp->sig_s_len)) != 0) {
error_fr(r, "compose inner");
goto out;
}
if ((r = sshbuf_put_stringb(sig, inner_sig)) != 0 ||
(r = sshbuf_put_u8(sig, resp->flags)) != 0 ||
(r = sshbuf_put_u32(sig, resp->counter)) != 0) {
error_fr(r, "compose");
goto out;
}
#ifdef DEBUG_SK
fprintf(stderr, "%s: sig_r:\n", __func__);
sshbuf_dump_data(resp->sig_r, resp->sig_r_len, stderr);
fprintf(stderr, "%s: sig_s:\n", __func__);
sshbuf_dump_data(resp->sig_s, resp->sig_s_len, stderr);
fprintf(stderr, "%s: inner:\n", __func__);
sshbuf_dump(inner_sig, stderr);
#endif
r = 0;
out:
sshbuf_free(inner_sig);
return r;
}
#endif /* WITH_OPENSSL */
static int
sshsk_ed25519_sig(struct sk_sign_response *resp, struct sshbuf *sig)
{
int r = SSH_ERR_INTERNAL_ERROR;
/* Check response validity */
if (resp->sig_r == NULL) {
error_f("sk_sign response invalid");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((r = sshbuf_put_string(sig,
resp->sig_r, resp->sig_r_len)) != 0 ||
(r = sshbuf_put_u8(sig, resp->flags)) != 0 ||
(r = sshbuf_put_u32(sig, resp->counter)) != 0) {
error_fr(r, "compose");
goto out;
}
#ifdef DEBUG_SK
fprintf(stderr, "%s: sig_r:\n", __func__);
sshbuf_dump_data(resp->sig_r, resp->sig_r_len, stderr);
#endif
r = 0;
out:
return r;
}
int
sshsk_sign(const char *provider_path, struct sshkey *key,
u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
u_int compat, const char *pin)
{
struct sshsk_provider *skp = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
int type, alg;
struct sk_sign_response *resp = NULL;
struct sshbuf *inner_sig = NULL, *sig = NULL;
struct sk_option **opts = NULL;
debug_f("provider \"%s\", key %s, flags 0x%02x%s",
provider_path, sshkey_type(key), key->sk_flags,
(pin != NULL && *pin != '\0') ? " with-pin" : "");
if (sigp != NULL)
*sigp = NULL;
if (lenp != NULL)
*lenp = 0;
type = sshkey_type_plain(key->type);
switch (type) {
#ifdef WITH_OPENSSL
case KEY_ECDSA_SK:
alg = SSH_SK_ECDSA;
break;
#endif /* WITH_OPENSSL */
case KEY_ED25519_SK:
alg = SSH_SK_ED25519;
break;
default:
return SSH_ERR_INVALID_ARGUMENT;
}
if (provider_path == NULL ||
key->sk_key_handle == NULL ||
key->sk_application == NULL || *key->sk_application == '\0') {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if ((skp = sshsk_open(provider_path)) == NULL) {
r = SSH_ERR_INVALID_FORMAT; /* XXX sshsk_open return code? */
goto out;
}
#ifdef DEBUG_SK
fprintf(stderr, "%s: sk_flags = 0x%02x, sk_application = \"%s\"\n",
__func__, key->sk_flags, key->sk_application);
fprintf(stderr, "%s: sk_key_handle:\n", __func__);
sshbuf_dump(key->sk_key_handle, stderr);
#endif
if ((r = skp->sk_sign(alg, data, datalen, key->sk_application,
sshbuf_ptr(key->sk_key_handle), sshbuf_len(key->sk_key_handle),
key->sk_flags, pin, opts, &resp)) != 0) {
debug_f("sk_sign failed with code %d", r);
r = skerr_to_ssherr(r);
goto out;
}
/* Assemble signature */
if ((sig = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_put_cstring(sig, sshkey_ssh_name_plain(key))) != 0) {
error_fr(r, "compose outer");
goto out;
}
switch (type) {
#ifdef WITH_OPENSSL
case KEY_ECDSA_SK:
if ((r = sshsk_ecdsa_sig(resp, sig)) != 0)
goto out;
break;
#endif /* WITH_OPENSSL */
case KEY_ED25519_SK:
if ((r = sshsk_ed25519_sig(resp, sig)) != 0)
goto out;
break;
}
#ifdef DEBUG_SK
fprintf(stderr, "%s: sig_flags = 0x%02x, sig_counter = %u\n",
__func__, resp->flags, resp->counter);
fprintf(stderr, "%s: data to sign:\n", __func__);
sshbuf_dump_data(data, datalen, stderr);
fprintf(stderr, "%s: sigbuf:\n", __func__);
sshbuf_dump(sig, stderr);
#endif
if (sigp != NULL) {
if ((*sigp = malloc(sshbuf_len(sig))) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(*sigp, sshbuf_ptr(sig), sshbuf_len(sig));
}
if (lenp != NULL)
*lenp = sshbuf_len(sig);
/* success */
r = 0;
out:
sshsk_free_options(opts);
sshsk_free(skp);
sshsk_free_sign_response(resp);
sshbuf_free(sig);
sshbuf_free(inner_sig);
return r;
}
static void
sshsk_free_sk_resident_keys(struct sk_resident_key **rks, size_t nrks)
{
size_t i;
if (nrks == 0 || rks == NULL)
return;
for (i = 0; i < nrks; i++) {
free(rks[i]->application);
freezero(rks[i]->user_id, rks[i]->user_id_len);
freezero(rks[i]->key.key_handle, rks[i]->key.key_handle_len);
freezero(rks[i]->key.public_key, rks[i]->key.public_key_len);
freezero(rks[i]->key.signature, rks[i]->key.signature_len);
freezero(rks[i]->key.attestation_cert,
rks[i]->key.attestation_cert_len);
freezero(rks[i], sizeof(**rks));
}
free(rks);
}
static void
sshsk_free_resident_key(struct sshsk_resident_key *srk)
{
if (srk == NULL)
return;
sshkey_free(srk->key);
freezero(srk->user_id, srk->user_id_len);
free(srk);
}
void
sshsk_free_resident_keys(struct sshsk_resident_key **srks, size_t nsrks)
{
size_t i;
if (srks == NULL || nsrks == 0)
return;
for (i = 0; i < nsrks; i++)
sshsk_free_resident_key(srks[i]);
free(srks);
}
int
sshsk_load_resident(const char *provider_path, const char *device,
const char *pin, u_int flags, struct sshsk_resident_key ***srksp,
size_t *nsrksp)
{
struct sshsk_provider *skp = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
struct sk_resident_key **rks = NULL;
size_t i, nrks = 0, nsrks = 0;
struct sshkey *key = NULL;
struct sshsk_resident_key *srk = NULL, **srks = NULL, **tmp;
uint8_t sk_flags;
struct sk_option **opts = NULL;
debug_f("provider \"%s\"%s", provider_path,
(pin != NULL && *pin != '\0') ? ", have-pin": "");
if (srksp == NULL || nsrksp == NULL)
return SSH_ERR_INVALID_ARGUMENT;
*srksp = NULL;
*nsrksp = 0;
if ((r = make_options(device, NULL, &opts)) != 0)
goto out;
if ((skp = sshsk_open(provider_path)) == NULL) {
r = SSH_ERR_INVALID_FORMAT; /* XXX sshsk_open return code? */
goto out;
}
if ((r = skp->sk_load_resident_keys(pin, opts, &rks, &nrks)) != 0) {
error("Provider \"%s\" returned failure %d", provider_path, r);
r = skerr_to_ssherr(r);
goto out;
}
for (i = 0; i < nrks; i++) {
debug3_f("rk %zu: slot %zu, alg %d, app \"%s\", uidlen %zu",
i, rks[i]->slot, rks[i]->alg, rks[i]->application,
rks[i]->user_id_len);
/* XXX need better filter here */
if (strncmp(rks[i]->application, "ssh:", 4) != 0)
continue;
switch (rks[i]->alg) {
case SSH_SK_ECDSA:
case SSH_SK_ED25519:
break;
default:
continue;
}
sk_flags = SSH_SK_USER_PRESENCE_REQD|SSH_SK_RESIDENT_KEY;
if ((rks[i]->flags & SSH_SK_USER_VERIFICATION_REQD))
sk_flags |= SSH_SK_USER_VERIFICATION_REQD;
if ((r = sshsk_key_from_response(rks[i]->alg,
rks[i]->application, sk_flags, &rks[i]->key, &key)) != 0)
goto out;
if ((srk = calloc(1, sizeof(*srk))) == NULL) {
error_f("calloc failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
srk->key = key;
key = NULL; /* transferred */
if ((srk->user_id = calloc(1, rks[i]->user_id_len)) == NULL) {
error_f("calloc failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(srk->user_id, rks[i]->user_id, rks[i]->user_id_len);
srk->user_id_len = rks[i]->user_id_len;
if ((tmp = recallocarray(srks, nsrks, nsrks + 1,
sizeof(*tmp))) == NULL) {
error_f("recallocarray failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
srks = tmp;
srks[nsrks++] = srk;
srk = NULL;
/* XXX synthesise comment */
}
/* success */
*srksp = srks;
*nsrksp = nsrks;
srks = NULL;
nsrks = 0;
r = 0;
out:
sshsk_free_options(opts);
sshsk_free(skp);
sshsk_free_sk_resident_keys(rks, nrks);
sshkey_free(key);
sshsk_free_resident_key(srk);
sshsk_free_resident_keys(srks, nsrks);
return r;
}
#endif /* ENABLE_SK */
diff --git a/ssh-xmss.c b/ssh-xmss.c
index 7bd3a96a3bf5..41ede29607c0 100644
--- a/ssh-xmss.c
+++ b/ssh-xmss.c
@@ -1,185 +1,187 @@
-/* $OpenBSD: ssh-xmss.c,v 1.4 2020/10/19 22:49:23 dtucker Exp $*/
+/* $OpenBSD: ssh-xmss.c,v 1.5 2022/04/20 15:59:18 millert Exp $*/
/*
* Copyright (c) 2017 Stefan-Lukas Gazdag.
* Copyright (c) 2017 Markus Friedl.
*
* 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_XMSS
#define SSHKEY_INTERNAL
#include <sys/types.h>
#include <limits.h>
+#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
+#include <stdint.h>
#include <unistd.h>
#include "log.h"
#include "sshbuf.h"
#include "sshkey.h"
#include "sshkey-xmss.h"
#include "ssherr.h"
#include "ssh.h"
#include "xmss_fast.h"
int
ssh_xmss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, u_int compat)
{
u_char *sig = NULL;
size_t slen = 0, len = 0, required_siglen;
unsigned long long smlen;
int r, ret;
struct sshbuf *b = NULL;
if (lenp != NULL)
*lenp = 0;
if (sigp != NULL)
*sigp = NULL;
if (key == NULL ||
sshkey_type_plain(key->type) != KEY_XMSS ||
key->xmss_sk == NULL ||
sshkey_xmss_params(key) == NULL)
return SSH_ERR_INVALID_ARGUMENT;
if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
return r;
if (datalen >= INT_MAX - required_siglen)
return SSH_ERR_INVALID_ARGUMENT;
smlen = slen = datalen + required_siglen;
if ((sig = malloc(slen)) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshkey_xmss_get_state(key, 1)) != 0)
goto out;
if ((ret = xmss_sign(key->xmss_sk, sshkey_xmss_bds_state(key), sig, &smlen,
data, datalen, sshkey_xmss_params(key))) != 0 || smlen <= datalen) {
r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */
goto out;
}
/* encode signature */
if ((b = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_put_cstring(b, "ssh-xmss@openssh.com")) != 0 ||
(r = sshbuf_put_string(b, sig, smlen - datalen)) != 0)
goto out;
len = sshbuf_len(b);
if (sigp != NULL) {
if ((*sigp = malloc(len)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(*sigp, sshbuf_ptr(b), len);
}
if (lenp != NULL)
*lenp = len;
/* success */
r = 0;
out:
if ((ret = sshkey_xmss_update_state(key, 1)) != 0) {
/* discard signature since we cannot update the state */
if (r == 0 && sigp != NULL && *sigp != NULL) {
explicit_bzero(*sigp, len);
free(*sigp);
}
if (sigp != NULL)
*sigp = NULL;
if (lenp != NULL)
*lenp = 0;
r = ret;
}
sshbuf_free(b);
if (sig != NULL)
freezero(sig, slen);
return r;
}
int
ssh_xmss_verify(const struct sshkey *key,
const u_char *signature, size_t signaturelen,
const u_char *data, size_t datalen, u_int compat)
{
struct sshbuf *b = NULL;
char *ktype = NULL;
const u_char *sigblob;
u_char *sm = NULL, *m = NULL;
size_t len, required_siglen;
unsigned long long smlen = 0, mlen = 0;
int r, ret;
if (key == NULL ||
sshkey_type_plain(key->type) != KEY_XMSS ||
key->xmss_pk == NULL ||
sshkey_xmss_params(key) == NULL ||
signature == NULL || signaturelen == 0)
return SSH_ERR_INVALID_ARGUMENT;
if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
return r;
if (datalen >= INT_MAX - required_siglen)
return SSH_ERR_INVALID_ARGUMENT;
if ((b = sshbuf_from(signature, signaturelen)) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 ||
(r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0)
goto out;
if (strcmp("ssh-xmss@openssh.com", ktype) != 0) {
r = SSH_ERR_KEY_TYPE_MISMATCH;
goto out;
}
if (sshbuf_len(b) != 0) {
r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
goto out;
}
if (len != required_siglen) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (datalen >= SIZE_MAX - len) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
smlen = len + datalen;
mlen = smlen;
if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(sm, sigblob, len);
memcpy(sm+len, data, datalen);
if ((ret = xmss_sign_open(m, &mlen, sm, smlen,
key->xmss_pk, sshkey_xmss_params(key))) != 0) {
debug2_f("xmss_sign_open failed: %d", ret);
}
if (ret != 0 || mlen != datalen) {
r = SSH_ERR_SIGNATURE_INVALID;
goto out;
}
/* XXX compare 'm' and 'data' ? */
/* success */
r = 0;
out:
if (sm != NULL)
freezero(sm, smlen);
if (m != NULL)
freezero(m, smlen);
sshbuf_free(b);
free(ktype);
return r;
}
#endif /* WITH_XMSS */
diff --git a/ssh.0 b/ssh.0
index d1140cf17dff..8449746bd71c 100644
--- a/ssh.0
+++ b/ssh.0
@@ -1,1016 +1,1017 @@
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 [argument ...]]
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 their identity to the
remote machine using one of several methods (see below).
If a command is specified, it will be executed on the remote host instead
of a login shell. A complete command line may be specified as command,
or it may have additional arguments. If supplied, the arguments will be
appended to the command, separated by spaces, before it is sent to the
server to be executed.
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.
+ configuration files; see the Compression option in ssh_config(5).
-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. Refer to the description of
ForkAfterAuthentication in ssh_config(5) for details.
-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. You can also specify a public key
file to use the corresponding private key that is loaded in
ssh-agent(1) when the private key file is not present locally.
The default is ~/.ssh/id_rsa, ~/.ssh/id_ecdsa,
~/.ssh/id_ecdsa_sk, ~/.ssh/id_ed25519, ~/.ssh/id_ed25519_sk and
~/.ssh/id_dsa. 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.
+ keyword in ssh_config(5) for more information.
-N Do not execute a remote command. This is useful for just
forwarding ports. Refer to the description of SessionType in
ssh_config(5) for details.
-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.) Refer to the description of StdinNull in ssh_config(5)
for details.
-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
CheckHostIP
Ciphers
ClearAllForwardings
Compression
ConnectionAttempts
ConnectTimeout
ControlMaster
ControlPath
ControlPersist
DynamicForward
EscapeChar
ExitOnForwardFailure
FingerprintHash
ForkAfterAuthentication
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
+ RequiredRSASize
SendEnv
ServerAliveInterval
ServerAliveCountMax
SessionType
SetEnv
StdinNull
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 for the algorithms supported by one of the following
features: 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. Refer to the description of
SessionType in ssh_config(5) for details.
-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. 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,
keyboard-interactive 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 their 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 their 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.
Keyboard-interactive authentication works as follows: The server sends an
arbitrary "challenge" text and prompts for a response, possibly multiple
times. Examples of keyboard-interactive 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 7.0 March 31, 2022 OpenBSD 7.0
+OpenBSD 7.1 September 17, 2022 OpenBSD 7.1
diff --git a/ssh.1 b/ssh.1
index 4a4f1683a82a..e255b9b9d2e4 100644
--- a/ssh.1
+++ b/ssh.1
@@ -1,1778 +1,1782 @@
.\"
.\" 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.1,v 1.430 2022/03/31 17:27:27 naddy Exp $
-.Dd $Mdocdate: March 31 2022 $
+.\" $OpenBSD: ssh.1,v 1.432 2022/09/17 10:33:18 djm Exp $
+.Dd $Mdocdate: September 17 2022 $
.Dt SSH 1
.Os
.Sh NAME
.Nm ssh
.Nd OpenSSH remote login client
.Sh SYNOPSIS
.Nm ssh
.Op Fl 46AaCfGgKkMNnqsTtVvXxYy
.Op Fl B Ar bind_interface
.Op Fl b Ar bind_address
.Op Fl c Ar cipher_spec
.Op Fl D Oo Ar bind_address : Oc Ns Ar port
.Op Fl E Ar log_file
.Op Fl e Ar escape_char
.Op Fl F Ar configfile
.Op Fl I Ar pkcs11
.Op Fl i Ar identity_file
.Op Fl J Ar destination
.Op Fl L Ar address
.Op Fl l Ar login_name
.Op Fl m Ar mac_spec
.Op Fl O Ar ctl_cmd
.Op Fl o Ar option
.Op Fl p Ar port
.Op Fl Q Ar query_option
.Op Fl R Ar address
.Op Fl S Ar ctl_path
.Op Fl W Ar host : Ns Ar port
.Op Fl w Ar local_tun Ns Op : Ns Ar remote_tun
.Ar destination
.Op Ar command Op Ar argument ...
.Sh DESCRIPTION
.Nm
(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
.Ux Ns -domain
sockets can also be forwarded over the secure channel.
.Pp
.Nm
connects and logs into the specified
.Ar destination ,
which may be specified as either
.Sm off
.Oo user @ Oc hostname
.Sm on
or a URI of the form
.Sm off
.No ssh:// Oo user @ Oc hostname Op : port .
.Sm on
The user must prove
their identity to the remote machine using one of several methods
(see below).
.Pp
If a
.Ar command
is specified,
it will be executed on the remote host instead of a login shell.
A complete command line may be specified as
.Ar command ,
or it may have additional arguments.
If supplied, the arguments will be appended to the command, separated by
spaces, before it is sent to the server to be executed.
.Pp
The options are as follows:
.Pp
.Bl -tag -width Ds -compact
.It Fl 4
Forces
.Nm
to use IPv4 addresses only.
.Pp
.It Fl 6
Forces
.Nm
to use IPv6 addresses only.
.Pp
.It Fl A
Enables forwarding of connections from an authentication agent such as
.Xr ssh-agent 1 .
This can also be specified on a per-host basis in a configuration file.
.Pp
Agent forwarding should be enabled with caution.
Users with the ability to bypass file permissions on the remote host
(for the agent's
.Ux Ns -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
.Fl J ) .
.Pp
.It Fl a
Disables forwarding of the authentication agent connection.
.Pp
.It Fl B Ar bind_interface
Bind to the address of
.Ar bind_interface
before attempting to connect to the destination host.
This is only useful on systems with more than one address.
.Pp
.It Fl b Ar bind_address
Use
.Ar bind_address
on the local machine as the source address
of the connection.
Only useful on systems with more than one address.
.Pp
.It Fl C
Requests compression of all data (including stdin, stdout, stderr, and
data for forwarded X11, TCP and
.Ux Ns -domain
connections).
The compression algorithm is the same used by
.Xr 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
.Cm Compression
-option.
+option in
+.Xr ssh_config 5 .
.Pp
.It Fl c Ar cipher_spec
Selects the cipher specification for encrypting the session.
.Ar cipher_spec
is a comma-separated list of ciphers
listed in order of preference.
See the
.Cm Ciphers
keyword in
.Xr ssh_config 5
for more information.
.Pp
.It Fl D Xo
.Sm off
.Oo Ar bind_address : Oc
.Ar port
.Sm on
.Xc
Specifies a local
.Dq dynamic
application-level port forwarding.
This works by allocating a socket to listen to
.Ar port
on the local side, optionally bound to the specified
.Ar 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
.Nm
will act as a SOCKS server.
Only root can forward privileged ports.
Dynamic port forwardings can also be specified in the configuration file.
.Pp
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
.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
.Dq 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
.It Fl E Ar log_file
Append debug logs to
.Ar log_file
instead of standard error.
.Pp
.It Fl e Ar escape_char
Sets the escape character for sessions with a pty (default:
.Ql ~ ) .
The escape character is only recognized at the beginning of a line.
The escape character followed by a dot
.Pq Ql \&.
closes the connection;
followed by control-Z suspends the connection;
and followed by itself sends the escape character once.
Setting the character to
.Dq none
disables any escapes and makes the session fully transparent.
.Pp
.It Fl F Ar configfile
Specifies an alternative per-user configuration file.
If a configuration file is given on the command line,
the system-wide configuration file
.Pq Pa /etc/ssh/ssh_config
will be ignored.
The default for the per-user configuration file is
.Pa ~/.ssh/config .
If set to
.Dq none ,
no configuration files will be read.
.Pp
.It Fl f
Requests
.Nm
to go to background just before command execution.
This is useful if
.Nm
is going to ask for passwords or passphrases, but the user
wants it in the background.
This implies
.Fl n .
The recommended way to start X11 programs at a remote site is with
something like
.Ic ssh -f host xterm .
.Pp
If the
.Cm ExitOnForwardFailure
configuration option is set to
.Dq yes ,
then a client started with
.Fl f
will wait for all remote port forwards to be successfully established
before placing itself in the background.
Refer to the description of
.Cm ForkAfterAuthentication
in
.Xr ssh_config 5
for details.
.Pp
.It Fl G
Causes
.Nm
to print its configuration after evaluating
.Cm Host
and
.Cm Match
blocks and exit.
.Pp
.It Fl 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.
.Pp
.It Fl I Ar pkcs11
Specify the PKCS#11 shared library
.Nm
should use to communicate with a PKCS#11 token providing keys for user
authentication.
.Pp
.It Fl i Ar identity_file
Selects a file from which the identity (private key) for
public key authentication is read.
You can also specify a public key file to use the corresponding
private key that is loaded in
.Xr ssh-agent 1
when the private key file is not present locally.
The default is
.Pa ~/.ssh/id_rsa ,
.Pa ~/.ssh/id_ecdsa ,
.Pa ~/.ssh/id_ecdsa_sk ,
.Pa ~/.ssh/id_ed25519 ,
.Pa ~/.ssh/id_ed25519_sk
and
.Pa ~/.ssh/id_dsa .
Identity files may also be specified on
a per-host basis in the configuration file.
It is possible to have multiple
.Fl i
options (and multiple identities specified in
configuration files).
If no certificates have been explicitly specified by the
.Cm CertificateFile
directive,
.Nm
will also try to load certificate information from the filename obtained
by appending
.Pa -cert.pub
to identity filenames.
.Pp
.It Fl J Ar destination
Connect to the target host by first making a
.Nm
connection to the jump host described by
.Ar 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
.Cm 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
.Pa ~/.ssh/config
to specify configuration for jump hosts.
.Pp
.It Fl K
Enables GSSAPI-based authentication and forwarding (delegation) of GSSAPI
credentials to the server.
.Pp
.It Fl k
Disables forwarding (delegation) of GSSAPI credentials to the server.
.Pp
.It Fl L Xo
.Sm off
.Oo Ar bind_address : Oc
.Ar port : host : hostport
.Sm on
.Xc
.It Fl L Xo
.Sm off
.Oo Ar bind_address : Oc
.Ar port : remote_socket
.Sm on
.Xc
.It Fl L Xo
.Sm off
.Ar local_socket : host : hostport
.Sm on
.Xc
.It Fl L Xo
.Sm off
.Ar local_socket : remote_socket
.Sm on
.Xc
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
.Ar port
on the local side, optionally bound to the specified
.Ar 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
.Ar host
port
.Ar hostport ,
or the Unix socket
.Ar remote_socket ,
from the remote machine.
.Pp
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.
.Pp
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
.Dq 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
.It Fl l Ar 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.
.Pp
.It Fl M
Places the
.Nm
client into
.Dq master
mode for connection sharing.
Multiple
.Fl M
options places
.Nm
into
.Dq master
mode but with confirmation required using
.Xr ssh-askpass 1
before each operation that changes the multiplexing state
(e.g. opening a new session).
Refer to the description of
.Cm ControlMaster
in
.Xr ssh_config 5
for details.
.Pp
.It Fl m Ar mac_spec
A comma-separated list of MAC (message authentication code) algorithms,
specified in order of preference.
See the
.Cm MACs
-keyword for more information.
+keyword in
+.Xr ssh_config 5
+for more information.
.Pp
.It Fl N
Do not execute a remote command.
This is useful for just forwarding ports.
Refer to the description of
.Cm SessionType
in
.Xr ssh_config 5
for details.
.Pp
.It Fl n
Redirects stdin from
.Pa /dev/null
(actually, prevents reading from stdin).
This must be used when
.Nm
is run in the background.
A common trick is to use this to run X11 programs on a remote machine.
For example,
.Ic 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
.Nm
program will be put in the background.
(This does not work if
.Nm
needs to ask for a password or passphrase; see also the
.Fl f
option.)
Refer to the description of
.Cm StdinNull
in
.Xr ssh_config 5
for details.
.Pp
.It Fl O Ar ctl_cmd
Control an active connection multiplexing master process.
When the
.Fl O
option is specified, the
.Ar ctl_cmd
argument is interpreted and passed to the master process.
Valid commands are:
.Dq check
(check that the master process is running),
.Dq forward
(request forwardings without command execution),
.Dq cancel
(cancel forwardings),
.Dq exit
(request the master to exit), and
.Dq stop
(request the master to stop accepting further multiplexing requests).
.Pp
.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 listed below, and their possible values, see
.Xr ssh_config 5 .
.Pp
.Bl -tag -width Ds -offset indent -compact
.It AddKeysToAgent
.It AddressFamily
.It BatchMode
.It BindAddress
.It CanonicalDomains
.It CanonicalizeFallbackLocal
.It CanonicalizeHostname
.It CanonicalizeMaxDots
.It CanonicalizePermittedCNAMEs
.It CASignatureAlgorithms
.It CertificateFile
.It CheckHostIP
.It Ciphers
.It ClearAllForwardings
.It Compression
.It ConnectionAttempts
.It ConnectTimeout
.It ControlMaster
.It ControlPath
.It ControlPersist
.It DynamicForward
.It EscapeChar
.It ExitOnForwardFailure
.It FingerprintHash
.It ForkAfterAuthentication
.It ForwardAgent
.It ForwardX11
.It ForwardX11Timeout
.It ForwardX11Trusted
.It GatewayPorts
.It GlobalKnownHostsFile
.It GSSAPIAuthentication
.It GSSAPIDelegateCredentials
.It HashKnownHosts
.It Host
.It HostbasedAcceptedAlgorithms
.It HostbasedAuthentication
.It HostKeyAlgorithms
.It HostKeyAlias
.It Hostname
.It IdentitiesOnly
.It IdentityAgent
.It IdentityFile
.It IPQoS
.It KbdInteractiveAuthentication
.It KbdInteractiveDevices
.It KexAlgorithms
.It KnownHostsCommand
.It LocalCommand
.It LocalForward
.It LogLevel
.It MACs
.It Match
.It NoHostAuthenticationForLocalhost
.It NumberOfPasswordPrompts
.It PasswordAuthentication
.It PermitLocalCommand
.It PermitRemoteOpen
.It PKCS11Provider
.It Port
.It PreferredAuthentications
.It ProxyCommand
.It ProxyJump
.It ProxyUseFdpass
.It PubkeyAcceptedAlgorithms
.It PubkeyAuthentication
.It RekeyLimit
.It RemoteCommand
.It RemoteForward
.It RequestTTY
+.It RequiredRSASize
.It SendEnv
.It ServerAliveInterval
.It ServerAliveCountMax
.It SessionType
.It SetEnv
.It StdinNull
.It StreamLocalBindMask
.It StreamLocalBindUnlink
.It StrictHostKeyChecking
.It TCPKeepAlive
.It Tunnel
.It TunnelDevice
.It UpdateHostKeys
.It User
.It UserKnownHostsFile
.It VerifyHostKeyDNS
.It VisualHostKey
.It XAuthLocation
.El
.Pp
.It Fl p Ar port
Port to connect to on the remote host.
This can be specified on a
per-host basis in the configuration file.
.Pp
.It Fl Q Ar query_option
Queries for the algorithms supported by one of the following features:
.Ar cipher
(supported symmetric ciphers),
.Ar cipher-auth
(supported symmetric ciphers that support authenticated encryption),
.Ar help
(supported query terms for use with the
.Fl Q
flag),
.Ar mac
(supported message integrity codes),
.Ar kex
(key exchange algorithms),
.Ar key
(key types),
.Ar key-cert
(certificate key types),
.Ar key-plain
(non-certificate key types),
.Ar key-sig
(all key types and signature algorithms),
.Ar protocol-version
(supported SSH protocol versions), and
.Ar sig
(supported signature algorithms).
Alternatively, any keyword from
.Xr ssh_config 5
or
.Xr sshd_config 5
that takes an algorithm list may be used as an alias for the corresponding
query_option.
.Pp
.It Fl q
Quiet mode.
Causes most warning and diagnostic messages to be suppressed.
.Pp
.It Fl R Xo
.Sm off
.Oo Ar bind_address : Oc
.Ar port : host : hostport
.Sm on
.Xc
.It Fl R Xo
.Sm off
.Oo Ar bind_address : Oc
.Ar port : local_socket
.Sm on
.Xc
.It Fl R Xo
.Sm off
.Ar remote_socket : host : hostport
.Sm on
.Xc
.It Fl R Xo
.Sm off
.Ar remote_socket : local_socket
.Sm on
.Xc
.It Fl R Xo
.Sm off
.Oo Ar bind_address : Oc
.Ar port
.Sm on
.Xc
Specifies that connections to the given TCP port or Unix socket on the remote
(server) host are to be forwarded to the local side.
.Pp
This works by allocating a socket to listen to either a TCP
.Ar 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
.Ar host
port
.Ar hostport ,
or
.Ar local_socket ,
or, if no explicit destination was specified,
.Nm
will act as a SOCKS 4/5 proxy and forward connections to the destinations
requested by the remote SOCKS client.
.Pp
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.
.Pp
By default, TCP listening sockets on the server will be bound to the loopback
interface only.
This may be overridden by specifying a
.Ar bind_address .
An empty
.Ar bind_address ,
or the address
.Ql * ,
indicates that the remote socket should 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 ) .
.Pp
If the
.Ar port
argument is
.Ql 0 ,
the listen port will be dynamically allocated on the server and reported
to the client at run time.
When used together with
.Ic -O forward ,
the allocated port will be printed to the standard output.
.Pp
.It Fl S Ar ctl_path
Specifies the location of a control socket for connection sharing,
or the string
.Dq none
to disable connection sharing.
Refer to the description of
.Cm ControlPath
and
.Cm ControlMaster
in
.Xr ssh_config 5
for details.
.Pp
.It Fl 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.\&
.Xr sftp 1 ) .
The subsystem is specified as the remote command.
Refer to the description of
.Cm SessionType
in
.Xr ssh_config 5
for details.
.Pp
.It Fl T
Disable pseudo-terminal allocation.
.Pp
.It Fl 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
.Fl t
options force tty allocation, even if
.Nm
has no local tty.
.Pp
.It Fl V
Display the version number and exit.
.Pp
.It Fl v
Verbose mode.
Causes
.Nm
to print debugging messages about its progress.
This is helpful in
debugging connection, authentication, and configuration problems.
Multiple
.Fl v
options increase the verbosity.
The maximum is 3.
.Pp
.It Fl W Ar host : Ns Ar port
Requests that standard input and output on the client be forwarded to
.Ar host
on
.Ar port
over the secure channel.
Implies
.Fl N ,
.Fl T ,
.Cm ExitOnForwardFailure
and
.Cm ClearAllForwardings ,
though these can be overridden in the configuration file or using
.Fl o
command line options.
.Pp
.It Fl w Xo
.Ar local_tun Ns Op : Ns Ar remote_tun
.Xc
Requests
tunnel
device forwarding with the specified
.Xr tun 4
devices between the client
.Pq Ar local_tun
and the server
.Pq Ar remote_tun .
.Pp
The devices may be specified by numerical ID or the keyword
.Dq any ,
which uses the next available tunnel device.
If
.Ar remote_tun
is not specified, it defaults to
.Dq any .
See also the
.Cm Tunnel
and
.Cm TunnelDevice
directives in
.Xr ssh_config 5 .
.Pp
If the
.Cm Tunnel
directive is unset, it will be set to the default tunnel mode, which is
.Dq point-to-point .
If a different
.Cm Tunnel
forwarding mode it desired, then it should be specified before
.Fl w .
.Pp
.It Fl X
Enables X11 forwarding.
This can also be specified on a per-host basis in a configuration file.
.Pp
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.
.Pp
For this reason, X11 forwarding is subjected to X11 SECURITY extension
restrictions by default.
Refer to the
.Nm
.Fl Y
option and the
.Cm ForwardX11Trusted
directive in
.Xr ssh_config 5
for more information.
.Pp
.It Fl x
Disables X11 forwarding.
.Pp
.It Fl Y
Enables trusted X11 forwarding.
Trusted X11 forwardings are not subjected to the X11 SECURITY extension
controls.
.Pp
.It Fl y
Send log information using the
.Xr syslog 3
system module.
By default this information is sent to stderr.
.El
.Pp
.Nm
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
.Xr ssh_config 5 .
.Sh AUTHENTICATION
The OpenSSH SSH client supports SSH protocol 2.
.Pp
The methods available for authentication are:
GSSAPI-based authentication,
host-based authentication,
public key authentication,
keyboard-interactive authentication,
and password authentication.
Authentication methods are tried in the order specified above,
though
.Cm PreferredAuthentications
can be used to change the default order.
.Pp
Host-based authentication works as follows:
If the machine the user logs in from is listed in
.Pa /etc/hosts.equiv
or
.Pa /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
.Pa ~/.rhosts
or
.Pa ~/.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
.Em must
be able to verify the client's
host key (see the description of
.Pa /etc/ssh/ssh_known_hosts
and
.Pa ~/.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:
.Pa /etc/hosts.equiv ,
.Pa ~/.rhosts ,
and the rlogin/rsh protocol in general, are inherently insecure and should be
disabled if security is desired.]
.Pp
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.
.Nm
implements public key authentication protocol automatically,
using one of the DSA, ECDSA, Ed25519 or RSA algorithms.
The HISTORY section of
.Xr ssl 8
contains a brief discussion of the DSA and RSA algorithms.
.Pp
The file
.Pa ~/.ssh/authorized_keys
lists the public keys that are permitted for logging in.
When the user logs in, the
.Nm
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.
.Pp
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
.Cm LogLevel
to
.Cm DEBUG
or higher (e.g. by using the
.Fl v
flag).
.Pp
The user creates their key pair by running
.Xr ssh-keygen 1 .
This stores the private key in
.Pa ~/.ssh/id_dsa
(DSA),
.Pa ~/.ssh/id_ecdsa
(ECDSA),
.Pa ~/.ssh/id_ecdsa_sk
(authenticator-hosted ECDSA),
.Pa ~/.ssh/id_ed25519
(Ed25519),
.Pa ~/.ssh/id_ed25519_sk
(authenticator-hosted Ed25519),
or
.Pa ~/.ssh/id_rsa
(RSA)
and stores the public key in
.Pa ~/.ssh/id_dsa.pub
(DSA),
.Pa ~/.ssh/id_ecdsa.pub
(ECDSA),
.Pa ~/.ssh/id_ecdsa_sk.pub
(authenticator-hosted ECDSA),
.Pa ~/.ssh/id_ed25519.pub
(Ed25519),
.Pa ~/.ssh/id_ed25519_sk.pub
(authenticator-hosted Ed25519),
or
.Pa ~/.ssh/id_rsa.pub
(RSA)
in the user's home directory.
The user should then copy the public key
to
.Pa ~/.ssh/authorized_keys
in their home directory on the remote machine.
The
.Pa authorized_keys
file corresponds to the conventional
.Pa ~/.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.
.Pp
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
.Xr ssh-keygen 1
for more information.
.Pp
The most convenient way to use public key or certificate authentication
may be with an authentication agent.
See
.Xr ssh-agent 1
and (optionally) the
.Cm AddKeysToAgent
directive in
.Xr ssh_config 5
for more information.
.Pp
Keyboard-interactive authentication works as follows:
The server sends an arbitrary
.Qq challenge
text and prompts for a response, possibly multiple times.
Examples of keyboard-interactive authentication include
.Bx
Authentication (see
.Xr login.conf 5 )
and PAM (some
.Pf non- Ox
systems).
.Pp
Finally, if other authentication methods fail,
.Nm
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.
.Pp
.Nm
automatically maintains and checks a database containing
identification for all hosts it has ever been used with.
Host keys are stored in
.Pa ~/.ssh/known_hosts
in the user's home directory.
Additionally, the file
.Pa /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,
.Nm
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
.Cm StrictHostKeyChecking
option can be used to control logins to machines whose
host key is not known or has changed.
.Pp
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.
.Pp
If an interactive session is requested,
.Nm
by default will only request a pseudo-terminal (pty) for interactive
sessions when the client has one.
The flags
.Fl T
and
.Fl t
can be used to override this behaviour.
.Pp
If a pseudo-terminal has been allocated, the
user may use the escape characters noted below.
.Pp
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
.Dq none
will also make the session transparent even if a tty is used.
.Pp
The session terminates when the command or shell on the remote
machine exits and all X11 and TCP connections have been closed.
.Sh ESCAPE CHARACTERS
When a pseudo-terminal has been requested,
.Nm
supports a number of functions through the use of an escape character.
.Pp
A single tilde character can be sent as
.Ic ~~
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
.Cm EscapeChar
configuration directive or on the command line by the
.Fl e
option.
.Pp
The supported escapes (assuming the default
.Ql ~ )
are:
.Bl -tag -width Ds
.It Cm ~.
Disconnect.
.It Cm ~^Z
Background
.Nm .
.It Cm ~#
List forwarded connections.
.It Cm ~&
Background
.Nm
at logout when waiting for forwarded connection / X11 sessions to terminate.
.It Cm ~?
Display a list of escape characters.
.It Cm ~B
Send a BREAK to the remote system
(only useful if the peer supports it).
.It Cm ~C
Open command line.
Currently this allows the addition of port forwardings using the
.Fl L ,
.Fl R
and
.Fl D
options (see above).
It also allows the cancellation of existing port-forwardings
with
.Sm off
.Fl KL Oo Ar bind_address : Oc Ar port
.Sm on
for local,
.Sm off
.Fl KR Oo Ar bind_address : Oc Ar port
.Sm on
for remote and
.Sm off
.Fl KD Oo Ar bind_address : Oc Ar port
.Sm on
for dynamic port-forwardings.
.Ic !\& Ns Ar command
allows the user to execute a local command if the
.Ic PermitLocalCommand
option is enabled in
.Xr ssh_config 5 .
Basic help is available, using the
.Fl h
option.
.It Cm ~R
Request rekeying of the connection
(only useful if the peer supports it).
.It Cm ~V
Decrease the verbosity
.Pq Ic LogLevel
when errors are being written to stderr.
.It Cm ~v
Increase the verbosity
.Pq Ic LogLevel
when errors are being written to stderr.
.El
.Sh 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.
.Pp
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
.Nm ,
specifying the ports to be used to forward the connection.
After that it is possible to start the program locally,
and
.Nm
will encrypt and forward the connection to the remote server.
.Pp
The following example tunnels an IRC session from the client
to an IRC server at
.Dq server.example.com ,
joining channel
.Dq #users ,
nickname
.Dq pinky ,
using the standard IRC port, 6667:
.Bd -literal -offset 4n
$ ssh -f -L 6667:localhost:6667 server.example.com sleep 10
$ irc -c '#users' pinky IRC/127.0.0.1
.Ed
.Pp
The
.Fl f
option backgrounds
.Nm
and the remote command
.Dq sleep 10
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,
.Nm
will exit.
.Sh X11 FORWARDING
If the
.Cm ForwardX11
variable is set to
.Dq yes
(or see the description of the
.Fl X ,
.Fl x ,
and
.Fl Y
options above)
and the user is using X11 (the
.Ev 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
.Ev DISPLAY .
Forwarding of X11 connections can be
configured on the command line or in configuration files.
.Pp
The
.Ev DISPLAY
value set by
.Nm
will point to the server machine, but with a display number greater than zero.
This is normal, and happens because
.Nm
creates a
.Dq proxy
X server on the server machine for forwarding the
connections over the encrypted channel.
.Pp
.Nm
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).
.Pp
If the
.Cm ForwardAgent
variable is set to
.Dq yes
(or see the description of the
.Fl A
and
.Fl a
options above) and
the user is using an authentication agent, the connection to the agent
is automatically forwarded to the remote side.
.Sh 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
.Cm StrictHostKeyChecking
has been disabled).
Fingerprints can be determined using
.Xr ssh-keygen 1 :
.Pp
.Dl $ ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key
.Pp
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
.Xr ssh-keygen 1
.Fl E
option may be used to downgrade the fingerprint algorithm to match.
.Pp
Because of the difficulty of comparing host keys
just by looking at fingerprint strings,
there is also support to compare host keys visually,
using
.Em random art .
By setting the
.Cm VisualHostKey
option to
.Dq yes ,
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.
.Pp
To get a listing of the fingerprints along with their random art for
all known hosts, the following command line can be used:
.Pp
.Dl $ ssh-keygen -lv -f ~/.ssh/known_hosts
.Pp
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.
.Pp
In this example, we are connecting a client to a server,
.Dq host.example.com .
The SSHFP resource records should first be added to the zonefile for
host.example.com:
.Bd -literal -offset indent
$ ssh-keygen -r host.example.com.
.Ed
.Pp
The output lines will have to be added to the zonefile.
To check that the zone is answering fingerprint queries:
.Pp
.Dl $ dig -t SSHFP host.example.com
.Pp
Finally the client connects:
.Bd -literal -offset indent
$ ssh -o "VerifyHostKeyDNS ask" host.example.com
[...]
Matching host key fingerprint found in DNS.
Are you sure you want to continue connecting (yes/no)?
.Ed
.Pp
See the
.Cm VerifyHostKeyDNS
option in
.Xr ssh_config 5
for more information.
.Sh SSH-BASED VIRTUAL PRIVATE NETWORKS
.Nm
contains support for Virtual Private Network (VPN) tunnelling
using the
.Xr tun 4
network pseudo-device,
allowing two networks to be joined securely.
The
.Xr sshd_config 5
configuration option
.Cm PermitTunnel
controls whether the server supports this,
and at what level (layer 2 or 3 traffic).
.Pp
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.
.Pp
On the client:
.Bd -literal -offset indent
# 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
.Ed
.Pp
On the server:
.Bd -literal -offset indent
# 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
.Ed
.Pp
Client access may be more finely tuned via the
.Pa /root/.ssh/authorized_keys
file (see below) and the
.Cm PermitRootLogin
server option.
The following entry would permit connections on
.Xr tun 4
device 1 from user
.Dq jane
and on tun device 2 from user
.Dq john ,
if
.Cm PermitRootLogin
is set to
.Dq forced-commands-only :
.Bd -literal -offset 2n
tunnel="1",command="sh /etc/netstart tun1" ssh-rsa ... jane
tunnel="2",command="sh /etc/netstart tun2" ssh-rsa ... john
.Ed
.Pp
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
.Xr ipsecctl 8
and
.Xr isakmpd 8 .
.Sh ENVIRONMENT
.Nm
will normally set the following environment variables:
.Bl -tag -width "SSH_ORIGINAL_COMMAND"
.It Ev DISPLAY
The
.Ev DISPLAY
variable indicates the location of the X11 server.
It is automatically set by
.Nm
to point to a value of the form
.Dq hostname:n ,
where
.Dq hostname
indicates the host where the shell runs, and
.Sq n
is an integer \*(Ge 1.
.Nm
uses this special value to forward X11 connections over the secure
channel.
The user should normally not set
.Ev DISPLAY
explicitly, as that
will render the X11 connection insecure (and will require the user to
manually copy any required authorization cookies).
.It Ev HOME
Set to the path of the user's home directory.
.It Ev LOGNAME
Synonym for
.Ev USER ;
set for compatibility with systems that use this variable.
.It Ev MAIL
Set to the path of the user's mailbox.
.It Ev PATH
Set to the default
.Ev PATH ,
as specified when compiling
.Nm .
.It Ev SSH_ASKPASS
If
.Nm
needs a passphrase, it will read the passphrase from the current
terminal if it was run from a terminal.
If
.Nm
does not have a terminal associated with it but
.Ev DISPLAY
and
.Ev SSH_ASKPASS
are set, it will execute the program specified by
.Ev SSH_ASKPASS
and open an X11 window to read the passphrase.
This is particularly useful when calling
.Nm
from a
.Pa .xsession
or related script.
(Note that on some machines it
may be necessary to redirect the input from
.Pa /dev/null
to make this work.)
.It Ev SSH_ASKPASS_REQUIRE
Allows further control over the use of an askpass program.
If this variable is set to
.Dq never
then
.Nm
will never attempt to use one.
If it is set to
.Dq prefer ,
then
.Nm
will prefer to use the askpass program instead of the TTY when requesting
passwords.
Finally, if the variable is set to
.Dq force ,
then the askpass program will be used for all passphrase input regardless
of whether
.Ev DISPLAY
is set.
.It Ev SSH_AUTH_SOCK
Identifies the path of a
.Ux Ns -domain
socket used to communicate with the agent.
.It Ev 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.
.It Ev 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.
.It Ev 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.
.It Ev SSH_TUNNEL
Optionally set by
.Xr sshd 8
to contain the interface names assigned if tunnel forwarding was
requested by the client.
.It Ev SSH_USER_AUTH
Optionally set by
.Xr 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.
.It Ev 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).
.It Ev USER
Set to the name of the user logging in.
.El
.Pp
Additionally,
.Nm
reads
.Pa ~/.ssh/environment ,
and adds lines of the format
.Dq VARNAME=value
to the environment if the file exists and users are allowed to
change their environment.
For more information, see the
.Cm PermitUserEnvironment
option in
.Xr sshd_config 5 .
.Sh FILES
.Bl -tag -width Ds -compact
.It Pa ~/.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
.Xr 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.
.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 in the
.Xr 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.
.Pp
.It Pa ~/.ssh/config
This is the per-user configuration file.
The file format and configuration options are described in
.Xr 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.
.Pp
.It Pa ~/.ssh/environment
Contains additional definitions for environment variables; see
.Sx ENVIRONMENT ,
above.
.Pp
.It Pa ~/.ssh/id_dsa
.It Pa ~/.ssh/id_ecdsa
.It Pa ~/.ssh/id_ecdsa_sk
.It Pa ~/.ssh/id_ed25519
.It Pa ~/.ssh/id_ed25519_sk
.It Pa ~/.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).
.Nm
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.
.Pp
.It Pa ~/.ssh/id_dsa.pub
.It Pa ~/.ssh/id_ecdsa.pub
.It Pa ~/.ssh/id_ecdsa_sk.pub
.It Pa ~/.ssh/id_ed25519.pub
.It Pa ~/.ssh/id_ed25519_sk.pub
.It Pa ~/.ssh/id_rsa.pub
Contains the public key for authentication.
These files are not
sensitive and can (but need not) be readable by anyone.
.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.
See
.Xr sshd 8
for further details of the format of this file.
.Pp
.It Pa ~/.ssh/rc
Commands in this file are executed by
.Nm
when the user logs in, just before the user's shell (or command) is
started.
See the
.Xr sshd 8
manual page for more information.
.Pp
.It Pa /etc/hosts.equiv
This file is for host-based authentication (see above).
It should only be writable by root.
.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_config
Systemwide configuration file.
The file format and configuration options are described in
.Xr ssh_config 5 .
.Pp
.It Pa /etc/ssh/ssh_host_key
.It Pa /etc/ssh/ssh_host_dsa_key
.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
and are used for host-based authentication.
.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.
It should be world-readable.
See
.Xr sshd 8
for further details of the format of this file.
.Pp
.It Pa /etc/ssh/sshrc
Commands in this file are executed by
.Nm
when the user logs in, just before the user's shell (or command) is started.
See the
.Xr sshd 8
manual page for more information.
.El
.Sh EXIT STATUS
.Nm
exits with the exit status of the remote command or with 255
if an error occurred.
.Sh SEE ALSO
.Xr scp 1 ,
.Xr sftp 1 ,
.Xr ssh-add 1 ,
.Xr ssh-agent 1 ,
.Xr ssh-keygen 1 ,
.Xr ssh-keyscan 1 ,
.Xr tun 4 ,
.Xr ssh_config 5 ,
.Xr ssh-keysign 8 ,
.Xr sshd 8
.Sh STANDARDS
.Rs
.%A S. Lehtinen
.%A C. Lonvick
.%D January 2006
.%R RFC 4250
.%T The Secure Shell (SSH) Protocol Assigned Numbers
.Re
.Pp
.Rs
.%A T. Ylonen
.%A C. Lonvick
.%D January 2006
.%R RFC 4251
.%T The Secure Shell (SSH) Protocol Architecture
.Re
.Pp
.Rs
.%A T. Ylonen
.%A C. Lonvick
.%D January 2006
.%R RFC 4252
.%T The Secure Shell (SSH) Authentication Protocol
.Re
.Pp
.Rs
.%A T. Ylonen
.%A C. Lonvick
.%D January 2006
.%R RFC 4253
.%T The Secure Shell (SSH) Transport Layer Protocol
.Re
.Pp
.Rs
.%A T. Ylonen
.%A C. Lonvick
.%D January 2006
.%R RFC 4254
.%T The Secure Shell (SSH) Connection Protocol
.Re
.Pp
.Rs
.%A J. Schlyter
.%A W. Griffin
.%D January 2006
.%R RFC 4255
.%T Using DNS to Securely Publish Secure Shell (SSH) Key Fingerprints
.Re
.Pp
.Rs
.%A F. Cusack
.%A M. Forssen
.%D January 2006
.%R RFC 4256
.%T Generic Message Exchange Authentication for the Secure Shell Protocol (SSH)
.Re
.Pp
.Rs
.%A J. Galbraith
.%A P. Remaker
.%D January 2006
.%R RFC 4335
.%T The Secure Shell (SSH) Session Channel Break Extension
.Re
.Pp
.Rs
.%A M. Bellare
.%A T. Kohno
.%A C. Namprempre
.%D January 2006
.%R RFC 4344
.%T The Secure Shell (SSH) Transport Layer Encryption Modes
.Re
.Pp
.Rs
.%A B. Harris
.%D January 2006
.%R RFC 4345
.%T Improved Arcfour Modes for the Secure Shell (SSH) Transport Layer Protocol
.Re
.Pp
.Rs
.%A M. Friedl
.%A N. Provos
.%A W. Simpson
.%D March 2006
.%R RFC 4419
.%T Diffie-Hellman Group Exchange for the Secure Shell (SSH) Transport Layer Protocol
.Re
.Pp
.Rs
.%A J. Galbraith
.%A R. Thayer
.%D November 2006
.%R RFC 4716
.%T The Secure Shell (SSH) Public Key File Format
.Re
.Pp
.Rs
.%A D. Stebila
.%A J. Green
.%D December 2009
.%R RFC 5656
.%T Elliptic Curve Algorithm Integration in the Secure Shell Transport Layer
.Re
.Pp
.Rs
.%A A. Perrig
.%A D. Song
.%D 1999
.%O International Workshop on Cryptographic Techniques and E-Commerce (CrypTEC '99)
.%T Hash Visualization: a New Technique to improve Real-World Security
.Re
.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.
diff --git a/ssh.c b/ssh.c
index 89ca1940c1ff..25be53d56918 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,2366 +1,2376 @@
-/* $OpenBSD: ssh.c,v 1.574 2022/03/30 04:33:09 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.576 2022/09/17 10:33:18 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;
/*
* 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, osession_type, otty_flag, orequest_tty;
/*
* 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;
/* # 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 [argument ...]]\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';
debug3_f("lookup %s:%d", name, port);
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' || !config_has_permitted_cnames(&options) ||
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++) {
if (strcasecmp(options.canonical_domains[i], "none") == 0)
break;
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.
+ * Check the result of hostkey loading, ignoring some errors and either
+ * discarding the key or fatal()ing for others.
*/
static void
-check_load(int r, const char *path, const char *message)
+check_load(int r, struct sshkey **k, const char *path, const char *message)
{
switch (r) {
case 0:
+ /* Check RSA keys size and discard if undersized */
+ if (k != NULL && *k != NULL &&
+ (r = sshkey_check_rsa_length(*k,
+ options.required_rsa_size)) != 0) {
+ error_r(r, "load %s \"%s\"", message, path);
+ free(*k);
+ *k = NULL;
+ }
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();
/*
* Discard other fds that are hanging around. These can cause problem
* with backgrounded ssh processes started by ControlPersist.
*/
closefrom(STDERR_FILENO + 1);
__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();
/* 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) { /* HUZdhjruz */
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':
options.stdin_null = 1;
break;
case 'f':
options.fork_after_authentication = 1;
options.stdin_null = 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;
options.session_type = SESSION_TYPE_NONE;
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':
if (options.session_type != -1 &&
options.session_type != SESSION_TYPE_NONE)
fatal("Cannot specify -N with -s/SessionType");
options.session_type = SESSION_TYPE_NONE;
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':
if (options.session_type != -1 &&
options.session_type != SESSION_TYPE_SUBSYSTEM)
fatal("Cannot specify -s with -N/SessionType");
options.session_type = SESSION_TYPE_SUBSYSTEM;
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 (options.session_type == SESSION_TYPE_SUBSYSTEM) {
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");
}
}
+ ssh_signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */
+
/*
* 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 && config_has_permitted_cnames(&options) && (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" argument 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 (options.fork_after_authentication && sshbuf_len(command) == 0 &&
options.remote_command == NULL &&
options.session_type != SESSION_TYPE_NONE)
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++) {
if (strcasecmp(options.log_verbose[j], "none") == 0)
break;
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) ||
options.session_type == SESSION_TYPE_NONE)
tty_flag = 0;
/* Do not allocate a tty if stdin is not a tty. */
if ((!isatty(fileno(stdin)) || options.stdin_null) &&
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);
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"); \
+ &(sensitive_data.keys[o]), p, "pubkey"); \
if (sensitive_data.keys[o] != NULL) \
debug2("hostbased key %d: %s key from \"%s\"", o, \
sshkey_ssh_name(sensitive_data.keys[o]), p); \
} 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"); \
+ check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), \
+ &(sensitive_data.keys[o]), p, "cert"); \
if (sensitive_data.keys[o] != NULL) \
debug2("hostbased key %d: %s cert from \"%s\"", o, \
sshkey_ssh_name(sensitive_data.keys[o]), p); \
} 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 = xstrdup(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);
/* 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);
options.stdin_null = ostdin_null_flag;
options.request_tty = orequest_tty;
tty_flag = otty_flag;
options.session_type = osession_type;
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");
options.fork_after_authentication = 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 (options.fork_after_authentication)
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_path ?
rfwd->connect_path : 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_f("dup() in/out failed");
if ((c = channel_connect_stdio_fwd(ssh, options.stdio_forward_host,
options.stdio_forward_port, in, out,
CHANNEL_NONBLOCK_STDIO)) == 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;
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]);
addr = hpdelim(&arg);
if (addr == NULL)
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, *term;
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);
if ((term = lookup_env_in_list("TERM", options.setenv,
options.num_setenv)) == NULL || *term == '\0')
term = getenv("TERM");
client_session2_setup(ssh, id, tty_flag,
options.session_type == SESSION_TYPE_SUBSYSTEM, 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 (options.stdin_null) {
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");
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", CHANNEL_NONBLOCK_STDIO);
debug3_f("channel_new: %d", c->self);
channel_send_open(ssh, c->self);
if (options.session_type != SESSION_TYPE_NONE)
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 = options.stdin_null;
osession_type = options.session_type;
orequest_tty = options.request_tty;
otty_flag = tty_flag;
options.stdin_null = 1;
options.session_type = SESSION_TYPE_NONE;
tty_flag = 0;
if (!options.fork_after_authentication &&
(osession_type != SESSION_TYPE_NONE ||
options.stdio_forward_host != NULL))
need_controlpersist_detach = 1;
options.fork_after_authentication = 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 (options.session_type != SESSION_TYPE_NONE)
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 (options.fork_after_authentication) {
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");
+ &public, 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");
+ &public, 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");
+ &public, 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_config.0 b/ssh_config.0
index 50cdbca70752..85eefd2a70ea 100644
--- a/ssh_config.0
+++ b/ssh_config.0
@@ -1,1311 +1,1318 @@
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. A value of
none disables the use of a ProxyJump host.
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.
A single argument of "none" causes no CNAMEs to be considered for
canonicalization. This is the default behaviour.
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,
sk-ssh-ed25519@openssh.com,
sk-ecdsa-sha2-nistp256@openssh.com,
rsa-sha2-512,rsa-sha2-256
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.
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.
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).
ForkAfterAuthentication
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 the StdinNull configuration option being set to M-bM-^@M-^\yesM-bM-^@M-^].
The recommended way to start X11 programs at a remote site is
with something like ssh -f host xterm, which is the same as ssh
host xterm if the ForkAfterAuthentication configuration option is
set to M-bM-^@M-^\yesM-bM-^@M-^].
If the ExitOnForwardFailure configuration option is set to M-bM-^@M-^\yesM-bM-^@M-^],
then a client started with the ForkAfterAuthentication
configuration option being set to M-bM-^@M-^\yesM-bM-^@M-^] will wait for all remote
port forwards to be successfully established before placing
itself in the background. The argument to this keyword must be
yes (same as the -f option) or no (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-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
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-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
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_rsa,
~/.ssh/id_ecdsa, ~/.ssh/id_ecdsa_sk, ~/.ssh/id_ed25519,
~/.ssh/id_ed25519_sk and ~/.ssh/id_dsa. 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.
ChallengeResponseAuthentication is a deprecated alias for this.
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 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 is:
sntrup761x25519-sha512@openssh.com,
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-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
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), no, unbound or
host-bound. The final two options enable public key
authentication while respectively disabling or enabling the
OpenSSH host-bound authentication protocol extension required for
restricted ssh-agent(1) forwarding.
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
+ Specifies the maximum amount of data that may be transmitted or
+ received 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).
+ RequiredRSASize
+ Specifies the minimum RSA key size (in bits) that ssh(1) will
+ accept. User authentication keys smaller than this limit will be
+ ignored. Servers that present host keys smaller than this limit
+ will cause the connection to be terminated. The default is 1024
+ bits. Note that this limit may only be raised from the default.
+
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.
SessionType
May be used to either request invocation of a subsystem on the
remote system, or to prevent the execution of a remote command at
all. The latter is useful for just forwarding ports. The
argument to this keyword must be none (same as the -N option),
subsystem (same as the -s option) or default (shell or command
execution).
SetEnv Directly specify one or more environment variables and their
contents to be sent to the server. Similarly to SendEnv, with
the exception of the TERM variable, the server must be prepared
to accept the environment variable.
StdinNull
Redirects stdin from /dev/null (actually, prevents reading from
stdin). Either this or the equivalent -n option must be used
when ssh is run in the background. The argument to this keyword
must be yes (same as the -n option) or no (the default).
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 accept-new then ssh will automatically add
new host keys to the user's known_hosts file, but will not permit
connections to hosts with changed host keys. If this flag is set
to no or 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 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 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.
+ ProxyCommand and ProxyJump accept 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,
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 7.0 March 31, 2022 OpenBSD 7.0
+OpenBSD 7.1 September 17, 2022 OpenBSD 7.1
diff --git a/ssh_config.5 b/ssh_config.5
index 59ff96465e1c..d1ede18e780d 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -1,2180 +1,2193 @@
.\"
.\" 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.371 2022/03/31 17:58:44 naddy Exp $
-.Dd $Mdocdate: March 31 2022 $
+.\" $OpenBSD: ssh_config.5,v 1.374 2022/09/17 10:33:18 djm Exp $
+.Dd $Mdocdate: September 17 2022 $
.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.
A value of
.Cm none
disables the use of a
.Cm ProxyJump
host.
.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.
.Pp
A single argument of
.Qq none
causes no CNAMEs to be considered for canonicalization.
This is the default behaviour.
.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,
sk-ssh-ed25519@openssh.com,
sk-ecdsa-sha2-nistp256@openssh.com,
rsa-sha2-512,rsa-sha2-256
.Ed
.Pp
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.
.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 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 ForkAfterAuthentication
Requests
.Nm ssh
to go to background just before command execution.
This is useful if
.Nm ssh
is going to ask for passwords or passphrases, but the user
wants it in the background.
This implies the
.Cm StdinNull
configuration option being set to
.Dq yes .
The recommended way to start X11 programs at a remote site is with
something like
.Ic ssh -f host xterm ,
which is the same as
.Ic ssh host xterm
if the
.Cm ForkAfterAuthentication
configuration option is set to
.Dq yes .
.Pp
If the
.Cm ExitOnForwardFailure
configuration option is set to
.Dq yes ,
then a client started with the
.Cm ForkAfterAuthentication
configuration option being set to
.Dq yes
will wait for all remote port forwards to be successfully established
before placing itself in the background.
The argument to this keyword must be
.Cm yes
(same as the
.Fl f
option) or
.Cm no
(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-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
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-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
.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_rsa ,
.Pa ~/.ssh/id_ecdsa ,
.Pa ~/.ssh/id_ecdsa_sk ,
.Pa ~/.ssh/id_ed25519 ,
.Pa ~/.ssh/id_ed25519_sk
and
.Pa ~/.ssh/id_dsa .
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 .
.Cm ChallengeResponseAuthentication
is a deprecated alias for this.
.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 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 is:
.Bd -literal -offset indent
sntrup761x25519-sha512@openssh.com,
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-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
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),
.Cm no ,
.Cm unbound
or
.Cm host-bound .
The final two options enable public key authentication while respectively
disabling or enabling the OpenSSH host-bound authentication protocol
extension required for restricted
.Xr ssh-agent 1
forwarding.
.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.
+Specifies the maximum amount of data that may be transmitted or received
+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 RequiredRSASize
+Specifies the minimum RSA key size (in bits) that
+.Xr ssh 1
+will accept.
+User authentication keys smaller than this limit will be ignored.
+Servers that present host keys smaller than this limit will cause the
+connection to be terminated.
+The default is
+.Cm 1024
+bits.
+Note that this limit may only be raised from the default.
.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 SessionType
May be used to either request invocation of a subsystem on the remote system,
or to prevent the execution of a remote command at all.
The latter is useful for just forwarding ports.
The argument to this keyword must be
.Cm none
(same as the
.Fl N
option),
.Cm subsystem
(same as the
.Fl s
option) or
.Cm default
(shell or command execution).
.It Cm SetEnv
Directly specify one or more environment variables and their contents to
be sent to the server.
Similarly to
.Cm SendEnv ,
with the exception of the
.Ev TERM
variable, the server must be prepared to accept the environment variable.
.It Cm StdinNull
Redirects stdin from
.Pa /dev/null
(actually, prevents reading from stdin).
Either this or the equivalent
.Fl n
option must be used when
.Nm ssh
is run in the background.
The argument to this keyword must be
.Cm yes
(same as the
.Fl n
option) or
.Cm no
(the default).
.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
.Cm accept-new
then ssh will automatically add new host keys to the user's
.Pa known_hosts
file, but will not permit connections to hosts with
changed host keys.
If this flag is set to
.Cm no
or
.Cm 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 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.
+and
+.Cm ProxyJump
+accept 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 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/sshbuf-getput-basic.c b/sshbuf-getput-basic.c
index 9803fb5ed904..5c71b0e53563 100644
--- a/sshbuf-getput-basic.c
+++ b/sshbuf-getput-basic.c
@@ -1,633 +1,633 @@
-/* $OpenBSD: sshbuf-getput-basic.c,v 1.11 2020/06/05 03:25:35 djm Exp $ */
+/* $OpenBSD: sshbuf-getput-basic.c,v 1.13 2022/05/25 06:03:44 djm Exp $ */
/*
* Copyright (c) 2011 Damien Miller
*
* 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.
*/
#define SSHBUF_INTERNAL
#include "includes.h"
#include <sys/types.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#include "ssherr.h"
#include "sshbuf.h"
int
sshbuf_get(struct sshbuf *buf, void *v, size_t len)
{
const u_char *p = sshbuf_ptr(buf);
int r;
if ((r = sshbuf_consume(buf, len)) < 0)
return r;
if (v != NULL && len != 0)
memcpy(v, p, len);
return 0;
}
int
sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp)
{
const u_char *p = sshbuf_ptr(buf);
int r;
if ((r = sshbuf_consume(buf, 8)) < 0)
return r;
if (valp != NULL)
*valp = PEEK_U64(p);
return 0;
}
int
sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp)
{
const u_char *p = sshbuf_ptr(buf);
int r;
if ((r = sshbuf_consume(buf, 4)) < 0)
return r;
if (valp != NULL)
*valp = PEEK_U32(p);
return 0;
}
int
sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp)
{
const u_char *p = sshbuf_ptr(buf);
int r;
if ((r = sshbuf_consume(buf, 2)) < 0)
return r;
if (valp != NULL)
*valp = PEEK_U16(p);
return 0;
}
int
sshbuf_get_u8(struct sshbuf *buf, u_char *valp)
{
const u_char *p = sshbuf_ptr(buf);
int r;
if ((r = sshbuf_consume(buf, 1)) < 0)
return r;
if (valp != NULL)
*valp = (u_int8_t)*p;
return 0;
}
static int
check_offset(const struct sshbuf *buf, int wr, size_t offset, size_t len)
{
if (sshbuf_ptr(buf) == NULL) /* calls sshbuf_check_sanity() */
return SSH_ERR_INTERNAL_ERROR;
if (offset >= SIZE_MAX - len)
return SSH_ERR_INVALID_ARGUMENT;
if (offset + len > sshbuf_len(buf)) {
return wr ?
SSH_ERR_NO_BUFFER_SPACE : SSH_ERR_MESSAGE_INCOMPLETE;
}
return 0;
}
static int
check_roffset(const struct sshbuf *buf, size_t offset, size_t len,
const u_char **p)
{
int r;
*p = NULL;
if ((r = check_offset(buf, 0, offset, len)) != 0)
return r;
*p = sshbuf_ptr(buf) + offset;
return 0;
}
int
sshbuf_peek_u64(const struct sshbuf *buf, size_t offset, u_int64_t *valp)
{
const u_char *p = NULL;
int r;
if (valp != NULL)
*valp = 0;
if ((r = check_roffset(buf, offset, 8, &p)) != 0)
return r;
if (valp != NULL)
*valp = PEEK_U64(p);
return 0;
}
int
sshbuf_peek_u32(const struct sshbuf *buf, size_t offset, u_int32_t *valp)
{
const u_char *p = NULL;
int r;
if (valp != NULL)
*valp = 0;
if ((r = check_roffset(buf, offset, 4, &p)) != 0)
return r;
if (valp != NULL)
*valp = PEEK_U32(p);
return 0;
}
int
sshbuf_peek_u16(const struct sshbuf *buf, size_t offset, u_int16_t *valp)
{
const u_char *p = NULL;
int r;
if (valp != NULL)
*valp = 0;
if ((r = check_roffset(buf, offset, 2, &p)) != 0)
return r;
if (valp != NULL)
*valp = PEEK_U16(p);
return 0;
}
int
sshbuf_peek_u8(const struct sshbuf *buf, size_t offset, u_char *valp)
{
const u_char *p = NULL;
int r;
if (valp != NULL)
*valp = 0;
if ((r = check_roffset(buf, offset, 1, &p)) != 0)
return r;
if (valp != NULL)
*valp = *p;
return 0;
}
int
sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp)
{
const u_char *val;
size_t len;
int r;
if (valp != NULL)
*valp = NULL;
if (lenp != NULL)
*lenp = 0;
if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
return r;
if (valp != NULL) {
if ((*valp = malloc(len + 1)) == NULL) {
SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
return SSH_ERR_ALLOC_FAIL;
}
if (len != 0)
memcpy(*valp, val, len);
(*valp)[len] = '\0';
}
if (lenp != NULL)
*lenp = len;
return 0;
}
int
sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
{
size_t len;
const u_char *p;
int r;
if (valp != NULL)
*valp = NULL;
if (lenp != NULL)
*lenp = 0;
if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
return r;
if (valp != NULL)
*valp = p;
if (lenp != NULL)
*lenp = len;
if (sshbuf_consume(buf, len + 4) != 0) {
/* Shouldn't happen */
SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
SSHBUF_ABORT();
return SSH_ERR_INTERNAL_ERROR;
}
return 0;
}
int
sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
size_t *lenp)
{
u_int32_t len;
const u_char *p = sshbuf_ptr(buf);
if (valp != NULL)
*valp = NULL;
if (lenp != NULL)
*lenp = 0;
if (sshbuf_len(buf) < 4) {
SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
return SSH_ERR_MESSAGE_INCOMPLETE;
}
len = PEEK_U32(p);
if (len > SSHBUF_SIZE_MAX - 4) {
SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
return SSH_ERR_STRING_TOO_LARGE;
}
if (sshbuf_len(buf) - 4 < len) {
SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
return SSH_ERR_MESSAGE_INCOMPLETE;
}
if (valp != NULL)
*valp = p + 4;
if (lenp != NULL)
*lenp = len;
return 0;
}
int
sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp)
{
size_t len;
const u_char *p, *z;
int r;
if (valp != NULL)
*valp = NULL;
if (lenp != NULL)
*lenp = 0;
if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
return r;
/* Allow a \0 only at the end of the string */
if (len > 0 &&
(z = memchr(p , '\0', len)) != NULL && z < p + len - 1) {
SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
return SSH_ERR_INVALID_FORMAT;
}
if ((r = sshbuf_skip_string(buf)) != 0)
return -1;
if (valp != NULL) {
if ((*valp = malloc(len + 1)) == NULL) {
SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
return SSH_ERR_ALLOC_FAIL;
}
if (len != 0)
memcpy(*valp, p, len);
(*valp)[len] = '\0';
}
if (lenp != NULL)
*lenp = (size_t)len;
return 0;
}
int
sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v)
{
u_int32_t len;
u_char *p;
int r;
/*
* Use sshbuf_peek_string_direct() to figure out if there is
* a complete string in 'buf' and copy the string directly
* into 'v'.
*/
if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 ||
(r = sshbuf_get_u32(buf, &len)) != 0 ||
(r = sshbuf_reserve(v, len, &p)) != 0 ||
(r = sshbuf_get(buf, p, len)) != 0)
return r;
return 0;
}
int
sshbuf_put(struct sshbuf *buf, const void *v, size_t len)
{
u_char *p;
int r;
if ((r = sshbuf_reserve(buf, len, &p)) < 0)
return r;
if (len != 0)
memcpy(p, v, len);
return 0;
}
int
sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
{
if (v == NULL)
return 0;
return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
}
int
sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
{
va_list ap;
int r;
va_start(ap, fmt);
r = sshbuf_putfv(buf, fmt, ap);
va_end(ap);
return r;
}
int
sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
{
va_list ap2;
int r, len;
u_char *p;
VA_COPY(ap2, ap);
if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if (len == 0) {
r = 0;
goto out; /* Nothing to do */
}
va_end(ap2);
VA_COPY(ap2, ap);
if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
goto out;
if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) {
r = SSH_ERR_INTERNAL_ERROR;
goto out; /* Shouldn't happen */
}
/* Consume terminating \0 */
if ((r = sshbuf_consume_end(buf, 1)) != 0)
goto out;
r = 0;
out:
va_end(ap2);
return r;
}
int
sshbuf_put_u64(struct sshbuf *buf, u_int64_t val)
{
u_char *p;
int r;
if ((r = sshbuf_reserve(buf, 8, &p)) < 0)
return r;
POKE_U64(p, val);
return 0;
}
int
sshbuf_put_u32(struct sshbuf *buf, u_int32_t val)
{
u_char *p;
int r;
if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
return r;
POKE_U32(p, val);
return 0;
}
int
sshbuf_put_u16(struct sshbuf *buf, u_int16_t val)
{
u_char *p;
int r;
if ((r = sshbuf_reserve(buf, 2, &p)) < 0)
return r;
POKE_U16(p, val);
return 0;
}
int
sshbuf_put_u8(struct sshbuf *buf, u_char val)
{
u_char *p;
int r;
if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
return r;
p[0] = val;
return 0;
}
static int
check_woffset(struct sshbuf *buf, size_t offset, size_t len, u_char **p)
{
int r;
*p = NULL;
if ((r = check_offset(buf, 1, offset, len)) != 0)
return r;
if (sshbuf_mutable_ptr(buf) == NULL)
return SSH_ERR_BUFFER_READ_ONLY;
*p = sshbuf_mutable_ptr(buf) + offset;
return 0;
}
int
sshbuf_poke_u64(struct sshbuf *buf, size_t offset, u_int64_t val)
{
u_char *p = NULL;
int r;
if ((r = check_woffset(buf, offset, 8, &p)) != 0)
return r;
POKE_U64(p, val);
return 0;
}
int
sshbuf_poke_u32(struct sshbuf *buf, size_t offset, u_int32_t val)
{
u_char *p = NULL;
int r;
if ((r = check_woffset(buf, offset, 4, &p)) != 0)
return r;
POKE_U32(p, val);
return 0;
}
int
sshbuf_poke_u16(struct sshbuf *buf, size_t offset, u_int16_t val)
{
u_char *p = NULL;
int r;
if ((r = check_woffset(buf, offset, 2, &p)) != 0)
return r;
POKE_U16(p, val);
return 0;
}
int
sshbuf_poke_u8(struct sshbuf *buf, size_t offset, u_char val)
{
u_char *p = NULL;
int r;
if ((r = check_woffset(buf, offset, 1, &p)) != 0)
return r;
*p = val;
return 0;
}
int
sshbuf_poke(struct sshbuf *buf, size_t offset, void *v, size_t len)
{
u_char *p = NULL;
int r;
if ((r = check_woffset(buf, offset, len, &p)) != 0)
return r;
memcpy(p, v, len);
return 0;
}
int
sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
{
u_char *d;
int r;
if (len > SSHBUF_SIZE_MAX - 4) {
SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
return SSH_ERR_NO_BUFFER_SPACE;
}
if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
return r;
POKE_U32(d, len);
if (len != 0)
memcpy(d + 4, v, len);
return 0;
}
int
sshbuf_put_cstring(struct sshbuf *buf, const char *v)
{
return sshbuf_put_string(buf, v, v == NULL ? 0 : strlen(v));
}
int
sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
{
if (v == NULL)
return sshbuf_put_string(buf, NULL, 0);
return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
}
int
sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp)
{
const u_char *p;
size_t len;
struct sshbuf *ret;
int r;
if (buf == NULL || bufp == NULL)
return SSH_ERR_INVALID_ARGUMENT;
*bufp = NULL;
if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
return r;
if ((ret = sshbuf_from(p, len)) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_consume(buf, len + 4)) != 0 || /* Shouldn't happen */
(r = sshbuf_set_parent(ret, buf)) != 0) {
sshbuf_free(ret);
return r;
}
*bufp = ret;
return 0;
}
int
sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len)
{
u_char *d;
const u_char *s = (const u_char *)v;
int r, prepend;
if (len > SSHBUF_SIZE_MAX - 5) {
SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
return SSH_ERR_NO_BUFFER_SPACE;
}
/* Skip leading zero bytes */
for (; len > 0 && *s == 0; len--, s++)
;
/*
* If most significant bit is set then prepend a zero byte to
* avoid interpretation as a negative number.
*/
prepend = len > 0 && (s[0] & 0x80) != 0;
if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0)
return r;
POKE_U32(d, len + prepend);
if (prepend)
d[4] = 0;
if (len != 0)
memcpy(d + 4 + prepend, s, len);
return 0;
}
int
sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf,
const u_char **valp, size_t *lenp)
{
const u_char *d;
size_t len, olen;
int r;
if ((r = sshbuf_peek_string_direct(buf, &d, &olen)) < 0)
return r;
len = olen;
/* Refuse negative (MSB set) bignums */
if ((len != 0 && (*d & 0x80) != 0))
return SSH_ERR_BIGNUM_IS_NEGATIVE;
/* Refuse overlong bignums, allow prepended \0 to avoid MSB set */
if (len > SSHBUF_MAX_BIGNUM + 1 ||
(len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
return SSH_ERR_BIGNUM_TOO_LARGE;
/* Trim leading zeros */
while (len > 0 && *d == 0x00) {
d++;
len--;
}
if (valp != NULL)
*valp = d;
if (lenp != NULL)
*lenp = len;
if (sshbuf_consume(buf, olen + 4) != 0) {
/* Shouldn't happen */
SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
SSHBUF_ABORT();
return SSH_ERR_INTERNAL_ERROR;
}
return 0;
}
diff --git a/sshbuf-getput-crypto.c b/sshbuf-getput-crypto.c
index 2e61d3bcd809..56ffdd86156a 100644
--- a/sshbuf-getput-crypto.c
+++ b/sshbuf-getput-crypto.c
@@ -1,180 +1,180 @@
-/* $OpenBSD: sshbuf-getput-crypto.c,v 1.8 2019/11/15 06:00:20 djm Exp $ */
+/* $OpenBSD: sshbuf-getput-crypto.c,v 1.10 2022/05/25 06:03:44 djm Exp $ */
/*
* Copyright (c) 2011 Damien Miller
*
* 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.
*/
#define SSHBUF_INTERNAL
#include "includes.h"
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef WITH_OPENSSL
#include <openssl/bn.h>
#ifdef OPENSSL_HAS_ECC
# include <openssl/ec.h>
#endif /* OPENSSL_HAS_ECC */
#include "ssherr.h"
#include "sshbuf.h"
int
sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM **valp)
{
BIGNUM *v;
const u_char *d;
size_t len;
int r;
if (valp != NULL)
*valp = NULL;
if ((r = sshbuf_get_bignum2_bytes_direct(buf, &d, &len)) != 0)
return r;
if (valp != NULL) {
if ((v = BN_new()) == NULL ||
BN_bin2bn(d, len, v) == NULL) {
BN_clear_free(v);
return SSH_ERR_ALLOC_FAIL;
}
*valp = v;
}
return 0;
}
#ifdef OPENSSL_HAS_ECC
static int
get_ec(const u_char *d, size_t len, EC_POINT *v, const EC_GROUP *g)
{
/* Refuse overlong bignums */
if (len == 0 || len > SSHBUF_MAX_ECPOINT)
return SSH_ERR_ECPOINT_TOO_LARGE;
/* Only handle uncompressed points */
if (*d != POINT_CONVERSION_UNCOMPRESSED)
return SSH_ERR_INVALID_FORMAT;
if (v != NULL && EC_POINT_oct2point(g, v, d, len, NULL) != 1)
return SSH_ERR_INVALID_FORMAT; /* XXX assumption */
return 0;
}
int
sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g)
{
const u_char *d;
size_t len;
int r;
if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
return r;
if ((r = get_ec(d, len, v, g)) != 0)
return r;
/* Skip string */
if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
/* Shouldn't happen */
SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
SSHBUF_ABORT();
return SSH_ERR_INTERNAL_ERROR;
}
return 0;
}
int
sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v)
{
EC_POINT *pt = EC_POINT_new(EC_KEY_get0_group(v));
int r;
const u_char *d;
size_t len;
if (pt == NULL) {
SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
return SSH_ERR_ALLOC_FAIL;
}
if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) {
EC_POINT_free(pt);
return r;
}
if ((r = get_ec(d, len, pt, EC_KEY_get0_group(v))) != 0) {
EC_POINT_free(pt);
return r;
}
if (EC_KEY_set_public_key(v, pt) != 1) {
EC_POINT_free(pt);
return SSH_ERR_ALLOC_FAIL; /* XXX assumption */
}
EC_POINT_free(pt);
/* Skip string */
if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
/* Shouldn't happen */
SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
SSHBUF_ABORT();
return SSH_ERR_INTERNAL_ERROR;
}
return 0;
}
#endif /* OPENSSL_HAS_ECC */
int
sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v)
{
u_char d[SSHBUF_MAX_BIGNUM + 1];
int len = BN_num_bytes(v), prepend = 0, r;
if (len < 0 || len > SSHBUF_MAX_BIGNUM)
return SSH_ERR_INVALID_ARGUMENT;
*d = '\0';
if (BN_bn2bin(v, d + 1) != len)
return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
/* If MSB is set, prepend a \0 */
if (len > 0 && (d[1] & 0x80) != 0)
prepend = 1;
if ((r = sshbuf_put_string(buf, d + 1 - prepend, len + prepend)) < 0) {
explicit_bzero(d, sizeof(d));
return r;
}
explicit_bzero(d, sizeof(d));
return 0;
}
#ifdef OPENSSL_HAS_ECC
int
sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g)
{
u_char d[SSHBUF_MAX_ECPOINT];
size_t len;
int ret;
if ((len = EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
NULL, 0, NULL)) > SSHBUF_MAX_ECPOINT) {
return SSH_ERR_INVALID_ARGUMENT;
}
if (EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
d, len, NULL) != len) {
return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
}
ret = sshbuf_put_string(buf, d, len);
explicit_bzero(d, len);
return ret;
}
int
sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v)
{
return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v),
EC_KEY_get0_group(v));
}
#endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
diff --git a/sshbuf.c b/sshbuf.c
index 368ba7980b75..d5757b7264ed 100644
--- a/sshbuf.c
+++ b/sshbuf.c
@@ -1,401 +1,404 @@
-/* $OpenBSD: sshbuf.c,v 1.15 2020/02/26 13:40:09 jsg Exp $ */
+/* $OpenBSD: sshbuf.c,v 1.18 2022/05/25 06:03:44 djm Exp $ */
/*
* Copyright (c) 2011 Damien Miller
*
* 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.
*/
#define SSHBUF_INTERNAL
#include "includes.h"
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "ssherr.h"
#include "sshbuf.h"
#include "misc.h"
static inline int
sshbuf_check_sanity(const struct sshbuf *buf)
{
SSHBUF_TELL("sanity");
if (__predict_false(buf == NULL ||
(!buf->readonly && buf->d != buf->cd) ||
buf->refcount < 1 || buf->refcount > SSHBUF_REFS_MAX ||
buf->cd == NULL ||
buf->max_size > SSHBUF_SIZE_MAX ||
buf->alloc > buf->max_size ||
buf->size > buf->alloc ||
buf->off > buf->size)) {
/* Do not try to recover from corrupted buffer internals */
SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
ssh_signal(SIGSEGV, SIG_DFL);
raise(SIGSEGV);
return SSH_ERR_INTERNAL_ERROR;
}
return 0;
}
static void
sshbuf_maybe_pack(struct sshbuf *buf, int force)
{
SSHBUF_DBG(("force %d", force));
SSHBUF_TELL("pre-pack");
if (buf->off == 0 || buf->readonly || buf->refcount > 1)
return;
if (force ||
(buf->off >= SSHBUF_PACK_MIN && buf->off >= buf->size / 2)) {
memmove(buf->d, buf->d + buf->off, buf->size - buf->off);
buf->size -= buf->off;
buf->off = 0;
SSHBUF_TELL("packed");
}
}
struct sshbuf *
sshbuf_new(void)
{
struct sshbuf *ret;
if ((ret = calloc(sizeof(*ret), 1)) == NULL)
return NULL;
ret->alloc = SSHBUF_SIZE_INIT;
ret->max_size = SSHBUF_SIZE_MAX;
ret->readonly = 0;
ret->refcount = 1;
ret->parent = NULL;
if ((ret->cd = ret->d = calloc(1, ret->alloc)) == NULL) {
free(ret);
return NULL;
}
return ret;
}
struct sshbuf *
sshbuf_from(const void *blob, size_t len)
{
struct sshbuf *ret;
if (blob == NULL || len > SSHBUF_SIZE_MAX ||
(ret = calloc(sizeof(*ret), 1)) == NULL)
return NULL;
ret->alloc = ret->size = ret->max_size = len;
ret->readonly = 1;
ret->refcount = 1;
ret->parent = NULL;
ret->cd = blob;
ret->d = NULL;
return ret;
}
int
sshbuf_set_parent(struct sshbuf *child, struct sshbuf *parent)
{
int r;
if ((r = sshbuf_check_sanity(child)) != 0 ||
(r = sshbuf_check_sanity(parent)) != 0)
return r;
+ if (child->parent != NULL && child->parent != parent)
+ return SSH_ERR_INTERNAL_ERROR;
child->parent = parent;
child->parent->refcount++;
return 0;
}
struct sshbuf *
sshbuf_fromb(struct sshbuf *buf)
{
struct sshbuf *ret;
if (sshbuf_check_sanity(buf) != 0)
return NULL;
if ((ret = sshbuf_from(sshbuf_ptr(buf), sshbuf_len(buf))) == NULL)
return NULL;
if (sshbuf_set_parent(ret, buf) != 0) {
sshbuf_free(ret);
return NULL;
}
return ret;
}
void
sshbuf_free(struct sshbuf *buf)
{
if (buf == NULL)
return;
/*
* The following will leak on insane buffers, but this is the safest
* course of action - an invalid pointer or already-freed pointer may
* have been passed to us and continuing to scribble over memory would
* be bad.
*/
if (sshbuf_check_sanity(buf) != 0)
return;
/*
* If we are a parent with still-extant children, then don't free just
* yet. The last child's call to sshbuf_free should decrement our
* refcount to 0 and trigger the actual free.
*/
buf->refcount--;
if (buf->refcount > 0)
return;
/*
* If we are a child, the free our parent to decrement its reference
* count and possibly free it.
*/
sshbuf_free(buf->parent);
buf->parent = NULL;
if (!buf->readonly) {
explicit_bzero(buf->d, buf->alloc);
free(buf->d);
}
freezero(buf, sizeof(*buf));
}
void
sshbuf_reset(struct sshbuf *buf)
{
u_char *d;
if (buf->readonly || buf->refcount > 1) {
/* Nonsensical. Just make buffer appear empty */
buf->off = buf->size;
return;
}
- (void) sshbuf_check_sanity(buf);
+ if (sshbuf_check_sanity(buf) != 0)
+ return;
buf->off = buf->size = 0;
if (buf->alloc != SSHBUF_SIZE_INIT) {
if ((d = recallocarray(buf->d, buf->alloc, SSHBUF_SIZE_INIT,
1)) != NULL) {
buf->cd = buf->d = d;
buf->alloc = SSHBUF_SIZE_INIT;
}
}
- explicit_bzero(buf->d, SSHBUF_SIZE_INIT);
+ explicit_bzero(buf->d, buf->alloc);
}
size_t
sshbuf_max_size(const struct sshbuf *buf)
{
return buf->max_size;
}
size_t
sshbuf_alloc(const struct sshbuf *buf)
{
return buf->alloc;
}
const struct sshbuf *
sshbuf_parent(const struct sshbuf *buf)
{
return buf->parent;
}
u_int
sshbuf_refcount(const struct sshbuf *buf)
{
return buf->refcount;
}
int
sshbuf_set_max_size(struct sshbuf *buf, size_t max_size)
{
size_t rlen;
u_char *dp;
int r;
SSHBUF_DBG(("set max buf = %p len = %zu", buf, max_size));
if ((r = sshbuf_check_sanity(buf)) != 0)
return r;
if (max_size == buf->max_size)
return 0;
if (buf->readonly || buf->refcount > 1)
return SSH_ERR_BUFFER_READ_ONLY;
if (max_size > SSHBUF_SIZE_MAX)
return SSH_ERR_NO_BUFFER_SPACE;
/* pack and realloc if necessary */
sshbuf_maybe_pack(buf, max_size < buf->size);
if (max_size < buf->alloc && max_size > buf->size) {
if (buf->size < SSHBUF_SIZE_INIT)
rlen = SSHBUF_SIZE_INIT;
else
rlen = ROUNDUP(buf->size, SSHBUF_SIZE_INC);
if (rlen > max_size)
rlen = max_size;
SSHBUF_DBG(("new alloc = %zu", rlen));
if ((dp = recallocarray(buf->d, buf->alloc, rlen, 1)) == NULL)
return SSH_ERR_ALLOC_FAIL;
buf->cd = buf->d = dp;
buf->alloc = rlen;
}
SSHBUF_TELL("new-max");
if (max_size < buf->alloc)
return SSH_ERR_NO_BUFFER_SPACE;
buf->max_size = max_size;
return 0;
}
size_t
sshbuf_len(const struct sshbuf *buf)
{
if (sshbuf_check_sanity(buf) != 0)
return 0;
return buf->size - buf->off;
}
size_t
sshbuf_avail(const struct sshbuf *buf)
{
if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1)
return 0;
return buf->max_size - (buf->size - buf->off);
}
const u_char *
sshbuf_ptr(const struct sshbuf *buf)
{
if (sshbuf_check_sanity(buf) != 0)
return NULL;
return buf->cd + buf->off;
}
u_char *
sshbuf_mutable_ptr(const struct sshbuf *buf)
{
if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1)
return NULL;
return buf->d + buf->off;
}
int
sshbuf_check_reserve(const struct sshbuf *buf, size_t len)
{
int r;
if ((r = sshbuf_check_sanity(buf)) != 0)
return r;
if (buf->readonly || buf->refcount > 1)
return SSH_ERR_BUFFER_READ_ONLY;
SSHBUF_TELL("check");
/* Check that len is reasonable and that max_size + available < len */
if (len > buf->max_size || buf->max_size - len < buf->size - buf->off)
return SSH_ERR_NO_BUFFER_SPACE;
return 0;
}
int
sshbuf_allocate(struct sshbuf *buf, size_t len)
{
size_t rlen, need;
u_char *dp;
int r;
SSHBUF_DBG(("allocate buf = %p len = %zu", buf, len));
if ((r = sshbuf_check_reserve(buf, len)) != 0)
return r;
/*
* If the requested allocation appended would push us past max_size
* then pack the buffer, zeroing buf->off.
*/
sshbuf_maybe_pack(buf, buf->size + len > buf->max_size);
SSHBUF_TELL("allocate");
if (len + buf->size <= buf->alloc)
return 0; /* already have it. */
/*
* Prefer to alloc in SSHBUF_SIZE_INC units, but
* allocate less if doing so would overflow max_size.
*/
need = len + buf->size - buf->alloc;
rlen = ROUNDUP(buf->alloc + need, SSHBUF_SIZE_INC);
SSHBUF_DBG(("need %zu initial rlen %zu", need, rlen));
if (rlen > buf->max_size)
rlen = buf->alloc + need;
SSHBUF_DBG(("adjusted rlen %zu", rlen));
if ((dp = recallocarray(buf->d, buf->alloc, rlen, 1)) == NULL) {
SSHBUF_DBG(("realloc fail"));
return SSH_ERR_ALLOC_FAIL;
}
buf->alloc = rlen;
buf->cd = buf->d = dp;
if ((r = sshbuf_check_reserve(buf, len)) < 0) {
/* shouldn't fail */
return r;
}
SSHBUF_TELL("done");
return 0;
}
int
sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp)
{
u_char *dp;
int r;
if (dpp != NULL)
*dpp = NULL;
SSHBUF_DBG(("reserve buf = %p len = %zu", buf, len));
if ((r = sshbuf_allocate(buf, len)) != 0)
return r;
dp = buf->d + buf->size;
buf->size += len;
if (dpp != NULL)
*dpp = dp;
return 0;
}
int
sshbuf_consume(struct sshbuf *buf, size_t len)
{
int r;
SSHBUF_DBG(("len = %zu", len));
if ((r = sshbuf_check_sanity(buf)) != 0)
return r;
if (len == 0)
return 0;
if (len > sshbuf_len(buf))
return SSH_ERR_MESSAGE_INCOMPLETE;
buf->off += len;
/* deal with empty buffer */
if (buf->off == buf->size)
buf->off = buf->size = 0;
SSHBUF_TELL("done");
return 0;
}
int
sshbuf_consume_end(struct sshbuf *buf, size_t len)
{
int r;
SSHBUF_DBG(("len = %zu", len));
if ((r = sshbuf_check_sanity(buf)) != 0)
return r;
if (len == 0)
return 0;
if (len > sshbuf_len(buf))
return SSH_ERR_MESSAGE_INCOMPLETE;
buf->size -= len;
SSHBUF_TELL("done");
return 0;
}
diff --git a/sshbuf.h b/sshbuf.h
index 07d54f0a988d..feb91f762b9d 100644
--- a/sshbuf.h
+++ b/sshbuf.h
@@ -1,415 +1,415 @@
-/* $OpenBSD: sshbuf.h,v 1.25 2022/01/22 00:43:43 djm Exp $ */
+/* $OpenBSD: sshbuf.h,v 1.27 2022/05/25 06:03:44 djm Exp $ */
/*
* Copyright (c) 2011 Damien Miller
*
* 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.
*/
#ifndef _SSHBUF_H
#define _SSHBUF_H
#include <sys/types.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef WITH_OPENSSL
# include <openssl/bn.h>
# ifdef OPENSSL_HAS_ECC
# include <openssl/ec.h>
# endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
#define SSHBUF_SIZE_MAX 0x8000000 /* Hard maximum size */
#define SSHBUF_REFS_MAX 0x100000 /* Max child buffers */
#define SSHBUF_MAX_BIGNUM (16384 / 8) /* Max bignum *bytes* */
#define SSHBUF_MAX_ECPOINT ((528 * 2 / 8) + 1) /* Max EC point *bytes* */
/*
* NB. do not depend on the internals of this. It will be made opaque
* one day.
*/
struct sshbuf {
u_char *d; /* Data */
const u_char *cd; /* Const data */
size_t off; /* First available byte is buf->d + buf->off */
size_t size; /* Last byte is buf->d + buf->size - 1 */
size_t max_size; /* Maximum size of buffer */
size_t alloc; /* Total bytes allocated to buf->d */
int readonly; /* Refers to external, const data */
int dont_free; /* Kludge to support sshbuf_init */
u_int refcount; /* Tracks self and number of child buffers */
struct sshbuf *parent; /* If child, pointer to parent */
};
/*
* Create a new sshbuf buffer.
* Returns pointer to buffer on success, or NULL on allocation failure.
*/
struct sshbuf *sshbuf_new(void);
/*
* Create a new, read-only sshbuf buffer from existing data.
* Returns pointer to buffer on success, or NULL on allocation failure.
*/
struct sshbuf *sshbuf_from(const void *blob, size_t len);
/*
* Create a new, read-only sshbuf buffer from the contents of an existing
* buffer. The contents of "buf" must not change in the lifetime of the
* resultant buffer.
* Returns pointer to buffer on success, or NULL on allocation failure.
*/
struct sshbuf *sshbuf_fromb(struct sshbuf *buf);
/*
* Create a new, read-only sshbuf buffer from the contents of a string in
* an existing buffer (the string is consumed in the process).
* The contents of "buf" must not change in the lifetime of the resultant
* buffer.
* Returns pointer to buffer on success, or NULL on allocation failure.
*/
int sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp);
/*
* Clear and free buf
*/
void sshbuf_free(struct sshbuf *buf);
/*
* Reset buf, clearing its contents. NB. max_size is preserved.
*/
void sshbuf_reset(struct sshbuf *buf);
/*
* Return the maximum size of buf
*/
size_t sshbuf_max_size(const struct sshbuf *buf);
/*
* Set the maximum size of buf
* Returns 0 on success, or a negative SSH_ERR_* error code on failure.
*/
int sshbuf_set_max_size(struct sshbuf *buf, size_t max_size);
/*
* Returns the length of data in buf
*/
size_t sshbuf_len(const struct sshbuf *buf);
/*
* Returns number of bytes left in buffer before hitting max_size.
*/
size_t sshbuf_avail(const struct sshbuf *buf);
/*
* Returns a read-only pointer to the start of the data in buf
*/
const u_char *sshbuf_ptr(const struct sshbuf *buf);
/*
* Returns a mutable pointer to the start of the data in buf, or
* NULL if the buffer is read-only.
*/
u_char *sshbuf_mutable_ptr(const struct sshbuf *buf);
/*
* Check whether a reservation of size len will succeed in buf
* Safer to use than direct comparisons again sshbuf_avail as it copes
* with unsigned overflows correctly.
* Returns 0 on success, or a negative SSH_ERR_* error code on failure.
*/
int sshbuf_check_reserve(const struct sshbuf *buf, size_t len);
/*
* Preallocates len additional bytes in buf.
* Useful for cases where the caller knows how many bytes will ultimately be
* required to avoid realloc in the buffer code.
* Returns 0 on success, or a negative SSH_ERR_* error code on failure.
*/
int sshbuf_allocate(struct sshbuf *buf, size_t len);
/*
* Reserve len bytes in buf.
* Returns 0 on success and a pointer to the first reserved byte via the
* optional dpp parameter or a negative SSH_ERR_* error code on failure.
*/
int sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp);
/*
* Consume len bytes from the start of buf
* Returns 0 on success, or a negative SSH_ERR_* error code on failure.
*/
int sshbuf_consume(struct sshbuf *buf, size_t len);
/*
* Consume len bytes from the end of buf
* Returns 0 on success, or a negative SSH_ERR_* error code on failure.
*/
int sshbuf_consume_end(struct sshbuf *buf, size_t len);
/* Extract or deposit some bytes */
int sshbuf_get(struct sshbuf *buf, void *v, size_t len);
int sshbuf_put(struct sshbuf *buf, const void *v, size_t len);
int sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v);
/* Append using a printf(3) format */
int sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
int sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap);
/* Functions to extract or store big-endian words of various sizes */
int sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp);
int sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp);
int sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp);
int sshbuf_get_u8(struct sshbuf *buf, u_char *valp);
int sshbuf_put_u64(struct sshbuf *buf, u_int64_t val);
int sshbuf_put_u32(struct sshbuf *buf, u_int32_t val);
int sshbuf_put_u16(struct sshbuf *buf, u_int16_t val);
int sshbuf_put_u8(struct sshbuf *buf, u_char val);
/* Functions to peek at the contents of a buffer without modifying it. */
int sshbuf_peek_u64(const struct sshbuf *buf, size_t offset,
u_int64_t *valp);
int sshbuf_peek_u32(const struct sshbuf *buf, size_t offset,
u_int32_t *valp);
int sshbuf_peek_u16(const struct sshbuf *buf, size_t offset,
u_int16_t *valp);
int sshbuf_peek_u8(const struct sshbuf *buf, size_t offset,
u_char *valp);
/*
* Functions to poke values into an existing buffer (e.g. a length header
* to a packet). The destination bytes must already exist in the buffer.
*/
int sshbuf_poke_u64(struct sshbuf *buf, size_t offset, u_int64_t val);
int sshbuf_poke_u32(struct sshbuf *buf, size_t offset, u_int32_t val);
int sshbuf_poke_u16(struct sshbuf *buf, size_t offset, u_int16_t val);
int sshbuf_poke_u8(struct sshbuf *buf, size_t offset, u_char val);
int sshbuf_poke(struct sshbuf *buf, size_t offset, void *v, size_t len);
/*
* Functions to extract or store SSH wire encoded strings (u32 len || data)
* The "cstring" variants admit no \0 characters in the string contents.
* Caller must free *valp.
*/
int sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp);
int sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp);
int sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v);
int sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len);
int sshbuf_put_cstring(struct sshbuf *buf, const char *v);
int sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v);
/*
* "Direct" variant of sshbuf_get_string, returns pointer into the sshbuf to
* avoid an malloc+memcpy. The pointer is guaranteed to be valid until the
* next sshbuf-modifying function call. Caller does not free.
*/
int sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp,
size_t *lenp);
/* Skip past a string */
#define sshbuf_skip_string(buf) sshbuf_get_string_direct(buf, NULL, NULL)
/* Another variant: "peeks" into the buffer without modifying it */
int sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
size_t *lenp);
/*
* Functions to extract or store SSH wire encoded bignums and elliptic
* curve points.
*/
int sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len);
int sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf,
const u_char **valp, size_t *lenp);
#ifdef WITH_OPENSSL
int sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM **valp);
int sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v);
# ifdef OPENSSL_HAS_ECC
int sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g);
int sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v);
int sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g);
int sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v);
# endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
/* Dump the contents of the buffer in a human-readable format */
void sshbuf_dump(const struct sshbuf *buf, FILE *f);
/* Dump specified memory in a human-readable format */
void sshbuf_dump_data(const void *s, size_t len, FILE *f);
/* Return the hexadecimal representation of the contents of the buffer */
char *sshbuf_dtob16(struct sshbuf *buf);
/* Encode the contents of the buffer as base64 */
char *sshbuf_dtob64_string(const struct sshbuf *buf, int wrap);
int sshbuf_dtob64(const struct sshbuf *d, struct sshbuf *b64, int wrap);
/* RFC4648 "base64url" encoding variant */
int sshbuf_dtourlb64(const struct sshbuf *d, struct sshbuf *b64, int wrap);
/* Decode base64 data and append it to the buffer */
int sshbuf_b64tod(struct sshbuf *buf, const char *b64);
/*
* Tests whether the buffer contains the specified byte sequence at the
* specified offset. Returns 0 on successful match, or a ssherr.h code
* otherwise. SSH_ERR_INVALID_FORMAT indicates sufficient bytes were
* present but the buffer contents did not match those supplied. Zero-
* length comparisons are not allowed.
*
* If sufficient data is present to make a comparison, then it is
* performed with timing independent of the value of the data. If
* insufficient data is present then the comparison is not attempted at
* all.
*/
int sshbuf_cmp(const struct sshbuf *b, size_t offset,
const void *s, size_t len);
/*
* Searches the buffer for the specified string. Returns 0 on success
* and updates *offsetp with the offset of the first match, relative to
* the start of the buffer. Otherwise sshbuf_find will return a ssherr.h
* error code. SSH_ERR_INVALID_FORMAT indicates sufficient bytes were
* present in the buffer for a match to be possible but none was found.
* Searches for zero-length data are not allowed.
*/
int
sshbuf_find(const struct sshbuf *b, size_t start_offset,
const void *s, size_t len, size_t *offsetp);
/*
* Duplicate the contents of a buffer to a string (caller to free).
* Returns NULL on buffer error, or if the buffer contains a premature
* nul character.
*/
char *sshbuf_dup_string(struct sshbuf *buf);
/*
* Fill a buffer from a file descriptor or filename. Both allocate the
* buffer for the caller.
*/
int sshbuf_load_fd(int, struct sshbuf **)
__attribute__((__nonnull__ (2)));
int sshbuf_load_file(const char *, struct sshbuf **)
__attribute__((__nonnull__ (2)));
/*
* Write a buffer to a path, creating/truncating as needed (mode 0644,
* subject to umask). The buffer contents are not modified.
*/
int sshbuf_write_file(const char *path, struct sshbuf *buf)
__attribute__((__nonnull__ (2)));
/* Read up to maxlen bytes from a fd directly to a buffer */
int sshbuf_read(int, struct sshbuf *, size_t, size_t *)
__attribute__((__nonnull__ (2)));
/* Macros for decoding/encoding integers */
#define PEEK_U64(p) \
(((u_int64_t)(((const u_char *)(p))[0]) << 56) | \
((u_int64_t)(((const u_char *)(p))[1]) << 48) | \
((u_int64_t)(((const u_char *)(p))[2]) << 40) | \
((u_int64_t)(((const u_char *)(p))[3]) << 32) | \
((u_int64_t)(((const u_char *)(p))[4]) << 24) | \
((u_int64_t)(((const u_char *)(p))[5]) << 16) | \
((u_int64_t)(((const u_char *)(p))[6]) << 8) | \
(u_int64_t)(((const u_char *)(p))[7]))
#define PEEK_U32(p) \
(((u_int32_t)(((const u_char *)(p))[0]) << 24) | \
((u_int32_t)(((const u_char *)(p))[1]) << 16) | \
((u_int32_t)(((const u_char *)(p))[2]) << 8) | \
(u_int32_t)(((const u_char *)(p))[3]))
#define PEEK_U16(p) \
(((u_int16_t)(((const u_char *)(p))[0]) << 8) | \
(u_int16_t)(((const u_char *)(p))[1]))
#define POKE_U64(p, v) \
do { \
const u_int64_t __v = (v); \
((u_char *)(p))[0] = (__v >> 56) & 0xff; \
((u_char *)(p))[1] = (__v >> 48) & 0xff; \
((u_char *)(p))[2] = (__v >> 40) & 0xff; \
((u_char *)(p))[3] = (__v >> 32) & 0xff; \
((u_char *)(p))[4] = (__v >> 24) & 0xff; \
((u_char *)(p))[5] = (__v >> 16) & 0xff; \
((u_char *)(p))[6] = (__v >> 8) & 0xff; \
((u_char *)(p))[7] = __v & 0xff; \
} while (0)
#define POKE_U32(p, v) \
do { \
const u_int32_t __v = (v); \
((u_char *)(p))[0] = (__v >> 24) & 0xff; \
((u_char *)(p))[1] = (__v >> 16) & 0xff; \
((u_char *)(p))[2] = (__v >> 8) & 0xff; \
((u_char *)(p))[3] = __v & 0xff; \
} while (0)
#define POKE_U16(p, v) \
do { \
const u_int16_t __v = (v); \
((u_char *)(p))[0] = (__v >> 8) & 0xff; \
((u_char *)(p))[1] = __v & 0xff; \
} while (0)
/* Internal definitions follow. Exposed for regress tests */
#ifdef SSHBUF_INTERNAL
/*
* Return the allocation size of buf
*/
size_t sshbuf_alloc(const struct sshbuf *buf);
/*
* Increment the reference count of buf.
*/
int sshbuf_set_parent(struct sshbuf *child, struct sshbuf *parent);
/*
* Return the parent buffer of buf, or NULL if it has no parent.
*/
const struct sshbuf *sshbuf_parent(const struct sshbuf *buf);
/*
* Return the reference count of buf
*/
u_int sshbuf_refcount(const struct sshbuf *buf);
# define SSHBUF_SIZE_INIT 256 /* Initial allocation */
# define SSHBUF_SIZE_INC 256 /* Preferred increment length */
# define SSHBUF_PACK_MIN 8192 /* Minimum packable offset */
/* # define SSHBUF_ABORT abort */
/* # define SSHBUF_DEBUG */
# ifndef SSHBUF_ABORT
# define SSHBUF_ABORT()
# endif
# ifdef SSHBUF_DEBUG
# define SSHBUF_TELL(what) do { \
printf("%s:%d %s: %s size %zu alloc %zu off %zu max %zu\n", \
__FILE__, __LINE__, __func__, what, \
buf->size, buf->alloc, buf->off, buf->max_size); \
fflush(stdout); \
} while (0)
# define SSHBUF_DBG(x) do { \
printf("%s:%d %s: ", __FILE__, __LINE__, __func__); \
printf x; \
printf("\n"); \
fflush(stdout); \
} while (0)
# else
# define SSHBUF_TELL(what)
# define SSHBUF_DBG(x)
# endif
#endif /* SSHBUF_INTERNAL */
#endif /* _SSHBUF_H */
diff --git a/sshconnect.c b/sshconnect.c
index ebecc83747bb..7b3f260ee788 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,1708 +1,1708 @@
-/* $OpenBSD: sshconnect.c,v 1.356 2021/12/19 22:10:24 djm Exp $ */
+/* $OpenBSD: sshconnect.c,v 1.358 2022/08/26 08:16:27 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;
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.
*/
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));
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);
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");
+ 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 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) != 0) {
error("%s \"%s\" contains invalid quotes", tag,
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;
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 they wish 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, NULL, 0)) == 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 b25225e645cb..58fe98db2200 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1,2376 +1,2396 @@
-/* $OpenBSD: sshconnect2.c,v 1.356 2022/02/01 23:32:51 djm Exp $ */
+/* $OpenBSD: sshconnect2.c,v 1.361 2022/09/17 10:33:18 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)
{
+ int r;
+
+ if ((r = sshkey_check_rsa_length(hostkey,
+ options.required_rsa_size)) != 0)
+ fatal_r(r, "Bad server host key");
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;
+ char *prop_kex = NULL, *prop_enc = NULL, *prop_hostkey = NULL;
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_KEX_ALGS] = prop_kex = compat_kex_proposal(ssh, s);
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
- compat_cipher_proposal(ssh, options.ciphers);
- myproposal[PROPOSAL_ENC_ALGS_STOC] =
+ myproposal[PROPOSAL_ENC_ALGS_STOC] = prop_enc =
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] =
+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey =
compat_pkalg_proposal(ssh,
order_hostkeyalgs(host, hostaddr, port, cinfo));
} else {
/* Use specified HostkeyAlgorithms exactly */
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey =
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
+ /* Free only parts of proposal that were dynamically allocated here. */
+ free(prop_kex);
+ free(prop_enc);
+ free(prop_hostkey);
}
/*
* 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(struct ssh *, 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.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(ssh, &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.");
if (ssh_packet_connection_is_on_socket(ssh)) {
verbose("Authenticated to %s ([%s]:%d) using \"%s\".", host,
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
authctxt.method->name);
} else {
verbose("Authenticated to %s (via proxy) using \"%s\".", host,
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 using \"%s\" with partial success.",
authctxt->method->name);
/* 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,
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;
const char *server_sig_algs;
/*
* 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);
}
/*
* Workaround OpenSSH 7.4 bug: this version supports RSA/SHA-2 but
* fails to advertise it via SSH2_MSG_EXT_INFO.
*/
server_sig_algs = ssh->kex->server_sig_algs;
if (key->type == KEY_RSA && (ssh->compat & SSH_BUG_SIGTYPE74))
server_sig_algs = "rsa-sha2-256,rsa-sha2-512";
/*
* 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),
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;
+ int is_agent = 0, 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;
+ is_agent = 1;
} 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);
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);
- }
- }
+ /* Prompt for touch for non-agent FIDO keys that request UP */
+ if (!is_agent && sshkey_is_sk(sign_key) &&
+ (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) &&
+ if (!retried && pin == NULL && !is_agent &&
+ sshkey_is_sk(sign_key) &&
r == SSH_ERR_KEY_WRONG_PASSPHRASE) {
notify_complete(notifier, NULL);
notifier = NULL;
+ xasprintf(&prompt, "Enter PIN for %s key %s: ",
+ sshkey_type(sign_key), id->filename);
+ pin = read_passphrase(prompt, 0);
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)
{
static const char * const 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 = "", *method = "publickey";
int hostbound = 0;
/* prefer host-bound pubkey signatures if supported by server */
if ((ssh->kex->flags & KEX_HAS_PUBKEY_HOSTBOUND) != 0 &&
(options.pubkey_authentication & SSH_PUBKEY_AUTH_HBOUND) != 0) {
hostbound = 1;
method = "publickey-hostbound-v00@openssh.com";
}
if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash,
SSH_FP_DEFAULT)) == NULL)
return 0;
debug3_f("using %s with %s %s", method, 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", sign_id->filename,
sign_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, method)) != 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");
}
if (hostbound) {
if (ssh->kex->initial_hostkey == NULL) {
fatal_f("internal error: initial hostkey "
"not recorded");
}
if ((r = sshkey_puts(ssh->kex->initial_hostkey, b)) != 0)
fatal_fr(r, "assemble %s hostkey", method);
}
/* 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 && (r = sshkey_check_rsa_length(private,
+ options.required_rsa_size)) != 0) {
+ debug_fr(r, "Skipping key %s", 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;
}
/* obtain a list of keys from the agent */
static int
get_agent_identities(struct ssh *ssh, int *agent_fdp,
struct ssh_identitylist **idlistp)
{
int r, agent_fd;
struct ssh_identitylist *idlist;
if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) {
if (r != SSH_ERR_AGENT_NOT_PRESENT)
debug_fr(r, "ssh_get_authentication_socket");
return r;
}
if ((r = ssh_agent_bind_hostkey(agent_fd, ssh->kex->initial_hostkey,
ssh->kex->session_id, ssh->kex->initial_sig, 0)) == 0)
debug_f("bound agent to hostkey");
else
debug2_fr(r, "ssh_agent_bind_hostkey");
if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) {
debug_fr(r, "ssh_fetch_identitylist");
close(agent_fd);
return r;
}
/* success */
*agent_fdp = agent_fd;
*idlistp = idlist;
debug_f("agent returned %zu keys", idlist->nkeys);
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(struct ssh *ssh, 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 = get_agent_identities(ssh, &agent_fd, &idlist)) == 0) {
for (j = 0; j < idlist->nkeys; j++) {
+ if ((r = sshkey_check_rsa_length(idlist->keys[j],
+ options.required_rsa_size)) != 0) {
+ debug_fr(r, "ignoring %s agent key",
+ sshkey_ssh_name(idlist->keys[j]));
+ continue;
+ }
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 (!sshkey_match_keyname_to_sigalgs(
sshkey_ssh_name(authctxt->sensitive->keys[i]),
authctxt->active_ktype))
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 using sigalg %s",
sshkey_ssh_name(private), fp, authctxt->active_ktype);
/* 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 d97624e253c7..2a4613e3296f 100644
--- a/sshd.0
+++ b/sshd.0
@@ -1,675 +1,676 @@
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). It provides
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-^\addrM-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(2) 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 an interactive shell or execution
or a non-interactive command, which sshd will execute via the user's
shell using its -c option. 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(1). 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.
+ time may be specified as a YYYYMMDD[Z] date or a
+ YYYYMMDDHHMM[SS][Z] time. Dates and times will be interpreted in
+ the system time zone unless suffixed by a Z character, in which
+ case they will be interpreted in the UTC 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 are allowed at start of line. Blank lines are allowed.
# Plain key, no restrictions
ssh-rsa ...
# Forced command, disable PTY and all forwarding
restrict,command="dump /home" ssh-rsa ...
# Restriction of ssh -L forwarding destinations
permitopen="192.0.2.1:80",permitopen="192.0.2.2:25" ssh-rsa ...
# Restriction of ssh -R forwarding listeners
permitlisten="localhost:8080",permitlisten="[::1]:22000" ssh-rsa ...
# Configuration for tunnel forwarding
tunnel="0",command="sh /etc/netstart tun0" ssh-rsa ...
# Override of restriction to allow PTY allocation
restrict,pty,command="nethack" ssh-rsa ...
# Allow FIDO key without requiring touch
no-touch-required sk-ecdsa-sha2-nistp256@openssh.com ...
# Require user-verification (e.g. PIN or biometric) for FIDO key
verify-required sk-ecdsa-sha2-nistp256@openssh.com ...
# Trust CA key, allow touch-less FIDO if requested in certificate
cert-authority,no-touch-required,principals="user_a" ssh-rsa ...
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: 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 7.0 March 31, 2022 OpenBSD 7.0
+OpenBSD 7.1 September 11, 2022 OpenBSD 7.1
diff --git a/sshd.8 b/sshd.8
index 350b08ad2380..ac1c62de0b0a 100644
--- a/sshd.8
+++ b/sshd.8
@@ -1,1028 +1,1028 @@
.\"
.\" 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.318 2022/03/31 17:27:27 naddy Exp $
-.Dd $Mdocdate: March 31 2022 $
+.\" $OpenBSD: sshd.8,v 1.321 2022/09/11 06:38:11 jmc Exp $
+.Dd $Mdocdate: September 11 2022 $
.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 .
It provides 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
.Xr fork 2
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
+.Vt 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 an interactive shell or execution
or a non-interactive command, which
.Nm
will execute via the user's shell using its
.Fl c
option.
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
.Xr xauth 1 .
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.
+The time may be specified as a YYYYMMDD[Z] date or a YYYYMMDDHHMM[SS][Z] time.
+Dates and times will be interpreted in the system time zone unless suffixed
+by a Z character, in which case they will be interpreted in the UTC 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 are allowed at start of line. Blank lines are allowed.
# Plain key, no restrictions
ssh-rsa ...
# Forced command, disable PTY and all forwarding
restrict,command="dump /home" ssh-rsa ...
# Restriction of ssh -L forwarding destinations
permitopen="192.0.2.1:80",permitopen="192.0.2.2:25" ssh-rsa ...
# Restriction of ssh -R forwarding listeners
permitlisten="localhost:8080",permitlisten="[::1]:22000" ssh-rsa ...
# Configuration for tunnel forwarding
tunnel="0",command="sh /etc/netstart tun0" ssh-rsa ...
# Override of restriction to allow PTY allocation
restrict,pty,command="nethack" ssh-rsa ...
# Allow FIDO key without requiring touch
no-touch-required sk-ecdsa-sha2-nistp256@openssh.com ...
# Require user-verification (e.g. PIN or biometric) for FIDO key
verify-required sk-ecdsa-sha2-nistp256@openssh.com ...
# Trust CA key, allow touch-less FIDO if requested in certificate
cert-authority,no-touch-required,principals="user_a" ssh-rsa ...
.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: 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 0ee65b54be9c..395ef493d461 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,2448 +1,2462 @@
-/* $OpenBSD: sshd.c,v 1.585 2022/03/18 04:04:11 djm Exp $ */
+/* $OpenBSD: sshd.c,v 1.591 2022/09/17 10:34:29 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>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#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 = 0;
}
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)
{
/*
* Try to kill any processes that we have spawned, E.g. authorized
* keys command helpers or privsep children.
*/
if (getpgid(0) == getpid()) {
ssh_signal(SIGTERM, SIG_IGN);
kill(0, SIGTERM);
}
/* 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)
{
struct pollfd *pfd = NULL;
int i, j, ret, npfd;
int ostartups = -1, startups = 0, listening = 0, lameduck = 0;
int startup_p[2] = { -1 , -1 }, *startup_pollfd;
char c = 0;
struct sockaddr_storage from;
socklen_t fromlen;
pid_t pid;
u_char rnd[256];
sigset_t nsigset, osigset;
/* pipes connected to unauthenticated child sshd processes */
startup_pipes = xcalloc(options.max_startups, sizeof(int));
startup_flags = xcalloc(options.max_startups, sizeof(int));
startup_pollfd = xcalloc(options.max_startups, sizeof(int));
for (i = 0; i < options.max_startups; i++)
startup_pipes[i] = -1;
/*
* Prepare signal mask that we use to block signals that might set
* received_sigterm or received_sighup, so that we are guaranteed
* to immediately wake up the ppoll if a signal is received after
* the flag is checked.
*/
sigemptyset(&nsigset);
sigaddset(&nsigset, SIGHUP);
sigaddset(&nsigset, SIGCHLD);
sigaddset(&nsigset, SIGTERM);
sigaddset(&nsigset, SIGQUIT);
/* sized for worst-case */
pfd = xcalloc(num_listen_socks + options.max_startups,
sizeof(struct pollfd));
/*
* Stay listening for connections until the system crashes or
* the daemon is killed with a signal.
*/
for (;;) {
sigprocmask(SIG_BLOCK, &nsigset, &osigset);
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 (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) {
sigprocmask(SIG_SETMASK, &osigset, NULL);
sighup_restart();
}
}
for (i = 0; i < num_listen_socks; i++) {
pfd[i].fd = listen_socks[i];
pfd[i].events = POLLIN;
}
npfd = num_listen_socks;
for (i = 0; i < options.max_startups; i++) {
startup_pollfd[i] = -1;
if (startup_pipes[i] != -1) {
pfd[npfd].fd = startup_pipes[i];
pfd[npfd].events = POLLIN;
startup_pollfd[i] = npfd++;
}
}
/* Wait until a connection arrives or a child exits. */
ret = ppoll(pfd, npfd, NULL, &osigset);
if (ret == -1 && errno != EINTR) {
error("ppoll: %.100s", strerror(errno));
if (errno == EINVAL)
cleanup_exit(1); /* can't recover */
}
sigprocmask(SIG_SETMASK, &osigset, NULL);
if (ret == -1)
continue;
for (i = 0; i < options.max_startups; i++) {
if (startup_pipes[i] == -1 ||
startup_pollfd[i] == -1 ||
!(pfd[startup_pollfd[i]].revents & (POLLIN|POLLHUP)))
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 (!(pfd[i].revents & POLLIN))
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) {
+ if (unset_nonblock(*newsock) == -1) {
+ close(*newsock);
+ continue;
+ }
+ if (pipe(startup_p) == -1) {
+ error_f("pipe(startup_p): %s", strerror(errno));
close(*newsock);
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];
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]);
}
free(pfd);
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);
}
free(pfd);
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)");
/* 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, rexeced_flag);
#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);
/* 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]);
}
+ if (pubkey != NULL && (r = sshkey_check_rsa_length(pubkey,
+ options.required_rsa_size)) != 0) {
+ error_fr(r, "Host key %s", options.host_key_files[i]);
+ sshkey_free(pubkey);
+ sshkey_free(key);
+ continue;
+ }
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_pubkeys[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.
*/
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 (!debug_flag && !inetd_flag && setsid() == -1)
error("setsid: %.100s", strerror(errno));
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;
+ char *prop_kex = NULL, *prop_enc = NULL, *prop_hostkey = NULL;
int r;
- myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(ssh,
+ myproposal[PROPOSAL_KEX_ALGS] = prop_kex = 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_ENC_ALGS_CTOS] =
+ myproposal[PROPOSAL_ENC_ALGS_STOC] = prop_enc =
+ 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());
+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey =
+ 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
+ free(prop_kex);
+ free(prop_enc);
+ free(prop_hostkey);
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 be2ccfcfc214..2278ba61db45 100644
--- a/sshd_config.0
+++ b/sshd_config.0
@@ -1,1194 +1,1200 @@
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,
sk-ssh-ed25519@openssh.com,
sk-ecdsa-sha2-nistp256@openssh.com,
rsa-sha2-512,rsa-sha2-256
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.
Certificates signed using other algorithms will not be accepted
for public key or host-based authentication.
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-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
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-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
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
+ the system-wide known hosts file /etc/ssh/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.
All authentication styles from login.conf(5) are supported. The
default is yes. The argument to this keyword must be yes or no.
ChallengeResponseAuthentication is a deprecated alias for this.
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 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 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:
sntrup761x25519-sha512@openssh.com,
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, CASignatureAlgorithms, ChrootDirectory,
ClientAliveCountMax, ClientAliveInterval, DenyGroups, DenyUsers,
DisableForwarding, ExposeAuthInfo, ForceCommand, GatewayPorts,
GSSAPIAuthentication, HostbasedAcceptedAlgorithms,
HostbasedAuthentication, HostbasedUsesNameFromPacketOnly,
IgnoreRhosts, Include, IPQoS, KbdInteractiveAuthentication,
KerberosAuthentication, LogLevel, MaxAuthTries, MaxSessions,
PasswordAuthentication, PermitEmptyPasswords, PermitListen,
PermitOpen, PermitRootLogin, PermitTTY, PermitTunnel,
PermitUserRC, PubkeyAcceptedAlgorithms, PubkeyAuthentication,
PubkeyAuthOptions, 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-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
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
+ Specifies the maximum amount of data that may be transmitted or
+ received 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.
+ RequiredRSASize
+ Specifies the minimum RSA key size (in bits) that sshd(8) will
+ accept. User and host-based authentication keys smaller than
+ this limit will be refused. The default is 1024 bits. Note that
+ this limit may only be raised from the default.
+
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 as 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
KbdInteractiveAuthentication and PasswordAuthentication in
addition to PAM account and session module processing for all
authentication types.
Because PAM keyboard-interactive authentication usually serves an
equivalent role to password authentication, you should disable
either PasswordAuthentication or KbdInteractiveAuthentication.
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 7.0 March 31, 2022 OpenBSD 7.0
+OpenBSD 7.1 September 17, 2022 OpenBSD 7.1
diff --git a/sshd_config.5 b/sshd_config.5
index 3a4ffab7c502..f5a06637f2c0 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -1,1974 +1,1984 @@
.\"
.\" 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.340 2022/03/31 17:58:44 naddy Exp $
-.Dd $Mdocdate: March 31 2022 $
+.\" $OpenBSD: sshd_config.5,v 1.343 2022/09/17 10:34:29 djm Exp $
+.Dd $Mdocdate: September 17 2022 $
.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,
sk-ssh-ed25519@openssh.com,
sk-ecdsa-sha2-nistp256@openssh.com,
rsa-sha2-512,rsa-sha2-256
.Ed
.Pp
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.
.Pp
Certificates signed using other algorithms will not be accepted for
public key or host-based authentication.
.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-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
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-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
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 .
+.Pa /etc/ssh/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.
All authentication styles from
.Xr login.conf 5
are supported.
The default is
.Cm yes .
The argument to this keyword must be
.Cm yes
or
.Cm no .
.Cm ChallengeResponseAuthentication
is a deprecated alias for this.
.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 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 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
sntrup761x25519-sha512@openssh.com,
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 CASignatureAlgorithms ,
.Cm ChrootDirectory ,
.Cm ClientAliveCountMax ,
.Cm ClientAliveInterval ,
.Cm DenyGroups ,
.Cm DenyUsers ,
.Cm DisableForwarding ,
.Cm ExposeAuthInfo ,
.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 PubkeyAuthOptions ,
.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-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
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.
+Specifies the maximum amount of data that may be transmitted or received
+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 RequiredRSASize
+Specifies the minimum RSA key size (in bits) that
+.Xr sshd 8
+will accept.
+User and host-based authentication keys smaller than this limit will be
+refused.
+The default is
+.Cm 1024
+bits.
+Note that this limit may only be raised from the default.
.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 as 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 KbdInteractiveAuthentication
and
.Cm PasswordAuthentication
in addition to PAM account and session module processing for all
authentication types.
.Pp
Because PAM keyboard-interactive authentication usually serves an equivalent
role to password authentication, you should disable either
.Cm PasswordAuthentication
or
.Cm KbdInteractiveAuthentication .
.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.c b/sshkey.c
index f1e92003b7e4..770932357139 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -1,4858 +1,4856 @@
-/* $OpenBSD: sshkey.c,v 1.120 2022/01/06 22:05:42 djm Exp $ */
+/* $OpenBSD: sshkey.c,v 1.122 2022/09/17 10:30:45 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 },
#ifdef ENABLE_SK
{ "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 },
#endif
#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 */
# ifdef ENABLE_SK
{ "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 /* ENABLE_SK */
# 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 },
# endif /* OPENSSL_HAS_NISTP521 */
# ifdef ENABLE_SK
{ "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-SK-CERT", NULL,
KEY_ECDSA_SK_CERT, NID_X9_62_prime256v1, 1, 0 },
# endif /* ENABLE_SK */
# 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;
}
int
sshkey_match_keyname_to_sigalgs(const char *keyname, const char *sigalgs)
{
int ktype;
if (sigalgs == NULL || *sigalgs == '\0' ||
(ktype = sshkey_type_from_name(keyname)) == KEY_UNSPEC)
return 0;
else if (ktype == KEY_RSA) {
return match_pattern_list("ssh-rsa", sigalgs, 0) == 1 ||
match_pattern_list("rsa-sha2-256", sigalgs, 0) == 1 ||
match_pattern_list("rsa-sha2-512", sigalgs, 0) == 1;
} else if (ktype == KEY_RSA_CERT) {
return match_pattern_list("ssh-rsa-cert-v01@openssh.com",
sigalgs, 0) == 1 ||
match_pattern_list("rsa-sha2-256-cert-v01@openssh.com",
sigalgs, 0) == 1 ||
match_pattern_list("rsa-sha2-512-cert-v01@openssh.com",
sigalgs, 0) == 1;
} else
return match_pattern_list(keyname, sigalgs, 0) == 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)
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;
}
+/* Check deterministic padding after private key */
+static int
+private2_check_padding(struct sshbuf *decrypted)
+{
+ u_char pad;
+ size_t i;
+ int r;
+
+ 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;
+}
+
int
sshkey_unshield_private(struct sshkey *k)
{
struct sshbuf *prvbuf = NULL;
- u_char pad, *cp, keyiv[SSH_DIGEST_MAX_LENGTH];
+ u_char *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;
- }
- }
+
+ if ((r = private2_check_padding(prvbuf)) != 0)
+ 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)
+int
+sshkey_check_rsa_length(const struct sshkey *k, int min_size)
{
+#ifdef WITH_OPENSSL
const BIGNUM *rsa_n;
+ int nbits;
- RSA_get0_key(rsa, &rsa_n, NULL, NULL);
- if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
+ if (k == NULL || k->rsa == NULL ||
+ (k->type != KEY_RSA && k->type != KEY_RSA_CERT))
+ return 0;
+ RSA_get0_key(k->rsa, &rsa_n, NULL, NULL);
+ nbits = BN_num_bits(rsa_n);
+ if (nbits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
+ (min_size > 0 && nbits < min_size))
return SSH_ERR_KEY_LENGTH;
+#endif /* WITH_OPENSSL */
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)
+ if ((ret = sshkey_check_rsa_length(key, 0)) != 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,
uint64_t verify_time, const char *name, const char **reason)
{
u_int i, principal_matches;
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 (verify_time < k->cert->valid_after) {
*reason = "Certificate invalid: not yet valid";
return SSH_ERR_KEY_CERT_INVALID;
}
if (verify_time >= 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_authority_now(const struct sshkey *k,
int want_host, int require_principal, int wildcard_pattern,
const char *name, const char **reason)
{
time_t now;
if ((now = time(NULL)) < 0) {
/* yikes - system clock before epoch! */
*reason = "Certificate invalid: not yet valid";
return SSH_ERR_KEY_CERT_INVALID;
}
return sshkey_cert_check_authority(k, want_host, require_principal,
wildcard_pattern, (uint64_t)now, name, reason);
}
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_now(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];
*from = *to = '\0';
if (cert->valid_after == 0 &&
cert->valid_before == 0xffffffffffffffffULL)
return strlcpy(s, "forever", l);
if (cert->valid_after != 0)
format_absolute_time(cert->valid_after, from, sizeof(from));
if (cert->valid_before != 0xffffffffffffffffULL)
format_absolute_time(cert->valid_before, to, sizeof(to));
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)
+ if ((r = sshkey_check_rsa_length(k, 0)) != 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))) {
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 ||
(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)
+ if (pubkeyblob != NULL)
freezero(pubkeyblob, pubkeylen);
- if (b64 != NULL)
+ 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) {
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.
*/
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)
+ if ((r = sshkey_check_rsa_length(prv, 0)) != 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/sshkey.h b/sshkey.h
index 094815e00a2a..be254e6be9dc 100644
--- a/sshkey.h
+++ b/sshkey.h
@@ -1,338 +1,339 @@
-/* $OpenBSD: sshkey.h,v 1.51 2022/01/06 22:05:42 djm Exp $ */
+/* $OpenBSD: sshkey.h,v 1.52 2022/09/17 10:30:45 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.
*/
#ifndef SSHKEY_H
#define SSHKEY_H
#include <sys/types.h>
#ifdef WITH_OPENSSL
#include <openssl/rsa.h>
#include <openssl/dsa.h>
# ifdef OPENSSL_HAS_ECC
# include <openssl/ec.h>
# include <openssl/ecdsa.h>
# else /* OPENSSL_HAS_ECC */
# define EC_KEY void
# define EC_GROUP void
# define EC_POINT void
# endif /* OPENSSL_HAS_ECC */
#define SSH_OPENSSL_VERSION OpenSSL_version(OPENSSL_VERSION)
#else /* WITH_OPENSSL */
# define BIGNUM void
# define RSA void
# define DSA void
# define EC_KEY void
# define EC_GROUP void
# define EC_POINT void
#define SSH_OPENSSL_VERSION "without OpenSSL"
#endif /* WITH_OPENSSL */
#define SSH_RSA_MINIMUM_MODULUS_SIZE 1024
#define SSH_KEY_MAX_SIGN_DATA_SIZE (1 << 20)
struct sshbuf;
/* Key types */
enum sshkey_types {
KEY_RSA,
KEY_DSA,
KEY_ECDSA,
KEY_ED25519,
KEY_RSA_CERT,
KEY_DSA_CERT,
KEY_ECDSA_CERT,
KEY_ED25519_CERT,
KEY_XMSS,
KEY_XMSS_CERT,
KEY_ECDSA_SK,
KEY_ECDSA_SK_CERT,
KEY_ED25519_SK,
KEY_ED25519_SK_CERT,
KEY_UNSPEC
};
/* Default fingerprint hash */
#define SSH_FP_HASH_DEFAULT SSH_DIGEST_SHA256
/* Fingerprint representation formats */
enum sshkey_fp_rep {
SSH_FP_DEFAULT = 0,
SSH_FP_HEX,
SSH_FP_BASE64,
SSH_FP_BUBBLEBABBLE,
SSH_FP_RANDOMART
};
/* Private key serialisation formats, used on the wire */
enum sshkey_serialize_rep {
SSHKEY_SERIALIZE_DEFAULT = 0,
SSHKEY_SERIALIZE_STATE = 1, /* only state is serialized */
SSHKEY_SERIALIZE_FULL = 2, /* include keys for saving to disk */
SSHKEY_SERIALIZE_SHIELD = 3, /* everything, for encrypting in ram */
SSHKEY_SERIALIZE_INFO = 254, /* minimal information */
};
/* Private key disk formats */
enum sshkey_private_format {
SSHKEY_PRIVATE_OPENSSH = 0,
SSHKEY_PRIVATE_PEM = 1,
SSHKEY_PRIVATE_PKCS8 = 2,
};
/* key is stored in external hardware */
#define SSHKEY_FLAG_EXT 0x0001
#define SSHKEY_CERT_MAX_PRINCIPALS 256
/* XXX opaquify? */
struct sshkey_cert {
struct sshbuf *certblob; /* Kept around for use on wire */
u_int type; /* SSH2_CERT_TYPE_USER or SSH2_CERT_TYPE_HOST */
u_int64_t serial;
char *key_id;
u_int nprincipals;
char **principals;
u_int64_t valid_after, valid_before;
struct sshbuf *critical;
struct sshbuf *extensions;
struct sshkey *signature_key;
char *signature_type;
};
/* XXX opaquify? */
struct sshkey {
int type;
int flags;
/* KEY_RSA */
RSA *rsa;
/* KEY_DSA */
DSA *dsa;
/* KEY_ECDSA and KEY_ECDSA_SK */
int ecdsa_nid; /* NID of curve */
EC_KEY *ecdsa;
/* KEY_ED25519 and KEY_ED25519_SK */
u_char *ed25519_sk;
u_char *ed25519_pk;
/* KEY_XMSS */
char *xmss_name;
char *xmss_filename; /* for state file updates */
void *xmss_state; /* depends on xmss_name, opaque */
u_char *xmss_sk;
u_char *xmss_pk;
/* KEY_ECDSA_SK and KEY_ED25519_SK */
char *sk_application;
uint8_t sk_flags;
struct sshbuf *sk_key_handle;
struct sshbuf *sk_reserved;
/* Certificates */
struct sshkey_cert *cert;
/* Private key shielding */
u_char *shielded_private;
size_t shielded_len;
u_char *shield_prekey;
size_t shield_prekey_len;
};
#define ED25519_SK_SZ crypto_sign_ed25519_SECRETKEYBYTES
#define ED25519_PK_SZ crypto_sign_ed25519_PUBLICKEYBYTES
/* Additional fields contained in signature */
struct sshkey_sig_details {
uint32_t sk_counter; /* U2F signature counter */
uint8_t sk_flags; /* U2F signature flags; see ssh-sk.h */
};
struct sshkey *sshkey_new(int);
void sshkey_free(struct sshkey *);
int sshkey_equal_public(const struct sshkey *,
const struct sshkey *);
int sshkey_equal(const struct sshkey *, const struct sshkey *);
char *sshkey_fingerprint(const struct sshkey *,
int, enum sshkey_fp_rep);
int sshkey_fingerprint_raw(const struct sshkey *k,
int, u_char **retp, size_t *lenp);
const char *sshkey_type(const struct sshkey *);
const char *sshkey_cert_type(const struct sshkey *);
int sshkey_format_text(const struct sshkey *, struct sshbuf *);
int sshkey_write(const struct sshkey *, FILE *);
int sshkey_read(struct sshkey *, char **);
u_int sshkey_size(const struct sshkey *);
int sshkey_generate(int type, u_int bits, struct sshkey **keyp);
int sshkey_from_private(const struct sshkey *, struct sshkey **);
int sshkey_is_shielded(struct sshkey *);
int sshkey_shield_private(struct sshkey *);
int sshkey_unshield_private(struct sshkey *);
int sshkey_type_from_name(const char *);
int sshkey_is_cert(const struct sshkey *);
int sshkey_is_sk(const struct sshkey *);
int sshkey_type_is_cert(int);
int sshkey_type_plain(int);
/* Returns non-zero if key name match sigalgs pattern list. (handles RSA) */
int sshkey_match_keyname_to_sigalgs(const char *, const char *);
int sshkey_to_certified(struct sshkey *);
int sshkey_drop_cert(struct sshkey *);
int sshkey_cert_copy(const struct sshkey *, struct sshkey *);
int sshkey_cert_check_authority(const struct sshkey *, int, int, int,
uint64_t, const char *, const char **);
int sshkey_cert_check_authority_now(const struct sshkey *, int, int, int,
const char *, const char **);
int sshkey_cert_check_host(const struct sshkey *, const char *,
int , const char *, const char **);
size_t sshkey_format_cert_validity(const struct sshkey_cert *,
char *, size_t) __attribute__((__bounded__(__string__, 2, 3)));
int sshkey_check_cert_sigtype(const struct sshkey *, const char *);
int sshkey_certify(struct sshkey *, struct sshkey *,
const char *, const char *, const char *);
/* Variant allowing use of a custom signature function (e.g. for ssh-agent) */
typedef int sshkey_certify_signer(struct sshkey *, u_char **, size_t *,
const u_char *, size_t, const char *, const char *, const char *,
u_int, void *);
int sshkey_certify_custom(struct sshkey *, struct sshkey *, const char *,
const char *, const char *, sshkey_certify_signer *, void *);
int sshkey_ecdsa_nid_from_name(const char *);
int sshkey_curve_name_to_nid(const char *);
const char * sshkey_curve_nid_to_name(int);
u_int sshkey_curve_nid_to_bits(int);
int sshkey_ecdsa_bits_to_nid(int);
int sshkey_ecdsa_key_to_nid(EC_KEY *);
int sshkey_ec_nid_to_hash_alg(int nid);
int sshkey_ec_validate_public(const EC_GROUP *, const EC_POINT *);
int sshkey_ec_validate_private(const EC_KEY *);
const char *sshkey_ssh_name(const struct sshkey *);
const char *sshkey_ssh_name_plain(const struct sshkey *);
int sshkey_names_valid2(const char *, int);
char *sshkey_alg_list(int, int, int, char);
int sshkey_from_blob(const u_char *, size_t, struct sshkey **);
int sshkey_fromb(struct sshbuf *, struct sshkey **);
int sshkey_froms(struct sshbuf *, struct sshkey **);
int sshkey_to_blob(const struct sshkey *, u_char **, size_t *);
int sshkey_to_base64(const struct sshkey *, char **);
int sshkey_putb(const struct sshkey *, struct sshbuf *);
int sshkey_puts(const struct sshkey *, struct sshbuf *);
int sshkey_puts_opts(const struct sshkey *, struct sshbuf *,
enum sshkey_serialize_rep);
int sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *);
int sshkey_putb_plain(const struct sshkey *, struct sshbuf *);
int sshkey_sign(struct sshkey *, u_char **, size_t *,
const u_char *, size_t, const char *, const char *, const char *, u_int);
int sshkey_verify(const struct sshkey *, const u_char *, size_t,
const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **);
int sshkey_check_sigtype(const u_char *, size_t, const char *);
const char *sshkey_sigalg_by_name(const char *);
int sshkey_get_sigtype(const u_char *, size_t, char **);
/* for debug */
void sshkey_dump_ec_point(const EC_GROUP *, const EC_POINT *);
void sshkey_dump_ec_key(const EC_KEY *);
/* private key parsing and serialisation */
int sshkey_private_serialize(struct sshkey *key, struct sshbuf *buf);
int sshkey_private_serialize_opt(struct sshkey *key, struct sshbuf *buf,
enum sshkey_serialize_rep);
int sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **keyp);
/* private key file format parsing and serialisation */
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);
int sshkey_parse_private_fileblob(struct sshbuf *buffer,
const char *passphrase, struct sshkey **keyp, char **commentp);
int sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
const char *passphrase, struct sshkey **keyp, char **commentp);
int sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob,
int type, struct sshkey **pubkeyp);
+int sshkey_check_rsa_length(const struct sshkey *, int);
/* XXX should be internal, but used by ssh-keygen */
int ssh_rsa_complete_crt_parameters(struct sshkey *, const BIGNUM *);
/* stateful keys (e.g. XMSS) */
int sshkey_set_filename(struct sshkey *, const char *);
int sshkey_enable_maxsign(struct sshkey *, u_int32_t);
u_int32_t sshkey_signatures_left(const struct sshkey *);
int sshkey_forward_state(const struct sshkey *, u_int32_t, int);
int sshkey_private_serialize_maxsign(struct sshkey *key,
struct sshbuf *buf, u_int32_t maxsign, int);
void sshkey_sig_details_free(struct sshkey_sig_details *);
#ifdef SSHKEY_INTERNAL
int ssh_rsa_sign(const struct sshkey *key,
u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
const char *ident);
int ssh_rsa_verify(const struct sshkey *key,
const u_char *sig, size_t siglen, const u_char *data, size_t datalen,
const char *alg);
int ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, u_int compat);
int ssh_dss_verify(const struct sshkey *key,
const u_char *signature, size_t signaturelen,
const u_char *data, size_t datalen, u_int compat);
int ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, u_int compat);
int ssh_ecdsa_verify(const struct sshkey *key,
const u_char *signature, size_t signaturelen,
const u_char *data, size_t datalen, u_int compat);
int ssh_ecdsa_sk_verify(const struct sshkey *key,
const u_char *signature, size_t signaturelen,
const u_char *data, size_t datalen, u_int compat,
struct sshkey_sig_details **detailsp);
int ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, u_int compat);
int ssh_ed25519_verify(const struct sshkey *key,
const u_char *signature, size_t signaturelen,
const u_char *data, size_t datalen, u_int compat);
int ssh_ed25519_sk_verify(const struct sshkey *key,
const u_char *signature, size_t signaturelen,
const u_char *data, size_t datalen, u_int compat,
struct sshkey_sig_details **detailsp);
int ssh_xmss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, u_int compat);
int ssh_xmss_verify(const struct sshkey *key,
const u_char *signature, size_t signaturelen,
const u_char *data, size_t datalen, u_int compat);
#endif
#if !defined(WITH_OPENSSL)
# undef RSA
# undef DSA
# undef EC_KEY
# undef EC_GROUP
# undef EC_POINT
#elif !defined(OPENSSL_HAS_ECC)
# undef EC_KEY
# undef EC_GROUP
# undef EC_POINT
#endif
#endif /* SSHKEY_H */
diff --git a/sshlogin.c b/sshlogin.c
index 82dd848191b1..06a7b381ade7 100644
--- a/sshlogin.c
+++ b/sshlogin.c
@@ -1,173 +1,174 @@
/* $OpenBSD: sshlogin.c,v 1.35 2020/10/18 11:32:02 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 performs some of the things login(1) normally does. We cannot
* easily use something like login -p -h host -f user, because there are
* several different logins around, and it is hard to determined what kind of
* login the current system has. Also, we want to be able to execute commands
* on a tty.
*
* 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 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/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <limits.h>
#include "sshlogin.h"
#include "ssherr.h"
#include "loginrec.h"
#include "log.h"
#include "sshbuf.h"
#include "misc.h"
#include "servconf.h"
extern struct sshbuf *loginmsg;
extern ServerOptions options;
/*
* Returns the time when the user last logged in. Returns 0 if the
* information is not available. This must be called before record_login.
* The host the user logged in from will be returned in buf.
*/
time_t
get_last_login_time(uid_t uid, const char *logname,
char *buf, size_t bufsize)
{
struct logininfo li;
login_get_lastlog(&li, uid);
strlcpy(buf, li.hostname, bufsize);
return (time_t)li.tv_sec;
}
/*
* Generate and store last login message. This must be done before
* login_login() is called and lastlog is updated.
*/
static void
store_lastlog_message(const char *user, uid_t uid)
{
#ifndef NO_SSH_LASTLOG
# ifndef CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG
char hostname[HOST_NAME_MAX+1] = "";
time_t last_login_time;
# endif
char *time_string;
int r;
if (!options.print_lastlog)
return;
# ifdef CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG
time_string = sys_auth_get_lastlogin_msg(user, uid);
if (time_string != NULL) {
if ((r = sshbuf_put(loginmsg,
time_string, strlen(time_string))) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
free(time_string);
}
# else
last_login_time = get_last_login_time(uid, user, hostname,
sizeof(hostname));
if (last_login_time != 0) {
time_string = ctime(&last_login_time);
time_string[strcspn(time_string, "\n")] = '\0';
if (strcmp(hostname, "") == 0)
r = sshbuf_putf(loginmsg, "Last login: %s\r\n",
time_string);
else
r = sshbuf_putf(loginmsg, "Last login: %s from %s\r\n",
time_string, hostname);
if (r != 0)
fatal_fr(r, "sshbuf_putf");
}
# endif /* CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG */
#endif /* NO_SSH_LASTLOG */
}
/*
* Records that the user has logged in. I wish these parts of operating
* systems were more standardized.
*/
void
record_login(pid_t pid, const char *tty, const char *user, uid_t uid,
const char *host, struct sockaddr *addr, socklen_t addrlen)
{
struct logininfo *li;
/* save previous login details before writing new */
store_lastlog_message(user, uid);
li = login_alloc_entry(pid, user, host, tty);
login_set_addr(li, addr, addrlen);
login_login(li);
login_free_entry(li);
}
#ifdef LOGIN_NEEDS_UTMPX
void
record_utmp_only(pid_t pid, const char *ttyname, const char *user,
const char *host, struct sockaddr *addr, socklen_t addrlen)
{
struct logininfo *li;
li = login_alloc_entry(pid, user, host, ttyname);
login_set_addr(li, addr, addrlen);
login_utmp_only(li);
login_free_entry(li);
}
#endif
/* Records that the user has logged out. */
void
record_logout(pid_t pid, const char *tty, const char *user)
{
struct logininfo *li;
li = login_alloc_entry(pid, user, NULL, tty);
login_logout(li);
login_free_entry(li);
}
diff --git a/sshsig.c b/sshsig.c
index 1e3b63982ba8..eb2a931e9c18 100644
--- a/sshsig.c
+++ b/sshsig.c
@@ -1,1147 +1,1148 @@
-/* $OpenBSD: sshsig.c,v 1.29 2022/03/30 04:27:51 djm Exp $ */
+/* $OpenBSD: sshsig.c,v 1.30 2022/08/19 03:06:30 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 <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "authfd.h"
#include "authfile.h"
#include "log.h"
#include "misc.h"
#include "sshbuf.h"
#include "sshsig.h"
#include "ssherr.h"
#include "sshkey.h"
#include "match.h"
#include "digest.h"
#define SIG_VERSION 0x01
#define MAGIC_PREAMBLE "SSHSIG"
#define MAGIC_PREAMBLE_LEN (sizeof(MAGIC_PREAMBLE) - 1)
#define BEGIN_SIGNATURE "-----BEGIN SSH SIGNATURE-----\n"
#define END_SIGNATURE "-----END SSH SIGNATURE-----"
#define RSA_SIGN_ALG "rsa-sha2-512" /* XXX maybe make configurable */
#define RSA_SIGN_ALLOWED "rsa-sha2-512,rsa-sha2-256"
#define HASHALG_DEFAULT "sha512" /* XXX maybe make configurable */
#define HASHALG_ALLOWED "sha256,sha512"
int
sshsig_armor(const struct sshbuf *blob, struct sshbuf **out)
{
struct sshbuf *buf = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
*out = NULL;
if ((buf = sshbuf_new()) == NULL) {
error_f("sshbuf_new failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_put(buf, BEGIN_SIGNATURE,
sizeof(BEGIN_SIGNATURE)-1)) != 0) {
error_fr(r, "sshbuf_putf");
goto out;
}
if ((r = sshbuf_dtob64(blob, buf, 1)) != 0) {
error_fr(r, "base64 encode signature");
goto out;
}
if ((r = sshbuf_put(buf, END_SIGNATURE,
sizeof(END_SIGNATURE)-1)) != 0 ||
(r = sshbuf_put_u8(buf, '\n')) != 0) {
error_fr(r, "sshbuf_put");
goto out;
}
/* success */
*out = buf;
buf = NULL; /* transferred */
r = 0;
out:
sshbuf_free(buf);
return r;
}
int
sshsig_dearmor(struct sshbuf *sig, struct sshbuf **out)
{
int r;
size_t eoffset = 0;
struct sshbuf *buf = NULL;
struct sshbuf *sbuf = NULL;
char *b64 = NULL;
if ((sbuf = sshbuf_fromb(sig)) == NULL) {
error_f("sshbuf_fromb failed");
return SSH_ERR_ALLOC_FAIL;
}
if ((r = sshbuf_cmp(sbuf, 0,
BEGIN_SIGNATURE, sizeof(BEGIN_SIGNATURE)-1)) != 0) {
error("Couldn't parse signature: missing header");
goto done;
}
if ((r = sshbuf_consume(sbuf, sizeof(BEGIN_SIGNATURE)-1)) != 0) {
error_fr(r, "consume");
goto done;
}
if ((r = sshbuf_find(sbuf, 0, "\n" END_SIGNATURE,
sizeof("\n" END_SIGNATURE)-1, &eoffset)) != 0) {
error("Couldn't parse signature: missing footer");
goto done;
}
if ((r = sshbuf_consume_end(sbuf, sshbuf_len(sbuf)-eoffset)) != 0) {
error_fr(r, "consume");
goto done;
}
if ((b64 = sshbuf_dup_string(sbuf)) == NULL) {
error_f("sshbuf_dup_string failed");
r = SSH_ERR_ALLOC_FAIL;
goto done;
}
if ((buf = sshbuf_new()) == NULL) {
error_f("sshbuf_new() failed");
r = SSH_ERR_ALLOC_FAIL;
goto done;
}
if ((r = sshbuf_b64tod(buf, b64)) != 0) {
error_fr(r, "decode base64");
goto done;
}
/* success */
*out = buf;
r = 0;
buf = NULL; /* transferred */
done:
sshbuf_free(buf);
sshbuf_free(sbuf);
free(b64);
return r;
}
static int
sshsig_wrap_sign(struct sshkey *key, const char *hashalg,
const char *sk_provider, const char *sk_pin, const struct sshbuf *h_message,
const char *sig_namespace, struct sshbuf **out,
sshsig_signer *signer, void *signer_ctx)
{
int r;
size_t slen = 0;
u_char *sig = NULL;
struct sshbuf *blob = NULL;
struct sshbuf *tosign = NULL;
const char *sign_alg = NULL;
if ((tosign = sshbuf_new()) == NULL ||
(blob = sshbuf_new()) == NULL) {
error_f("sshbuf_new failed");
r = SSH_ERR_ALLOC_FAIL;
goto done;
}
if ((r = sshbuf_put(tosign, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
(r = sshbuf_put_cstring(tosign, sig_namespace)) != 0 ||
(r = sshbuf_put_string(tosign, NULL, 0)) != 0 || /* reserved */
(r = sshbuf_put_cstring(tosign, hashalg)) != 0 ||
(r = sshbuf_put_stringb(tosign, h_message)) != 0) {
error_fr(r, "assemble message to sign");
goto done;
}
/* If using RSA keys then default to a good signature algorithm */
if (sshkey_type_plain(key->type) == KEY_RSA)
sign_alg = RSA_SIGN_ALG;
if (signer != NULL) {
if ((r = signer(key, &sig, &slen,
sshbuf_ptr(tosign), sshbuf_len(tosign),
sign_alg, sk_provider, sk_pin, 0, signer_ctx)) != 0) {
error_r(r, "Couldn't sign message (signer)");
goto done;
}
} else {
if ((r = sshkey_sign(key, &sig, &slen,
sshbuf_ptr(tosign), sshbuf_len(tosign),
sign_alg, sk_provider, sk_pin, 0)) != 0) {
error_r(r, "Couldn't sign message");
goto done;
}
}
if ((r = sshbuf_put(blob, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
(r = sshbuf_put_u32(blob, SIG_VERSION)) != 0 ||
(r = sshkey_puts(key, blob)) != 0 ||
(r = sshbuf_put_cstring(blob, sig_namespace)) != 0 ||
(r = sshbuf_put_string(blob, NULL, 0)) != 0 || /* reserved */
(r = sshbuf_put_cstring(blob, hashalg)) != 0 ||
(r = sshbuf_put_string(blob, sig, slen)) != 0) {
error_fr(r, "assemble signature object");
goto done;
}
if (out != NULL) {
*out = blob;
blob = NULL;
}
r = 0;
done:
free(sig);
sshbuf_free(blob);
sshbuf_free(tosign);
return r;
}
/* Check preamble and version. */
static int
sshsig_parse_preamble(struct sshbuf *buf)
{
int r = SSH_ERR_INTERNAL_ERROR;
uint32_t sversion;
if ((r = sshbuf_cmp(buf, 0, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
(r = sshbuf_consume(buf, (sizeof(MAGIC_PREAMBLE)-1))) != 0 ||
(r = sshbuf_get_u32(buf, &sversion)) != 0) {
error("Couldn't verify signature: invalid format");
return r;
}
if (sversion > SIG_VERSION) {
error("Signature version %lu is larger than supported "
"version %u", (unsigned long)sversion, SIG_VERSION);
return SSH_ERR_INVALID_FORMAT;
}
return 0;
}
static int
sshsig_check_hashalg(const char *hashalg)
{
if (hashalg == NULL ||
match_pattern_list(hashalg, HASHALG_ALLOWED, 0) == 1)
return 0;
error_f("unsupported hash algorithm \"%.100s\"", hashalg);
return SSH_ERR_SIGN_ALG_UNSUPPORTED;
}
static int
sshsig_peek_hashalg(struct sshbuf *signature, char **hashalgp)
{
struct sshbuf *buf = NULL;
char *hashalg = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
if (hashalgp != NULL)
*hashalgp = NULL;
if ((buf = sshbuf_fromb(signature)) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshsig_parse_preamble(buf)) != 0)
goto done;
if ((r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0 ||
(r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0 ||
(r = sshbuf_get_string(buf, NULL, NULL)) != 0 ||
(r = sshbuf_get_cstring(buf, &hashalg, NULL)) != 0 ||
(r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0) {
error_fr(r, "parse signature object");
goto done;
}
/* success */
r = 0;
*hashalgp = hashalg;
hashalg = NULL;
done:
free(hashalg);
sshbuf_free(buf);
return r;
}
static int
sshsig_wrap_verify(struct sshbuf *signature, const char *hashalg,
const struct sshbuf *h_message, const char *expect_namespace,
struct sshkey **sign_keyp, struct sshkey_sig_details **sig_details)
{
int r = SSH_ERR_INTERNAL_ERROR;
struct sshbuf *buf = NULL, *toverify = NULL;
struct sshkey *key = NULL;
const u_char *sig;
char *got_namespace = NULL, *sigtype = NULL, *sig_hashalg = NULL;
size_t siglen;
debug_f("verify message length %zu", sshbuf_len(h_message));
if (sig_details != NULL)
*sig_details = NULL;
if (sign_keyp != NULL)
*sign_keyp = NULL;
if ((toverify = sshbuf_new()) == NULL) {
error_f("sshbuf_new failed");
r = SSH_ERR_ALLOC_FAIL;
goto done;
}
if ((r = sshbuf_put(toverify, MAGIC_PREAMBLE,
MAGIC_PREAMBLE_LEN)) != 0 ||
(r = sshbuf_put_cstring(toverify, expect_namespace)) != 0 ||
(r = sshbuf_put_string(toverify, NULL, 0)) != 0 || /* reserved */
(r = sshbuf_put_cstring(toverify, hashalg)) != 0 ||
(r = sshbuf_put_stringb(toverify, h_message)) != 0) {
error_fr(r, "assemble message to verify");
goto done;
}
if ((r = sshsig_parse_preamble(signature)) != 0)
goto done;
if ((r = sshkey_froms(signature, &key)) != 0 ||
(r = sshbuf_get_cstring(signature, &got_namespace, NULL)) != 0 ||
(r = sshbuf_get_string(signature, NULL, NULL)) != 0 ||
(r = sshbuf_get_cstring(signature, &sig_hashalg, NULL)) != 0 ||
(r = sshbuf_get_string_direct(signature, &sig, &siglen)) != 0) {
error_fr(r, "parse signature object");
goto done;
}
if (sshbuf_len(signature) != 0) {
error("Signature contains trailing data");
r = SSH_ERR_INVALID_FORMAT;
goto done;
}
if (strcmp(expect_namespace, got_namespace) != 0) {
error("Couldn't verify signature: namespace does not match");
debug_f("expected namespace \"%s\" received \"%s\"",
expect_namespace, got_namespace);
r = SSH_ERR_SIGNATURE_INVALID;
goto done;
}
if (strcmp(hashalg, sig_hashalg) != 0) {
error("Couldn't verify signature: hash algorithm mismatch");
debug_f("expected algorithm \"%s\" received \"%s\"",
hashalg, sig_hashalg);
r = SSH_ERR_SIGNATURE_INVALID;
goto done;
}
/* Ensure that RSA keys use an acceptable signature algorithm */
if (sshkey_type_plain(key->type) == KEY_RSA) {
if ((r = sshkey_get_sigtype(sig, siglen, &sigtype)) != 0) {
error_r(r, "Couldn't verify signature: unable to get "
"signature type");
goto done;
}
if (match_pattern_list(sigtype, RSA_SIGN_ALLOWED, 0) != 1) {
error("Couldn't verify signature: unsupported RSA "
"signature algorithm %s", sigtype);
r = SSH_ERR_SIGN_ALG_UNSUPPORTED;
goto done;
}
}
if ((r = sshkey_verify(key, sig, siglen, sshbuf_ptr(toverify),
sshbuf_len(toverify), NULL, 0, sig_details)) != 0) {
error_r(r, "Signature verification failed");
goto done;
}
/* success */
r = 0;
if (sign_keyp != NULL) {
*sign_keyp = key;
key = NULL; /* transferred */
}
done:
free(got_namespace);
free(sigtype);
free(sig_hashalg);
sshbuf_free(buf);
sshbuf_free(toverify);
sshkey_free(key);
return r;
}
static int
hash_buffer(const struct sshbuf *m, const char *hashalg, struct sshbuf **bp)
{
char *hex, hash[SSH_DIGEST_MAX_LENGTH];
int alg, r = SSH_ERR_INTERNAL_ERROR;
struct sshbuf *b = NULL;
*bp = NULL;
memset(hash, 0, sizeof(hash));
if ((r = sshsig_check_hashalg(hashalg)) != 0)
return r;
if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) {
error_f("can't look up hash algorithm %s", hashalg);
return SSH_ERR_INTERNAL_ERROR;
}
if ((r = ssh_digest_buffer(alg, m, hash, sizeof(hash))) != 0) {
error_fr(r, "ssh_digest_buffer");
return r;
}
if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) {
debug3_f("final hash: %s", hex);
freezero(hex, strlen(hex));
}
if ((b = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) {
error_fr(r, "sshbuf_put");
goto out;
}
*bp = b;
b = NULL; /* transferred */
/* success */
r = 0;
out:
sshbuf_free(b);
explicit_bzero(hash, sizeof(hash));
return r;
}
int
sshsig_signb(struct sshkey *key, const char *hashalg,
const char *sk_provider, const char *sk_pin,
const struct sshbuf *message, const char *sig_namespace,
struct sshbuf **out, sshsig_signer *signer, void *signer_ctx)
{
struct sshbuf *b = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
if (hashalg == NULL)
hashalg = HASHALG_DEFAULT;
if (out != NULL)
*out = NULL;
if ((r = hash_buffer(message, hashalg, &b)) != 0) {
error_fr(r, "hash buffer");
goto out;
}
if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b,
sig_namespace, out, signer, signer_ctx)) != 0)
goto out;
/* success */
r = 0;
out:
sshbuf_free(b);
return r;
}
int
sshsig_verifyb(struct sshbuf *signature, const struct sshbuf *message,
const char *expect_namespace, struct sshkey **sign_keyp,
struct sshkey_sig_details **sig_details)
{
struct sshbuf *b = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
char *hashalg = NULL;
if (sig_details != NULL)
*sig_details = NULL;
if (sign_keyp != NULL)
*sign_keyp = NULL;
if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0)
return r;
debug_f("signature made with hash \"%s\"", hashalg);
if ((r = hash_buffer(message, hashalg, &b)) != 0) {
error_fr(r, "hash buffer");
goto out;
}
if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace,
sign_keyp, sig_details)) != 0)
goto out;
/* success */
r = 0;
out:
sshbuf_free(b);
free(hashalg);
return r;
}
static int
hash_file(int fd, const char *hashalg, struct sshbuf **bp)
{
char *hex, rbuf[8192], hash[SSH_DIGEST_MAX_LENGTH];
ssize_t n, total = 0;
- struct ssh_digest_ctx *ctx;
+ struct ssh_digest_ctx *ctx = NULL;
int alg, oerrno, r = SSH_ERR_INTERNAL_ERROR;
struct sshbuf *b = NULL;
*bp = NULL;
memset(hash, 0, sizeof(hash));
if ((r = sshsig_check_hashalg(hashalg)) != 0)
return r;
if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) {
error_f("can't look up hash algorithm %s", hashalg);
return SSH_ERR_INTERNAL_ERROR;
}
if ((ctx = ssh_digest_start(alg)) == NULL) {
error_f("ssh_digest_start failed");
return SSH_ERR_INTERNAL_ERROR;
}
for (;;) {
if ((n = read(fd, rbuf, sizeof(rbuf))) == -1) {
if (errno == EINTR || errno == EAGAIN)
continue;
oerrno = errno;
error_f("read: %s", strerror(errno));
- ssh_digest_free(ctx);
errno = oerrno;
r = SSH_ERR_SYSTEM_ERROR;
goto out;
} else if (n == 0) {
debug2_f("hashed %zu bytes", total);
break; /* EOF */
}
total += (size_t)n;
if ((r = ssh_digest_update(ctx, rbuf, (size_t)n)) != 0) {
error_fr(r, "ssh_digest_update");
goto out;
}
}
if ((r = ssh_digest_final(ctx, hash, sizeof(hash))) != 0) {
error_fr(r, "ssh_digest_final");
goto out;
}
if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) {
debug3_f("final hash: %s", hex);
freezero(hex, strlen(hex));
}
if ((b = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) {
error_fr(r, "sshbuf_put");
goto out;
}
*bp = b;
b = NULL; /* transferred */
/* success */
r = 0;
out:
+ oerrno = errno;
sshbuf_free(b);
ssh_digest_free(ctx);
explicit_bzero(hash, sizeof(hash));
+ errno = oerrno;
return r;
}
int
sshsig_sign_fd(struct sshkey *key, const char *hashalg,
const char *sk_provider, const char *sk_pin,
int fd, const char *sig_namespace, struct sshbuf **out,
sshsig_signer *signer, void *signer_ctx)
{
struct sshbuf *b = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
if (hashalg == NULL)
hashalg = HASHALG_DEFAULT;
if (out != NULL)
*out = NULL;
if ((r = hash_file(fd, hashalg, &b)) != 0) {
error_fr(r, "hash_file");
return r;
}
if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b,
sig_namespace, out, signer, signer_ctx)) != 0)
goto out;
/* success */
r = 0;
out:
sshbuf_free(b);
return r;
}
int
sshsig_verify_fd(struct sshbuf *signature, int fd,
const char *expect_namespace, struct sshkey **sign_keyp,
struct sshkey_sig_details **sig_details)
{
struct sshbuf *b = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
char *hashalg = NULL;
if (sig_details != NULL)
*sig_details = NULL;
if (sign_keyp != NULL)
*sign_keyp = NULL;
if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0)
return r;
debug_f("signature made with hash \"%s\"", hashalg);
if ((r = hash_file(fd, hashalg, &b)) != 0) {
error_fr(r, "hash_file");
goto out;
}
if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace,
sign_keyp, sig_details)) != 0)
goto out;
/* success */
r = 0;
out:
sshbuf_free(b);
free(hashalg);
return r;
}
struct sshsigopt {
int ca;
char *namespaces;
uint64_t valid_after, valid_before;
};
struct sshsigopt *
sshsigopt_parse(const char *opts, const char *path, u_long linenum,
const char **errstrp)
{
struct sshsigopt *ret;
int r;
char *opt;
const char *errstr = NULL;
if ((ret = calloc(1, sizeof(*ret))) == NULL)
return NULL;
if (opts == NULL || *opts == '\0')
return ret; /* Empty options yields empty options :) */
while (*opts && *opts != ' ' && *opts != '\t') {
/* flag options */
if ((r = opt_flag("cert-authority", 0, &opts)) != -1) {
ret->ca = 1;
} else if (opt_match(&opts, "namespaces")) {
if (ret->namespaces != NULL) {
errstr = "multiple \"namespaces\" clauses";
goto fail;
}
ret->namespaces = opt_dequote(&opts, &errstr);
if (ret->namespaces == NULL)
goto fail;
} else if (opt_match(&opts, "valid-after")) {
if (ret->valid_after != 0) {
errstr = "multiple \"valid-after\" clauses";
goto fail;
}
if ((opt = opt_dequote(&opts, &errstr)) == NULL)
goto fail;
if (parse_absolute_time(opt, &ret->valid_after) != 0 ||
ret->valid_after == 0) {
free(opt);
errstr = "invalid \"valid-after\" time";
goto fail;
}
free(opt);
} else if (opt_match(&opts, "valid-before")) {
if (ret->valid_before != 0) {
errstr = "multiple \"valid-before\" clauses";
goto fail;
}
if ((opt = opt_dequote(&opts, &errstr)) == NULL)
goto fail;
if (parse_absolute_time(opt, &ret->valid_before) != 0 ||
ret->valid_before == 0) {
free(opt);
errstr = "invalid \"valid-before\" time";
goto fail;
}
free(opt);
}
/*
* 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;
}
}
/* final consistency check */
if (ret->valid_after != 0 && ret->valid_before != 0 &&
ret->valid_before <= ret->valid_after) {
errstr = "\"valid-before\" time is before \"valid-after\"";
goto fail;
}
/* success */
return ret;
fail:
if (errstrp != NULL)
*errstrp = errstr;
sshsigopt_free(ret);
return NULL;
}
void
sshsigopt_free(struct sshsigopt *opts)
{
if (opts == NULL)
return;
free(opts->namespaces);
free(opts);
}
static int
parse_principals_key_and_options(const char *path, u_long linenum, char *line,
const char *required_principal, char **principalsp, struct sshkey **keyp,
struct sshsigopt **sigoptsp)
{
char *opts = NULL, *tmp, *cp, *principals = NULL;
const char *reason = NULL;
struct sshsigopt *sigopts = NULL;
struct sshkey *key = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
if (principalsp != NULL)
*principalsp = NULL;
if (sigoptsp != NULL)
*sigoptsp = NULL;
if (keyp != NULL)
*keyp = NULL;
cp = line;
cp = cp + strspn(cp, " \t"); /* skip leading whitespace */
if (*cp == '#' || *cp == '\0')
return SSH_ERR_KEY_NOT_FOUND; /* blank or all-comment line */
/* format: identity[,identity...] [option[,option...]] key */
if ((tmp = strdelimw(&cp)) == NULL || cp == NULL) {
error("%s:%lu: invalid line", path, linenum);
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((principals = strdup(tmp)) == NULL) {
error_f("strdup failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/*
* Bail out early if we're looking for a particular principal and this
* line does not list it.
*/
if (required_principal != NULL) {
if (match_pattern_list(required_principal,
principals, 0) != 1) {
/* principal didn't match */
r = SSH_ERR_KEY_NOT_FOUND;
goto out;
}
debug_f("%s:%lu: matched principal \"%s\"",
path, linenum, required_principal);
}
if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
error_f("sshkey_new failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (sshkey_read(key, &cp) != 0) {
/* no key? Check for options */
opts = cp;
if (sshkey_advance_past_options(&cp) != 0) {
error("%s:%lu: invalid options", path, linenum);
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (cp == NULL || *cp == '\0') {
error("%s:%lu: missing key", path, linenum);
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
*cp++ = '\0';
skip_space(&cp);
if (sshkey_read(key, &cp) != 0) {
error("%s:%lu: invalid key", path, linenum);
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
}
debug3("%s:%lu: options %s", path, linenum, opts == NULL ? "" : opts);
if ((sigopts = sshsigopt_parse(opts, path, linenum, &reason)) == NULL) {
error("%s:%lu: bad options: %s", path, linenum, reason);
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
/* success */
if (principalsp != NULL) {
*principalsp = principals;
principals = NULL; /* transferred */
}
if (sigoptsp != NULL) {
*sigoptsp = sigopts;
sigopts = NULL; /* transferred */
}
if (keyp != NULL) {
*keyp = key;
key = NULL; /* transferred */
}
r = 0;
out:
free(principals);
sshsigopt_free(sigopts);
sshkey_free(key);
return r;
}
static int
cert_filter_principals(const char *path, u_long linenum,
char **principalsp, const struct sshkey *cert, uint64_t verify_time)
{
char *cp, *oprincipals, *principals;
const char *reason;
struct sshbuf *nprincipals;
int r = SSH_ERR_INTERNAL_ERROR, success = 0;
u_int i;
oprincipals = principals = *principalsp;
*principalsp = NULL;
if ((nprincipals = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
while ((cp = strsep(&principals, ",")) != NULL && *cp != '\0') {
/* Check certificate validity */
if ((r = sshkey_cert_check_authority(cert, 0, 1, 0,
verify_time, NULL, &reason)) != 0) {
debug("%s:%lu: principal \"%s\" not authorized: %s",
path, linenum, cp, reason);
continue;
}
/* Return all matching principal names from the cert */
for (i = 0; i < cert->cert->nprincipals; i++) {
if (match_pattern(cert->cert->principals[i], cp)) {
if ((r = sshbuf_putf(nprincipals, "%s%s",
sshbuf_len(nprincipals) != 0 ? "," : "",
cert->cert->principals[i])) != 0) {
error_f("buffer error");
goto out;
}
}
}
}
if (sshbuf_len(nprincipals) == 0) {
error("%s:%lu: no valid principals found", path, linenum);
r = SSH_ERR_KEY_CERT_INVALID;
goto out;
}
if ((principals = sshbuf_dup_string(nprincipals)) == NULL) {
error_f("buffer error");
goto out;
}
/* success */
success = 1;
*principalsp = principals;
out:
sshbuf_free(nprincipals);
free(oprincipals);
return success ? 0 : r;
}
static int
check_allowed_keys_line(const char *path, u_long linenum, char *line,
const struct sshkey *sign_key, const char *principal,
const char *sig_namespace, uint64_t verify_time, char **principalsp)
{
struct sshkey *found_key = NULL;
char *principals = NULL;
int r, success = 0;
const char *reason = NULL;
struct sshsigopt *sigopts = NULL;
char tvalid[64], tverify[64];
if (principalsp != NULL)
*principalsp = NULL;
/* Parse the line */
if ((r = parse_principals_key_and_options(path, linenum, line,
principal, &principals, &found_key, &sigopts)) != 0) {
/* error already logged */
goto done;
}
if (!sigopts->ca && sshkey_equal(found_key, sign_key)) {
/* Exact match of key */
debug("%s:%lu: matched key", path, linenum);
} else if (sigopts->ca && sshkey_is_cert(sign_key) &&
sshkey_equal_public(sign_key->cert->signature_key, found_key)) {
if (principal) {
/* Match certificate CA key with specified principal */
if ((r = sshkey_cert_check_authority(sign_key, 0, 1, 0,
verify_time, principal, &reason)) != 0) {
error("%s:%lu: certificate not authorized: %s",
path, linenum, reason);
goto done;
}
debug("%s:%lu: matched certificate CA key",
path, linenum);
} else {
/* No principal specified - find all matching ones */
if ((r = cert_filter_principals(path, linenum,
&principals, sign_key, verify_time)) != 0) {
/* error already displayed */
debug_r(r, "%s:%lu: cert_filter_principals",
path, linenum);
goto done;
}
debug("%s:%lu: matched certificate CA key",
path, linenum);
}
} else {
/* Didn't match key */
goto done;
}
/* Check whether options preclude the use of this key */
if (sigopts->namespaces != NULL && sig_namespace != NULL &&
match_pattern_list(sig_namespace, sigopts->namespaces, 0) != 1) {
error("%s:%lu: key is not permitted for use in signature "
"namespace \"%s\"", path, linenum, sig_namespace);
goto done;
}
/* check key time validity */
format_absolute_time((uint64_t)verify_time, tverify, sizeof(tverify));
if (sigopts->valid_after != 0 &&
(uint64_t)verify_time < sigopts->valid_after) {
format_absolute_time(sigopts->valid_after,
tvalid, sizeof(tvalid));
error("%s:%lu: key is not yet valid: "
"verify time %s < valid-after %s", path, linenum,
tverify, tvalid);
goto done;
}
if (sigopts->valid_before != 0 &&
(uint64_t)verify_time > sigopts->valid_before) {
format_absolute_time(sigopts->valid_before,
tvalid, sizeof(tvalid));
error("%s:%lu: key has expired: "
"verify time %s > valid-before %s", path, linenum,
tverify, tvalid);
goto done;
}
success = 1;
done:
if (success && principalsp != NULL) {
*principalsp = principals;
principals = NULL; /* transferred */
}
free(principals);
sshkey_free(found_key);
sshsigopt_free(sigopts);
return success ? 0 : SSH_ERR_KEY_NOT_FOUND;
}
int
sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key,
const char *principal, const char *sig_namespace, uint64_t verify_time)
{
FILE *f = NULL;
char *line = NULL;
size_t linesize = 0;
u_long linenum = 0;
int r = SSH_ERR_INTERNAL_ERROR, oerrno;
/* Check key and principal against file */
if ((f = fopen(path, "r")) == NULL) {
oerrno = errno;
error("Unable to open allowed keys file \"%s\": %s",
path, strerror(errno));
errno = oerrno;
return SSH_ERR_SYSTEM_ERROR;
}
while (getline(&line, &linesize, f) != -1) {
linenum++;
r = check_allowed_keys_line(path, linenum, line, sign_key,
principal, sig_namespace, verify_time, NULL);
free(line);
line = NULL;
linesize = 0;
if (r == SSH_ERR_KEY_NOT_FOUND)
continue;
else if (r == 0) {
/* success */
fclose(f);
return 0;
} else
break;
}
/* Either we hit an error parsing or we simply didn't find the key */
fclose(f);
free(line);
return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
}
int
sshsig_find_principals(const char *path, const struct sshkey *sign_key,
uint64_t verify_time, char **principals)
{
FILE *f = NULL;
char *line = NULL;
size_t linesize = 0;
u_long linenum = 0;
int r = SSH_ERR_INTERNAL_ERROR, oerrno;
if ((f = fopen(path, "r")) == NULL) {
oerrno = errno;
error("Unable to open allowed keys file \"%s\": %s",
path, strerror(errno));
errno = oerrno;
return SSH_ERR_SYSTEM_ERROR;
}
r = SSH_ERR_KEY_NOT_FOUND;
while (getline(&line, &linesize, f) != -1) {
linenum++;
r = check_allowed_keys_line(path, linenum, line,
sign_key, NULL, NULL, verify_time, principals);
free(line);
line = NULL;
linesize = 0;
if (r == SSH_ERR_KEY_NOT_FOUND)
continue;
else if (r == 0) {
/* success */
fclose(f);
return 0;
} else
break;
}
free(line);
/* Either we hit an error parsing or we simply didn't find the key */
if (ferror(f) != 0) {
oerrno = errno;
fclose(f);
error("Unable to read allowed keys file \"%s\": %s",
path, strerror(errno));
errno = oerrno;
return SSH_ERR_SYSTEM_ERROR;
}
fclose(f);
return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
}
int
sshsig_match_principals(const char *path, const char *principal,
char ***principalsp, size_t *nprincipalsp)
{
FILE *f = NULL;
char *found, *line = NULL, **principals = NULL, **tmp;
size_t i, nprincipals = 0, linesize = 0;
u_long linenum = 0;
int oerrno = 0, r, ret = 0;
if (principalsp != NULL)
*principalsp = NULL;
if (nprincipalsp != NULL)
*nprincipalsp = 0;
/* Check key and principal against file */
if ((f = fopen(path, "r")) == NULL) {
oerrno = errno;
error("Unable to open allowed keys file \"%s\": %s",
path, strerror(errno));
errno = oerrno;
return SSH_ERR_SYSTEM_ERROR;
}
while (getline(&line, &linesize, f) != -1) {
linenum++;
/* Parse the line */
if ((r = parse_principals_key_and_options(path, linenum, line,
principal, &found, NULL, NULL)) != 0) {
if (r == SSH_ERR_KEY_NOT_FOUND)
continue;
ret = r;
oerrno = errno;
break; /* unexpected error */
}
if ((tmp = recallocarray(principals, nprincipals,
nprincipals + 1, sizeof(*principals))) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
free(found);
break;
}
principals = tmp;
principals[nprincipals++] = found; /* transferred */
free(line);
line = NULL;
linesize = 0;
}
fclose(f);
if (ret == 0) {
if (nprincipals == 0)
ret = SSH_ERR_KEY_NOT_FOUND;
if (principalsp != NULL) {
*principalsp = principals;
principals = NULL; /* transferred */
}
if (nprincipalsp != 0) {
*nprincipalsp = nprincipals;
nprincipals = 0;
}
}
for (i = 0; i < nprincipals; i++)
free(principals[i]);
free(principals);
errno = oerrno;
return ret;
}
int
sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey)
{
struct sshkey *pk = NULL;
int r = SSH_ERR_SIGNATURE_INVALID;
if (pubkey == NULL)
return SSH_ERR_INTERNAL_ERROR;
if ((r = sshsig_parse_preamble(signature)) != 0)
return r;
if ((r = sshkey_froms(signature, &pk)) != 0)
return r;
*pubkey = pk;
pk = NULL;
return 0;
}
diff --git a/version.h b/version.h
index e600fe4c34c9..1a034c838dd2 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
-/* $OpenBSD: version.h,v 1.94 2022/04/04 22:45:25 djm Exp $ */
+/* $OpenBSD: version.h,v 1.95 2022/09/26 22:18:40 djm Exp $ */
-#define SSH_VERSION "OpenSSH_9.0"
+#define SSH_VERSION "OpenSSH_9.1"
#define SSH_PORTABLE "p1"
#define SSH_RELEASE SSH_VERSION SSH_PORTABLE
diff --git a/xmss_hash.c b/xmss_hash.c
index 50a577943974..db0e5fa36597 100644
--- a/xmss_hash.c
+++ b/xmss_hash.c
@@ -1,140 +1,137 @@
-/* $OpenBSD: xmss_hash.c,v 1.2 2018/02/26 03:56:44 dtucker Exp $ */
+/* $OpenBSD: xmss_hash.c,v 1.3 2022/04/20 16:00:25 millert Exp $ */
/*
hash.c version 20160722
Andreas Hülsing
Joost Rijneveld
Public domain.
*/
#include "includes.h"
#ifdef WITH_XMSS
#include "xmss_hash_address.h"
#include "xmss_commons.h"
#include "xmss_hash.h"
#include <stddef.h>
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#include <stdio.h>
#include <string.h>
-#include <openssl/sha.h>
-#include <openssl/hmac.h>
-#include <openssl/evp.h>
int core_hash_SHA2(unsigned char *, const unsigned int, const unsigned char *,
unsigned int, const unsigned char *, unsigned long long, unsigned int);
unsigned char* addr_to_byte(unsigned char *bytes, const uint32_t addr[8]){
#if IS_LITTLE_ENDIAN==1
int i = 0;
for(i=0;i<8;i++)
to_byte(bytes+i*4, addr[i],4);
return bytes;
#else
memcpy(bytes, addr, 32);
return bytes;
#endif
}
int core_hash_SHA2(unsigned char *out, const unsigned int type, const unsigned char *key, unsigned int keylen, const unsigned char *in, unsigned long long inlen, unsigned int n){
unsigned long long i = 0;
unsigned char buf[inlen + n + keylen];
// Input is (toByte(X, 32) || KEY || M)
// set toByte
to_byte(buf, type, n);
for (i=0; i < keylen; i++) {
buf[i+n] = key[i];
}
for (i=0; i < inlen; i++) {
buf[keylen + n + i] = in[i];
}
if (n == 32) {
SHA256(buf, inlen + keylen + n, out);
return 0;
}
else {
if (n == 64) {
SHA512(buf, inlen + keylen + n, out);
return 0;
}
}
return 1;
}
/**
* Implements PRF
*/
int prf(unsigned char *out, const unsigned char *in, const unsigned char *key, unsigned int keylen)
{
return core_hash_SHA2(out, 3, key, keylen, in, 32, keylen);
}
/*
* Implemts H_msg
*/
int h_msg(unsigned char *out, const unsigned char *in, unsigned long long inlen, const unsigned char *key, const unsigned int keylen, const unsigned int n)
{
if (keylen != 3*n){
// H_msg takes 3n-bit keys, but n does not match the keylength of keylen
return -1;
}
return core_hash_SHA2(out, 2, key, keylen, in, inlen, n);
}
/**
* We assume the left half is in in[0]...in[n-1]
*/
int hash_h(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n)
{
unsigned char buf[2*n];
unsigned char key[n];
unsigned char bitmask[2*n];
unsigned char byte_addr[32];
unsigned int i;
setKeyAndMask(addr, 0);
addr_to_byte(byte_addr, addr);
prf(key, byte_addr, pub_seed, n);
// Use MSB order
setKeyAndMask(addr, 1);
addr_to_byte(byte_addr, addr);
prf(bitmask, byte_addr, pub_seed, n);
setKeyAndMask(addr, 2);
addr_to_byte(byte_addr, addr);
prf(bitmask+n, byte_addr, pub_seed, n);
for (i = 0; i < 2*n; i++) {
buf[i] = in[i] ^ bitmask[i];
}
return core_hash_SHA2(out, 1, key, n, buf, 2*n, n);
}
int hash_f(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n)
{
unsigned char buf[n];
unsigned char key[n];
unsigned char bitmask[n];
unsigned char byte_addr[32];
unsigned int i;
setKeyAndMask(addr, 0);
addr_to_byte(byte_addr, addr);
prf(key, byte_addr, pub_seed, n);
setKeyAndMask(addr, 1);
addr_to_byte(byte_addr, addr);
prf(bitmask, byte_addr, pub_seed, n);
for (i = 0; i < n; i++) {
buf[i] = in[i] ^ bitmask[i];
}
return core_hash_SHA2(out, 0, key, n, buf, n, n);
}
#endif /* WITH_XMSS */

File Metadata

Mime Type
application/octet-stream
Expires
Wed, Jul 3, 4:55 AM (1 d, 23 h)
Storage Engine
chunks
Storage Format
Chunks
Storage Handle
9qunj3A0y3qX
Default Alt Text
(5 MB)

Event Timeline