diff --git a/crypto/openssh/.depend b/crypto/openssh/.depend index 945a01dcc05d..cd38d15f8f52 100644 --- a/crypto/openssh/.depend +++ b/crypto/openssh/.depend @@ -1,182 +1,182 @@ # 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.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 xmalloc.h sshbuf.h ssherr.h log.h misc.h match.h uidswap.h sftp.h sftp-common.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 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/crypto/openssh/.github/configs b/crypto/openssh/.github/configs index 853da58a51e3..871a3d414d94 100755 --- a/crypto/openssh/.github/configs +++ b/crypto/openssh/.github/configs @@ -1,214 +1,231 @@ #!/bin/sh # # usage: configs vmname test_config (or '' for default) # # Sets the following variables: # CONFIGFLAGS options to ./configure # SSHD_CONFOPTS sshd_config options # TEST_TARGET make target used when testing. defaults to "tests". # LTESTS config=$1 TEST_TARGET="tests" LTESTS="" SKIP_LTESTS="" SUDO=sudo # run with sudo by default TEST_SSH_UNSAFE_PERMISSIONS=1 # 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" ;; 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" + CFLAGS="-Wall -Wextra -O2 -Wno-error=implicit-fallthrough -Wno-error=unused-parameter" CONFIGFLAGS="--with-pam --with-Werror" ;; gcc-11-Werror) CC="gcc" # -Wnoformat-truncation in gcc 7.3.1 20180130 fails on fmt_scaled - CFLAGS="-Wall -Wextra -Wno-format-truncation -O2 -Wimplicit-fallthrough=4" + 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" 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}" ;; 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 *-darwin*) 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 TEST_TARGET TEST_SSH_UNSAFE_PERMISSIONS TEST_SSH_FAIL_FATAL diff --git a/crypto/openssh/.github/setup_ci.sh b/crypto/openssh/.github/setup_ci.sh index ca37f8c5512f..a3bb8587eab1 100755 --- a/crypto/openssh/.github/setup_ci.sh +++ b/crypto/openssh/.github/setup_ci.sh @@ -1,132 +1,141 @@ #!/bin/sh . .github/configs $@ case "`./config.guess`" in *-darwin*) brew install automake exit 0 ;; esac TARGETS=$@ PACKAGES="" INSTALL_FIDO_PPA="no" export DEBIAN_FRONTEND=noninteractive #echo "Setting up for '$TARGETS'" set -ex lsb_release -a 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" ;; esac done for TARGET in $TARGETS; do case $TARGET in default|without-openssl|without-zlib|c89|libedit|*pam) # nothing to do ;; clang-*|gcc-*) compiler=$(echo $TARGET | sed 's/-Werror//') PACKAGES="$PACKAGES $compiler" ;; krb5) PACKAGES="$PACKAGES libkrb5-dev" ;; heimdal) PACKAGES="$PACKAGES heimdal-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="v$(echo ${TARGET} | cut -f2 -d-)" ;; + *) 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 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 - (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) + 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/crypto/openssh/.github/workflows/c-cpp.yml b/crypto/openssh/.github/workflows/c-cpp.yml index 5ee896308478..b778c9804203 100644 --- a/crypto/openssh/.github/workflows/c-cpp.yml +++ b/crypto/openssh/.github/workflows/c-cpp.yml @@ -1,101 +1,104 @@ name: C/C++ CI on: push: branches: [ master, ci ] pull_request: branches: [ master ] jobs: ci: if: github.repository != 'openssh/openssh-portable-selfhosted' strategy: fail-fast: false matrix: # First we test all OSes in the default configuration. os: [ubuntu-20.04, ubuntu-18.04, macos-10.15, macos-11.0] configs: [default] # Then we include any extra configs we want to test for specific VMs. # Valgrind slows things down quite a bit, so start them first. include: - { os: ubuntu-20.04, configs: valgrind-1 } - { os: ubuntu-20.04, configs: valgrind-2 } - { os: ubuntu-20.04, configs: valgrind-3 } - { os: ubuntu-20.04, configs: valgrind-4 } - { os: ubuntu-20.04, configs: valgrind-unit } - { os: ubuntu-20.04, configs: 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: 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: 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-3.0.0 } + - { os: ubuntu-latest, configs: openssl-3.0.1 } - { 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 } runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - name: setup CI system run: ./.github/setup_ci.sh ${{ matrix.configs }} - name: autoreconf run: autoreconf - name: configure run: ./.github/configure.sh ${{ matrix.configs }} - name: 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 }} env: TEST_SSH_UNSAFE_PERMISSIONS: 1 - 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/ diff --git a/crypto/openssh/.github/workflows/selfhosted.yml b/crypto/openssh/.github/workflows/selfhosted.yml index 09f7af939912..ec2c29825c85 100644 --- a/crypto/openssh/.github/workflows/selfhosted.yml +++ b/crypto/openssh/.github/workflows/selfhosted.yml @@ -1,103 +1,108 @@ name: C/C++ CI self-hosted on: push: branches: [ master, ci ] jobs: selfhosted: if: github.repository == 'openssh/openssh-portable-selfhosted' runs-on: ${{ matrix.os }} env: TARGET_HOST: ${{ matrix.os }} 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 - ARM64 - alpine - bbone + - debian-i386 - 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: - 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: 300 + 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/crypto/openssh/ChangeLog b/crypto/openssh/ChangeLog index c225b94dfd3e..063b54769d53 100644 --- a/crypto/openssh/ChangeLog +++ b/crypto/openssh/ChangeLog @@ -1,11979 +1,11889 @@ +commit 94eb6858efecc1b4f02d8a6bd35e149f55c814c8 +Author: Damien Miller +Date: Wed Apr 6 10:47:48 2022 +1000 + + update version numbers for release + +commit 8e4a8eadf4fe74e65e6492f34250f8cf7d67e8da +Author: djm@openbsd.org +Date: Mon Apr 4 22:45:25 2022 +0000 + + upstream: openssh-9.0 + + OpenBSD-Commit-ID: 0dfb461188f4513ec024c1534da8c1ce14c20b64 + +commit a9f23ea2e3227f406880c2634d066f6f50fa5eaa +Author: naddy@openbsd.org +Date: Thu Mar 31 17:58:44 2022 +0000 + + upstream: ssh: document sntrup761x25519-sha512@openssh.com as + + default KEX + + OpenBSD-Commit-ID: 12545bfa10bcbf552d04d9d9520d0f4e98b0e171 + +commit 9ec2713d122af79d66ebb9c1d6d9ae8621a8945f +Author: naddy@openbsd.org +Date: Thu Mar 31 17:27:27 2022 +0000 + + upstream: man pages: add missing commas between subordinate and + + main clauses + + jmc@ dislikes a comma before "then" in a conditional, so leave those + untouched. + + ok jmc@ + + OpenBSD-Commit-ID: 9520801729bebcb3c9fe43ad7f9776ab4dd05ea3 + +commit 3741df98ffaaff92b474ee70d8ef276b5882f85a +Author: Darren Tucker +Date: Mon Apr 4 23:52:11 2022 +1000 + + Disable security key on fbsd6 test host. + +commit 32c12236f27ae83bfe6d2983b67c9bc67a83a417 +Author: Darren Tucker +Date: Mon Apr 4 15:16:51 2022 +1000 + + Specify TEST_SHELL=bash on AIX. + + 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 90452c8b69d065b7c7c285ff78b81418a75bcd76 +Author: Darren Tucker +Date: Fri Apr 1 23:38:44 2022 +1100 + + Only return events from ppoll that were requested. + + 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 6c49eb5fabc56f4865164ed818aa5112d09c31a8 +Author: Darren Tucker +Date: Fri Apr 1 23:21:40 2022 +1100 + + Only run regression tests on slow VMs. + +commit f67e47903977b42cb6abcd5565a61bd7293e4dc3 +Author: Darren Tucker +Date: Fri Apr 1 23:21:06 2022 +1100 + + Increase test timeout to allow slow VMs to finish + +commit 02488c1b54065ddc4f25835dbd2618b2a2fe21f5 +Author: Darren Tucker +Date: Fri Apr 1 16:27:38 2022 +1100 + + Use bash or ksh if available for SH in Makefile. + +commit 34c7018c316af4773e432066de28d0ef9d0888cd +Author: Darren Tucker +Date: Fri Apr 1 14:56:54 2022 +1100 + + Set Makefile SHELL as determined by configure. + + 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 5b054d76402faab38c48377efd112426469553a0 +Author: Darren Tucker +Date: Fri Apr 1 13:16:47 2022 +1100 + + Skip slow tests on (very) slow test targets. + +commit b275818065b31a865142c48c2acf6a7c1655c542 +Author: Damien Miller +Date: Thu Mar 31 14:11:36 2022 +1100 + + depend + +commit 3fa539c3ffaabd6211995512d33e29150f88c5c5 +Author: djm@openbsd.org +Date: Thu Mar 31 03:07:03 2022 +0000 + + upstream: add a sftp client "cp" command that supports server-side + + copying of files. Useful for this task and for testing the copy-data + extension. Patch from Mike Frysinger; ok dtucker@ + + OpenBSD-Commit-ID: 1bb1b950af0d49f0d5425b1f267e197aa1b57444 + +commit 7988bfc4b701c4b3fe9b36c8561a3d1c5d4c9a74 +Author: djm@openbsd.org +Date: Thu Mar 31 03:05:49 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@ + + OpenBSD-Commit-ID: 00aa510940fedd66dab1843b58682de4eb7156d5 + +commit 32dc1c29a4ac9c592ddfef0a4895eb36c1f567ba +Author: djm@openbsd.org +Date: Wed Mar 30 21:13:23 2022 +0000 + + upstream: select post-quantum KEX + + sntrup761x25519-sha512@openssh.com as the default; ok markus@ + + OpenBSD-Commit-ID: f02d99cbfce22dffec2e2ab1b60905fbddf48fb9 + +commit d6556de1db0822c76ba2745cf5c097d9472adf7c +Author: djm@openbsd.org +Date: Wed Mar 30 21:10:25 2022 +0000 + + upstream: fix poll() spin when a channel's output fd closes without + + data in the channel buffer. Introduce more exact packing of channel fds into + the pollfd array. fixes bz3405 and bz3411; ok deraadt@ markus@ + + OpenBSD-Commit-ID: 06740737849c9047785622ad5d472cb6a3907d10 + +commit 8a74a96d25ca4d32fbf298f6c0ac5a148501777d +Author: djm@openbsd.org +Date: Wed Mar 30 04:33:09 2022 +0000 + + upstream: ssh is almost out of getopt() characters; note the + + remaining remaining available ones in a comment + + OpenBSD-Commit-ID: 48d38cef59d6bc8e84c6c066f6d601875d3253fd + +commit 6d4fc51adb9d8a42f67b5474f02f877422379de6 +Author: djm@openbsd.org +Date: Wed Mar 30 04:27:51 2022 +0000 + + upstream: avoid NULL deref via ssh-keygen -Y find-principals. + + bz3409, reported by Mateusz Adamowski + + OpenBSD-Commit-ID: a3b2c02438052ee858e0ee18e5a288586b5df2c5 + +commit e937514920335b92b543fd9be79cd6481d1eb0b6 +Author: Darren Tucker +Date: Mon Mar 28 17:51:03 2022 +1100 + + Add AIX 5.1 test target. + +commit 4bbe815ba974b4fd89cc3fc3e3ef1be847a0befe +Author: Darren Tucker +Date: Sat Mar 26 22:01:31 2022 +1100 + + 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 f5cdd3b3c275dffaebfca91df782dca29975e9ac +Author: Darren Tucker +Date: Sat Mar 26 16:28:04 2022 +1100 + + 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 24dc37d198f35a7cf71bf4d5384363c7ef4209d4 +Author: Darren Tucker +Date: Sat Mar 26 15:02:45 2022 +1100 + + Remove now-unused passwd variable. + +commit 5b467ceef2c356f0a77f5e8ab4eb0fac367e4d24 +Author: Darren Tucker +Date: Sat Mar 26 13:15:44 2022 +1100 + + Missing semicolon. + +commit 2923d026e55998133c0f6e5186dca2a3c0fa5ff5 +Author: Darren Tucker +Date: Sat Mar 26 12:49:50 2022 +1100 + + Factor out platform-specific locked account check. + + 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 d23efe4b12886ffe416be10bc0a7da6ca8aa72d1 +Author: Darren Tucker +Date: Sat Mar 26 08:13:46 2022 +1100 + + Add OpenWRT mips and mipsel test targets. + +commit 16ea8b85838dd7a4dbeba4e51ac4f43fd68b1e5b +Author: djm@openbsd.org +Date: Sun Mar 20 08:52:17 2022 +0000 + + upstream: don't leak argument list; bz3404, reported by Balu + + Gajjala ok dtucker@ + + OpenBSD-Commit-ID: fddc32d74e5dd5cff1a49ddd6297b0867eae56a6 + +commit a72bde294fe0518c9a44ba63864093a1ef2425e3 +Author: djm@openbsd.org +Date: Sun Mar 20 08:51:21 2022 +0000 + + upstream: make addargs() and replacearg() a little more robust and + + improve error reporting + + make freeargs(NULL) a noop like the other free functions + + ok dtucker as part of bz3403 + + OpenBSD-Commit-ID: 15f86da83176978b4d1d288caa24c766dfa2983d + +commit 731087d2619fa7f01e675b23f57af10d745e8af2 +Author: djm@openbsd.org +Date: Fri Mar 18 04:04:11 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@ + + OpenBSD-Commit-ID: 44c53a43909a328e2f5ab26070fdef3594eded60 + +commit 1c83c082128694ddd11ac05fdf31d70312ff1763 +Author: djm@openbsd.org +Date: Fri Mar 18 02:50:21 2022 +0000 + + upstream: remove blank line + + OpenBSD-Commit-ID: d5e0182965b2fbfb03ad5f256d1a1ce5706bcddf + +commit 807be68684da7a1fe969c399ddce2fafb7997dcb +Author: djm@openbsd.org +Date: Fri Mar 18 02:32:22 2022 +0000 + + upstream: helpful comment + + OpenBSD-Commit-ID: e3315a45cb04e7feeb614d76ec80a9fe4ca0e8c7 + +commit a0b5816f8f1f645acdf74f7bc11b34455ec30bac +Author: djm@openbsd.org +Date: Fri Mar 18 02:31:25 2022 +0000 + + upstream: ssh-keygen -Y check-novalidate requires namespace or SEGV + + will ensue. Patch from Mateusz Adamowski via GHPR#307 + + OpenBSD-Commit-ID: 99e8ec38f9feb38bce6de240335be34aedeba5fd + +commit 5a252d54a63be30d5ba4be76210942d754a531c0 +Author: djm@openbsd.org +Date: Tue Mar 15 05:27:37 2022 +0000 + + upstream: improve DEBUG_CHANNEL_POLL debugging message + + OpenBSD-Commit-ID: 2275eb7bc4707d019b1a0194b9c92c0b78da848f + +commit ce324cf58ba2840e31afeb996935800780c8fa4b +Author: cheloha@openbsd.org +Date: Sun Mar 13 23:27:54 2022 +0000 + + 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 + +commit 2893c5e764557f48f9d6a929e224ed49c59545db +Author: Darren Tucker +Date: Fri Mar 11 18:43:58 2022 +1100 + + Resync fmt_scaled. with OpenBSD. + + Fixes underflow reported in bz#3401. + +commit 5ae31a0fdd27855af29f48ff027491629fff5979 +Author: Darren Tucker +Date: Wed Mar 9 09:41:56 2022 +1100 + + Provide killpg implementation. + + Based on github PR#301 for Tandem NonStop. + +commit c41c84b439f4cd74d4fe44298a4b4037ddd7d2ae +Author: Darren Tucker +Date: Wed Mar 9 09:29:30 2022 +1100 + + Check for missing ftruncate prototype. + + From github PR#301 in conjunction with rsbeckerca. + +commit 8cf5275452a950869cb90eeac7d220b01f77b12e +Author: Darren Tucker +Date: Tue Mar 8 20:04:06 2022 +1100 + + Default to not using sandbox when cross compiling. + + 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 +Date: Tue Mar 1 01:59:19 2022 +0000 + + upstream: pack pollfd array before server_accept_loop() ppoll() + + call, and terminate sshd if ppoll() returns errno==EINVAL + + avoids spin in ppoll when MaxStartups > RLIMIT_NOFILE, reported by + Daniel Micay + + feedback/ok deraadt + + OpenBSD-Commit-ID: dbab1c24993ac977ec24d83283b8b7528f7c2c15 + +commit eceafbe0bdbbd9bd2f3cf024ccb350666a9934dd +Author: naddy@openbsd.org +Date: Sun Feb 27 01:33:59 2022 +0000 + + upstream: include rejected signature algorithm in error message and + + not the (useless) key type; ok djm@ + + OpenBSD-Commit-ID: d0c0f552a4d9161203e07e95d58a76eb602a76ff + +commit f2f3269423618a83157e18902385e720f9776007 +Author: dtucker@openbsd.org +Date: Fri Feb 25 09:46:24 2022 +0000 + + upstream: Remove the char * casts from arguments to do_lstat, + + do_readdir and do_stat paths since the underlying functions now take a const + char *. Patch from vapier at gentoo.org. + + OpenBSD-Commit-ID: 9e4d964dbfb0ed683a2a2900711b88e7f1c0297b + +commit 4a66dac052c5ff5047161853f36904607649e4f9 +Author: djm@openbsd.org +Date: Fri Feb 25 02:09:27 2022 +0000 + + upstream: save an unneccessary alloc/free, based on patch from + + Martin Vahlensieck; ok dtucker@ + + OpenBSD-Commit-ID: 90ffbf1f837e509742f2c31a1fbf2c0fd376fd5f + +commit 6f117cb151efe138ac57bdd8e26165f350328f5f +Author: Darren Tucker +Date: Tue Mar 1 09:02:06 2022 +1100 + + Remove unused ivbits argument from chacha_keysetup + +commit 15974235dd528aeab0ec67fb92a0a1d733f62be2 +Author: Darren Tucker +Date: Tue Mar 1 09:00:20 2022 +1100 + + Add OPENBSD ORIGINAL marker. + +commit f2ff669347d320532e7c1b63cdf5c62f46e73150 +Author: Darren Tucker +Date: Mon Feb 28 22:21:36 2022 +1100 + + 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. + +commit 96558ecd87adac62efa9a2b5479f686ab86b0be1 +Author: Darren Tucker +Date: Sat Feb 26 14:10:41 2022 +1100 + + Add debian-i386 test target. + +commit 284b6e5394652d519e31782e3b3cdfd7b21d1a81 +Author: Darren Tucker +Date: Sat Feb 26 14:06:14 2022 +1100 + + Allow ppoll_time64 in seccomp sandbox. + + 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 0132056efabc5edb85c3c7105d2fb6dee41843c6 +Author: Darren Tucker +Date: Fri Feb 25 19:47:48 2022 +1100 + + 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 8e206e0dd6b9f757b07979e48f53ad5bf9b7b52b +Author: Darren Tucker +Date: Fri Feb 25 15:14:22 2022 +1100 + + Constify utimes in compat library to match specs. + + Patch from vapier at chromium.org. + +commit 1b2920e3b63db2eddebeec7330ffe8b723055573 +Author: Darren Tucker +Date: Fri Feb 25 13:50:56 2022 +1100 + + 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. + +commit 54a86f4f6e1c43a2ca2be23ef799ab8910d4af70 +Author: Darren Tucker +Date: Fri Feb 25 13:23:04 2022 +1100 + + Use PICFLAG instead of hard coding -fPIC. + +commit 3016ba47035ac3561aabd48e2be70167fe157d6a +Author: Darren Tucker +Date: Fri Feb 25 11:37:11 2022 +1100 + + Add tests for latest releases of {Libre,Open}SSL. + +commit f107467179428a0e3ea9e4aa9738ac12ff02822d +Author: Colin Watson +Date: Thu Feb 24 16:04:18 2022 +0000 + + Improve detection of -fzero-call-used-regs=all support + + 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 3383b2cac0e9275bc93c4b4760e6e048f537e1d6 +Author: djm@openbsd.org +Date: Wed Feb 23 21:21:49 2022 +0000 + + upstream: free(3) wants stdlib.h + + OpenBSD-Commit-ID: 227a8c70a95b4428c49e46863c9ef4bd318a3b8a + +commit a4537e79ab4ac6db4493c5158744b9ebde5efcb0 +Author: djm@openbsd.org +Date: Wed Feb 23 21:21:16 2022 +0000 + + upstream: put back the scp manpage changes for SFTP mode too + + OpenBSD-Commit-ID: 05dc53921f927e1b5e5694e1f3aa314549f2e768 + +commit 449bcb8403adfb9724805d02a51aea76046de185 +Author: deraadt@openbsd.org +Date: Wed Feb 23 19:01:00 2022 +0000 + + upstream: and we go back to testing sftp-scp after the 8.9 + + release... + + OpenBSD-Commit-ID: a80440168258adca543a4607b871327a279c569c + commit 166456cedad3962b83b848b1e9caf80794831f0f Author: Damien Miller Date: Wed Feb 23 22:31:11 2022 +1100 makedepend commit 32ebaa0dbca5d0bb86e384e72bebc153f48413e4 Author: djm@openbsd.org Date: Wed Feb 23 11:18:13 2022 +0000 upstream: avoid integer overflow of auth attempts (harmless, caught by monitor) OpenBSD-Commit-ID: 488ad570b003b21e0cd9e7a00349cfc1003b4d86 commit 6e0258c64c901753df695e06498b26f9f4812ea6 Author: djm@openbsd.org Date: Wed Feb 23 11:17:10 2022 +0000 upstream: randomise the password used in fakepw OpenBSD-Commit-ID: 34e159f73b1fbf0a924a9c042d8d61edde293947 commit bf114d6f0a9df0b8369823d9a0daa6c72b0c4cc9 Author: djm@openbsd.org Date: Wed Feb 23 11:15:57 2022 +0000 upstream: use asprintf to construct .rhosts paths OpenBSD-Commit-ID: 8286e8d3d2c6ff916ff13d041d1713073f738a8b commit c07e154fbdc7285e9ec54e78d8a31f7325d43537 Author: djm@openbsd.org Date: Wed Feb 23 11:07:09 2022 +0000 upstream: openssh-8.9 OpenBSD-Commit-ID: 5c5f791c87c483cdab6d9266b43acdd9ca7bde0e commit bc16667b4a1c3cad7029304853c143a32ae04bd4 Author: Darren Tucker Date: Tue Feb 22 15:29:22 2022 +1100 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. 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 6520c488de95366be031d49287ed243620399e23 Author: Darren Tucker Date: Tue Feb 22 13:08:59 2022 +1100 Add Alpine Linux test VM. commit a4b325a3fc82d11e0f5d61f62e7fde29415f7afb Author: Darren Tucker Date: Tue Feb 22 12:27:07 2022 +1100 Include sys/param.h if present. Needed for howmany() on MUSL systems such as Alpine. commit 5a102e9cb287a43bd7dfe594b775a89a8e94697c Author: Darren Tucker Date: Tue Feb 22 12:25:52 2022 +1100 Only include sys/poll.h if we don't have poll.h. Prevents warnings on MUSL based systems such as Alpine. commit 7c0d4ce911d5c58b6166b2db754a4e91f352adf5 Author: Damien Miller Date: Tue Feb 22 11:14:51 2022 +1100 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. Refer to: 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 81d33d8e3cf7ea5ce3a5653c6102b623e019428a Author: Darren Tucker Date: Mon Feb 21 21:27:20 2022 +1100 Skip agent-getpeereid when running as root. commit fbd772570a25436a33924d91c164d2b24021f010 Author: dtucker@openbsd.org Date: Sun Feb 20 03:47:26 2022 +0000 upstream: Aproximate realpath on the expected output by deduping leading slashes. Fixes test failure when user's home dir is / which is possible in some portable configurations. OpenBSD-Regress-ID: 53b8c53734f8893806961475c7106397f98d9f63 commit 336685d223a59f893faeedf0a562e053fd84058e Author: Darren Tucker Date: Sun Feb 20 13:30:52 2022 +1100 Really move DSA to end of list. 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 63bf4f49ed2fdf2da6f97136c9df0c8168546eb3 Author: Darren Tucker Date: Fri Feb 18 12:12:21 2022 +1100 Add test configs for MUSL C library. commit f7fc6a43f1173e8b2c38770bf6cee485a562d03b Author: Damien Miller Date: Thu Feb 17 22:54:19 2022 +1100 minix needs BROKEN_POLL too; chokes on /dev/null commit 667fec5d4fe4406745750a32f69b5d2e1a75e94b Author: djm@openbsd.org Date: Thu Feb 17 10:58:27 2022 +0000 upstream: check for EINTR/EAGAIN failures in the rfd fast-path; caught by dtucker's minix3 vm :) ok dtucker@ OpenBSD-Commit-ID: 2e2c895a3e82ef347aa6694394a76a438be91361 commit 41417dbda9fb55a0af49a8236e3ef9d50d862644 Author: Darren Tucker Date: Thu Feb 17 22:05:29 2022 +1100 Comment hurd test, the VM is currently broken. commit b2aee35a1f0dc798339b3fcf96136da71b7e3f6d Author: Damien Miller Date: Thu Feb 17 21:15:16 2022 +1100 find sk-dummy.so when build_dir != src_dir spotted by Corinna Vinschen; feedback & ok dtucker@ commit 62a2d4e50b2e89f2ef04576931895d5139a5d037 Author: Damien Miller Date: Wed Feb 16 16:26:17 2022 +1100 update versions in preparation for 8.9 release commit dd6d3dded721ac653ea73c017325e5bfeeec837f Author: djm@openbsd.org Date: Tue Feb 15 05:13:36 2022 +0000 upstream: document the unbound/host-bound options to PubkeyAuthentication; spotted by HARUYAMA Seigo OpenBSD-Commit-ID: 298f681b66a9ecd498f0700082c7a6c46e948981 commit df93529dd727fdf2fb290700cd4f1adb0c3c084b Author: Darren Tucker Date: Mon Feb 14 14:19:40 2022 +1100 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 766176cfdbfd7ec38bb6118dde6e4daa0df34888 Author: Darren Tucker Date: Sat Feb 12 10:24:56 2022 +1100 Add cygwin-release test config. This tests the flags used to build the cygwin release binaries. commit b30698662b862f5397116d23688aac0764e0886e Author: Darren Tucker Date: Fri Feb 11 21:00:35 2022 +1100 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 cd00b48cf10f3565936a418c1e6d7e48b5c36140 Author: Darren Tucker Date: Fri Feb 11 20:09:32 2022 +1100 Simplify handling of --with-ssl-dir. ok djm@ commit ea13fc830fc0e0dce2459f1fab2ec5099f73bdf0 Author: Darren Tucker Date: Fri Feb 11 13:39:29 2022 +1100 Stop testing OpenBSD HEAD on 6.9 and 7.0. 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 Date: Fri Feb 11 00:43:56 2022 +0000 upstream: Always initialize delim before passing to hpdelim2 which might not set it. Found by the Valgrind tests on github, ok deraadt@ OpenBSD-Commit-ID: c830c0db185ca43beff3f41c19943c724b4f636d commit 6ee53064f476cf163acd5521da45b11b7c57321b Author: Darren Tucker Date: Fri Feb 11 10:03:06 2022 +1100 Fix helper include path and remove excess code. 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 Date: Thu Feb 10 23:27:02 2022 +1100 Put poll.h inside ifdef. commit 3ac00dfeb54b252c15dcbf1971582e9e3b946de6 Author: Darren Tucker Date: Thu Feb 10 22:17:31 2022 +1100 We now support POLLPRI so actually define it. commit 25bd659cc72268f2858c5415740c442ee950049f Author: dtucker@openbsd.org Date: Sun Feb 6 22:58:33 2022 +0000 upstream: Add test for empty hostname with port. OpenBSD-Regress-ID: e19e89d3c432b68997667efea44cf015bbe2a7e3 commit a29af853cff41c0635f0378c00fe91bf9c91dea4 Author: 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 Date: Thu Feb 10 04:12:38 2022 +0000 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. OpenBSD-Commit-ID: 0c725481a78210aceecff1537322c0b2df03e768 commit 45279abceb37c3cbfac8ba36dde8b2c8cdd63d32 Author: dtucker@openbsd.org Date: Tue Feb 8 08:59:12 2022 +0000 upstream: Switch hpdelim interface to accept only ":" as delimiter. 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 a1bcbf04a7c2d81944141db7ecd0ba292d175a66 Author: pedro martelletto Date: Mon Feb 7 09:09:59 2022 +0100 fix typos in previous commit 56192518e329b39f063487bc2dc4d796f791eca0 Author: Damien Miller Date: Mon Feb 7 12:53:47 2022 +1100 compat code for fido_assert_set_clientdata() commit d6b5aa08fdcf9b527f8b8f932432941d5b76b7ab Author: djm@openbsd.org Date: Mon Feb 7 01:25:12 2022 +0000 upstream: use libfido2 1.8.0+ fido_assert_set_clientdata() instead of manually hashing data outselves. Saves a fair bit of code and makes life easier for some -portable platforms. OpenBSD-Commit-ID: 351dfaaa5ab1ee928c0e623041fca28078cff0e0 commit 86cc93fd3c26b2e0c7663c6394995fb04ebfbf3b Author: jsg@openbsd.org Date: Sun Feb 6 00:29:03 2022 +0000 upstream: remove please from manual pages ok jmc@ sthen@ millert@ OpenBSD-Commit-ID: 6543acb00f4f38a23472538e1685c013ca1a99aa commit ad16a84e64a8cf1c69c63de3fb9008320a37009c Author: dtucker@openbsd.org Date: Fri Feb 4 02:49:17 2022 +0000 upstream: Since they are deprecated, move DSA to the end of the 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 253de42753de85dde266e061b6fec12ca6589f7d Author: Damien Miller Date: Wed Feb 2 16:52:07 2022 +1100 portable-specific string array constification from Mike Frysinger commit dfdcc2220cf359c492d5d34eb723370e8bd8a19e Author: djm@openbsd.org Date: Tue Feb 1 23:37:15 2022 +0000 upstream: test 'ssh-keygen -Y find-principals' with wildcard principals; from Fabian Stelzer OpenBSD-Regress-ID: fbe4da5f0032e7ab496527a5bf0010fd700f8f40 commit 968e508967ef42480cebad8cf3172465883baa77 Author: dtucker@openbsd.org Date: Fri Jan 21 02:54:41 2022 +0000 upstream: Enable all supported ciphers and macs in the server before trying to benchmark them. Increase the data file size to get more signal. OpenBSD-Regress-ID: dc3697d9f7defdfc51c608782c8e750128e46eb6 commit 15b7199a1fd37eff4c695e09d573f3db9f4274b7 Author: djm@openbsd.org Date: Tue Feb 1 23:34:47 2022 +0000 upstream: allow 'ssh-keygen -Y find-principals' to match wildcard principals in allowed_signers files; from Fabian Stelzer OpenBSD-Commit-ID: 1e970b9c025b80717dddff5018fe5e6f470c5098 commit 541667fe6dc26d7881e55f0bb3a4baa6f3171645 Author: djm@openbsd.org Date: Tue Feb 1 23:32:51 2022 +0000 upstream: mark const string array contents const too, i.e. static const char *array => static const char * const array from Mike Frysinger OpenBSD-Commit-ID: a664e31ea6a795d7c81153274a5f47b22bdc9bc1 commit 8cfa73f8a2bde4c98773f33f974c650bdb40dd3c Author: djm@openbsd.org Date: Tue Feb 1 23:11:11 2022 +0000 upstream: better match legacy scp behaviour: show un-expanded paths in error messages. Spotted by and ok tb@ OpenBSD-Commit-ID: 866c8ffac5bd7d38ecbfc3357c8adfa58af637b7 commit 4e62c13ab419b4b224c8bc6a761e91fcf048012d Author: dtucker@openbsd.org Date: Tue Feb 1 07:57:32 2022 +0000 upstream: Remove explicit kill of privsep preauth child's PID in 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: 2be1ffa28b4051ad9e33bb4371e2ec8a31d6d663 commit 2a7ccd2ec4022917b745af7186f514f365b7ebe9 Author: guenther@openbsd.org Date: Fri Jan 28 06:18:42 2022 +0000 upstream: When it's the possessive of 'it', it's spelled "its", without the apostrophe. OpenBSD-Commit-ID: fb6ab9c65bd31de831da1eb4631ddac018c5fae7 commit 8a0848cdd3b25c049332cd56034186b7853ae754 Author: Alex James Date: Sun Jan 30 16:13:36 2022 -0600 sandbox-seccomp-filter: allow gettid Some allocators (such as Scudo) use gettid while tracing allocations [1]. Allow gettid in preauth to prevent sshd from crashing with Scudo. [1]: https://github.com/llvm/llvm-project/blob/llvmorg-13.0.0/compiler-rt/lib/gwp_asan/common.cpp#L46 commit b30d32159dc3c7052f4bfdf36357996c905af739 Author: djm@openbsd.org Date: Sat Jan 22 00:49:34 2022 +0000 upstream: add a ssh_packet_process_read() function that reads from a fd directly into the transport input buffer. Use this in the client and server mainloops to avoid unnecessary copying. It also lets us use a more greedy read size without penalty. 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 a1a8efeaaa9cccb15cdc0a2bd7c347a149a3a7e3 Author: djm@openbsd.org Date: Sat Jan 22 00:45:31 2022 +0000 upstream: Use sshbuf_read() to read directly into the channel input 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 29a76994e21623a1f84d68ebb9dc5a3c909fa3a7 Author: Damien Miller Date: Tue Jan 25 11:52:34 2022 +1100 depend commit 754e0d5c7712296a7a3a83ace863812604c7bc4f Author: djm@openbsd.org Date: Sat Jan 22 00:43:43 2022 +0000 upstream: Add a sshbuf_read() that attempts to read(2) directly in to a sshbuf; ok markus@ OpenBSD-Commit-ID: 2d8f249040a4279f3bc23c018947384de8d4a45b commit c7964fb9829d9ae2ece8b51a76e4a02e8449338d Author: djm@openbsd.org Date: Fri Jan 21 07:04:19 2022 +0000 upstream: add a helper for writing an error message to the stderr_buf and setting quit_pending; no functional change but saves a bunch of boilerplate OpenBSD-Commit-ID: 0747657cad6b9eabd514a6732adad537568e232d commit d23b4f7fdb1bd87e2cd7a9ae7c198ae99d347916 Author: djm@openbsd.org Date: Fri Jan 21 06:58:06 2022 +0000 upstream: correct comment and use local variable instead of long indirection; spotted by dtucker@ OpenBSD-Commit-ID: 5f65f5f69db2b7d80a0a81b08f390a63f8845965 commit d069b020a02b6e3935080204ee44d233e8158ebb Author: deraadt@openbsd.org Date: Fri Jan 21 00:53:40 2022 +0000 upstream: When poll(2) returns -1, for some error conditions 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-Commit-ID: 00f839b16861f7fb2adcf122e95e8a82fa6a375c commit e204b34337a965feb439826157c191919fd9ecf8 Author: Damien Miller Date: Sat Jan 22 11:38:21 2022 +1100 restore tty force-read hack 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 68085066b6bad43643b43f5957fcc5fd34782ccd Author: Corinna Vinschen Date: Fri Jan 21 03:22:56 2022 +1100 Fix signedness bug in Cygwin code 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. Signed-off-by: Corinna Vinschen commit 2e5cfed513e84444483baf1d8b31c40072b05103 Author: Darren Tucker Date: Thu Jan 20 13:26:27 2022 +1100 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 3fe6800b6027add478e648934cbb29d684e51943 Author: Darren Tucker Date: Thu Jan 20 00:49:57 2022 +1100 Move more tests out of valgrind-1 runner. commit 20da6ed136dd76e6a0b229ca3036ef9c7c7ef798 Author: Darren Tucker Date: Wed Jan 19 15:37:39 2022 +1100 Invoke EXIT handler early when using Valgrind. 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 ad2e0580c87b0714cf166bca9d926a95ddeee1c8 Author: Darren Tucker Date: Tue Jan 18 12:55:21 2022 +1100 Remove line leftover from upstream sync. commit d1051c0f11a6b749027e26bbeb61b07df4b67e15 Author: djm@openbsd.org Date: Mon Jan 17 22:56:04 2022 +0000 upstream: when decompressing zlib compressed packets, use 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. repoted by lamm AT ibm.com via bz3372; ok markus OpenBSD-Commit-ID: 67cfc1fa8261feae6d2cc0c554711c97867cc81b commit d5981b1883746b1ae178a46229c26b53af99e37a Author: djm@openbsd.org Date: Mon Jan 17 21:41:04 2022 +0000 upstream: make most of the sftp errors more idiomatic, following the general form of "[local/remote] operation path: error message"; ok markus OpenBSD-Commit-ID: 61364cd5f3a9fecaf8d63b4c38a42c0c91f8b571 commit ac7c9ec894ed0825d04ef69c55babb49bab1d32e Author: djm@openbsd.org Date: Mon Jan 17 21:39:51 2022 +0000 upstream: when transferring multiple files in SFTP mode, create the destination directory if it doesn't already exist to match olde-scp(1) behaviour. noticed by deraadt@ ok markus@ OpenBSD-Commit-ID: cf44dfa231d4112f697c24ff39d7ecf2e6311407 commit 39d17e189f8e72c34c722579d8d4e701fa5132da Author: 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). ssh-askpass will be used to request the PIN at authentication time. From Pedro Martelletto, ok djm OpenBSD-Commit-ID: de8189fcd35b45f632484864523c1655550e2950 commit 52423f64e13db2bdc31a51b32e999cb1bfcf1263 Author: djm@openbsd.org Date: Fri Jan 14 03:35:10 2022 +0000 upstream: ssh-sk: free a resident key's user id From Pedro Martelletto; ok dtucker & me OpenBSD-Commit-ID: 47be40d602b7a6458c4c71114df9b53d149fc2e9 commit 014e2f147a2788bfb3cc58d1b170dcf2bf2ee493 Author: djm@openbsd.org Date: Fri Jan 14 03:34:00 2022 +0000 upstream: sshsk_load_resident: don't preallocate resp resp is allocated by client_converse(), at which point we lose the original pointer. From Pedro Martelletto; ok dtucker & me OpenBSD-Commit-ID: 1f1b5ea3282017d6584dfed4f8370dc1db1f44b1 commit c88265f207dfe0e8bdbaf9f0eda63ed6b33781cf Author: djm@openbsd.org Date: Fri Jan 14 03:32:52 2022 +0000 upstream: sshsk_sign: trim call to sshkey_fingerprint() the resulting fingerprint doesn't appear to be used for anything, and we end up leaking it. from Pedro Martelletto; ok dtucker & me OpenBSD-Commit-ID: 5625cf6c68f082bc2cbbd348e69a3ed731d2f9b7 commit 1cd1b2eac39661b849d5a4b4b56363e22bb5f61e Author: djm@openbsd.org Date: Fri Jan 14 03:31:52 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 (forgot to include this file in previous commit) OpenBSD-Commit-ID: d37cc4c8c861ce48cd6ea9899e96aaac3476847b commit a1d42a6ce0398da3833bedf374ef2571af7fea50 Author: Damien Miller Date: Fri Jan 14 13:49:32 2022 +1100 fix edge case in poll(2) wrapper Correct handling of select(2) exceptfds. These should only be consulted for POLLPRI flagged pfds and not unconditionally converted to POLLERR. with and ok dtucker@ commit 976b9588b4b5babcaceec4767a241c11a67a5ccb Author: Darren Tucker Date: Fri Jan 14 13:46:35 2022 +1100 Wrap OpenSSL includes in unit tests in ifdef. Fixes unit test on systems that do not have OpenSSL headers installed. commit c171879374b2e8b07157503f5639ed0bce59ce89 Author: Darren Tucker Date: Thu Jan 13 15:53:33 2022 +1100 Remove sort wrapper. agent-restrict now takes care of this itself. commit 9cc2654403f1a686bb26c07a6ac790edf334cef5 Author: dtucker@openbsd.org Date: Thu Jan 13 04:53:16 2022 +0000 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 7a75f748cb2dd2f771bf70ea72698aa027996ab1 Author: dtucker@openbsd.org Date: Thu Jan 13 04:22:10 2022 +0000 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 6c435bd4994d71442192001483a1cdb846e5ffcd Author: Darren Tucker Date: Wed Jan 12 16:58:13 2022 +1100 Stop on first test failure to minimize logs. commit 4bc2ba6095620a4484b708ece12842afd8c7685b Author: dtucker@openbsd.org Date: Wed Jan 12 07:18:37 2022 +0000 upstream: Use egrep when searching for an anchored string. OpenBSD-Regress-ID: dd114a2ac27ac4b06f9e4a586d3f6320c54aeeb4 commit 6bf2efa2679da1e8e60731f41677b2081dedae2c Author: Darren Tucker Date: Wed Jan 12 18:25:06 2022 +1100 Add "rev" command replacement if needed. commit 72bcd7993dadaf967bb3d8564ee31cbf38132b5d Author: dtucker@openbsd.org Date: Wed Jan 12 03:30:32 2022 +0000 upstream: Don't log NULL hostname in restricted agent code, printf("%s", NULL) is not safe on all platforms. with & ok djm OpenBSD-Commit-ID: faf10cdae4adde00cdd668cd1f6e05d0a0e32a02 commit acabefe3f8fb58c867c99fed9bbf84dfa1771727 Author: djm@openbsd.org Date: Tue Jan 11 22:33:16 2022 +0000 upstream: remove hardcoded domain and use window.location.host, so this can be run anywhere OpenBSD-Regress-ID: 2ac2ade3b6227d9c547351d3ccdfe671e62b7f92 commit 96da0946e44f34adc0397eb7caa6ec35a3e79891 Author: dtucker@openbsd.org Date: Tue Jan 11 02:56:19 2022 +0000 upstream: "void" functions should not return anything. From Tim Rice via -portable. OpenBSD-Commit-ID: ce6616304f4c9881b46413e616b226c306830e2a commit a882a09722c9f086c9edb65d0c4022fd965ec1ed Author: djm@openbsd.org Date: Tue Jan 11 01:26:47 2022 +0000 upstream: suppress "Connection to xxx closed" messages at LogLevel >= error bz3378; ok dtucker@ OpenBSD-Commit-ID: d5bf457d5d2eb927b81d0663f45248a31028265c commit 61a1a6af22e17fc94999a5d1294f27346e6c4668 Author: Damien Miller Date: Wed Jan 12 08:57:49 2022 +1100 OS X poll(2) is broken; use compat replacement 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 613a6545fc5a9542753b503cbe5906538a640b60 Author: Darren Tucker Date: Tue Jan 11 20:56:01 2022 +1100 libhardended_malloc.so moved into out dir. commit 61761340be5e11046556623f8f5412b236cefa95 Author: Tim Rice Date: Mon Jan 10 11:07:04 2022 -0800 Make USL compilers happy UX:acomp: ERROR: "sftp-server.c", line 567: void function cannot return value commit 3ef403f351e80a59b6f7e9d43cb82c181855483c Author: Darren Tucker Date: Mon Jan 10 21:07:38 2022 +1100 Add wrapper for "sort" to set LC_ALL=C. Found by djm, this should make sorts stable and reduce test flakiness. commit bd69e29f5716090181dbe0b8272eb7eab1a383bb Author: dtucker@openbsd.org Date: Sat Jan 8 07:55:26 2022 +0000 upstream: Remove errant "set -x" left over from debugging. OpenBSD-Regress-ID: cd989268e034264cec5df97be7581549032c87dc commit 1a7c88e26fd673813dc5f61c4ac278564845e004 Author: dtucker@openbsd.org Date: Sat Jan 8 07:01:13 2022 +0000 upstream: Enable all supported hostkey algorithms (but no others). Allows hostbased test to pass when built without OpenSSL. OpenBSD-Regress-ID: 5ddd677a68b672517e1e78460dc6ca2ccc0a9562 commit 12b457c2a42ff271e7967d9bedd068cebb048db9 Author: djm@openbsd.org Date: Sat Jan 8 07:37:32 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 OpenBSD-Commit-ID: fc610ce00ca0cdc2ecdabbd49ce7cb82033f905f commit 63670d4e9030bcee490d5a9cce561373ac5b3b23 Author: djm@openbsd.org Date: Sat Jan 8 07:36:11 2022 +0000 upstream: fix some corner-case bugs in scp sftp-mode handling of ~-prefixed paths; spotted by jsg; feedback jsg & deraadt, ok jsg & markus OpenBSD-Commit-ID: d1697dbaaa9f0f5649d69be897eab25c7d37c222 commit e14940bbec57fc7d3ce0644dbefa35f5a8ec97d0 Author: djm@openbsd.org Date: Sat Jan 8 07:34:57 2022 +0000 upstream: more idiomatic error messages; spotted by jsg & deraadt ok jsg & markus OpenBSD-Commit-ID: 43618c692f3951747b4151c477c7df22afe2bcc8 commit 9acddcd5918c623f7ebf454520ffe946a8f15e90 Author: djm@openbsd.org Date: Sat Jan 8 07:33:54 2022 +0000 upstream: add a variant of send_status() that allows overriding the default, generic error message. feedback/ok markus & jsg OpenBSD-Commit-ID: 81f251e975d759994131b717ee7c0b439659c40f commit 961411337719d4cd78f1ab33e4ac549f3fa22f50 Author: djm@openbsd.org Date: Sat Jan 8 07:32:45 2022 +0000 upstream: refactor tilde_expand_filename() and make it handle ~user paths with no trailing slash; feedback/ok markus and jsg OpenBSD-Commit-ID: a2ab365598a902f0f14ba6a4f8fb2d07a9b5d51d commit dc38236ab6827dec575064cac65c8e7035768773 Author: dtucker@openbsd.org Date: Thu Jan 6 22:14:25 2022 +0000 upstream: Don't explicitly set HostbasedAuthentication in 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 e12d912ddf1c873cb72e5de9a197afbe0b6622d2 Author: dtucker@openbsd.org Date: Thu Jan 6 21:46:56 2022 +0000 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 a48533a8da6a0f4f05ecd055dc8048047e53569e Author: Damien Miller Date: Fri Jan 7 09:24:26 2022 +1100 depend commit d9dbb5d9a0326e252d3c7bc13beb9c2434f59409 Author: djm@openbsd.org Date: Thu Jan 6 22:06:51 2022 +0000 upstream: allow hostbased auth to select RSA keys when only RSA/SHA2 are configured (this is the default case); ok markus@ OpenBSD-Commit-ID: 411c18c7bde40c60cc6dfb7017968577b4d4a827 commit fdb1d58d0d3888b042e5a500f6ce524486aaf782 Author: djm@openbsd.org Date: Thu Jan 6 22:05:42 2022 +0000 upstream: add a helper function to match a key type to a list of signature algorithms. RSA keys can make signatures with multiple algorithms, so some special handling is required. ok markus@ OpenBSD-Commit-ID: 03b41b2bda06fa4cd9c84cef6095033b9e49b6ff commit 11e8c4309a5086a45fbbbc87d0af5323c6152914 Author: djm@openbsd.org Date: Thu Jan 6 22:04:20 2022 +0000 upstream: log some details on hostkeys that ssh loads for hostbased authn ok markus@ OpenBSD-Commit-ID: da17061fa1f0e58cb31b88478a40643e18233e38 commit c6706f661739514a34125aa3136532a958929510 Author: djm@openbsd.org Date: Thu Jan 6 22:03:59 2022 +0000 upstream: log signature algorithm during verification by monitor; ok markus OpenBSD-Commit-ID: 02b92bb42c4d4bf05a051702a56eb915151d9ecc commit 8832402bd500d1661ccc80a476fd563335ef6cdc Author: djm@openbsd.org Date: Thu Jan 6 22:02:52 2022 +0000 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 commit c2d9ced1da0276961d86690b3bd7ebdaca7fdbf7 Author: djm@openbsd.org Date: Thu Jan 6 22:01:14 2022 +0000 upstream: include rejected signature algorithm in error message and not the (useless) key type; ok markus OpenBSD-Commit-ID: 4180b5ec7ab347b43f84e00b1972515296dab023 commit 7aa7b096cf2bafe2777085abdeed5ce00581f641 Author: djm@openbsd.org Date: Thu Jan 6 22:00:18 2022 +0000 upstream: make ssh-keysign use the requested signature algorithm and not the default for the keytype. Part of unbreaking hostbased auth for RSA/SHA2 keys. ok markus@ OpenBSD-Commit-ID: b5639a14462948970da3a8020dc06f9a80ecccdc commit 291721bc7c840d113a49518f3fca70e86248b8e8 Author: djm@openbsd.org Date: Thu Jan 6 21:57:28 2022 +0000 upstream: stricter UpdateHostkey signature verification logic on the client- side. Require RSA/SHA2 signatures for RSA hostkeys except when RSA/SHA1 was explicitly negotiated during initial KEX; bz3375 ok markus@ OpenBSD-Commit-ID: 46e75e8dfa2c813781805b842580dcfbd888cf29 commit 0fa33683223c76289470a954404047bc762be84c Author: djm@openbsd.org Date: Thu Jan 6 21:55:23 2022 +0000 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 Mostly by Dmitry Belyavskiy with some tweaks by me. ok markus@ OpenBSD-Commit-ID: c17ba0c3236340d2c6a248158ebed042ac6a8029 commit 17877bc81db3846e6e7d4cfb124d966bb9c9296b Author: djm@openbsd.org Date: Thu Jan 6 21:48:38 2022 +0000 upstream: convert ssh, sshd mainloops from select() to poll(); feedback & ok deraadt@ and markus@ has been in snaps for a few months OpenBSD-Commit-ID: a77e16a667d5b194dcdb3b76308b8bba7fa7239c commit 5c79952dfe1aa36105c93b3f383ce9be04dee384 Author: djm@openbsd.org Date: Thu Jan 6 21:46:23 2022 +0000 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 commit 24c5187edfef4651a625b7d5d692c8c7e794f71f Author: djm@openbsd.org Date: Wed Jan 5 21:54:37 2022 +0000 upstream: add a comment so I don't make this mistake again OpenBSD-Commit-ID: 69c7f2362f9de913bb29b6318580c5a1b52c921e commit 7369900441929058263a17f56aa67e05ff7ec628 Author: djm@openbsd.org Date: Wed Jan 5 21:50:00 2022 +0000 upstream: fix cut-and-pasto in error message OpenBSD-Commit-ID: 4cc5c619e4b456cd2e9bb760d17e3a9c84659198 commit 294c11b1c7d56d3fb61e329603a782315ed70c62 Author: djm@openbsd.org Date: Wed Jan 5 08:25:05 2022 +0000 upstream: select all RSA hostkey algorithms for UpdateHostkeys tests, not just RSA-SHA1 OpenBSD-Regress-ID: b40e62b65863f2702a0c10aca583b2fe76772bd8 commit 2ea1108c30e3edb6f872dfc1e6da10b041ddf2c0 Author: djm@openbsd.org Date: Wed Jan 5 04:56:15 2022 +0000 upstream: regress test both sshsig message hash algorithms, possible now because the algorithm is controllable via the CLI OpenBSD-Regress-ID: 0196fa87acc3544b2b4fd98de844a571cb09a39f commit 2327c306b5d4a2b7e71178e5a4d139af9902c2b0 Author: djm@openbsd.org Date: Wed Jan 5 04:50:11 2022 +0000 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 commit 56e941d0a00d6d8bae88317717d5e1b7395c9529 Author: djm@openbsd.org Date: Wed Jan 5 04:27:54 2022 +0000 upstream: add missing -O option to usage() for ssh-keygen -Y sign; from Linus Nordberg OpenBSD-Commit-ID: 4e78feb4aa830727ab76bb2e3d940440ae1d7af0 commit 141a14ec9b0924709c98df2dd8013bde5d8d12c7 Author: djm@openbsd.org Date: Wed Jan 5 04:27:01 2022 +0000 upstream: move sig_process_opts() to before sig_sign(); no functional code change OpenBSD-Commit-ID: da02d61f5464f72b4e8b299f83e93c3b657932f9 commit 37a14249ec993599a9051731e4fb0ac5e976aec1 Author: djm@openbsd.org Date: Wed Jan 5 04:10:39 2022 +0000 upstream: regression test for find-principals NULL deref; from Fabian Stelzer OpenBSD-Regress-ID: f845a8632a5a7d5ae26978004c93e796270fd3e5 commit eb1f042142fdaba93f6c9560cf6c91ae25f6884a Author: djm@openbsd.org Date: Wed Jan 5 04:02:42 2022 +0000 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 commit 8f3b18030579f395eca2181da31a5f945af12a59 Author: dtucker@openbsd.org Date: Tue Jan 4 08:38:53 2022 +0000 upstream: Log command invocation while debugging. This will aid in manually reproducing failing commands. OpenBSD-Regress-ID: b4aba8d5ac5675ceebeeeefa3261ce344e67333a commit bbf285164df535f0d38c36237f007551bbdae27f Author: Darren Tucker Date: Sun Dec 26 10:31:15 2021 +1100 Always save config.h as build artifact. Should allow better comparison between failing and succeeding test platforms. commit 03bd4ed0db699687c5cd83405d26f81d2dc28d22 Author: Darren Tucker Date: Sat Dec 25 16:42:51 2021 +1100 Add OpenBSD 7.0 target. Retire 6.8. commit c45a752f0de611afd87755c2887c8a24816d08ee Author: jsg@openbsd.org Date: Sat Jan 1 05:55:06 2022 +0000 upstream: spelling OpenBSD-Commit-ID: c63e43087a64d0727af13409c708938e05147b62 commit c672f83a89a756564db0d3af9934ba0e1cf8fa3e Author: djm@openbsd.org Date: Tue Jan 4 07:20:33 2022 +0000 upstream: unbreak test: was picking up system ssh-add instead of the one supposedly being tested. Spotted by dtucker and using his VM zoo (which includes some systems old enough to lack ed25519 key support) OpenBSD-Regress-ID: 7976eb3df11cc2ca3af91030a6a8c0cef1590bb5 commit a23698c3082ffe661abed14b020eac9b0c25eb9f Author: djm@openbsd.org Date: Sat Jan 1 04:18:06 2022 +0000 upstream: fix memleak in process_extension(); oss-fuzz issue #42719 OpenBSD-Commit-ID: d8d49f840162fb7b8949e3a5adb8107444b6de1e commit cb885178f36b83d0f14cfe9f345d2068103feed0 Author: jsg@openbsd.org Date: Sat Jan 1 01:55:30 2022 +0000 upstream: spelling ok dtucker@ OpenBSD-Commit-ID: bfc7ba74c22c928de2e257328b3f1274a3dfdf19 commit 6b977f8080a32c5b3cbb9edb634b9d5789fb79be Author: djm@openbsd.org Date: Sun Dec 26 23:34:41 2021 +0000 upstream: split method list search functionality from authmethod_lookup() into a separate authmethod_byname(), for cases where we don't need to check whether a method is enabled, etc. use this to fix the "none" authentication method regression reported by Nam Nguyen via bugs@ ok deraadt@ OpenBSD-Commit-ID: 8cd188dc3a83aa8abe5b7693e762975cd8ea8a17 commit 0074aa2c8d605ee7587279a22cdad4270b4ddd07 Author: jmc@openbsd.org Date: Wed Dec 22 06:56:41 2021 +0000 upstream: sort -H and -h in SYNOPSIS/usage(); tweak the -H text; ok djm OpenBSD-Commit-ID: 90721643e41e9e09deb5b776aaa0443456ab0965 commit 1c9853a68b2319f2e5f929179735e8fbb9988a67 Author: Darren Tucker 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 Date: Wed Dec 22 09:02:50 2021 +1100 remove sys/param.h in -portable, after upstream commit 7a7c69d8b4022b1e5c0afb169c416af8ce70f3e8 Author: Damien Miller Date: Mon Dec 20 13:05:20 2021 +1100 add agent-restrict.sh file, missed in last commit commit f539136ca51a4976644db5d0be8158cc1914c72a Author: djm@openbsd.org Date: Sun Dec 19 22:20:12 2021 +0000 upstream: regression test for destination restrictions in ssh-agent OpenBSD-Regress-ID: 3c799d91e736b1753b4a42d80c42fc40de5ad33d commit 6e4980eb8ef94c04874a79dd380c3f568e8416d6 Author: anton@openbsd.org Date: Sat Dec 18 06:53:59 2021 +0000 upstream: Make use of ntests variable, pointed out by clang 13. OpenBSD-Regress-ID: 4241a3d21bdfa1630ed429b6d4fee51038d1be72 commit 3eead8158393b697f663ec4301e3c7b6f24580b1 Author: deraadt@openbsd.org Date: Tue Dec 14 21:25:27 2021 +0000 upstream: sys/param.h cleanup, mostly using MINIMUM() and ok dtucker OpenBSD-Regress-ID: 172a4c45d3bcf92fa6cdf6c4b9db3f1b3abe4db0 commit 266678e19eb0e86fdf865b431b6e172e7a95bf48 Author: djm@openbsd.org Date: Sun Dec 19 22:15:42 2021 +0000 upstream: document host-bound publickey authentication OpenBSD-Commit-ID: ea6ed91779a81f06d961e30ecc49316b3d71961b commit 3d00024b3b156aa9bbd05d105f1deb9cb088f6f7 Author: djm@openbsd.org Date: Sun Dec 19 22:15:21 2021 +0000 upstream: document agent protocol extensions OpenBSD-Commit-ID: 09e8bb391bbaf24c409b75a4af44e0cac65405a7 commit c385abf76511451bcba78568167b1cd9e90587d5 Author: djm@openbsd.org Date: Sun Dec 19 22:14:47 2021 +0000 upstream: PubkeyAuthentication=yes|no|unbound|host-bound 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. feedback / ok markus@ OpenBSD-Commit-ID: ee52580db95c355cf6d563ba89974c210e603b1a commit 34b1e9cc7654f41cd4c5b1cc290b999dcf6579bb Author: djm@openbsd.org Date: Sun Dec 19 22:14:12 2021 +0000 upstream: document destination-constrained keys feedback / ok markus@ OpenBSD-Commit-ID: cd8c526c77268f6d91c06adbee66b014d22d672e commit a6d7677c4abcfba268053e5867f2acabe3aa371b Author: djm@openbsd.org Date: Sun Dec 19 22:13:55 2021 +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@ OpenBSD-Commit-ID: d69877c9a3bd8d1189a5dbdeceefa432044dae02 commit baaff0ff4357cc5a079621ba6e2d7e247b765061 Author: djm@openbsd.org Date: Sun Dec 19 22:13:33 2021 +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@ OpenBSD-Commit-ID: 81c064255634c1109477dc65c3e983581d336df8 commit 3e16365a79cdeb2d758cf1da6051b1c5266ceed7 Author: djm@openbsd.org Date: Sun Dec 19 22:13:12 2021 +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"). ok markus@ OpenBSD-Commit-ID: 4cdb2ca5017ec1ed7a9d33bda95c1d6a97b583b0 commit 94ae0c6f0e35903b695e033bf4beacea1d376bb1 Author: djm@openbsd.org Date: Sun Dec 19 22:12:54 2021 +0000 upstream: client side of host-bound pubkey authentication Add kex->flags member to enable the publickey-hostbound-v00@openssh.com authentication method. Use the new hostbound method in client if the kex->flags flag was set, and include the inital KEX hostkey in the userauth request. Note: nothing in kex.c actually sets the new flag yet ok markus@ OpenBSD-Commit-ID: 5a6fce8c6c8a77a80ee1526dc467d91036a5910d commit 288fd0218dbfdcb05d9fbd1885904bed9b6d42e6 Author: djm@openbsd.org Date: Sun Dec 19 22:12:30 2021 +0000 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. feedback / ok markus@ OpenBSD-Commit-ID: 7ea01bb7238a560c1bfb426fda0c10a8aac07862 commit dbb339f015c33d63484261d140c84ad875a9e548 Author: djm@openbsd.org Date: Sun Dec 19 22:12:07 2021 +0000 upstream: prepare for multiple names for authmethods allow authentication methods to have one additional name beyond their primary name. allow lookup by this synonym Use primary name for authentication decisions, e.g. for PermitRootLogin=publickey Pass actual invoked name to the authmethods, so they can tell whether they were requested via the their primary name or synonym. ok markus@ OpenBSD-Commit-ID: 9e613fcb44b8168823195602ed3d09ffd7994559 commit 39f00dcf44915f20684160f0a88d3ef8a3278351 Author: djm@openbsd.org Date: Sun Dec 19 22:11:39 2021 +0000 upstream: ssh-agent side of destination constraints 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@ OpenBSD-Commit-ID: 84a7fb81106c2d609a6ac17469436df16d196319 commit ce943912df812c573a33d00bf9e5435b7fcca3f7 Author: djm@openbsd.org Date: Sun Dec 19 22:11:06 2021 +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. feedback Jann Horn & markus@ ok markus@ OpenBSD-Commit-ID: 6b52cd2b637f3d29ef543f0ce532a2bce6d86af5 commit 5e950d765727ee0b20fc3d2cbb0c790b21ac2425 Author: djm@openbsd.org Date: Sun Dec 19 22:10:24 2021 +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. feedback Jann Horn & markus@ ok markus@ OpenBSD-Commit-ID: ef47fa9ec0e3c2a82e30d37ef616e245df73163e commit 4c1e3ce85e183a9d0c955c88589fed18e4d6a058 Author: djm@openbsd.org Date: Sun Dec 19 22:09:23 2021 +0000 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 commit e9497ecf73f3c16667288bce48d4e3d7e746fea1 Author: djm@openbsd.org Date: Sun Dec 19 22:08:48 2021 +0000 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 commit b42c61d6840d16ef392ed0f365e8c000734669aa Author: djm@openbsd.org Date: Sun Dec 19 22:08:06 2021 +0000 upstream: Record session ID, host key and sig at intital KEX These will be used later for agent session ID / hostkey binding ok markus@ OpenBSD-Commit-ID: a9af29e33772b18e3e867c6fa8ab35e1694a81fe commit 26ca33d186473d58a32d812e19273ce078b6ffff Author: djm@openbsd.org Date: Tue Dec 7 22:06:45 2021 +0000 upstream: better error message for FIDO keys when we can't match them to a token OpenBSD-Commit-ID: 58255c2a1980088f4ed144db67d879ada2607650 commit adb0ea006d7668190f0c42aafe3a2864d352e34a Author: Darren Tucker Date: Wed Dec 15 10:50:33 2021 +1100 Correct value for IPTOS_DSCP_LE. 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 3dafd3fe220bd9046f11fcf5191a79ec8800819f Author: Darren Tucker Date: Fri Dec 10 11:57:30 2021 +1100 Increase timeout for test step. commit 5aefb05cd5b843e975b191d6ebb7ddf8de35c112 Author: Darren Tucker Date: Fri Dec 10 10:27:27 2021 +1100 Update the list of tests that don't work on Minix. While there, remove CC (configure will now find clang) and make the test list easier to update via cut and paste. commit 1c09bb1b2e207d091cec299c49416c23d24a1b31 Author: Darren Tucker Date: Fri Dec 10 10:12:57 2021 +1100 Add minix host tuple. Define SETEUID_BREAKS_SETUID for it which should make privsep work. commit a2188579032cf080213a78255373263466cb90cc Author: jsg@openbsd.org Date: Sun Dec 5 12:28:27 2021 +0000 upstream: fix unintended sizeof pointer in debug path ok markus@ OpenBSD-Commit-ID: b9c0481ffc0cd801e0840e342e6a282a85aac93c commit da40355234068c82f1a36196f2d18dd2d81aaafd Author: 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: 64abef6cfc3e53088225f6b8a1dcd86d52dc8353 commit e9c71498a083a8b502aa831ea931ce294228eda0 Author: djm@openbsd.org Date: Thu Dec 2 23:45:36 2021 +0000 upstream: hash full host:port when asked to hash output, fixes hashes for non- default ports. bz3367 ok dtucker@ OpenBSD-Commit-ID: 096021cc847da7318ac408742f2d0813ebe9aa73 commit b5601202145a03106012c22cb8980bcac2949f0b Author: djm@openbsd.org Date: Thu Dec 2 23:23:13 2021 +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 OpenBSD-Commit-ID: ffac7f3215842397800e1ae2e20229671a55a63d commit ca709e27c41c90f4565b17282c48dca7756e083c Author: djm@openbsd.org Date: Thu Dec 2 22:40:05 2021 +0000 upstream: move check_sk_options() up so we can use it earlier OpenBSD-Commit-ID: 67fe98ba1c846d22035279782c4664c1865763b4 commit b711bc01a7ec76bb6a285730990cbce9b8ca5773 Author: 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 Date: Thu Dec 2 02:44:44 2021 +0000 upstream: don't put the tty into raw mode when SessionType=none, avoids ^c being unable to kill such a session. bz3360; ok dtucker@ OpenBSD-Commit-ID: 83960c433052303b643b4c380ae2f799ac896f65 commit e6e7d2654a13ba10141da7b42ea683ea4eeb1f38 Author: Damien Miller 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 Date: Mon Nov 29 14:03:19 2021 +1100 Fix typo in Neils' name. commit 158bf854e2a22cf09064305f4a4e442670562685 Author: Damien Miller Date: Mon Nov 29 12:30:22 2021 +1100 sync bcrypt-related files with OpenBSD The main change is that Niels Provos kindly agreed to rescind the BSD license advertising clause, shifting them to the 3-term BSD license. This was the last thing in OpenSSH that used the advertising clause. commit e8976d92a42883ff6b8991438f07df60c2c0d82d Author: Damien Miller Date: Mon Nov 29 12:29:29 2021 +1100 depend commit 8249afeec013e557fe7491a72ca3285de03e25b1 Author: djm@openbsd.org Date: Sun Nov 28 07:21:26 2021 +0000 upstream: sshsig: return "key not found" when searching empty files rather than "internal error" OpenBSD-Commit-ID: e2ccae554c78d7a7cd33fc5d217f35be7e2507ed commit 9e3227d4dbb5ad9c9091b4c14982cab4bba87b4d Author: djm@openbsd.org Date: Sun Nov 28 07:15:10 2021 +0000 upstream: ssh-keygen -Y match-principals doesn't accept any -O options at present, so don't say otherwise in SYNOPSIS; spotted jmc@ OpenBSD-Commit-ID: 9cc43a18f4091010741930b48b3db2f2e4f1d35c commit 56db1f4a4cf5039fc3b42e84c4b16291fdff32b1 Author: djm@openbsd.org Date: Sun Nov 28 07:14:29 2021 +0000 upstream: fix indenting in last commit OpenBSD-Commit-ID: 8b9ba989815d0dec1fdf5427a4a4b58eb9cac4d2 commit 50bea24a9a9bdebad327c76e700def3261f5694e Author: djm@openbsd.org Date: Sun Nov 28 07:10:18 2021 +0000 upstream: missing initialisation for oerrno OpenBSD-Commit-ID: 05d646bba238080259bec821c831a6f0b48d2a95 commit 5a0f4619041d09cd29f3a08da41db5040372bdd1 Author: Darren Tucker Date: Sun Nov 28 15:31:37 2021 +1100 Correct ifdef to activate poll() only if needed. commit d4035c81a71237f690edd7eda32bef7d63fd9528 Author: djm@openbsd.org Date: Sat Nov 27 07:23:35 2021 +0000 upstream: whitespac e OpenBSD-Regress-ID: b9511d41568056bda489e13524390167889908f8 commit a443491e6782ef0f5a8bb87a5536c8ee4ff233a1 Author: djm@openbsd.org Date: Sat Nov 27 07:20:58 2021 +0000 upstream: regression test for match-principals. Mostly by Fabian Stelzer OpenBSD-Regress-ID: ced0bec89af90935103438986bbbc4ad1df9cfa7 commit 78230b3ec8cbabc1e7de68732dc5cbd4837c6675 Author: djm@openbsd.org Date: Sat Nov 27 07:14:46 2021 +0000 upstream: Add ssh-keygen -Y match-principals operation to perform matching of principals names against an allowed signers file. 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 15db86611baaafb24c40632784dabf82e3ddb1a7 Author: djm@openbsd.org Date: Thu Nov 25 23:02:24 2021 +0000 upstream: debug("func: ...") -> debug_f("...") OpenBSD-Commit-ID: d58494dc05c985326a895adfbe16fbd5bcc54347 commit b7ffbb17e37f59249c31f1ff59d6c5d80888f689 Author: Darren Tucker Date: Fri Nov 19 18:53:46 2021 +1100 Allow for fd = -1 in compat ppoll overflow check. Fixes tests on at least FreeBSD 6, possibly others. commit 04b172da5b96a51b0d55c905b423ababff9f4e0b Author: Darren Tucker Date: Fri Nov 19 16:01:51 2021 +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. commit a823f39986e7b879f26412e64c15630e1cfa0dc5 Author: djm@openbsd.org Date: Thu Nov 18 03:53:48 2021 +0000 upstream: regression test for ssh-keygen -Y find-principals fix; from Fabian Stelzer ok djm markus OpenBSD-Regress-ID: 34fe4088854c1a2eb4c0c51cc4676ba24096bac4 commit 199c4df66c0e39dd5c3333b162af274678c0501d Author: djm@openbsd.org Date: Thu Nov 18 21:32:11 2021 +0000 upstream: less confusing debug message; bz#3365 OpenBSD-Commit-ID: 836268d3642c2cdc84d39b98d65837f5241e4a50 commit 97f9b6e61316c97a32dad94b7a37daa9b5f6b836 Author: djm@openbsd.org Date: Thu Nov 18 21:11:01 2021 +0000 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 OpenBSD-Commit-ID: 054d4dc1d6a99a2e6f8eebc48207b534057c154d commit c74aa0eb73bd1edf79947d92d9c618fc3424c4a6 Author: djm@openbsd.org Date: Thu Nov 18 03:50:41 2021 +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. patch from Fabian Stelzer; feedback/ok djm markus OpenBSD-Commit-ID: b108ed0a76b813226baf683ab468dc1cc79e0905 commit d902d728dfd81622454260e23bc09d5e5a9a795e Author: Darren Tucker Date: Thu Nov 18 23:44:07 2021 +1100 Correct calculation of tv_nsec in poll(). commit 21dd5a9a3fb35e8299a1fbcf8d506f1f6b752b85 Author: Darren Tucker Date: Thu Nov 18 23:11:37 2021 +1100 Add compat implementation of ppoll using pselect. commit b544ce1ad4afb7ee2b09f714aa63efffc73fa93a Author: Darren Tucker Date: Thu Nov 18 23:05:34 2021 +1100 Put poll.h inside ifdef HAVE_POLL_H. commit 875408270c5a7dd69ed5449e5d85bd7120c88f70 Author: djm@openbsd.org Date: Thu Nov 18 03:31:44 2021 +0000 upstream: check for POLLHUP wherever we check for POLLIN OpenBSD-Commit-ID: 6aa6f3ec6b17c3bd9bfec672a917f003a76d93e5 commit 36b5e37030d35bbaa18ba56825b1af55971d18a0 Author: djm@openbsd.org Date: Thu Nov 18 03:07:59 2021 +0000 upstream: fd leak in sshd listen loop error path; from Gleb Smirnoff OpenBSD-Commit-ID: a7a2be27a690a74bf2381bc16cea38e265657412 commit b99498d0c93f1edd04857b318308a66b28316bd8 Author: djm@openbsd.org Date: Thu Nov 18 03:07:20 2021 +0000 upstream: check for POLLHUP as well as POLLIN in sshd listen loop; ok deraadt millert OpenBSD-Commit-ID: a4f1244c5a9c2b08dac4f3b1dc22e9d1dc60c587 commit 1f3055d788e8cf80851eb1728b535d57eb0dba6a Author: djm@openbsd.org Date: Thu Nov 18 03:06:03 2021 +0000 upstream: check for POLLHUP as well as POLLIN, handle transient IO errors as well as half-close on the output side; ok deraadt millert OpenBSD-Commit-ID: de5c5b9939a37476d256328cbb96305bdecf511e commit 9778a15fa6dbdac6a95bf15865c2688b4bd6944e Author: Damien Miller Date: Thu Nov 18 10:16:55 2021 +1100 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 fcd8d895bbb849c64f0aed934e3303d37f696f5d Author: Damien Miller Date: Thu Nov 18 10:16:44 2021 +1100 update depends commit 76292787a1e93e668f10e36b4bf59ce0ae28e156 Author: Damien Miller Date: Thu Nov 18 09:26:20 2021 +1100 compat for timespecsub() and friends commit fd7e7de4ddb4399c7e929b44f2bbfc118eddfcf8 Author: djm@openbsd.org Date: Wed Nov 17 21:06:39 2021 +0000 upstream: set num_listen_socks to 0 on close-all instead of -1, which interferes with the new poll()-based listen loop; spotted and debugged by anton@+deraadt@ OpenBSD-Commit-ID: f7ab8ab124f615a2e0c45fee14c38d2f2abbabbd commit fd9343579afac30a971f06643a669733d9acb407 Author: deraadt@openbsd.org Date: Sun Nov 14 18:47:43 2021 +0000 upstream: use ppoll() instead of pselect() with djm OpenBSD-Commit-ID: 980f87c9564d5d2ad55722b7a6f44f21284cd215 commit 092d29b232ef1a19609a5316ed7e4d896bb2e696 Author: deraadt@openbsd.org Date: Sun Nov 14 06:15:36 2021 +0000 upstream: match .events with .fd better OpenBSD-Commit-ID: 77eef212ca0add905949532af390164489c5984b commit 8d642c9a90fa4ed5a3effd785fb3591e14de00cd Author: deraadt@openbsd.org Date: Sun Nov 14 03:25:10 2021 +0000 upstream: convert select() to poll() ok djm OpenBSD-Commit-ID: b53e4940ff10dd24f8d16e8db8ef1970015d7ead commit 6582a31c388968f4073af2bd8621880735c3d42b Author: deraadt@openbsd.org Date: Sat Nov 13 21:14:13 2021 +0000 upstream: replace select() with ppoll(), including converting timeval's to timespec's to make things easier. back and forth and ok; djm OpenBSD-Commit-ID: 89d3b23c60875da919e7820f9de6213286ffbec9 commit 7c025c005550c86a40200a2bcdd355d09413d61a Author: deraadt@openbsd.org Date: Sat Nov 13 17:26:13 2021 +0000 upstream: It really looks like pledge "stdio dns" is possible earlier. Discussed with mestre OpenBSD-Commit-ID: 610873de63a593e0ac7bbbcb7a0f2894d36f4c01 commit 06acb04c20ee483fe4757bd12aec870cc4bb1076 Author: deraadt@openbsd.org Date: Fri Nov 12 05:23:49 2021 +0000 upstream: aggressively pre-fill the pollfd array with fd=-1 OpenBSD-Commit-ID: c2a525de8f83c1a04405bd79122c424140552a5b commit 7eec76793dec06e8f06b6cf71f9473141c69d109 Author: 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 OpenBSD-Commit-ID: 548e05bfc31b2af02319eb3d051286d4128dec96 commit e665ed2d0c24fe11d5470ce72fa1e187377d3fc4 Author: Darren Tucker Date: Fri Nov 12 22:55:27 2021 +1100 Switch from LibreSSL 3.4.0 to 3.4.1. 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 21b6b5a06c8c53c548d25e6074c5240e88e2ef34 Author: djm@openbsd.org Date: Wed Nov 10 06:29:25 2021 +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). ok markus@ OpenBSD-Commit-ID: 22b77e27a04e497a10e22f138107579652854210 commit 239da797cbf07a640d7b1ea02d3f99ace3ef792d Author: djm@openbsd.org Date: Wed Nov 10 06:25:08 2021 +0000 upstream: fix ssh-keysign for KEX algorithms that use SHA384/512 exchange hashes; feedback/ok markus@ OpenBSD-Commit-ID: 09a8fda1c081f5de1e3128df64f28b7bdadee239 commit 6997a592ecb1013df0c6d7f8df3e6517827aef11 Author: djm@openbsd.org Date: Mon Nov 8 21:32:49 2021 +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 ok deraadt@ OpenBSD-Commit-ID: 1ddefa3c3a78b69ce13d1b8f67bc9f2cefd23ad6 commit 10b899a15c88eb40eb5f73cd0fa84ef0966f79c9 Author: Darren Tucker Date: Wed Nov 10 12:34:25 2021 +1100 Don't trust closefrom() on Linux. 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 eb1f63195a9a38b519536a5b398d9939261ec081 Author: dtucker@openbsd.org Date: Sat Nov 6 10:13:39 2021 +0000 upstream: Plug a couple of minor mem leaks. From beldmit at gmail.com via github PR#283, ok markus@ OpenBSD-Commit-ID: ec1fa7d305d46226861c3ca6fb9c9beb2ada2892 commit e4f501bf1d3b53f1cc23d9521fd7c5163307b760 Author: djm@openbsd.org Date: Fri Nov 5 03:10:58 2021 +0000 upstream: move cert_filter_principals() to earlier in the file for reuse; no code change OpenBSD-Commit-ID: 598fa9528b656b2f38bcc3cf5b6f3869a8c115cf commit 59c60f96fee321c7f38f00372826d37f289534af Author: deraadt@openbsd.org Date: Wed Nov 3 22:00:56 2021 +0000 upstream: Many downstreams expect ssh to compile as non-C99... OpenBSD-Commit-ID: e6aa3e08bda68e5fb838fc8a49b1d2dfc38ee783 commit 7a78fe63b0b28ef7231913dfefe9d08f9bc41c61 Author: Darren Tucker Date: Sat Nov 6 21:07:03 2021 +1100 Skip getline() on HP-UX 10.x. 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 343ae252ebb35c6ecae26b447bf1551a7666720e Author: Damien Miller Date: Wed Nov 3 12:08:21 2021 +1100 basic SECURITY.md (refers people to the website) commit ed45a0168638319e0a710633f6085b96b9cec656 Author: djm@openbsd.org Date: Tue Nov 2 22:57:27 2021 +0000 upstream: crank SSH_SK_VERSION_MAJOR to match recent change in usr/bin/ssh OpenBSD-Regress-ID: 113d181c7e3305e138db9b688cdb8b0a0019e552 commit f3c34df860c4c1ebddacb973954e58167d9dbade Author: djm@openbsd.org Date: Tue Nov 2 22:56:40 2021 +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@ NB. cranks SSH_SK_VERSION_MAJOR OpenBSD-Commit-ID: e318a8c258d9833a0b7eb0236cdb68b5143b2f27 commit 0328a081f38c09d2d4d650e94461a47fb5eef536 Author: djm@openbsd.org Date: Fri Oct 29 03:03:06 2021 +0000 upstream: sshsig: add tests for signing key validity and find-principals - 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 by Fabian Stelzer OpenBSD-Regress-ID: 9704b2c6df5b8ccfbdf2c06c5431f5f8cad280c9 commit ccd358e1e25e25c13f0825996283cbf7a1647a3b Author: djm@openbsd.org Date: Fri Oct 29 02:48:19 2021 +0000 upstream: avoid signedness warning; spotted in -portable OpenBSD-Regress-ID: 4cacc126086487c0ea7f3d86b42dec458cf0d0c6 commit 2741f52beb11490d7033a25e56ed0496f0c78006 Author: djm@openbsd.org Date: Fri Oct 29 03:20:46 2021 +0000 upstream: ssh-keygen: make verify-time argument parsing optional From Fabian Stelzer OpenBSD-Commit-ID: 1ff35e4c366a45a073663df90381be6a8ef4d370 commit a1217d363b88b32cfe54c4f02c6c1cf4bdefdd23 Author: Damien Miller Date: Fri Oct 29 13:48:34 2021 +1100 unbreak fuzz harness for recent changes commit 68e522ed8183587c9367fa3842c5b75f64f3d12b Author: Darren Tucker Date: Fri Oct 29 13:32:24 2021 +1100 Use -Wbitwise-instead-of-logical if supported. commit be28b23012aa3fa323be7ec84863cf238927c078 Author: Damien Miller Date: Thu Oct 28 16:24:53 2021 +1100 use -Wmisleading-indentation cflag if available ok dtucker@ commit 2e6f5f24dd2f9217f4ab8b737ed428d5d5278f91 Author: Damien Miller Date: Thu Oct 28 16:24:44 2021 +1100 depend commit a5ab4882348d26addc9830a44e053238dfa2cb58 Author: Damien Miller Date: Thu May 6 10:08:30 2021 +1000 remove built-in support for md5crypt() 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. feedback and ok dtucker@ commit c5de1fffa6328b8246b87da28fa9df05813f76a3 Author: djm@openbsd.org Date: Thu Oct 28 02:55:30 2021 +0000 upstream: increment SSH_SK_VERSION_MAJOR to match last change OpenBSD-Regress-ID: 17873814d1cbda97f49c8528d7b5ac9cadf6ddc0 commit 0001d04e55802d5bd9d6dece1081a99aa4ba2828 Author: djm@openbsd.org Date: Thu Oct 28 02:54:18 2021 +0000 upstream: When downloading resident keys from a FIDO token, pass 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). Avoids keys being clobbered if the user created multiple resident keys with the same application string but different user IDs. feedback Pedro Martelletto; ok markus NB. increments SSH_SK_VERSION_MAJOR OpenBSD-Commit-ID: dbd658b5950f583106d945641a634bc6562dd3a3 commit d4bed5445646e605c383a4374fa962e23bf9e3a3 Author: deraadt@openbsd.org Date: Sun Oct 24 21:24:17 2021 +0000 upstream: For open/openat, if the flags parameter does not contain 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-Commit-ID: 503d11633497115688c0c6952686524f01f53121 commit d575cf44895104e0fcb0629920fb645207218129 Author: Darren Tucker Date: Fri Oct 22 23:27:41 2021 +1100 kitchensink test target now needs krb5. commit 4ae39cada214e955bcfd3448ff28f0ed18886706 Author: Darren Tucker Date: Fri Oct 22 22:54:33 2021 +1100 Test both MIT KRB5 and Heimdal. commit 22b2681d88619e5247dc53c9f112058a7e248d48 Author: dtucker@openbsd.org Date: Fri Oct 22 10:51:57 2021 +0000 upstream: Plug mem addrinfo mem leaks. 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 27c8c343b610263f83ac2328735feeb881c6c92f Author: dtucker@openbsd.org Date: Fri Oct 22 09:22:04 2021 +0000 upstream: Remove unnecessary semicolons ... in case statements. From khaleesicodes via github PR#280. OpenBSD-Commit-ID: e1e89360b65775cff83e77ce040b342015caf4ed commit e7eb73b8d1fe1008d92433ea949491ce654bfaba Author: dtucker@openbsd.org Date: Fri Oct 22 09:19:34 2021 +0000 upstream: Fix typos in comments. From khaleesicodes via github PR#280. OpenBSD-Commit-ID: 26fdd83652c40f098bf7c685e8ebb9eb72cc45fc commit 052a9d8494175e24312daa6c132665e58c17fe6e Author: deraadt@openbsd.org Date: Fri Oct 15 14:46:46 2021 +0000 upstream: switch scp(1) back to sftp protocol. 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-Commit-ID: 9eaa35d95fd547b78b0a043b3f518e135f151f30 commit a07664646bf6d293f5bbd45a5de54f3c36bb85da Author: Darren Tucker Date: Fri Oct 22 14:00:05 2021 +1100 Source configs script so setup_ci can use settings commit 34df52c201c6b47e5a46b50c215e4d98a8bf6587 Author: Darren Tucker Date: Fri Oct 22 09:42:14 2021 +1100 Install libedit and pam based on config flags. commit 8c626cc563e8d21d844d06f9971a9ee01de6aa2a Author: Darren Tucker Date: Thu Oct 21 16:53:39 2021 +1100 Don't use 'here string", it's not POSIX. commit 086a4b5977472aefa3de918b88efad0faf83b2b1 Author: Darren Tucker Date: Thu Oct 21 15:33:27 2021 +1100 Remove -Werror from compiler package to install. commit 5a7a4687507d057f9b5e7497f3d3f82e64753c02 Author: Darren Tucker Date: Thu Oct 21 15:00:53 2021 +1100 Build with -Werror on most recent gcc and clang. commit 4d2cbdb525d673acf941d48a7044fcf03125611a Author: Darren Tucker Date: Fri Oct 15 12:59:06 2021 +1100 Include string.h and stdio.h for strerror. commit fff13aaa262b7b3ec83ed21e29674cbf331780a7 Author: Darren Tucker Date: Fri Oct 15 12:43:36 2021 +1100 Include error reason if trace disabling fails. commit d4b38144c02f3faa5271e5fb35df93507e06f1b4 Author: Darren Tucker Date: Tue Oct 12 22:55:51 2021 +1100 Add tcmalloc test target. commit 002d65b0a30063c6e49bf8a53e709d8d5a0d45c1 Author: dtucker@openbsd.org Date: Sat Oct 9 10:52:42 2021 +0000 upstream: Document that CASignatureAlgorithms, ExposeAuthInfo and PubkeyAuthOptions can be used in a Match block. Patch from eehakkin via github PR#277. OpenBSD-Commit-ID: c0a63f5f52e918645967ac022b28392da4b866aa commit 40bd3709dddaae3a1b6113748bec3faa6a607531 Author: Darren Tucker Date: Thu Oct 7 15:55:49 2021 +1100 Skip SK unit tests when built without security-key commit 482f73be10f10b93f818df19fcc8a912c0c371fc Author: Darren Tucker Date: Thu Oct 7 15:55:04 2021 +1100 Include relevant env vars on command line. Makes it easier to reproduce a build by cut/pasting the configure line. commit ef5916b8acd9b1d2f39fad4951dae03b00dbe390 Author: Darren Tucker Date: Thu Oct 7 14:28:02 2021 +1100 Only enable sk-* key types if ENABLE_SK is defined commit 52d4232b493a9858fe616e28a8bbcc89afa2ad4d Author: Darren Tucker Date: Wed Oct 6 18:14:37 2021 +1100 Disable security key on minix3. The test doesn't work so disable. commit 7cd062c3a29669b8d7dc2a97e6575f4dcb7d35a2 Author: Darren Tucker Date: Wed Oct 6 17:45:28 2021 +1100 Add USE_LIBC_SHA2 for (at least) NetBSD 9. commit 639c440f6c3c2a8216a5eb9455ef13bf4204089c Author: Darren Tucker Date: Wed Oct 6 17:09:31 2021 +1100 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. commit 8f4be526a338d06624f146fa26007bb9dd3a4f7b Author: Darren Tucker Date: Wed Oct 6 15:40:58 2021 +1100 Disable security key on NetBSD4 test. 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 Date: Wed Oct 6 15:07:01 2021 +1100 clean regress/misc/sk-dummy in cleandir target commit 57680a2ab43518c5ccbd8242c40482106cde6ac1 Author: dtucker@openbsd.org Date: Sat Oct 2 03:17:01 2021 +0000 upstream: Dynamically allocate encoded HashKnownHosts and free as 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: e254ae723f7e3dce352c7d5abc4b6d87faf61bf4 commit e3e62deb549fde215b777d95276c304f84bf00c6 Author: djm@openbsd.org Date: Wed Oct 6 03:35:13 2021 +0000 upstream: use libc SHA256 functions; make this work when compiled !WITH_OPENSSL OpenBSD-Regress-ID: fda0764c1097cd42f979ace29b07eb3481259890 commit 12937d867019469ebce83c2ff614cdc6688fc2d8 Author: dtucker@openbsd.org Date: Fri Oct 1 05:20:20 2021 +0000 upstream: Add test for ssh hashed known_hosts handling. OpenBSD-Regress-ID: bcef3b3cd5a1ad9899327b4b2183de2541aaf9cf commit 5a37cc118f464416d08cd0291a9b1611d8de9943 Author: Damien Miller Date: Wed Oct 6 13:16:21 2021 +1100 fix broken OPENSSL_HAS_ECC test spotted by dtucker commit 16a25414f303cd6790eb967aeb962040e32c9c7a Author: Damien Miller Date: Fri Oct 1 22:40:06 2021 +1000 make sk-dummy.so work without libcrypto installed commit dee22129bbc61e25b1003adfa2bc584c5406ef2d Author: Damien Miller Date: Fri Oct 1 16:35:49 2021 +1000 make OPENSSL_HAS_ECC checks more thorough ok dtucker commit 872595572b6c9a584ed754165e8b7c4c9e7e1d61 Author: Damien Miller Date: Fri Oct 1 16:35:05 2021 +1000 fix FIDO key support for !OPENSSL_HAS_ECC case ok dtucker commit 489741dc68366940d369ac670b210b4834a6c272 Author: Damien Miller Date: Fri Oct 1 14:51:37 2021 +1000 enable security key support for --without-openssl commit c978565c8589acfe4ea37ab5099d39c84158c713 Author: Damien Miller Date: Fri Oct 1 13:27:50 2021 +1000 need stdlib.h for free(3) commit 76a398edfb51951b2d65d522d7b02c72304db300 Author: dtucker@openbsd.org Date: Thu Sep 30 05:26:26 2021 +0000 upstream: Fix up whitespace left by previous change removing privsep. No other changes. OpenBSD-Regress-ID: 87adec225d8afaee4d6a91b2b71203f52bf14b15 commit ddcb53b7a7b29be65d57562302b2d5f41733e8dd Author: dtucker@openbsd.org Date: Thu Sep 30 05:20:08 2021 +0000 upstream: Remove references to privsep. 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-Regress-ID: 4bed1a0249df7b4a87c965066ce689e79472a8f7 commit ece2fbe486164860de8df3f8b943cccca3085eff Author: dtucker@openbsd.org Date: Thu Sep 30 04:22:50 2021 +0000 upstream: Use "skip" instead of "fatal" 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-Regress-ID: bd4dbbb02f34b2e8c890558ad4a696248def763a commit bb754b470c360e787a99fb4e88e2668198e97b41 Author: djm@openbsd.org Date: Fri Oct 1 04:50:36 2021 +0000 upstream: unbreak FIDO sk-ed25519 key enrollment for OPENSSL=no builds; ok dtucker@ OpenBSD-Commit-ID: 6323a5241728626cbb2bf0452cf6a5bcbd7ff709 commit 207648d7a6415dc915260ca75850404dbf9f0a0b Author: Darren Tucker Date: Wed Sep 29 20:03:58 2021 +1000 Include stdlib.h for arc4random_uniform prototype. commit 696aadc854582c164d5fc04933d2f3e212dc0e06 Author: Darren Tucker Date: Wed Sep 29 20:00:30 2021 +1000 Look for clang after cc and gcc. commit a3c6375555026d85dbf811fab566b9f76f196144 Author: Darren Tucker 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 Date: Wed Sep 29 18:53:32 2021 +1000 Skip file-based tests by default on Mac OS. The file-based tests need OpenSSL so skip them. commit 55c8bdf6e9afb0f9fa8e4f10c25c7f0081b48fd0 Author: Darren Tucker Date: Wed Sep 29 18:42:47 2021 +1000 Build without OpenSSL on Mac OS. Modern versions don't ship enough libcrypto to build against. commit c9172193ea975415facf0afb356d87df21535f88 Author: Darren Tucker Date: Wed Sep 29 18:33:38 2021 +1000 Remove TEST_SSH_ECC. Convert the only remaining user of it to runtime detection using ssh -Q. commit 5e6d28b7874b0deae95d2c68947c45212d32e599 Author: Darren Tucker Date: Wed Sep 29 17:48:09 2021 +1000 Split c89 test openssl setting out. commit c4ac7f98e230e83c015678dc958b1ffe828564ad Author: Darren Tucker Date: Wed Sep 29 17:40:50 2021 +1000 Expand TEST_SHELL consistently with other vars. commit cfe5f7b0eb7621bfb0a756222de0431315c2ab8b Author: Darren Tucker Date: Wed Sep 29 17:26:50 2021 +1000 Replace `pwd` with make variable in regress cmd. commit 899be59da5fbc3372444bd0fbe74af48313bed33 Author: Darren Tucker Date: Wed Sep 29 17:14:33 2021 +1000 Get BUILDDIR from autoconf. Use this to replace `pwd`s in regress test command line. commit c8d92d3d4f7d560146f2f936156ec4dac3fc5811 Author: Darren Tucker Date: Wed Sep 29 13:28:56 2021 +1000 Add make clean step to tests. commit 360fb41ef8359619ab90b0d131c914494e55d3dd Author: Darren Tucker Date: Wed Sep 29 11:36:13 2021 +1000 Test all available clang and gcc versions. commit 4fb49899d7da22952d35a4bc4c9bdb2311087893 Author: djm@openbsd.org Date: Wed Sep 29 01:32:21 2021 +0000 upstream: Test certificate hostkeys held in ssh-agent too. Would have caught regression fixed in sshd r1.575 ok markus@ OpenBSD-Regress-ID: 1f164d7bd89f83762db823eec4ddf2d2556145ed commit ce4854e12e749a05646e5775e9deb8cfaf49a755 Author: djm@openbsd.org Date: Wed Sep 29 01:33:32 2021 +0000 upstream: add some debug output showing how many key file/command lines were processed. Useful to see whether a file or command actually has keys present OpenBSD-Commit-ID: 0bd9ff94e84e03a22df8e6c12f6074a95d27f23c commit 15abdd523501c349b703d9a27e2bb4252ad921ef Author: dtucker@openbsd.org Date: Tue Sep 28 11:14:50 2021 +0000 upstream: Make prototype for rijndaelEncrypt match function including the bounds. Fixes error in portable where GCC>=11 takes notice of the bounds. ok deraadt@ OpenBSD-Commit-ID: cdd2f05fd1549e1786a70871e513cf9e9cf099a6 commit d1d29ea1d1ef1a1a54b209f062ec1dcc8399cf03 Author: dtucker@openbsd.org Date: Tue Sep 28 11:10:05 2021 +0000 upstream: Import regenerated moduli. OpenBSD-Commit-ID: 4bec5db13b736b64b06a0fca704cbecc2874c8e1 commit 39f2111b1d5f00206446257377dcce58cc72369f Author: Darren Tucker Date: Wed Sep 29 10:53:55 2021 +1000 Add new compiler hardening flags. 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 bf944e3794eff5413f2df1ef37cddf96918c6bde Author: Damien Miller Date: Mon Sep 27 00:03:19 2021 +1000 initgroups needs grp.h commit 8c5b5655149bd76ea21026d7fe73ab387dbc3bc7 Author: djm@openbsd.org Date: Sun Sep 26 14:01:11 2021 +0000 upstream: openssh-8.8 OpenBSD-Commit-ID: 12357794602ac979eb7312a1fb190c453f492ec4 commit f3cbe43e28fe71427d41cfe3a17125b972710455 Author: djm@openbsd.org Date: Sun Sep 26 14:01:03 2021 +0000 upstream: need initgroups() before setresgid(); reported by anton@, ok deraadt@ OpenBSD-Commit-ID: 6aa003ee658b316960d94078f2a16edbc25087ce commit 8acaff41f7518be40774c626334157b1b1c5583c Author: Damien Miller Date: Sun Sep 26 22:16:36 2021 +1000 update version numbers for release commit d39039ddc0010baa91c70a0fa0753a2699bbf435 Author: kn@openbsd.org Date: Sat Sep 25 09:40:33 2021 +0000 upstream: RSA/SHA-1 is not used by default anymore OK dtucker deraadt djm OpenBSD-Commit-ID: 055c51a221c3f099dd75c95362f902da1b8678c6 commit 9b2ee74e3aa8c461eb5552a6ebf260449bb06f7e Author: Darren Tucker Date: Fri Sep 24 11:08:03 2021 +1000 Move the fgrep replacement to hostkey-rotate.sh. 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 Date: Fri Sep 24 08:04:14 2021 +1000 Replacement function for buggy fgrep. 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 Date: Thu Sep 23 17:03:18 2021 -0400 Don't prompt for yes/no questions. commit 7ed1a3117c09f8c3f1add35aad77d3ebe1b85b4d Author: djm@openbsd.org Date: Mon Sep 20 06:53:56 2021 +0000 upstream: fix missing -s in SYNOPSYS and usage() as well as a capitalisation mistake; spotted by jmc@ OpenBSD-Commit-ID: 0ed8ee085c7503c60578941d8b45f3a61d4c9710 commit 8c07170135dde82a26886b600a8bf6fb290b633d Author: dtucker@openbsd.org Date: Mon Sep 20 04:02:13 2021 +0000 upstream: Fix "Allocated port" debug message for unix domain sockets. From peder.stray at gmail.com via github PR#272, ok deraadt@ OpenBSD-Commit-ID: 8d5ef3fbdcdd29ebb0792b5022a4942db03f017e commit 277d3c6adfb128b4129db08e3d65195d94b55fe7 Author: djm@openbsd.org Date: Mon Sep 20 01:55:42 2021 +0000 upstream: Switch scp back to use the old protocol by default, ahead of 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-Commit-ID: f281f603a705fba317ff076e7b11bcf2df941871 commit ace19b34cc15bea3482be90450c1ed0cd0dd0669 Author: djm@openbsd.org Date: Sat Sep 18 02:03:25 2021 +0000 upstream: better error message for ~user failures when the sftp-server lacks the expand-path extension; ok deraadt@ OpenBSD-Commit-ID: 9c1d965d389411f7e86f0a445158bf09b8f9e4bc commit 6b1238ba971ee722a310d95037b498ede5539c03 Author: djm@openbsd.org Date: Thu Sep 16 15:22:22 2021 +0000 upstream: make some more scp-in-SFTP mode better match Unix idioms suggested by deraadt@ OpenBSD-Commit-ID: 0f2439404ed4cf0b0be8bf49a1ee734836e1ac87 commit e694f8ac4409931e67d08ac44ed251b20b10a957 Author: djm@openbsd.org Date: Thu Sep 16 15:11:19 2021 +0000 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@ OpenBSD-Commit-ID: 0e821dbde423fc2280e47414bdc22aaa5b4e0733 commit 8a7a06ee505cb833e613f74a07392e9296286c30 Author: Darren Tucker Date: Fri Sep 17 13:03:31 2021 +1000 Test against LibreSSL 3.2.6, 3.3.4, 3.4.0. commit c25c84074a47f700dd6534995b4af4b456927150 Author: djm@openbsd.org Date: Thu Sep 16 05:36:03 2021 +0000 upstream: missing space character in ssh -G output broke the t-sshcfgparse regression test; spotted by anton@ OpenBSD-Commit-ID: bcc36fae2f233caac4baa8e58482da4aa350eed0 commit a4bee1934bf5e5575fea486628f4123d6a29dff8 Author: djm@openbsd.org Date: Wed Sep 15 06:56:01 2021 +0000 upstream: allow CanonicalizePermittedCNAMEs=none in ssh_config; ok markus@ OpenBSD-Commit-ID: 668a82ba8e56d731b26ffc5703213bfe071df623 commit d0fffc88c8fe90c1815c6f4097bc8cbcabc0f3dd Author: mbuhl@openbsd.org Date: Tue Sep 14 11:04:21 2021 +0000 upstream: put back the mux_ctx memleak fix for SSH_CHANNEL_MUX_CLIENT OK mfriedl@ OpenBSD-Commit-ID: 1aba1da828956cacaadb81a637338734697d9798 commit 19b3d846f06697c85957ab79a63454f57f8e22d6 Author: schwarze@openbsd.org Date: Sat Sep 11 09:05:50 2021 +0000 upstream: Do not ignore SIGINT while waiting for input if editline(3) 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 ba61123eef9c6356d438c90c1199a57a0d7bcb0a Author: djm@openbsd.org Date: Sat Sep 11 00:40:24 2021 +0000 upstream: when using SFTP protocol, continue transferring files after a transfer error occurs. This matches original scp/rcp behaviour. ok dtucker@ OpenBSD-Commit-ID: dfe4558d71dd09707e9b5d6e7d2e53b793da69fa commit b0ec59a708b493c6f3940336b1a537bcb64dd2a7 Author: dtucker@openbsd.org Date: Fri Sep 10 11:38:38 2021 +0000 upstream: Document that non-interactive commands are run via the user's shell using the -c flag. ok jmc@ OpenBSD-Commit-ID: 4f0d912077732eead10423afd1acf4fc0ceec477 commit 66a658b5d9e009ea11f8a0ca6e69c7feb2d851ea Author: dtucker@openbsd.org Date: Fri Sep 10 10:26:02 2021 +0000 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 1d47e28e407d1f95fdf8f799be23f48dcfa5206b Author: dtucker@openbsd.org Date: Fri Sep 10 07:11:11 2021 +0000 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 b344db7a413478e4c21e4cadba4a970ad3e6128a Author: djm@openbsd.org Date: Fri Sep 10 05:46:09 2021 +0000 upstream: openssh-7.4 was incorrectly listed twice; spotted by Dmitry Belyavskiy, ok dtucker@ OpenBSD-Commit-ID: 4b823ae448f6e899927ce7b04225ac9e489f58ef commit 9136d6239ad7a4a293e0418a49b69e70c76d58b8 Author: jmc@openbsd.org Date: Thu Sep 9 06:17:39 2021 +0000 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 2d678c5e3bdc2f5c99f7af5122e9d054925d560d Author: David Carlier Date: Wed Sep 8 19:49:54 2021 +0100 Disable tracing on FreeBSD using procctl. 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 73050fa38fb36ae3326d768b574806352b97002d Author: djm@openbsd.org Date: Wed Sep 8 23:31:39 2021 +0000 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 c4565e69ffa2485cff715aa842ea7a350296bfb6 Author: Darren Tucker Date: Wed Sep 8 21:09:49 2021 +1000 Really fix test on OpenSSL 1.1.1 stable. commit 79f1bb5f56cef3ae9276207316345b8309248478 Author: Darren Tucker Date: Wed Sep 8 18:51:39 2021 +1000 Correct OpenSSL 1.1.1 stable identifier. commit b6255593ed5ccbe5e7d3d4b26b2ad31ad4afc232 Author: Darren Tucker 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 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 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 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 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 Date: Sun Sep 5 20:45:42 2021 +1000 Correct version_num for OpenSSL dev branch. commit 65bb01111320dfd0d25e21e1fd4d3f2b77532669 Author: Darren Tucker 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 Date: Sun Sep 5 19:33:22 2021 +1000 OpenSSL development is now 3.1.* commit a60209a586a928f92ab323bf23bd07f57093342e Author: 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 Date: Sun Aug 29 23:44:07 2021 +0000 upstream: wrap at 80 columns OpenBSD-Commit-ID: 47ca2286d6b52a9747f34da16d742879e1a37bf0 commit 95401eea8503943449f712e5f3de52fc0bc612c5 Author: Darren Tucker 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 Date: Fri Aug 20 15:39:05 2021 +1000 Remove obsolete Redhat PAM config and init script. commit e1a596186c81e65a34ce13076449712d3bf97eb4 Author: Damien Miller Date: Fri Aug 20 14:03:49 2021 +1000 depend commit 5450606c8f7f7a0d70211cea78bc2dab74ab35d1 Author: Damien Miller Date: Fri Aug 20 13:59:43 2021 +1000 update version numbers commit feee2384ab8d694c770b7750cfa76a512bdf8246 Author: 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 Date: Fri Aug 20 10:48:13 2021 +1000 Also check pid in pselect_notify_setup. Spotted by djm@. commit deaadcb93ca15d4f38aa38fb340156077792ce87 Author: Darren Tucker Date: Fri Aug 20 08:39:33 2021 +1000 Prefix pselect functions to clarify debug messages commit 10e45654cff221ca60fd35ee069df67208fcf415 Author: Darren Tucker 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 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 Date: Tue Aug 17 15:12:04 2021 +1000 Remove trailing backslash on regress-unit-binaries commit b71b2508f17c68c5d9dbbe537686d81cedb9a781 Author: Darren Tucker 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 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 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 Date: Sun Aug 15 23:25:26 2021 +1000 Skip agent ptrace test on hurd. commit 7c9115bbbf958fbf85259a061c1122e2d046aabf Author: Darren Tucker Date: Sun Aug 15 19:37:22 2021 +1000 Add hurd test target. commit 7909a566f6c6a78fcd30708dc49f4e4f9bb80ce3 Author: Darren Tucker Date: Sun Aug 15 12:45:10 2021 +1000 Skip scp3 tests on all dfly58 and 60 configs. commit e65198e52cb03534e8c846d1bca74c310b1526de Author: Tim Rice 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 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 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 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 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 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 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 Date: Wed Aug 11 08:55:04 2021 +0000 upstream: test -Oprint-pubkey OpenBSD-Regress-ID: 3d51afb6d1f287975fb6fddd7a2c00a3bc5094e0 commit b9f4635ea5bc33ed5ebbacf332d79bae463b0f54 Author: 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 Date: Sat Aug 7 11:30:57 2021 +1000 Include poll.h and friends for struct pollfd. commit a9e2c533195f28627f205682482d9da384c4c52e Author: 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 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 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 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 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 Date: Sat Aug 7 00:07:18 2021 +0000 upstream: factor out a structure duplicated between downloading and crossloading; ok markus@ OpenBSD-Commit-ID: 96eede24d520569232086a129febe342e4765d39 commit 318c06bb04ee21a0cfa6b6022a201eacaa53f388 Author: djm@openbsd.org Date: Sat Aug 7 00:06:30 2021 +0000 upstream: use sftp_client crossloading to implement scp -3 feedback/ok markus@ OpenBSD-Commit-ID: 7db4c0086cfc12afc9cfb71d4c2fd3c7e9416ee9 commit de7115b373ba0be3861c65de9b606a3e0e9d29a3 Author: djm@openbsd.org Date: Sat Aug 7 00:02:41 2021 +0000 upstream: support for "cross"-loading files/directories, i.e. downloading from one SFTP server while simultaneously uploading to another. feedback & ok markus@ OpenBSD-Commit-ID: 3982878e29d8df0fa4ddc502f5ff6126ac714235 commit a50bd0367ff2063bbc70a387740a2aa6914de094 Author: djm@openbsd.org Date: Sat Aug 7 00:01:29 2021 +0000 upstream: factor our SSH2_FXP_OPEN calls into their own function; "looks fine" markus@ OpenBSD-Commit-ID: d3dea2153f08855c6d9dacc01973248944adeffb commit e3c0ba05873cf3d3f7d19d595667a251026b2d84 Author: djm@openbsd.org Date: Sat Aug 7 00:00:33 2021 +0000 upstream: prepare for scp -3 implemented via sftp OpenBSD-Commit-ID: 194aac0dd87cb175334b71c2a30623a5ad55bb44 commit 395d8fbdb094497211e1461cf0e2f80af5617e0a Author: dtucker@openbsd.org Date: Fri Aug 6 09:00:18 2021 +0000 upstream: Make diff invocation more portable. 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-Regress-ID: 0e2ec8594556a6f369ed5a0a90c6806419b845f7 commit d247a73ce27b460138599648d9c637c6f2b77605 Author: 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 Date: Fri Aug 6 05:04:42 2021 +0000 upstream: Document "ProxyJump none". bz#3334. OpenBSD-Commit-ID: f78cc6f55731f2cd35c3a41d5352ac1ee419eba7 commit 911ec6411821bda535d09778df7503b92f0eafab Author: dtucker@openbsd.org Date: Wed Aug 4 01:34:55 2021 +0000 upstream: Allow for different (but POSIX compliant) behaviour of basename(3) and prevent a use-after-free in that case in the new sftp-compat code. 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 6df1fecb5d3e51f3a8027a74885c3a44f6cbfcbd Author: Damien Miller Date: Wed Aug 4 11:05:11 2021 +1000 use openbsd-compat glob.h is required commit 9ebd1828881dfc9014a344587934a5ce7db6fa1b Author: Darren Tucker Date: Tue Aug 3 21:03:23 2021 +1000 Missing space between macro arg and punctuation. From jmc@ commit 0fd3f62eddc7cf54dcc9053be6f58998f3eb926a Author: Darren Tucker Date: Tue Aug 3 21:02:33 2021 +1000 Avoid lines >80 chars. From jmc@ commit af5d8094d8b755e1daaf2e20ff1dc252800b4c9b Author: djm@openbsd.org Date: Tue Aug 3 01:05:24 2021 +0000 upstream: regression tests for scp SFTP protocol support; mostly by Jakub Jelen in GHPR#194 ok markus OpenBSD-Regress-ID: 36f1458525bcb111741ec8547eaf58b13cddc715 commit e4673b7f67ae7740131a4ecea29a846593049a91 Author: anton@openbsd.org Date: Thu Jul 29 15:34:09 2021 +0000 upstream: Treat doas with arguments as a valid SUDO variable. Allows one to specify SUDO="doas -n" which I do while running make regress. ok dtucker@ OpenBSD-Regress-ID: 4fe5814b5010dbf0885500d703bea06048d11005 commit 197e29f1cca190d767c4b2b63a662f9a9e5da0b3 Author: djm@openbsd.org Date: Mon Aug 2 23:38:27 2021 +0000 upstream: support for using the SFTP protocol for file transfers in scp, via a new "-M sftp" option. Marked as experimental for now. Some corner-cases exist, in particular there is no attempt to provide bug-compatibility with scp's weird "double shell" quoting rules. 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 dd533c7ab79d61a7796b77b64bd81b098e0d7f9f Author: jmc@openbsd.org Date: Fri Jul 30 14:28:13 2021 +0000 upstream: fix a formatting error and add some Xr; from debian at helgefjell de removed references to rlogin etc. as no longer relevant; suggested by djm ok djm dtucker OpenBSD-Commit-ID: 3c431c303068d3aec5bb18573a0bd5e0cd77c5ae commit c7cd347a8823819411222c1e10a0d26747d0fd5c Author: jmc@openbsd.org Date: Fri Jul 30 14:25:01 2021 +0000 upstream: fix a formatting error and mark up known_hosts consistently; issues reported by debian at helgefjell de ok djm dtucker OpenBSD-Commit-ID: a1fd8d21dc77f507685443832df0c9700481b0ce commit 4455aec2e4fc90f64ae4fc47e78ebc9c18721738 Author: 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 rewrite the text to read better; issue reported by debian at helgefjell de ok djm dtucker OpenBSD-Commit-ID: 59fe2e8219c37906740ad062e0fdaea487dbe9cf commit bec429338e9b30d2c7668060e82608286a8a4777 Author: jmc@openbsd.org Date: Tue Jul 27 14:28:46 2021 +0000 upstream: word fix; reported by debian at helgefjell de OpenBSD-Commit-ID: 0c6fd22142422a25343c5bd1a618f31618f41ece commit efad4deb5a1f1cf79ebefd63c6625059060bfbe1 Author: jmc@openbsd.org Date: Tue Jul 27 14:14:25 2021 +0000 upstream: standardise the grammar in the options list; issue reported by debian at helgefjell de ok dtucker djm OpenBSD-Commit-ID: 7ac15575045d82f4b205a42cc7d5207fe4c3f8e6 commit 1e11fb24066f3fc259ee30db3dbb2a3127e05956 Author: Darren Tucker Date: Mon Aug 2 18:56:29 2021 +1000 Check for RLIMIT_NOFILE before trying to use it. commit 0f494236b49fb48c1ef33669f14822ca4f3ce2f4 Author: Darren Tucker Date: Tue Jul 27 17:45:34 2021 +1000 lastenv is only used in setenv. Prevents an unused variable warning on platforms that have setenv but not unsetenv. commit a1f78e08bdb3eaa88603ba3c6e01de7c8671e28a Author: Darren Tucker Date: Mon Jul 26 12:45:30 2021 +1000 Move SUDO to "make test" command line. Environment variables don't get passed by vmrun, so move to command line. commit 02e624273b9c78a49a01239159b8c09b8409b1a0 Author: Darren Tucker Date: Sun Jul 25 23:26:36 2021 +1000 Set SUDO for tests and cleanup. commit 460ae5d93051bab70239ad823dd784822d58baad Author: Darren Tucker Date: Sun Jul 25 22:37:55 2021 +1000 Pass OPENSSL=no to make tests too. commit b398f499c68d74ebe3298b73757cf3f36e14e0cb Author: dtucker@openbsd.org Date: Sun Jul 25 12:27:37 2021 +0000 upstream: Skip unit and makefile-based key conversion tests when we're building with OPENSSL=no. OpenBSD-Regress-ID: 20455ed9a977c93f846059d1fcb48e29e2c8d732 commit 727ce36c8c5941bde99216d27109405907caae4f Author: dtucker@openbsd.org Date: Sun Jul 25 12:13:03 2021 +0000 upstream: Replace OPENSSL as the variable that points to the 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-Regress-ID: 2d788fade3264d7803e5b54cae8875963f688c4e commit 55e17101a9075f6a63af724261c5744809dcb95c Author: dtucker@openbsd.org Date: Sat Jul 24 02:57:28 2021 +0000 upstream: Skip RFC4716 format import and export tests when built without OpenSSL. OpenBSD-Regress-ID: d2c2d5d38c1acc2b88cc99cfe00a2eb8bb39dfa4 commit f5ccb5895d39cd627ad9e7b2c671d2587616100d Author: dtucker@openbsd.org Date: Sat Jul 24 02:51:14 2021 +0000 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 819d57ac23469f1f03baa8feb38ddefbada90fdc Author: dtucker@openbsd.org Date: Sat Jul 24 02:08:13 2021 +0000 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. OpenBSD-Commit-ID: 3c82caa398cf99cd4518c23bba5a2fc66b16bafe commit b6673b1d2ee90b4690ee84f634efe40225423c38 Author: Darren Tucker Date: Sat Jul 24 13:02:51 2021 +1000 Test OpenBSD upstream with and without OpenSSL. commit 9d38074b5453c1abbdf888e80828c278d3b886ac Author: djm@openbsd.org Date: Sat Jul 24 01:54:23 2021 +0000 upstream: test for first-match-wins in authorized_keys environment= options OpenBSD-Regress-ID: 1517c90276fe84b5dc5821c59f88877fcc34c0e8 commit 2b76f1dd19787e784711ea297ad8fc938b4484fd Author: dtucker@openbsd.org Date: Fri Jul 23 05:53:02 2021 +0000 upstream: Simplify keygen-convert by using $SSH_KEYTYPES directly. OpenBSD-Regress-ID: cdbe408ec3671ea9ee9b55651ee551370d2a4108 commit 7d64a9fb587ba9592f027f7a2264226c713d6579 Author: djm@openbsd.org Date: Sat Jul 24 01:55:19 2021 +0000 upstream: don't leak environment= variable when it is not the first match OpenBSD-Commit-ID: 7fbdc3dfe0032deaf003fd937eeb4d434ee4efe0 commit db2130e2340bf923e41c791aa9cd27b9e926042c Author: jmc@openbsd.org Date: Fri Jul 23 06:01:17 2021 +0000 upstream: punctuation; OpenBSD-Commit-ID: 64be152e378c45975073ab1c07e0db7eddd15806 commit 03190d10980c6fc9124e988cb2df13101f266507 Author: djm@openbsd.org Date: Fri Jul 23 05:56:47 2021 +0000 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 1653ece6832b2b304d46866b262d5f69880a9ec7 Author: dtucker@openbsd.org Date: Fri Jul 23 05:07:16 2021 +0000 upstream: Test conversion of ed25519 and ecdsa keys too. OpenBSD-Regress-ID: 3676d2d00e58e0d6d37f2878f108cc2b83bbe4bb commit 8b7af02dcf9d2b738787efd27da7ffda9859bed2 Author: dtucker@openbsd.org Date: Fri Jul 23 04:56:21 2021 +0000 upstream: Add test for exporting pubkey from a passphrase-protected private key. OpenBSD-Regress-ID: da99d93e7b235fbd5b5aaa01efc411225e6ba8ac commit 441095d4a3e5048fe3c87a6c5db5bc3383d767fb Author: djm@openbsd.org Date: Fri Jul 23 03:54:55 2021 +0000 upstream: regression test for time-limited signature keys OpenBSD-Regress-ID: 2a6f3bd900dbee0a3c96f1ff23e032c93ab392bc commit 9e1882ef6489a7dd16b6d7794af96629cae61a53 Author: djm@openbsd.org Date: Fri Jul 23 05:24:02 2021 +0000 upstream: note successful authentication method in final "Authenticated to ..." message and partial auth success messages (all at LogLevel=verbose) ok dtucker@ OpenBSD-Commit-ID: 06834b89ceb89f8f16c5321d368a66c08f441984 commit a917e973a1b90b40ff1e950df083364b48fc6c78 Author: djm@openbsd.org Date: Fri Jul 23 04:04:52 2021 +0000 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 commit e0c5088f1c96a145eb6ea1dee438010da78f9ef5 Author: djm@openbsd.org Date: Fri Jul 23 04:00:59 2021 +0000 upstream: Add a StdinNull directive to ssh_config(5) that allows 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: 66ddf3f15c76796d4dcd22ff464aed1edd62468e commit e3957e21ffdc119d6d04c0b1686f8e2fe052f5ea Author: djm@openbsd.org Date: Fri Jul 23 03:57:20 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). feedback and ok dtucker@ OpenBSD-Commit-ID: 01f63fc10dcd995e7aed9c378ad879161af83121 commit d0bb1ce731762c55acb95817df4d5fab526c7ecd Author: djm@openbsd.org Date: Fri Jul 23 03:37:52 2021 +0000 upstream: Let allowed signers files used by ssh-keygen(1) 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@ OpenBSD-Commit-ID: 3e2c67b7dcd94f0610194d1e8e4907829a40cf31 commit 44142068dc7ef783d135e91ff954e754d2ed432e Author: dtucker@openbsd.org Date: Mon Jul 19 08:48:33 2021 +0000 upstream: Use SUDO when setting up hostkey. OpenBSD-Regress-ID: 990cf4481cab8dad62e90818a9b4b36c533851a7 commit 6b67f3f1d1d187597e54a139cc7785c0acebd9a2 Author: dtucker@openbsd.org Date: Mon Jul 19 05:08:54 2021 +0000 upstream: Increase time margin for rekey tests. Should help reliability on very heavily loaded hosts. OpenBSD-Regress-ID: 4c28a0fce3ea89ebde441d7091464176e9730533 commit 7953e1bfce9e76bec41c1331a29bc6cff9d416b8 Author: Darren Tucker Date: Mon Jul 19 13:47:51 2021 +1000 Add sshfp-connect.sh file missed in previous. commit b75a80fa8369864916d4c93a50576155cad4df03 Author: dtucker@openbsd.org Date: Mon Jul 19 03:13:28 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@. OpenBSD-Commit-ID: 0a6a0a476eb7f9dfe8fe2c05a1a395e3e9b22ee4 commit 1cc1fd095393663cd72ddac927d82c6384c622ba Author: dtucker@openbsd.org Date: Mon Jul 19 02:21:50 2021 +0000 upstream: Id sync only, -portable already has this. Put dh_set_moduli_file call inside ifdef WITH_OPENSSL. Fixes build with OPENSSL=no. OpenBSD-Commit-ID: af54abbebfb12bcde6219a44d544e18204defb15 commit 33abbe2f4153f5ca5c874582f6a7cc91ae167485 Author: dtucker@openbsd.org Date: Mon Jul 19 02:46:34 2021 +0000 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 f0cd000d8e3afeb0416dce1c711c3d7c28d89bdd Author: dtucker@openbsd.org Date: Mon Jul 19 02:29:28 2021 +0000 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 0075511e27e5394faa28edca02bfbf13b9a6693e Author: dtucker@openbsd.org Date: Mon Jul 19 00:16:26 2021 +0000 upstream: Group keygen tests together. OpenBSD-Regress-ID: 07e2d25c527bb44f03b7c329d893a1f2d6c5c40c commit 034828820c7e62652e7c48f9ee6b67fb7ba6fa26 Author: dtucker@openbsd.org Date: Sun Jul 18 23:10:10 2021 +0000 upstream: Add test for ssh-keygen printing of SSHFP records. OpenBSD-Regress-ID: fde9566b56eeb980e149bbe157a884838507c46b commit 52c3b6985ef1d5dadb4c4fe212f8b3a78ca96812 Author: djm@openbsd.org Date: Sat Jul 17 00:38:11 2021 +0000 upstream: wrap some long lines OpenBSD-Commit-ID: 4f5186b1466656762dae37d3e569438d900c350d commit 43ec991a782791d0b3f42898cd789f99a07bfaa4 Author: djm@openbsd.org Date: Sat Jul 17 00:36:53 2021 +0000 upstream: fix sftp on ControlPersist connections, broken by recent SessionType change; spotted by sthen@ OpenBSD-Commit-ID: 4c5ddc5698790ae6ff50d2a4f8f832f0eeeaa234 commit 073f45c236550f158c9a94003e4611c07dea5279 Author: djm@openbsd.org Date: Fri Jul 16 09:00:23 2021 +0000 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 ef7c4e52d5d840607f9ca3a302a4cbb81053eccf Author: jmc@openbsd.org Date: Wed Jul 14 06:46:38 2021 +0000 upstream: reorder SessionType; ok djm OpenBSD-Commit-ID: c7dd0b39e942b1caf4976a0b1cf0fed33d05418c commit 8aa2f9aeb56506dca996d68ab90ab9c0bebd7ec3 Author: Darren Tucker Date: Wed Jul 14 11:26:50 2021 +1000 Make whitespace consistent. commit 4f4297ee9b8a39f4dfd243a74c5f51f9e7a05723 Author: Darren Tucker Date: Wed Jul 14 11:26:12 2021 +1000 Add ARM64 Linux self-hosted runner. commit eda8909d1b0a85b9c3804a04d03ec6738fd9dc7f Author: djm@openbsd.org Date: Tue Jul 13 23:48:36 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@ OpenBSD-Commit-ID: 726ee931dd4c5cc7f1d7a187b26f41257f9a2d12 commit 7ae69f2628e338ba6e0eae7ee8a63bcf8fea7538 Author: 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 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 Date: Mon Jul 12 06:22:57 2021 +0000 upstream: Make limit for time_t test unconditional in the 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 6c29b387cd64a57b0ec8ae7d2c8d02789d88fcc3 Author: dtucker@openbsd.org Date: Mon Jul 12 06:08:57 2021 +0000 upstream: Use existing format_absolute_time() function when printing cert validity instead of doing it inline. Part of bz#3329. OpenBSD-Commit-ID: a13d4e3c4f59644c23745eb02a09b2a4e717c00c commit 99981d5f8bfa383791afea03f6bce8454e96e323 Author: djm@openbsd.org Date: Fri Jul 9 09:55:56 2021 +0000 upstream: silence redundant error message; reported by Fabian Stelzer OpenBSD-Commit-ID: 9349a703016579a60557dafd03af2fe1d44e6aa2 commit e86097813419b49d5bff5c4b51d1c3a5d4d2d804 Author: John Ericson Date: Sat Dec 26 11:40:49 2020 -0500 Re-indent krb5 section after pkg-config addition. commit 32dd2daa56c294e40ff7efea482c9eac536d8cbb Author: John Ericson Date: Sat Dec 26 11:40:49 2020 -0500 Support finding Kerberos via pkg-config This makes cross compilation easier. commit def7a72234d7e4f684d72d33a0f7229f9eee0aa4 Author: Darren Tucker Date: Fri Jul 9 14:34:06 2021 +1000 Update comments about EGD to include prngd. commit b5d23150b4e3368f4983fd169d432c07afeee45a Author: dtucker@openbsd.org Date: Mon Jul 5 01:21:07 2021 +0000 upstream: Fix a couple of whitespace things. Portable already has these so this removes two diffs between the two. OpenBSD-Commit-ID: 769f017ebafd8e741e337b3e9e89eb5ac73c9c56 commit 8f57be9f279b8e905f9883066aa633c7e67b31cf Author: dtucker@openbsd.org Date: Mon Jul 5 01:16:46 2021 +0000 upstream: Order includes as per style(9). Portable already has these so this removes a handful of diffs between the two. OpenBSD-Commit-ID: 8bd7452d809b199c19bfc49511a798f414eb4a77 commit b75624f8733b3ed9e240f86cac5d4a39dae11848 Author: dtucker@openbsd.org Date: Mon Jul 5 00:50:25 2021 +0000 upstream: Remove comment referencing now-removed RhostsRSAAuthentication. ok djm@ OpenBSD-Commit-ID: 3d864bfbd99a1d4429a58e301688f3be464827a9 commit b67eb12f013c5441bb4f0893a97533582ad4eb13 Author: djm@openbsd.org Date: Mon Jul 5 00:25:42 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 OpenBSD-Commit-ID: e9b550f3a85ffbb079b6720833da31317901d6dd commit 8c4ef0943e574f614fc7c6c7e427fd81ee64ab87 Author: dtucker@openbsd.org Date: Fri Jul 2 07:20:44 2021 +0000 upstream: Remove obsolete comments about SSHv1 auth methods. ok djm@ OpenBSD-Commit-ID: 6060f70966f362d8eb4bec3da2f6c4712fbfb98f commit 88908c9b61bcb99f16e8d398fc41e2b3b4be2003 Author: Darren Tucker Date: Sat Jul 3 23:00:19 2021 +1000 Remove reference to ChallengeResponse. challenge_response_authentication was removed from the struct, keeping kbd_interactive_authentication. commit 321874416d610ad2158ce6112f094a4862c2e37f Author: Darren Tucker Date: Sat Jul 3 20:38:09 2021 +1000 Move signal.h up include order to match upstream. commit 4fa83e2d0e32c2dd758653e0359984bbf1334f32 Author: Darren Tucker Date: Sat Jul 3 20:36:06 2021 +1000 Remove old OpenBSD version marker. Looks like an accidental leftover from a sync. commit 9d5e31f55d5f3899b72645bac41a932d298ad73b Author: Darren Tucker Date: Sat Jul 3 20:34:19 2021 +1000 Remove duplicate error on error path. 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 Date: Sat Jul 3 20:32:46 2021 +1000 Remove some whitespace not in upstream. Reduces diff vs OpenBSD by a small amount. commit 4d2d4d47a18d93f3e0a91a241a6fdb545bbf7dc2 Author: Darren Tucker Date: Sat Jul 3 19:27:43 2021 +1000 Replace remaining references to ChallengeResponse. Portable had a few additional references to ChallengeResponse related to UsePAM, replaces these with equivalent keyboard-interactive ones. commit 53237ac789183946dac6dcb8838bc3b6b9b43be1 Author: Darren Tucker Date: Sat Jul 3 19:23:28 2021 +1000 Sync remaining ChallengeResponse removal. These were omitted from commit 88868fd131. commit 2c9e4b319f7e98744b188b0f58859d431def343b Author: Darren Tucker Date: Sat Jul 3 19:17:31 2021 +1000 Disable rocky84 to figure out why agent test fails commit bfe19197a92b7916f64a121fbd3c179abf15e218 Author: Darren Tucker Date: Fri Jul 2 15:43:28 2021 +1000 Remove now-unused SSHv1 enums. sRhostsRSAAuthentication and sRSAAuthentication are protocol 1 options and are no longer used. commit c73b02d92d72458a5312bd098f32ce88868fd131 Author: dtucker@openbsd.org Date: Fri Jul 2 05:11:20 2021 +0000 upstream: Remove references to ChallengeResponseAuthentication in 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 f841fc9c8c7568a3b5d84a4cc0cefacb7dbc16b9 Author: Darren Tucker Date: Fri Jul 2 15:20:32 2021 +1000 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 0767627cf66574484b9c0834500b42ea04fe528a Author: Damien Miller Date: Fri Jul 2 14:30:23 2021 +1000 wrap get_random_bytes_prngd() in ifdef avoid unused static function warning commit f93fdc4de158386efe1116bd44c5b3f4a7a82c25 Author: Darren Tucker Date: Mon Jun 28 13:06:37 2021 +1000 Add rocky84 test target. commit d443006c0ddfa7f6a5bd9c0ae92036f3d5f2fa3b Author: djm@openbsd.org Date: Fri Jun 25 06:30:22 2021 +0000 upstream: fix decoding of X.509 subject name; from Leif Thuresson via bz3327 ok markus@ OpenBSD-Commit-ID: 0ea2e28f39750dd388b7e317bc43dd997a217ae8 commit 2a5704ec142202d387fda2d6872fd4715ab81347 Author: dtucker@openbsd.org Date: Fri Jun 25 06:20:39 2021 +0000 upstream: Use better language to refer to the user. From l1ving via github PR#250, ok jmc@ OpenBSD-Commit-ID: 07ca3526626996613e128aeddf7748c93c4d6bbf commit 4bdf7a04797a0ea1c431a9d54588417c29177d19 Author: dtucker@openbsd.org Date: Fri Jun 25 03:38:17 2021 +0000 upstream: Replace SIGCHLD/notify_pipe kludge with pselect. 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. 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 c9f7bba2e6f70b7ac1f5ea190d890cb5162ce127 Author: Darren Tucker Date: Fri Jun 25 15:08:18 2021 +1000 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 7ebfe4e439853b88997c9cfc2ff703408a1cca92 Author: Darren Tucker Date: Fri Jun 18 20:41:45 2021 +1000 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 e409d7966785cfd9f5970e66a820685c42169717 Author: Darren Tucker Date: Fri Jun 18 18:34:08 2021 +1000 Try EGD/PRNGD if random device fails. When built --without-openssl, try EGD/PRGGD (if configured) as a last resort before failing. commit e43a898043faa3a965dbaa1193cc60e0b479033d Author: Darren Tucker Date: Fri Jun 18 18:32:51 2021 +1000 Split EGD/PRNGD interface into its own file. This will allow us to use it when building --without-openssl. commit acb2887a769a1b1912cfd7067f3ce04fad240260 Author: Darren Tucker Date: Thu Jun 17 21:03:19 2021 +1000 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 31fac20c941126281b527605b73bff30a8f02edd Author: dtucker@openbsd.org Date: Thu Jun 10 09:46:28 2021 +0000 upstream: Use $SUDO when reading sshd's pidfile here too. OpenBSD-Regress-ID: 6bfb0d455d493f24839034a629c5306f84dbd409 commit a3a58acffc8cc527f8fc6729486d34e4c3d27643 Author: dtucker@openbsd.org Date: Thu Jun 10 09:43:51 2021 +0000 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 249ad4ae51cd3bc235e75a4846eccdf8b1416611 Author: dtucker@openbsd.org Date: Thu Jun 10 09:37:59 2021 +0000 upstream: Set umask when creating hostkeys to prevent excessive permissions warning. OpenBSD-Regress-ID: 382841db0ee28dfef7f7bffbd511803e1b8ab0ef commit 9d0892153c005cc65897e9372b01fa66fcbe2842 Author: dtucker@openbsd.org Date: Thu Jun 10 03:45:31 2021 +0000 upstream: Add regress test for SIGHUP restart while handling active and unauthenticated clients. Should catch anything similar to the pselect bug just fixed in sshd.c. OpenBSD-Regress-ID: 3b3c19b5e75e43af1ebcb9586875b3ae3a4cac73 commit 73f6f191f44440ca3049b9d3c8e5401d10b55097 Author: 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 Date: Tue Jun 8 22:30:27 2021 +0000 upstream: test that UserKnownHostsFile correctly accepts multiple arguments; would have caught readconf.c r1.356 regression OpenBSD-Regress-ID: 71ca54e66c2a0211b04999263e56390b1f323a6a commit 1a6f6b08e62c78906a3032e8d9a83e721c84574e Author: djm@openbsd.org Date: Tue Jun 8 22:06:12 2021 +0000 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@ OpenBSD-Commit-ID: 7cbf182f7449bf1cb7c5b4452667dc2b41170d6d commit 78e30af3e2b2dd540a341cc827c6b98dd8b0a6de Author: djm@openbsd.org Date: Tue Jun 8 07:40:12 2021 +0000 upstream: test argv_split() optional termination on comments OpenBSD-Regress-ID: 9fd1c4a27a409897437c010cfd79c54b639a059c commit a023138957ea2becf1c7f93fcc42b0aaac6f2b03 Author: dtucker@openbsd.org Date: Tue Jun 8 07:05:27 2021 +0000 upstream: Add testcases from bz#3319 for IPQoS and TunnelDevice being overridden on the command line. OpenBSD-Regress-ID: 801674d5d2d02abd58274a78cab2711f11de14a8 commit 660cea10b2cdc11f13ba99c89b1bbb368a4d9ff2 Author: djm@openbsd.org Date: Tue Jun 8 06:52:43 2021 +0000 upstream: sprinkle some "# comment" at end of configuration lines to test comment handling OpenBSD-Regress-ID: cb82fbf40bda5c257a9f742c63b1798e5a8fdda7 commit acc9c32dcb6def6c7d3688bceb4c0e59bd26b411 Author: djm@openbsd.org Date: Tue Jun 8 06:51:47 2021 +0000 upstream: more descriptive failure message OpenBSD-Regress-ID: 5300f6faf1d9e99c0cd10827b51756c5510e3509 commit ce04dd4eae23d1c9cf7c424a702f48ee78573bc1 Author: djm@openbsd.org Date: Mon Jun 7 01:16:34 2021 +0000 upstream: test AuthenticationMethods inside a Match block as well as in the main config section OpenBSD-Regress-ID: ebe0a686621b7cb8bb003ac520975279c28747f7 commit 9018bd821fca17e26e92f7a7e51d9b24cd62f2db Author: djm@openbsd.org Date: Mon Jun 7 00:00:50 2021 +0000 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 commit a10f929d1ce80640129fc5b6bc1acd9bf689169e Author: djm@openbsd.org Date: Tue Jun 8 07:09:42 2021 +0000 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 commit ea9e45c89a4822d74a9d97fef8480707d584da4d Author: djm@openbsd.org Date: Tue Jun 8 07:07:15 2021 +0000 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 commit d786424986c04d1d375f231fda177c8408e05c3e Author: dtucker@openbsd.org Date: Tue Jun 8 07:02:46 2021 +0000 upstream: Check if IPQoS or TunnelDevice are already set before overriding. Prevents values in config files from overriding values supplied on the command line. bz#3319, ok markus. OpenBSD-Commit-ID: f3b08b898c324debb9195e6865d8999406938f74 commit aae4b4d3585b9f944d7dbd3c9e5ba0006c55e457 Author: djm@openbsd.org Date: Tue Jun 8 06:54:40 2021 +0000 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 commit da9f9acaac5bab95dca642b48e0c8182b246ab69 Author: Darren Tucker Date: Mon Jun 7 19:19:23 2021 +1000 Save logs on failure for upstream test commit 76883c60161e5f3808787085a27a8c37f8cc4e08 Author: Darren Tucker Date: Mon Jun 7 14:36:32 2021 +1000 Add obsdsnap-i386 upstream test target. commit d45b9c63f947ec5ec314696e70281f6afddc0ac3 Author: djm@openbsd.org Date: Mon Jun 7 03:38:38 2021 +0000 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 OpenBSD-Commit-ID: d5af3be66d0f22c371dc1fe6195e774a18b2327b commit 530739d42f6102668aecd699be0ce59815c1eceb Author: djm@openbsd.org Date: Sun Jun 6 11:34:16 2021 +0000 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 commit 4265215d7300901fd7097061c7517688ade82f8e Author: djm@openbsd.org Date: Sun Jun 6 03:40:39 2021 +0000 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. Reported by and based on patch from Gordon Messmer via bz3213, thanks also for additional analysis by Jakub Jelen. ok dtucker OpenBSD-Commit-ID: d6d0b7351d5d44c45f3daaa26efac65847a564f7 commit bda270d7fb8522d43c21a79a4b02a052d7c64de8 Author: djm@openbsd.org Date: Sun Jun 6 03:17:02 2021 +0000 upstream: degrade gracefully if a sftp-server offers the limits@openssh.com extension but fails when the client tries to invoke it. Reported by Hector Martin via bz3318 OpenBSD-Commit-ID: bd9d1839c41811616ede4da467e25746fcd9b967 commit d345d5811afdc2d6923019b653cdd93c4cc95f76 Author: djm@openbsd.org Date: Sun Jun 6 03:15:39 2021 +0000 upstream: the limits@openssh.com extension was incorrectly marked as an operation that writes to the filesystem, which made it unavailable in sftp-server read-only mode. Spotted by Hector Martin via bz3318 OpenBSD-Commit-ID: f054465230787e37516c4b57098fc7975e00f067 commit 2b71010d9b43d7b8c9ec1bf010beb00d98fa765a Author: naddy@openbsd.org Date: Sat Jun 5 13:47:00 2021 +0000 upstream: PROTOCOL.certkeys: update reference from IETF draft to RFC Also fix some typos. ok djm@ OpenBSD-Commit-ID: 5e855b6c5a22b5b13f8ffa3897a868e40d349b44 commit aa99b2d9a3e45b943196914e8d8bf086646fdb54 Author: Darren Tucker Date: Fri Jun 4 23:41:29 2021 +1000 Clear notify_pipe from readset if present. Prevents leaking an implementation detail to the caller. commit 6de8dadf6b4d0627d35bca0667ca44b1d61c2c6b Author: Darren Tucker Date: Fri Jun 4 23:24:25 2021 +1000 space->tabs. commit c8677065070ee34c05c7582a9c2f58d8642e552d Author: Darren Tucker Date: Fri Jun 4 18:39:48 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. 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 7cd7f302d3a072748299f362f9e241d81fcecd26 Author: Vincent Brillault Date: Sun May 24 09:15:06 2020 +0200 auth_log: dont log partial successes as failures 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 e7606919180661edc7f698e6a1b4ef2cfb363ebf Author: djm@openbsd.org Date: Fri Jun 4 06:19:07 2021 +0000 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 commit c298c4da574ab92df2f051561aeb3e106b0ec954 Author: djm@openbsd.org Date: Fri Jun 4 05:59:18 2021 +0000 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 commit d9cb35bbec5f623589d7c58fc094817b33030f35 Author: djm@openbsd.org Date: Fri Jun 4 05:10:03 2021 +0000 upstream: adjust SetEnv description to clarify $TERM handling OpenBSD-Commit-ID: 8b8cc0124856bc1094949d55615e5c44390bcb22 commit 771f57a8626709f2ad207058efd68fbf30d31553 Author: dtucker@openbsd.org Date: Fri Jun 4 05:09: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. 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 f64f8c00d158acc1359b8a096835849b23aa2e86 Author: djm@openbsd.org Date: Fri Jun 4 05:02:40 2021 +0000 upstream: allow ssh_config SetEnv to override $TERM, which is otherwise 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: 38b1ef4d5bc159c7d9d589d05e3017433e2d5758 commit 60107677dc0ce1e93c61f23c433ad54687fcd9f5 Author: djm@openbsd.org Date: Fri Jun 4 04:02:21 2021 +0000 upstream: correct extension name "no-presence-required" => "no-touch-required" document "verify-required" option OpenBSD-Commit-ID: 1879ff4062cf61d79b515e433aff0bf49a6c55c5 commit ecc186e46e3e30f27539b4311366dfda502f0a08 Author: Darren Tucker Date: Wed Jun 2 13:54:11 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. commit 5de0867b822ec48b5eec9abde0f5f95d1d646546 Author: Darren Tucker Date: Wed Jun 2 11:21:40 2021 +1000 Check for $OPENSSL in md5 fallback too. commit 1db69d1b6542f8419c04cee7fd523a4a11004be2 Author: Darren Tucker Date: Wed Jun 2 11:17:54 2021 +1000 Add dfly60 target. commit a3f2dd955f1c19cad387a139f0e719af346ca6ef Author: dtucker@openbsd.org Date: Wed Jun 2 00:17:45 2021 +0000 upstream: Merge back shell portability changes bringing it back in sync with -portable. OpenBSD-Regress-ID: c07905ba931e66ad7d849b87b7d19648007175d1 commit 9d482295c9f073e84d75af46b720a1c0f7ec2867 Author: dtucker@openbsd.org Date: Tue Jun 1 23:56:20 2021 +0000 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. OpenBSD-Regress-ID: c49dcd6aa7602a8606b7afa192196ca1fa65de16 commit 07660b3c99f8ea74ddf4a440e55c16c9f7fb3dd1 Author: dtucker@openbsd.org Date: Mon May 24 10:25:18 2021 +0000 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). OpenBSD-Regress-ID: 491f39cae9e762c71aa4bf045803d077139815c5 commit 1a4d1da9188d7c88f646b61f0d6a3b34f47c5439 Author: djm@openbsd.org Date: Fri May 21 04:03:47 2021 +0000 upstream: fix memleak in test OpenBSD-Regress-ID: 5e529d0982aa04666604936df43242e97a7a6f81 commit 60455a5d98065a73ec9a1f303345856bbd49aecc Author: djm@openbsd.org Date: Fri May 21 03:59:01 2021 +0000 upstream: also check contents of remaining string OpenBSD-Regress-ID: d526fa07253f4eebbc7d6205a0ab3d491ec71a28 commit 39f6cd207851d7b67ca46903bfce4a9f615b5b1c Author: djm@openbsd.org Date: Fri May 21 03:48:07 2021 +0000 upstream: unit test for misc.c:strdelim() that mostly servces to highlight its inconsistencies OpenBSD-Regress-ID: 8d2bf970fcc01ccc6e36a5065f89b9c7fa934195 commit 7a3a1dd2c7d4461962acbcc0ebee9445ba892be0 Author: Darren Tucker Date: Thu May 27 21:23:15 2021 +1000 Put minix3 config in the host-specific block. commit 59a194825f12fff8a7f75d91bf751ea17645711b Author: djm@openbsd.org Date: Mon May 31 06:48:42 2021 +0000 upstream: Hash challenge supplied by client during FIDO key enrollment prior to passing it to libfido2, which does expect a hash. 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 eb68e669bc8ab968d4cca5bf1357baca7136a826 Author: Darren Tucker 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 Date: Thu May 27 21:13:38 2021 +1000 Add minix3 test target. commit 2e1efcfd9f94352ca5f4b6958af8a454f8cf48cd Author: djm@openbsd.org Date: Wed May 26 01:47:24 2021 +0000 upstream: fix SEGV in UpdateHostkeys debug() message, triggered when the update removed more host keys than remain present. Fix tested by reporter James Cook, via bugs@ OpenBSD-Commit-ID: 44f641f6ee02bb957f0c1d150495b60cf7b869d3 commit 9acd76e6e4d2b519773e7119c33cf77f09534909 Author: naddy@openbsd.org Date: Sun May 23 18:22:57 2021 +0000 upstream: ssh: The client configuration keyword is "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 078a0e60c92700da4c536c93c007257828ccd05b Author: Darren Tucker Date: Tue May 25 11:40:47 2021 +1000 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 7be4ac813662f68e89f23c50de058a49aa32f7e4 Author: djm@openbsd.org Date: Wed May 19 01:24:05 2021 +0000 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 c4902e1a653c67fea850ec99c7537f358904c0af Author: djm@openbsd.org Date: Mon May 17 11:43:16 2021 +0000 upstream: fix breakage of -W forwaring introduced in 1.554; reported by naddy@ and sthen@, ok sthen@ OpenBSD-Commit-ID: f72558e643a26dc4150cff6e5097b5502f6c85fd commit afea01381ad1fcea1543b133040f75f7542257e6 Author: dtucker@openbsd.org Date: Mon May 17 07:22:45 2021 +0000 upstream: Regenerate moduli. OpenBSD-Commit-ID: 83c93a2a07c584c347ac6114d6329b18ce515557 commit be2866d6207b090615ff083c9ef212b603816a56 Author: Damien Miller Date: Mon May 17 09:40:23 2021 +1000 Handle Android libc returning NULL pw->pw_passwd Reported by Luke Dashjr commit 5953c143008259d87342fb5155bd0b8835ba88e5 Author: 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 Date: Fri May 14 03:09:48 2021 +0000 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 OpenBSD-Commit-ID: ea1ea4af16a95687302f7690bdbe36a6aabf87e1 commit d1320c492f655d8f5baef8c93899d79dded217a5 Author: dtucker@openbsd.org Date: Wed May 12 11:34:30 2021 +0000 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@ OpenBSD-Commit-ID: f0c18cc8e79c2fbf537a432a9070ed94e96a622a commit d3cc4d650ce3e59f3e370b101778b0e8f1c02c4d Author: djm@openbsd.org Date: Fri May 7 04:11:51 2021 +0000 upstream: include pid in LogVerbose spam OpenBSD-Commit-ID: aacb86f96ee90c7cb84ec27452374285f89a7f00 commit e3c032333be5fdbbaf2751f6f478e044922b4ec4 Author: djm@openbsd.org Date: Fri May 7 03:09:38 2021 +0000 upstream: don't sigdie() in signal handler in privsep child process; this can end up causing sandbox violations per bz3286; ok dtucker@ OpenBSD-Commit-ID: a7f40b2141dca4287920da68ede812bff7ccfdda commit a4039724a3f2abac810735fc95cf9114a3856049 Author: dtucker@openbsd.org Date: Fri May 7 09:23:40 2021 +0000 upstream: Increase ConnectionAttempts from 4 to 10 as the tests occasionally time out on heavily loaded hosts. OpenBSD-Regress-ID: 29a8cdef354fc9da471a301f7f65184770434f3a commit c0d7e36e979fa3cdb60f5dcb6ac9ad3fd018543b Author: djm@openbsd.org Date: Fri May 7 02:26:55 2021 +0000 upstream: dump out a usable private key string too; inspired by Tyson Whitehead OpenBSD-Regress-ID: 65572d5333801cb2f650ebc778cbdc955e372058 commit 24fee8973abdf1c521cd2c0047d89e86d9c3fc38 Author: djm@openbsd.org Date: Fri May 7 02:29:40 2021 +0000 upstream: correct mistake in spec - the private key blobs are encoded verbatim and not as strings (i.e. no 4-byte length header) OpenBSD-Commit-ID: 3606b5d443d72118c5b76c4af6dd87a5d5a4f837 commit f43859159cc62396ad5d080f0b1f2635a67dac02 Author: dtucker@openbsd.org Date: Tue May 4 22:53:52 2021 +0000 upstream: Don't pass NULL as a string in debugging as it does not work on some platforms in -portable. ok djm@ OpenBSD-Commit-ID: 937c892c99aa3c9c272a8ed78fa7c2aba3a44fc9 commit ac31aa3c6341905935e75f0539cf4a61bbe99779 Author: djm@openbsd.org Date: Mon May 3 00:16:45 2021 +0000 upstream: more debugging for UpdateHostKeys signature failures OpenBSD-Commit-ID: 1ee95f03875e1725df15d5e4bea3e73493d57d36 commit 8e32e97e788e0676ce83018a742203614df6a2b3 Author: Darren Tucker Date: Sat May 1 20:07:47 2021 +1000 Add obsd69 test target. commit f06893063597c5bb9d9e93f851c4070e77d2fba9 Author: djm@openbsd.org Date: Fri Apr 30 04:29:53 2021 +0000 upstream: a little debugging in the main mux process for status confirmation failures in multiplexed sessions OpenBSD-Commit-ID: 6e27b87c95176107597035424e1439c3232bcb49 commit e65cf00da6bc31e5f54603b7feb7252dc018c033 Author: dtucker@openbsd.org Date: Fri Apr 30 04:02:52 2021 +0000 upstream: Remove now-unused skey function prototypes leftover from skey removal. OpenBSD-Commit-ID: 2fc36d519fd37c6f10ce74854c628561555a94c3 commit ae5f9b0d5c8126214244ee6b35aae29c21028133 Author: Darren Tucker Date: Thu Apr 29 13:01:50 2021 +1000 Wrap sntrup761x25519 inside ifdef. From balu.gajjala at gmail.com via bz#3306. commit 70a8dc138a6480f85065cdb239915ad4b7f928cf Author: Darren Tucker Date: Wed Apr 28 14:44:07 2021 +1000 Add status badges for Actions-based tests. commit 40b59024cc3365815381474cdf4fe423102e391b Author: Darren Tucker Date: Wed Apr 28 12:22:11 2021 +1000 Add obsdsnap (OpenBSD snapshot) test target. commit e627067ec8ef9ae8e7a638f4dbac91d52dee3e6d Author: Darren Tucker Date: Wed Apr 28 11:35:28 2021 +1000 Add test building upstream OpenBSD source. commit 1b8108ebd12fc4ed0fb39ef94c5ba122558ac373 Author: Darren Tucker Date: Tue Apr 27 14:22:20 2021 +1000 Test against OpenSSL 1.1.0h instead of 1.1.0g. 1.1.0g requires a perl glob module that's not installed by default. commit 9bc20efd39ce8525be33df3ee009f5a4564224f1 Author: Darren Tucker Date: Tue Apr 27 12:37:59 2021 +1000 Use the default VM type for libcrypto ver tests. commit 9f79e80dc40965c2e73164531250b83b176c1eea Author: Darren Tucker Date: Tue Apr 27 12:24:10 2021 +1000 Always build OpenSSL shared. This is the default for current versions but we need it to test against earlier versions. commit b3cc9fbdff2782eca79e33e02ac22450dc63bce9 Author: Darren Tucker Date: Tue Apr 27 09:18:02 2021 +1000 Fix custom OpenSSL tests. 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 77532609874a99a19e3e2eb2d1b7fa93aef963bb Author: Darren Tucker Date: Mon Apr 26 17:18:25 2021 +1000 Export CC and CFLAGS for c89 test. commit 33f62dfbe865f4de77980ab88774bf1eb5e4e040 Author: Darren Tucker Date: Mon Apr 26 17:13:44 2021 +1000 Add c89 here too. commit da9d59f526fce58e11cba49cd8eb011dc0bf5677 Author: Darren Tucker Date: Mon Apr 26 15:34:23 2021 +1000 Add test against OpenSSL w/out ECC. commit 29e194a752359ebf85bf7fce100f23a0477fc4de Author: Darren Tucker Date: Mon Apr 26 14:49:59 2021 +1000 Ensure we can still build with C89. commit a38016d369d21df5d35f761f2b67e175e132ba22 Author: Darren Tucker Date: Mon Apr 26 14:29:03 2021 +1000 Interop test agains PuTTY. commit 095b0307a77be8803768857cc6c0963fa52ed85b Author: Darren Tucker Date: Mon Apr 26 14:02:03 2021 +1000 Support testing against arbitary libcrytpo vers. Add tests against various LibreSSL and OpenSSL versions. commit b16082aa110fa7128ece2a9037ff420c4a285317 Author: Darren Tucker Date: Mon Apr 26 13:35:44 2021 +1000 Add fbsd10 test target. commit 2c805f16b24ea37cc051c6018fcb05defab6e57a Author: Darren Tucker Date: Sun Apr 25 14:15:02 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. commit 6a5d39305649da5dff1934ee54292ee0cebd579d Author: Darren Tucker Date: Sun Apr 25 13:01:34 2021 +1000 Add nbsd3, nbsd4 and nbsd9 test targets. commit d1aed05bd2e4ae70f359a394dc60a2d96b88f78c Author: Darren Tucker Date: Sat Apr 24 22:03:46 2021 +1000 Comment out nbsd2 test target for now. commit a6b4ec94e5bd5a8a18cd2c9942d829d2e5698837 Author: Darren Tucker Date: Sat Apr 24 17:52:24 2021 +1000 Add OPENBSD ORIGINAL marker. commit 3737c9f66ee590255546c4b637b6d2be669a11eb Author: Darren Tucker Date: Fri Apr 23 19:49:46 2021 +1000 Replace "==" (a bashism) with "=". commit a116b6f5be17a1dd345b7d54bf8aa3779a28a0df Author: Darren Tucker Date: Fri Apr 23 16:34:48 2021 +1000 Add nbsd2 test target. commit 196bf2a9bb771f45d9b0429cee7d325962233c44 Author: Darren Tucker Date: Fri Apr 23 14:54:10 2021 +1000 Add obsd68 test target. commit e3ba6574ed69e8b7af725cf5e8a9edaac04ff077 Author: Darren Tucker Date: Fri Apr 23 14:53:32 2021 +1000 Remove dependency on bash. commit db1f9ab8feb838aee9f5b99c6fd3f211355dfdcf Author: Darren Tucker Date: Fri Apr 23 14:41:13 2021 +1000 Add obsd67 test target. commit c039a6bf79192fe1daa9ddcc7c87dd98e258ae7c Author: Darren Tucker Date: Fri Apr 23 11:08:23 2021 +1000 Re-add macos-11.0 test target. commit a6db3a47b56adb76870d59225ffb90a65bc4daf2 Author: Darren Tucker Date: Fri Apr 23 10:28:28 2021 +1000 Add openindiana test target. commit 3fe7e73b025c07eda46d78049f1da8ed7dfc0c69 Author: Darren Tucker Date: Fri Apr 23 10:26:35 2021 +1000 Test krb5 on Solaris 11 too. commit f57fbfe5eb02df1a91f1a237c4d27165afd87c13 Author: Darren Tucker Date: Thu Apr 22 22:27:26 2021 +1000 Don't always set SUDO. Rely on sourcing configs to set as appropriate. commit e428f29402fb6ac140b52f8f12e06ece7bb104a0 Author: Darren Tucker Date: Thu Apr 22 22:26:08 2021 +1000 Remove now-unused 2nd arg to configs. commit cb4ff640d79b3c736879582139778f016bbb2cd7 Author: Darren Tucker Date: Wed Apr 21 01:08:04 2021 +1000 Add win10 test target. commit 4457837238072836b2fa3107d603aac809624983 Author: Darren Tucker Date: Tue Apr 20 23:31:29 2021 +1000 Add nbsd8 test target. commit bd4fba22e14da2fa196009010aabec5a8ba9dd42 Author: Darren Tucker Date: Sat Apr 17 09:55:47 2021 +1000 Add obsd51 target. commit 9403d0e805c77a5741ea8c3281bbe92558c2f125 Author: Darren Tucker Date: Fri Apr 16 18:14:25 2021 +1000 Add fbsd13 target. commit e86968280e358e62649d268d41f698d64d0dc9fa Author: Damien Miller Date: Fri Apr 16 13:55:25 2021 +1000 depend commit 2fb25ca11e8b281363a2a2a4dec4c497a1475d9a Author: Damien Miller Date: Fri Apr 16 13:53:02 2021 +1000 crank version in README and RPM spec files commit b2b60ebab0cb77b5bc02d364d72e13db882f33ae Author: djm@openbsd.org Date: Fri Apr 16 03:42:00 2021 +0000 upstream: openssh-8.6 OpenBSD-Commit-ID: b5f3e133c846127ec114812248bc17eff07c3e19 commit faf2b86a46c9281d237bcdec18c99e94a4eb820a Author: markus@openbsd.org Date: Thu Apr 15 16:24:31 2021 +0000 upstream: do not pass file/func to monitor; noted by Ilja van Sprundel; ok djm@ OpenBSD-Commit-ID: 85ae5c063845c410283cbdce685515dcd19479fa commit 2dc328023f60212cd29504fc05d849133ae47355 Author: Damien Miller Date: Wed Apr 14 11:42:55 2021 +1000 sshd don't exit on transient read errors openssh-8.5 introduced a regression that would cause sshd to exit because of transient read errors on the network socket (e.g. EINTR, EAGAIN). Reported by balu.gajjala AT gmail.com via bz3297 commit d5d6b7d76d171a2e6861609dcd92e714ee62ad88 Author: Damien Miller Date: Sat Apr 10 18:45:00 2021 +1000 perform report_failed_grab() inline commit ea996ce2d023aa3c6d31125e2c3ebda1cb42db8c Author: Damien Miller Date: Sat Apr 10 18:22:57 2021 +1000 dedicated gnome-ssk-askpass3 source Compatibility with Wayland requires that we use the gdk_seat_grab() API for grabbing mouse/keyboard, however these API don't exist in Gtk+2. This branches gnome-ssk-askpass2.c => gnome-ssk-askpass3.c and makes the changes to use the gdk_seat_grab() instead of grabbing mouse/focus separately via GDK. In the future, we can also use the branched file to avoid some API that has been soft-deprecated in GTK+3, e.g. gtk_widget_modify_fg commit bfa5405da05d906ffd58216eb77c4375b62d64c2 Author: Darren Tucker Date: Thu Apr 8 15:18:15 2021 +1000 Ensure valgrind-out exists. Normally the regress tests would create it, but running the unit tests on their own would fail because the directory did not exist. commit 1f189181f3ea09a9b08aa866f78843fec800874f Author: Darren Tucker Date: Thu Apr 8 15:17:19 2021 +1000 Pass OBJ to unit test make invocation. At least the Valgrind unit tests uses $OBJ. commit f42b550c281d28bd19e9dd6ce65069164f3482b0 Author: Darren Tucker Date: Thu Apr 8 14:20:12 2021 +1000 Add pattern for valgrind-unit. commit 19e534462710e98737478fd9c44768b50c27c4c6 Author: Darren Tucker Date: Thu Apr 8 13:31:08 2021 +1000 Run unit tests under valgrind. Run a separate build for the unit tests under Valgrind. They take long enough that running in parallel with the other Valgrind tests helps. commit 80032102d05e866dc2a48a5caf760cf42c2e090e Author: Darren Tucker Date: Thu Apr 8 13:25:57 2021 +1000 ifdef out MIN and MAX. In -portable, defines.h ensures that these are defined, so redefining potentially causes a warning. We don't just delete it to make any future code syncs a little but easier. bz#3293. commit d1bd184046bc310c405f45da3614a1dc5b3e521a Author: Darren Tucker Date: Wed Apr 7 10:23:51 2021 +1000 Remove only use of warn(). The warn() function is only used in one place in portable and does not exist upstream. Upgrade the only instance it's used to fail() (the privsep/sandbox+proxyconnect, from back when that was new) and remove the now-unused function. commit fea8f4b1aa85026ad5aee5ad8e1599a8d5141fe0 Author: Darren Tucker Date: Wed Apr 7 10:18:32 2021 +1000 Move make_tmpdir() into portable-specific area. Reduces diff vs OpenBSD and makes it more likely diffs will apply cleanly. commit 13e5fa2acffd26e754c6ee1d070d0afd035d4cb7 Author: dtucker@openbsd.org Date: Tue Apr 6 23:57:56 2021 +0000 upstream: Add TEST_SSH_ELAPSED_TIMES environment variable to print the elapsed time in seconds of each test. This depends on "date +%s" which is not specified by POSIX but is commonly implemented. OpenBSD-Regress-ID: ec3c8c19ff49b2192116a0a646ee7c9b944e8a9c commit ef4f46ab4387bb863b471bad124d46e8d911a79a Author: Darren Tucker Date: Wed Apr 7 09:59:15 2021 +1000 Move the TEST_SSH_PORT section down a bit. This groups the portable-specific changes together and makes it a little more likely that patches will apply cleanly. commit 3674e33fa70dfa1fe69b345bf576113af7b7be11 Author: Darren Tucker Date: Wed Apr 7 10:05:10 2021 +1000 Further split Valgrind tests. Even split in two, the Valgrind tests take by far the longest to run, so split them four ways to further increase parallelism. commit 961af266b861e30fce1e26170ee0dbb5bf591f29 Author: djm@openbsd.org Date: Tue Apr 6 23:24:30 2021 +0000 upstream: include "ssherr.h" not ; from Balu Gajjala via bz#3292 OpenBSD-Commit-ID: e9535cd9966eb2e69e73d1ede1f44905c30310bd commit e7d0a285dbdd65d8df16123ad90f15e91862f959 Author: Damien Miller Date: Wed Apr 7 08:50:38 2021 +1000 wrap struct rlimit in HAVE_GETRLIMIT too commit f283a6c2e0a9bd9369e18462acd00be56fbe5b0d Author: Damien Miller Date: Wed Apr 7 08:20:35 2021 +1000 wrap getrlimit call in HAVE_GETRLIMIT; bz3291 commit 679bdc4a5c9244f427a7aee9c14b0a0ed086da1f Author: dtucker@openbsd.org Date: Tue Apr 6 09:07:33 2021 +0000 upstream: Don't check return value of unsetenv(). It's part of the environment setup and not part of the actual test, and some platforms -portable runs on declare it as returning void, which prevents the test from compiling. OpenBSD-Regress-ID: 24f08543ee3cdebc404f2951f3e388cc82b844a1 commit 320af2f3de6333aa123f1b088eca146a245e968a Author: jmc@openbsd.org Date: Sun Apr 4 11:36:56 2021 +0000 upstream: remove stray inserts; from matthias schmidt OpenBSD-Commit-ID: 2c36ebdc54e14bbf1daad70c6a05479a073d5c63 commit 801f710953b24dd2f21939171c622eac77c7484d Author: jmc@openbsd.org Date: Sun Apr 4 06:11:24 2021 +0000 upstream: missing comma; from kawashima james OpenBSD-Commit-ID: 31cec6bf26c6db4ffefc8a070715ebef274e68ea commit b3ca08cb174266884d44ec710a84cd64c12414ea Author: Darren Tucker Date: Mon Apr 5 23:46:42 2021 +1000 Install libcbor with libfido2. commit f3ca8af87a4c32ada660da12ae95cf03d190c083 Author: Damien Miller Date: Sat Apr 3 18:21:08 2021 +1100 enable authopt and misc unit tests Neither were wired into the build, both required some build adaptations for -portable commit dc1b45841fb97e3d7f655ddbcfef3839735cae5f Author: djm@openbsd.org Date: Sat Apr 3 06:58:30 2021 +0000 upstream: typos in comments; GHPR#180 from Vill =?UTF-8?q?e=20Skytt=C3=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OpenBSD-Commit-ID: 93c732381ae0e2b680c79e67c40c1814b7ceed2c commit 53ea05e09b04fd7b6dea66b42b34d65fe61b9636 Author: djm@openbsd.org Date: Sat Apr 3 06:55:52 2021 +0000 upstream: sync CASignatureAlgorithms lists with reality. GHPR#174 from Matt Hazinski OpenBSD-Commit-ID: f05e4ca54d7e67b90fe58fe1bdb1d2a37e0e2696 commit 57ed647ee07bb883a2f2264231bcd1df6a5b9392 Author: Damien Miller Date: Sat Apr 3 17:47:37 2021 +1100 polish whitespace for portable files commit 31d8d231eb9377df474746a822d380c5d68d7ad6 Author: djm@openbsd.org Date: Sat Apr 3 06:18:40 2021 +0000 upstream: highly polished whitespace, mostly fixing spaces-for-tab and bad indentation on continuation lines. Prompted by GHPR#185 OpenBSD-Commit-ID: e5c81f0cbdcc6144df1ce468ec1bac366d8ad6e9 commit 34afde5c73b5570d6f8cce9b49993b23b77bfb86 Author: djm@openbsd.org Date: Sat Apr 3 05:54:14 2021 +0000 upstream: whitespace (tab after space) OpenBSD-Commit-ID: 0e2b3f7674e985d3f7c27ff5028e690ba1c2efd4 commit 7cd262c1c5a08cc7f4f30e3cab108ef089d0a57b Author: Darren Tucker Date: Sat Apr 3 16:59:10 2021 +1100 Save config.h and config.log on failure too. commit 460aee9298f365357e9fd26851c22e0dca51fd6a Author: djm@openbsd.org Date: Sat Apr 3 05:46:41 2021 +0000 upstream: fix incorrect plural; from Ville Skyt =?UTF-8?q?t=C3=A4=20via=20GHPR#181?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OpenBSD-Commit-ID: 92f31754c6296d8f403d7c293e09dc27292d22c9 commit 082804c14e548cada75c81003a3c68ee098138ee Author: djm@openbsd.org Date: Sat Apr 3 05:40:39 2021 +0000 upstream: ensure that pkcs11_del_provider() is called before exit - some PKCS#11 providers get upset if C_Initialize is not matched with C_Finalize. From Adithya Baglody via GHPR#234; ok markus OpenBSD-Commit-ID: f8e770e03b416ee9a58f9762e162add900f832b6 commit 464ebc82aa926dd132ec75a0b064574ef375675e Author: djm@openbsd.org Date: Sat Apr 3 05:28:43 2021 +0000 upstream: unused variable OpenBSD-Commit-ID: 85f6a394c8e0f60d15ecddda75176f112007b205 commit dc3c0be8208c488e64a8bcb7d9efad98514e0ffb Author: djm@openbsd.org Date: Sat Apr 3 05:21:46 2021 +0000 upstream: Fix two problems in string->argv conversion: 1) multiple backslashes were not being dequoted correctly and 2) quoted space in the middle of a string was being incorrectly split. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A unit test for these cases has already been committed prompted by and based on GHPR#223 by Eero Häkkinen; ok markus@ OpenBSD-Commit-ID: d7ef27abb4eeeaf6e167e9312e4abe9e89faf1e4 commit f75bcbba58a08c670727ece5e3f8812125969799 Author: Damien Miller Date: Sat Apr 3 16:22:48 2021 +1100 missing bits from 259d648e commit 4cbc4a722873d9b68cb5496304dc050d7168df78 Author: djm@openbsd.org Date: Wed Mar 31 21:59:26 2021 +0000 upstream: cannot effectively test posix-rename extension after changes in feature advertisment. OpenBSD-Regress-ID: 5e390bf88d379162aaa81b60ed86b34cb0c54d29 commit 259d648e63e82ade4fe2c2c73c8b67fe57d9d049 Author: djm@openbsd.org Date: Fri Mar 19 04:23:50 2021 +0000 upstream: add a test for misc.c:argv_split(), currently fails OpenBSD-Regress-ID: ad6b96d6ebeb9643b698b3575bdd6f78bb144200 commit 473ddfc2d6b602cb2d1d897e0e5c204de145cd9a Author: djm@openbsd.org Date: Fri Mar 19 03:25:01 2021 +0000 upstream: split OpenBSD-Regress-ID: f6c03c0e4c58b3b9e04b161757b8c10dc8378c34 commit 1339800fef8d0dfbfeabff71b34670105bcfddd2 Author: djm@openbsd.org Date: Wed Mar 31 22:16:34 2021 +0000 upstream: Use new limits@openssh.com protocol extension to let the client select good limits based on what the server supports. Split the download and upload buffer sizes to allow them to be chosen independently. In practice (and assuming upgraded sftp/sftp-server at each end), this increases the download buffer 32->64KiB and the upload buffer 32->255KiB. Patches from Mike Frysinger; ok dtucker@ OpenBSD-Commit-ID: ebd61c80d85b951b794164acc4b2f2fd8e88606c commit 6653c61202d104e59c8e741329fcc567f7bc36b8 Author: djm@openbsd.org Date: Wed Mar 31 21:58:07 2021 +0000 upstream: do not advertise protocol extensions that have been disallowed by the command-line options (e.g. -p/-P/-R); ok dtucker@ OpenBSD-Commit-ID: 3a8a76b3f5131741aca4b41bfab8d101c9926205 commit 71241fc05db4bbb11bb29340b44b92e2575373d8 Author: Damien Miller Date: Mon Mar 29 15:14:25 2021 +1100 gnome-ssh-askpass3 is a valid target here commit 8a9520836e71830f4fccca066dba73fea3d16bda Author: djm@openbsd.org Date: Fri Mar 19 02:22:34 2021 +0000 upstream: return non-zero exit status when killed by signal; bz#3281 ok dtucker@ OpenBSD-Commit-ID: 117b31cf3c807993077b596bd730c24da9e9b816 commit 1269b8a686bf1254b03cd38af78167a04aa6ec88 Author: djm@openbsd.org Date: Fri Mar 19 02:18:28 2021 +0000 upstream: increase maximum SSH2_FXP_READ to match the maximum packet size. Also handle zero-length reads that are borderline nonsensical but not explicitly banned by the spec. Based on patch from Mike Frysinger, feedback deraadt@ ok dtucker@ OpenBSD-Commit-ID: 4e67d60d81bde7b84a742b4ee5a34001bdf80d9c commit 860b67604416640e8db14f365adc3f840aebcb1f Author: djm@openbsd.org Date: Tue Mar 16 06:15:43 2021 +0000 upstream: don't let logging clobber errno before use OpenBSD-Commit-ID: ce6cca370005c270c277c51c111bb6911e1680ec commit 5ca8a9216559349c56e09039c4335636fd85c241 Author: Darren Tucker Date: Sat Mar 13 14:40:43 2021 +1100 Only call dh_set_moduli_file if using OpenSSL. Fixes link failure when configuring --without-openssl since dh.c is not linked in. commit 867a7dcf003c51d5a83f83565771a35f0d9530ac Author: Darren Tucker Date: Sat Mar 13 13:52:53 2021 +1100 Don't install moduli during tests. Now that we have TEST_SSH_MODULI_FILE pointing to the moduli in the soure directory we don't need to install the file to prevent warnings about it being missing. commit 0c054538fccf92b4a028008321d3711107bee6d5 Author: Darren Tucker Date: Sat Mar 13 13:51:26 2021 +1100 Point TEST_SSH_MODULI_FILE at our own moduli. This will allow the test to run without requiring a moduli file installed at the configured default path. commit 4d48219c72ab0c71238806f057f0e9630b7dd25c Author: jsg@openbsd.org Date: Fri Mar 12 05:18:01 2021 +0000 upstream: spelling OpenBSD-Commit-ID: 478bc3db04f62f1048ed6e1765400f3ab325e60f commit 88057eb6df912abf2678ea5c846d9d9cbc92752c Author: dtucker@openbsd.org Date: Fri Mar 12 04:08:19 2021 +0000 upstream: Add ModuliFile keyword to sshd_config to specify the location of the "moduli" file containing the groups for DH-GEX. This will allow us to run tests against arbitrary moduli files without having to install them. ok djm@ OpenBSD-Commit-ID: 8df99d60b14ecaaa28f3469d01fc7f56bff49f66 commit f07519a2af96109325b5a48b1af18b57601074ca Author: djm@openbsd.org Date: Fri Mar 12 03:43:40 2021 +0000 upstream: pwcopy() struct passwd that we're going to reuse across a bunch of library calls; bz3273 ok dtucker@ OpenBSD-Commit-ID: b6eafa977b2e44607b1b121f5de855107809b762 commit 69d6d4b0c8a88d3d1288415605f36e2df61a2f12 Author: dtucker@openbsd.org Date: Wed Mar 10 06:32:27 2021 +0000 upstream: Import regenerated moduli file. OpenBSD-Commit-ID: 7ac6c252d2a5be8fbad4c66d9d35db507c9dac5b commit e5895e8ecfac65086ea6b34d0d168409a66a15e1 Author: djm@openbsd.org Date: Wed Mar 10 04:58:45 2021 +0000 upstream: no need to reset buffer after send_msg() as that is done for us; patch from Mike Frysinger OpenBSD-Commit-ID: 565516495ff8362a38231e0f1a087b8ae66da59c commit 721948e67488767df0fa0db71ff2578ee2bb9210 Author: dtucker@openbsd.org Date: Sat Mar 13 01:52:16 2021 +0000 upstream: Add TEST_SSH_MODULI_FILE variable to allow overriding of the moduli file used during the test run. OpenBSD-Regress-ID: be10f785263120edb64fc87db0e0d6570a10220a commit 82fef71e20ffef425b932bec26f5bc46aa1ed41c Author: Darren Tucker Date: Fri Mar 12 15:58:57 2021 +1100 Allow (but return EACCES) fstatat64 in sandbox. This is apparently used in some configurations of OpenSSL when glibc has getrandom(). bz#3276, patch from Kris Karas, ok djm@ commit 1cd67ee15ce3d192ab51be22bc4872a6a7a4b6d9 Author: Darren Tucker Date: Fri Mar 12 13:16:10 2021 +1100 Move generic includes outside of ifdef. This ensures that the macros in log.h are defined in the case where either of --with-solaris-projects or --with-solaris-privs are used without --with-solaris-contracts. bz#3278. commit 2421a567a8862fe5102a4e7d60003ebffd1313dd Author: Darren Tucker Date: Wed Mar 10 17:41:21 2021 +1100 Import regenerated moduli file. commit e99080c05d9d48dbbdb022538533d53ae1bd567d Author: millert@openbsd.org Date: Sat Mar 6 20:36:31 2021 +0000 upstream: Fix PRINT macro, the suffix param to sshlog() was missing. Also remove redundant __func__ prefix from PRINT calls as the macro already adds __FILE__, __func__ and __LINE__. From Christos Zoulas. OK dtucker@ OpenBSD-Commit-ID: 01fdfa9c5541151b5461d9d7d6ca186a3413d949 commit 160db17fc678ceb5e3fd4a7e006cc73866f484aa Author: djm@openbsd.org Date: Wed Mar 3 22:41:49 2021 +0000 upstream: don't sshbuf_get_u32() into an enum; reported by goetze AT dovetail.com via bz3269 OpenBSD-Commit-ID: 99a30a8f1df9bd72be54e21eee5c56a0f050921a commit cffd033817a5aa388764b6661855dcdaabab0588 Author: sthen@openbsd.org Date: Wed Mar 3 21:40:16 2021 +0000 upstream: typo in other_hostkeys_message() display output, ok djm OpenBSD-Commit-ID: 276f58afc97b6f5826e0be58380b737603dbf5f5 commit 7fe141b96b13bd7dc67ca985e14d55b9bd8a03fd Author: djm@openbsd.org Date: Wed Mar 3 08:42:52 2021 +0000 upstream: needs FILE*; from Mike Frysinger OpenBSD-Commit-ID: dddb3aa9cb5792eeeaa37a1af67b5a3f25ded41d commit d2afd717e62d76bb41ab5f3ab4ce6f885c8edc98 Author: Damien Miller Date: Tue Mar 2 21:31:47 2021 +1100 update depend commit f0c4eddf7cf224ebcac1f07ac8afdb30c6e9fe0a Author: Damien Miller Date: Tue Mar 2 21:30:14 2021 +1100 update relnotes URL commit 67a8bb7fe62a381634db4c261720092e7d514a3d Author: Damien Miller Date: Tue Mar 2 21:29:54 2021 +1100 update RPM spec version numbers commit 0a4b23b11b9a4e6eec332dd5c6ab2ac6f62aa164 Author: djm@openbsd.org Date: Tue Mar 2 01:48:18 2021 +0000 upstream: openssh-8.5 OpenBSD-Commit-ID: 185e85d60fe042b8f8fa1ef29d4ef637bdf397d6 commit de3866383b6720ad4cad83be76fe4c8aa111a249 Author: Darren Tucker Date: Mon Mar 1 21:13:24 2021 +1100 Only upload config logs if configure fails. commit 85ff2a564ce838f8690050081176c1de1fb33116 Author: dtucker@openbsd.org Date: Sun Feb 28 22:56:30 2021 +0000 upstream: Add %k to list of keywords. From =?UTF-8?q?=20Eero=20H=C3=A4kkinenvia=20bz#3267?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OpenBSD-Commit-ID: 9c87f39a048cee2a7d1c8bab951b2f716256865e commit e774bac35933e71f924f4301786e7fb5bbe1422f Author: dtucker@openbsd.org Date: Sun Feb 28 01:50:47 2021 +0000 upstream: Do not try to reset signal handler for signal 0 in subprocess. Prevents spurious debug message. ok djm@ OpenBSD-Commit-ID: 7f9785e292dcf304457566ad4637effd27ad1d46 commit 351c5dbbd74ce300c4f058112f9731c867c6e225 Author: djm@openbsd.org Date: Sat Feb 27 23:42:37 2021 +0000 upstream: fix alphabetic ordering of options; spotted by Iain Morgan OpenBSD-Commit-ID: f955fec617d74af0feb5b275831a9fee813d7ad5 commit 0d1c9dbe578597f8d45d3ac7690df10d32d743e5 Author: Darren Tucker Date: Sat Feb 27 12:25:25 2021 +1100 zlib is now optional. commit b7c6ee7b437d9adfd19ef49d6c0f19f13f26f9b3 Author: Jeffrey H. Johnson <61629094+johnsonjh@users.noreply.github.com> Date: Sat Feb 27 01:04:58 2021 +0000 Fix punctuatio and typo in README.md. Some very minor fixes, missing 's' and punctuation. commit 6248b86074804983e8f7a2058856a516dbfe2924 Author: Damien Miller Date: Fri Feb 26 16:45:50 2021 +1100 Revert "ssh: optional bind interface if bind address specified." This reverts commit 5a878a71a3528c2626aa1d331934fd964782d41c. Apologies - I accidentally pushed this. commit 493339a940b13be6071629c3c2dd5a3b6fc17023 Author: Damien Miller Date: Fri Feb 26 15:45:38 2021 +1100 detech BSD libc hash functions in libbsd / libmd Some Linux distributions are shipping the BSD-style hashing functions (e.g. SHA256Update) in libbsd and/or libmd. Detect this situation to avoid header/replacement clashes later. ok dtucker@ commit 5a878a71a3528c2626aa1d331934fd964782d41c Author: Dmitrii Turlupov Date: Thu Feb 4 16:27:31 2021 +0300 ssh: optional bind interface if bind address specified. Allows the -b and -B options to be used together. For example, when the interface is in the VRF. commit 1fe4d70df94d3bcc2b35fd57cad6b5fc4b2d7b16 Author: djm@openbsd.org Date: Fri Feb 26 04:18:42 2021 +0000 upstream: remove this KEX fuzzer; it's awkward to use and doesn't play nice with popular fuzzing drivers like libfuzzer. AFAIK nobody has used it but me. OpenBSD-Regress-ID: cad919522b3ce90c147c95abaf81b0492ac296c9 commit 24a3a67bd7421740d08803b84bd784e764107928 Author: Darren Tucker Date: Fri Feb 26 11:49:19 2021 +1100 Remove macos-11.00 PAM test target too. These are failing apparently due to some kind of infrastructure problem, making it look like every commit is busted. commit 473201783f732ca8b0ec528b56aa55fa0d8cf717 Author: djm@openbsd.org Date: Fri Feb 26 00:16:58 2021 +0000 upstream: a bit more debugging behind #ifdef DEBUG_SK OpenBSD-Commit-ID: d9fbce14945721061cb322f0084c2165d33d1993 commit fd9fa76a344118fe1ef10b9a6c9e85d39599e9a8 Author: Darren Tucker Date: Fri Feb 26 01:15:10 2021 +1100 Remove macos-11.0 from the test target list. It has been consistently failing for the past few days with a github actions internal error. commit 476ac8e9d33dbf96ef97aab812b8d7089d0cdc24 Author: Philip Hands Date: Wed Feb 24 23:43:16 2021 +0100 tidy the $INSTALLKEY_SH code layout a little SSH-Copy-ID-Upstream: 78178aa5017222773e4c23d9001391eeaeca8983 commit 983e05ef3b81329d76d6a802b39ad0d1f637c06c Author: Jakub Jelen Date: Tue Sep 29 10:02:45 2020 +0000 if unable to add a missing newline, fail SSH-Copy-ID-Upstream: 76b25e18f55499ea9edb4c4d6dc4a80bebc36d95 commit 3594b3b015f6014591da88ba71bf6ff010be7411 Author: Philip Hands Date: Tue Oct 13 14:12:58 2020 +0200 use $AUTH_KEY_DIR, now that we have it since that was a change made since jjelen's commit was written also, quote the variables SSH-Copy-ID-Upstream: 588cd8e5cbf95f3443d92b9ab27c5d73ceaf6616 commit 333e25f7bc43cee6e36f766e39dad6f9918b318c Author: Jakub Jelen Date: Tue Sep 29 10:00:01 2020 +0000 restorecon the correct directory if using different path for authorized_keys file SSH-Copy-ID-Upstream: 791a3df47b48412c726bff6f7b1d190721e65d51 commit 9beeab8a37a49a9e3ffb1972fff6621ee5bd7a71 Author: djm@openbsd.org Date: Thu Feb 25 03:27:34 2021 +0000 upstream: s/PubkeyAcceptedKeyTypes/PubkeyAcceptedAlgorithms/ OpenBSD-Regress-ID: 3dbc005fa29f69dc23d97e433b6dffed6fe7cb69 commit 2dd9870c16ddbd83740adeead5030d6840288c8f Author: dtucker@openbsd.org Date: Wed Feb 24 23:12:35 2021 +0000 upstream: Rename pubkeyacceptedkeytypes to pubkeyacceptedalgorithms in test to match change to config-dump output. OpenBSD-Regress-ID: 74c9a4ad50306be873d032819d5e55c24eb74d5d commit b9225c3a1c3f5827e31d5d64a71b8e0504a25619 Author: dtucker@openbsd.org Date: Wed Feb 24 01:18:08 2021 +0000 upstream: Put obsolete aliases for hostbasedalgorithms and pubkeyacceptedalgorithms after their current names so that the config-dump mode finds and uses the current names. Spotted by Phil Pennock. OpenBSD-Commit-ID: 5dd10e93cccfaff3aaaa09060c917adff04a9b15 commit 8b8b60542d6652b2c91e0ef9e9cc81bcb65e6b42 Author: djm@openbsd.org Date: Tue Feb 23 21:55:08 2021 +0000 upstream: lots more s/key types/signature algorithms/ mostly in HostbasedAcceptedAlgorithms and HostKeyAlgorithms; prompted by Jakub Jelen OpenBSD-Commit-ID: 3f719de4385b1a89e4323b2549c66aae050129cb commit 0aeb508aaabc4818970c90831e3d21843c3c6d09 Author: djm@openbsd.org Date: Tue Feb 23 21:50:18 2021 +0000 upstream: Correct reference to signature algorithms as keys; from Jakub Jelen OpenBSD-Commit-ID: 36f7ecee86fc811aa0f8e21e7a872eee044b4be5 commit f186a020f2ba5f9c462a23293750e29ba0a746b1 Author: Darren Tucker Date: Tue Feb 23 16:05:22 2021 +1100 Add a couple more test VMs. commit ffcdd3d90e74176b3bb22937ad1f65a6c1cd3f9d Author: Darren Tucker Date: Mon Feb 22 08:09:27 2021 +1100 Valgrind test: split and move up list. Since the valgrind test takes so long it approaches the limit allowed by github, move it to the head of the list so it's the first one started and split the longest tests out into a second instance that runs concurrently with the first. commit c3b1636770785cc2830dedd0f22ef7d3d3491d6d Author: djm@openbsd.org Date: Tue Feb 23 00:05:31 2021 +0000 upstream: warn when the user specifies a ForwardAgent path that does not exist and exit if ExitOnForwardFailure is set; bz3264 OpenBSD-Commit-ID: 72f7875865e723e464c71bf8692e83110699bf26 commit 5fcb0514949d61aadaf4a89cf16eb78fb47491ec Author: Darren Tucker Date: Sat Feb 20 13:34:02 2021 +1100 Disable rlimit sandbox, doesn't work with valgrind Only run regress tests, runing unit tests as well makes it run longer than allowed y github. commit bb0b9bf45396c19486080d3eb0a159f94de7e6ba Author: Darren Tucker Date: Sat Feb 20 13:06:25 2021 +1100 Upload valgrind logs on failure. commit ebb3b75e974cb241c6b9b9f5881b09c7bd32b651 Author: Darren Tucker Date: Fri Feb 19 22:18:50 2021 +1100 Rename "vm" to "os" in selfhosted to match c-cpp. Should make it easier to share code or maybe merge at some point. commit 76c0be0fe0465cb2b975dbd409f8d38b55e55bcb Author: Darren Tucker Date: Fri Feb 19 22:15:22 2021 +1100 Upload regress failure logs in c-cpp too. commit 8751b6c3136f5225c40f41bbf29aa29e15795f6e Author: Darren Tucker Date: Fri Feb 19 22:13:36 2021 +1100 Comment out Solaris 64bit PAM build... until I can figure out why it's failing. commit e9f6d563c06886b277c6b9abafa99fa80726dc48 Author: Darren Tucker Date: Fri Feb 19 10:20:17 2021 +1100 Actually run Valgrind tests. commit 41d232e226624f1a81c17091c36b44c9010aae62 Author: Darren Tucker Date: Fri Feb 19 10:16:56 2021 +1100 Add test against Valgrind. commit e6528d91f12fba05f0ea64224091c9d0f38bdf1d Author: Darren Tucker Date: Thu Feb 18 16:30:01 2021 +1100 Add fbsd12 test target. commit 6506cb2798d98ff03a7cc06567c392a81f540680 Author: Darren Tucker Date: Thu Feb 18 15:21:13 2021 +1100 Remove unused arg. commit 93c31a623973b0fad508214593aab6ca94b11dcb Author: Darren Tucker Date: Thu Feb 18 14:54:07 2021 +1100 Add DEBUG_SK to kitchensink builds. commit 65085740d3574eeb3289d592f042df62c2689bb0 Author: Darren Tucker Date: Thu Feb 18 14:53:14 2021 +1100 Add bbone test target (arm32). commit 63238f5aed66148b8d6ca7bd5fb347d624200155 Author: djm@openbsd.org Date: Thu Feb 18 02:49:35 2021 +0000 upstream: Fix the hostkeys rotation extension documentation The documentation was lacking the needed want-reply field in the initial global request. https://github.com/openssh/openssh-portable/pull/218 by dbussink OpenBSD-Commit-ID: 051824fd78edf6d647a0b9ac011bf88e28775054 commit 34c5ef6e2d06d9f0e20cb04a9aebf67a6f96609a Author: djm@openbsd.org Date: Thu Feb 18 02:15:07 2021 +0000 upstream: make names in function prototypes match those in definition from https://github.com/openssh/openssh-portable/pull/225 by ZenithalHourlyRate OpenBSD-Commit-ID: 7c736307bf3f2c7cb24d6f82f244eee959485acd commit 88e3d4de31ab4f14cac658e9e0c512043b15b146 Author: djm@openbsd.org Date: Thu Feb 18 02:13:58 2021 +0000 upstream: unbreak SK_DEBUG builds from https://github.com/openssh/openssh-portable/pull/225 by ZenithalHourlyRate OpenBSD-Commit-ID: 28d7259ce1b04d025411464decfa2f1a097b43eb commit 788cbc5b74a53956ba9fff11e1ca506271a3597f Author: djm@openbsd.org Date: Thu Feb 18 00:30:17 2021 +0000 upstream: sftp-server: implement limits@openssh.com extension This is a simple extension that allows the server to clearly communicate transfer limits it is imposing so the client doesn't have to guess, or force the user to manually tune. This is particularly useful when an attempt to use too large of a value causes the server to abort the connection. Patch from Mike Frysinger; ok dtucker@ OpenBSD-Commit-ID: f96293221e5aa24102d9bf30e4f4ef04d5f4fb51 commit 324449a68d510720d0e4dfcc8e9e5a702fe6a48f Author: Damien Miller Date: Thu Feb 18 12:06:25 2021 +1100 support OpenSSL 3.x cipher IV API change OpenSSL renamed the "get current CIPHER_CTX" IV operation in 3.x. This uses the new name if available. https://github.com/openssl/openssl/issues/13411 bz#3238 ok dtucker@ commit 845fe9811c047063d935eca89188ed55c993626b Author: Damien Miller Date: Thu Feb 18 11:25:38 2021 +1100 prefer login_getpwclass() to login_getclass() FreeBSD has login_getpwclass() that does some special magic for UID=0. Prefer this to login_getclass() as its easier to emulate the former with the latter. Based on FreeBSD PR 37416 via Ed Maste; ok dtucker@ commit d0763c8d566119cce84d9806e419badf20444b02 Author: Darren Tucker Date: Thu Feb 18 10:45:27 2021 +1100 Fixing quoting for installing moduli on target guest. commit b3afc243bc820f323a09e3218e9ec8a30a3c1933 Author: Darren Tucker Date: Thu Feb 18 10:27:16 2021 +1100 Install moduli on target not host. commit f060c2bc85d59d111fa18a12eb3872ee4b9f7e97 Author: Damien Miller Date: Thu Feb 18 10:33:58 2021 +1100 don't free string returned by login_getcapstr(3) OpenBSD and NetBSD require the caller to free strings returned bu the login_* functions, but FreeBSD requires that callers don't. Fortunately in this case, we can harmlessly leak as the process is about to exec the shell/command. From https://reviews.freebsd.org/D28617 via Ed Maste; ok dtucker@ commit bc9b0c25703215501da28aa7a6539f96c0fa656f Author: Darren Tucker Date: Thu Feb 18 10:10:00 2021 +1100 Skip unit tests on sol11 to speed things up. commit 161873035c12cc22211fc73d07170ade47746bc5 Author: Darren Tucker Date: Thu Feb 18 10:09:27 2021 +1100 Remove SKIP_UNIT as it needs to be a make arg. commit 1c293868e4b4e8e74e3ea15b8dff90f6b089967a Author: Darren Tucker Date: Thu Feb 18 10:05:03 2021 +1100 Always intall moduli. Allows us to run tests without falling back to a fixed modulus. Ensure that the directory exists. commit 5c8f41ad100601ec2fdcbccdfe92890c31f81bbe Author: Darren Tucker Date: Thu Feb 18 09:59:09 2021 +1100 Quote SSHD_CONFOPTS in case it contains spaces. commit 4653116c1f5384ea7006e6396d9b53c33d218975 Author: Darren Tucker Date: Thu Feb 18 09:51:18 2021 +1100 Fix labels on targets (dots vs underscores). commit 4512047f57ca3c6e8cd68f0cc69be59e98b25287 Author: Darren Tucker Date: Wed Feb 17 21:47:48 2021 +1100 More compact representation of config matrix. commit 0406cd09f05c2e419b113dd4c0eac8bc34ec915b Author: Darren Tucker Date: Wed Feb 17 21:19:18 2021 +1100 Skip unit tests on hosted VMs to speed things up. commit 4582612e6147d766c336198c498740242fb8f1ec Author: Darren Tucker Date: Wed Feb 17 20:21:29 2021 +1100 Merge macos and ubuntu tests. commit 09f4b84654b71099559492e9aed5e1a38bf24815 Author: Darren Tucker Date: Wed Feb 17 18:41:30 2021 +1100 Convert most github hosted tests to new config structure. commit 65380ff7e054be1454e5ab4fd7bb9c66f8fcbaa9 Author: Darren Tucker Date: Wed Feb 17 18:27:36 2021 +1100 Only run selfhosted tests from selfhosted repo. commit f031366535650b88248ed7dbf23033afdf466240 Author: Darren Tucker Date: Fri Jan 15 14:11:43 2021 +1100 Add self-hosted runners for VMs of other platforms. Github only hosts a limited number of platforms, and the runner code is only supported on slightly wider range of platforms. To increase our test coverage beyond that, we run the runner natively on a VM host, where it runs a jobs that boot VMs of other platforms, waits for them to come up then runs the build and test by ssh'ing into the guest. This means that the minimum dependencies for the guests are quite low (basically just sshd, a compiler and make). The interface to the VM host is fairly simple (basically 3 scripts: vmstartup, vmrun and vmshutdown), but those are specific to the VM host so are not in the public repo. We also mount the working directory on the host via sshfs, so things like artifact upload by the runner also work. As part of this we are moving the per-test-target configs into a single place (.github/configs) where there will be referenced by a single short "config" key. I plan to make the github-hosted runners use this too. The self-hosted runners are run off a private repo on github since that prevents third parties from accessing them[0], and since runner quota is limited on private repos, we avoid running the tests we run on the public repo. [0] https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners#self-hosted-runner-security-with-public-repositories commit 64bbd7444d658ef7ee14a7ea5ccc7f5810279ee7 Author: dtucker@openbsd.org Date: Wed Feb 17 03:59:00 2021 +0000 upstream: Make sure puttygen is new enough to successfully run the PuTTY interop tests, otherwise skip them. OpenBSD-Regress-ID: 34565bb50b8aec58331ed02a5e9e0a9a929bef51 commit da0a9afcc446a30ca49dd216612c41ac3cb1f2d4 Author: markus@openbsd.org Date: Mon Feb 15 20:43:15 2021 +0000 upstream: ssh: add PermitRemoteOpen for remote dynamic forwarding with SOCKS ok djm@, dtucker@ OpenBSD-Commit-ID: 64fe7b6360acc4ea56aa61b66498b5ecc0a96a7c commit b696858a7f9db72a83d02cb6edaca4b30a91b386 Author: markus@openbsd.org Date: Mon Feb 15 20:36:35 2021 +0000 upstream: factor out opt_array_append; ok djm@ OpenBSD-Commit-ID: 571bc5dd35f99c5cf9de6aaeac428b168218e74a commit ad74fc127cc45567e170e8c6dfa2cfd9767324ec Author: dlg@openbsd.org Date: Mon Feb 15 11:09:22 2021 +0000 upstream: ProxyJump takes "none" to disable processing like ProxyCommand does ok djm@ jmc@ OpenBSD-Commit-ID: 941a2399da2193356bdc30b879d6e1692f18b6d3 commit 16eacdb016ccf38dd9959c78edd3a6282513aa53 Author: djm@openbsd.org Date: Fri Feb 12 03:49:09 2021 +0000 upstream: sftp: add missing lsetstat@openssh.com documentation patch from Mike Frysinger OpenBSD-Commit-ID: 9c114db88d505864075bfe7888b7c8745549715b commit e04fd6dde16de1cdc5a4d9946397ff60d96568db Author: djm@openbsd.org Date: Fri Feb 12 03:14:18 2021 +0000 upstream: factor SSH_AGENT_CONSTRAIN_EXTENSION parsing into its own function and remove an unused variable; ok dtucker@ OpenBSD-Commit-ID: e1a938657fbf7ef0ba5e73b30365734a0cc96559 commit 1bb130ed34721d46452529d094d9bbf045607d79 Author: Darren Tucker Date: Thu Feb 11 10:18:05 2021 +1100 Add __NR_futex_time64 to seccomp sandbox. This is apparently needed for (some) 32 bit platforms with glibc 2.33. Patch from nix at esperi.org.uk and jjelen at redhat.com via bz#3260. commit f88a7a431212a16e572ecabd559e632f369c363e Author: Darren Tucker Date: Sat Feb 6 09:37:01 2021 +1100 Add a hostname function for systems that don't have it. Some systems don't have a hostname command (it's not required by POSIX). The do have uname -n (which is), but as found by tim@ some others (eg UnixWare) do not report the FQDN from uname -n. commit 5e385a71ef2317856f37c91a98658eb12eb5a89c Author: dtucker@openbsd.org Date: Fri Feb 5 22:03:40 2021 +0000 upstream: Roll back the hostname->uname change in rev 1.10. It turns out uname -n doesn't do what we need for some platforms in portable, so we'll fix the original problem (that some other platforms don't have hostname at all) by providing wrapper function to implement it. OpenBSD-Regress-ID: 827a707d6201d5a8e196a8c28aec1d2c76c52341 commit b446c214279de50ed8388e54897eb1be5281c894 Author: dtucker@openbsd.org Date: Fri Feb 5 06:01:58 2021 +0000 upstream: hostname is not specified by POSIX but uname -n is, so use the latter for portability. Patch from Geert Hendrickx via github PR#208. OpenBSD-Regress-ID: d6a79c7c4d141a0d05ade4a042eb57dddbce89f3 commit 1cb6ce98d658e5fbdae025a3bd65793980e3b5d9 Author: David Carlier Date: Sat Nov 21 12:22:23 2020 +0000 Using explicit_memset for the explicit_bzero compatibility layer. Favoriting the native implementation in this case. commit 2e0beff67def2120f4b051b1016d7fbf84823e78 Author: Luca Weiss Date: Sun Nov 8 14:19:23 2020 +0100 Deny (non-fatal) statx in preauth privsep child. commit a35d3e911e193a652bd09eed40907e3e165b0a7b Author: dtucker@openbsd.org Date: Fri Feb 5 02:20:23 2021 +0000 upstream: Remove debug message from sigchld handler. While this works on OpenBSD it can cause problems on other platforms. From kircherlike at outlook.com via bz#3259, ok djm@ OpenBSD-Commit-ID: 3e241d7ac1ee77e3de3651780b5dc47b283a7668 commit 69338ab46afe9e3dfb7762ad65351d854077c998 Author: djm@openbsd.org Date: Tue Feb 2 22:36:59 2021 +0000 upstream: whitespace OpenBSD-Commit-ID: 544bb092e03fcbecb420196cd0f70af13ea868ad commit f71219a01d8f71c4b3ed7e456337a84ddba1653e Author: djm@openbsd.org Date: Tue Feb 2 22:36:46 2021 +0000 upstream: fix memleaks in private key deserialisation; enforce more consistency between redundant fields in private key certificate and private key body; ok markus@ OpenBSD-Commit-ID: dec344e414d47f0a7adc13aecf3760fe58101240 commit 3287790e78bf5b53c4a3cafb67bb5aa03e3910f0 Author: djm@openbsd.org Date: Tue Feb 2 22:35:14 2021 +0000 upstream: memleak on error path; ok markus@ OpenBSD-Commit-ID: 2091a36d6ca3980c81891a6c4bdc544e63cb13a8 commit 3dd0c64e08f1bba21d71996d635c7256c8c139d1 Author: djm@openbsd.org Date: Sun Jan 31 22:55:29 2021 +0000 upstream: more strictly enforce KEX state-machine by banning packet types once they are received. Fixes memleak caused by duplicate SSH2_MSG_KEX_DH_GEX_REQUEST (spotted by portable OpenSSH kex_fuzz via oss-fuzz #30078). ok markus@ OpenBSD-Commit-ID: 87331c715c095b587d5c88724694cdeb701c9def commit 7a92a324a2e351fabd0ba8ef9b434d3b12d54ee3 Author: dtucker@openbsd.org Date: Sun Jan 31 10:50:10 2021 +0000 upstream: Set linesize returned by getline to zero when freeing and NULLing the returned string. OpenBSD's getline handles this just fine, but some implementations used by -portable do not. ok djm@ OpenBSD-Commit-ID: 4d7bd5169d3397654247db9655cc69a9908d165c commit a5dfc5bae8c16e2a7caf564758d812c7672480b5 Author: Damien Miller Date: Sat Jan 30 16:32:29 2021 +1100 allow a fuzz case to contain more than one request loop until input buffer empty, no message consumed or 256 messages processed commit 0ef24ad60204022f7e33b6e9d171172c50514132 Author: Damien Miller Date: Sat Jan 30 16:28:23 2021 +1100 expect fuzz cases to have length prefix might make life a little easier for the fuzzer, e.g. it can now produce valid (multi-request) messages by smashing two cases together. commit de613f2713d2dfcd3b03c00e5558a40997f52712 Author: Damien Miller Date: Sat Jan 30 12:03:30 2021 +1100 ssh-agent fuzzer commit 7e96c877bcb2fb645355a687b8cb7347987c1c58 Author: Damien Miller Date: Sat Jan 30 12:02:46 2021 +1100 move keys out of kex_fuzz.cc into separate header add certificates and missing key types commit 76f46d75664fdaa1112739ca523ff85ee4eb52b4 Author: Damien Miller Date: Sat Jan 30 12:02:10 2021 +1100 some fixed test data (mostly keys) for fuzzing commit 7c2e3d6de1f2edb0c8b4725b4c2b56360e032b19 Author: djm@openbsd.org Date: Sat Jan 30 00:56:38 2021 +0000 upstream: add a SK_DUMMY_INTEGRATE define that allows the dummy security key middleware to be directly linked; useful for writing fuzzers, etc. OpenBSD-Regress-ID: 0ebd00159b58ebd85e61d8270fc02f1e45df1544 commit 1a4b92758690faa12f49079dd3b72567f909466d Author: djm@openbsd.org Date: Fri Jan 29 06:29:46 2021 +0000 upstream: fix the values of enum sock_type OpenBSD-Commit-ID: 18d048f4dbfbb159ff500cfc2700b8fb1407facd commit 8afaa7d7918419d3da6c0477b83db2159879cb33 Author: djm@openbsd.org Date: Fri Jan 29 06:28:10 2021 +0000 upstream: give typedef'd struct a struct name; makes the fuzzer I'm writing a bit easier OpenBSD-Commit-ID: 1052ab521505a4d8384d67acb3974ef81b8896cb commit 1e660115f0c7c4a750cd31e468ff889f33dd8088 Author: Damien Miller Date: Fri Jan 29 11:09:14 2021 +1100 fuzz diffie-hellman-group-exchange-sha1 kex too commit be5f0048ea2aaeddd27be7dcca23aaad345fa16c Author: Damien Miller Date: Fri Jan 29 11:03:35 2021 +1100 support for running kex fuzzer with null cipher commit 3d59e88c0e42182c3749b446ccd9027933c84be4 Author: Darren Tucker Date: Thu Jan 28 20:55:16 2021 +1100 make with -j2 to use available CPUs. commit 66dd9ddb5d2ea8c407908c8e8468c9d6e71db05b Author: Darren Tucker Date: Thu Jan 28 14:31:01 2021 +1100 Add test against openssl head and libressl head. commit 237dbb34e24b6b7ea888d54bda4d17da0a0fd0fa Author: Darren Tucker Date: Thu Jan 28 14:30:50 2021 +1100 Remove whitespace. commit d983e1732b8135d7ee8d92290d6dce35f736ab88 Author: djm@openbsd.org Date: Wed Jan 27 23:49:46 2021 +0000 upstream: fix leak: was double allocating kex->session_id buffer OpenBSD-Commit-ID: 3765f4cc3ae1df874dba9102a3588ba7b48b8183 commit 1134a48cdcef8e7363b9f6c73ebdd24405066738 Author: Damien Miller Date: Thu Jan 28 08:57:31 2021 +1100 correct kex name in disabled code commit 67f47f1965abafc1830a287761125c2f4790857e Author: djm@openbsd.org Date: Wed Jan 27 10:15:08 2021 +0000 upstream: this needs kex.h now OpenBSD-Commit-ID: c5a42166c5aa002197217421a971e48be7cb5d41 commit 39be3dc209f28f9c1ebfeba42adde8963b01e1cd Author: djm@openbsd.org Date: Wed Jan 27 10:05:28 2021 +0000 upstream: make ssh->kex->session_id a sshbuf instead of u_char*/size_t and use that instead of global variables containing copies of it. feedback/ok markus@ OpenBSD-Commit-ID: a4b1b1ca4afd2e37cb9f64f737b30a6a7f96af68 commit 4ca6a1fac328477c642329676d6469dba59019a3 Author: djm@openbsd.org Date: Wed Jan 27 09:26:53 2021 +0000 upstream: remove global variable used to stash compat flags and use the purpose-built ssh->compat variable instead; feedback/ok markus@ OpenBSD-Commit-ID: 7c4f200e112dae6bcf99f5bae1a5629288378a06 commit bba229b6f3328171f5e3ae85de443002523c0452 Author: Darren Tucker Date: Wed Jan 27 12:34:07 2021 +1100 Install moduli file before tests. Reduces warnings during test runs. commit 1b83185593a90a73860a503d753a95ca6d726c00 Author: Darren Tucker Date: Wed Jan 27 11:58:26 2021 +1100 Run one test with -Werror to catch warnings. commit d1532d90074b212054d5fd965f833231b09982f5 Author: dtucker@openbsd.org Date: Wed Jan 27 00:37:26 2021 +0000 upstream: Logical not bitwise or. ok djm@ OpenBSD-Commit-ID: d4dc855cf04951b93c45caa383e1ac9af0a3b0e5 commit 507b448a2465a53ab03a88acbc71cc51b48ca6ac Author: naddy@openbsd.org Date: Tue Jan 26 15:40:17 2021 +0000 upstream: move HostbasedAcceptedAlgorithms to the right place in alphabetical order OpenBSD-Commit-ID: d766820d33dd874d944c14b0638239adb522c7ec commit e26c980778b228bdd42b8353cc70101cf49b731b Author: dtucker@openbsd.org Date: Tue Jan 26 11:25:01 2021 +0000 upstream: Remove unused variables leftover from refactoring. ok djm@ OpenBSD-Commit-ID: 8b3ad58bff828fcf874e54b2fc27a4cf1d9505e8 commit e9f78d6b06fc323bba1890b2dc3b8423138fb35c Author: dtucker@openbsd.org Date: Tue Jan 26 05:32:21 2021 +0000 upstream: Rename HostbasedKeyTypes (ssh) and HostbasedAcceptedKeyTypes (sshd) to HostbasedAcceptedAlgorithms, which more accurately reflects its effect. This matches a previous change to PubkeyAcceptedAlgorithms. The previous names are retained as aliases. ok djm@ OpenBSD-Commit-ID: 49451c382adc6e69d3fa0e0663eeef2daa4b199e commit 48d0d7a4dd31154c4208ec39029d60646192f978 Author: Darren Tucker Date: Tue Jan 26 14:48:07 2021 +1100 Disable sntrup761 if compiler doesn't support VLAs. The sntrup761 code sourced from supercop uses variable length arrays. Although widely supported, they are not part of the ANSI C89 spec so if the compiler does not support VLAs, disable the sntrup761x25519-sha512@openssh.com KEX method by replacing the kex functions with no-op ones similar to what we do in kexecdh.c. This should allow OpenSSH to build with a plain C89 compiler again. Spotted by tim@, ok djm@. commit 37c70ea8d4f3664a88141bcdf0bf7a16bd5fd1ac Author: djm@openbsd.org Date: Tue Jan 26 00:54:49 2021 +0000 upstream: refactor key constraint parsing in ssh-agent Key constraints parsing code previously existed in both the "add regular key" and "add smartcard key" path. This unifies them but also introduces more consistency checking: duplicated constraints and constraints that are nonsensical for a particular situation (e.g. FIDO provider for a smartcard key) are now banned. ok markus@ OpenBSD-Commit-ID: 511cb1b1c021ee1d51a4c2d649b937445de7983c commit e0e8bee8024fa9e31974244d14f03d799e5c0775 Author: djm@openbsd.org Date: Tue Jan 26 00:53:31 2021 +0000 upstream: more ssh-agent refactoring Allow confirm_key() to accept an additional reason suffix Factor publickey userauth parsing out into its own function and allow it to optionally return things it parsed out of the message to its caller. feedback/ok markus@ OpenBSD-Commit-ID: 29006515617d1aa2d8b85cd2bf667e849146477e commit dfe18a295542c169ffde8533b3d7fe42088e2de7 Author: djm@openbsd.org Date: Tue Jan 26 00:51:30 2021 +0000 upstream: make struct hostkeys public; I have no idea why I made it opaque originally. ok markus@ OpenBSD-Commit-ID: e50780b34d4bbe628d69b2405b024dd749d982f3 commit 3b44f2513cae89c920e8fe927b9bc910a1c8c65a Author: djm@openbsd.org Date: Tue Jan 26 00:49:30 2021 +0000 upstream: move check_host_cert() from sshconnect,c to sshkey.c and refactor it to make it more generally usable and testable. ok markus@ OpenBSD-Commit-ID: 536f489f5ff38808c1fa711ba58d4579b636f9e4 commit 1fe16fd61bb53944ec510882acc0491abd66ff76 Author: djm@openbsd.org Date: Tue Jan 26 00:47:47 2021 +0000 upstream: use recallocarray to allocate the agent sockets table; also clear socket entries that are being marked as unused. spinkle in some debug2() spam to make it easier to watch an agent do its thing. ok markus OpenBSD-Commit-ID: 74582c8e82e96afea46f6c7b6813a429cbc75922 commit cb7b22ea20a01332c81c0ddcb3555ad50de9cce2 Author: djm@openbsd.org Date: Tue Jan 26 00:46:17 2021 +0000 upstream: factor out common code in the agent client Add a ssh_request_reply_decode() function that sends a message to the agent, reads and parses a success/failure reply. Use it for all requests that only expect success/failure ok markus@ OpenBSD-Commit-ID: e0c1f4d5e6cfa525d62581e2b8de93be0cb85adb commit d1e578afe7cd48140ad6e92a453f9b035363fd7f Author: djm@openbsd.org Date: Mon Jan 25 06:00:17 2021 +0000 upstream: make ssh hostbased authentication send the signature algorithm in its SSH2_MSG_USERAUTH_REQUEST packets instead of the key type. This make HostbasedAcceptedAlgorithms do what it is supposed to - filter on signature algorithm and not key type. spotted with dtucker@ ok markus@ OpenBSD-Commit-ID: 25bffe19f0326972f5728170f7da81d5f45c78c6 commit 95eca1e195a3b41baa1a725c2c5af8a09d885e4b Author: Darren Tucker Date: Sat Jan 23 18:26:05 2021 +1100 ifdef new instance of sin6_scope_id Put inside HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID similar to existing instance. Should fix error on UnixWare 7. commit 6ffdcdda128045226dda7fbb3956407978028a1e Author: dtucker@openbsd.org Date: Mon Jan 18 11:43:34 2021 +0000 upstream: Fix long->int for convtime tests here too. Spotted by tobhe@. OpenBSD-Regress-ID: a87094f5863312d00938afba771d25f788c849d0 commit b55b7565f15327d82ad7acbddafa90b658c5f0af Author: dtucker@openbsd.org Date: Fri Jan 22 02:46:40 2021 +0000 upstream: PubkeyAcceptedKeyTypes->PubkeyAcceptedAlgorithms here too. OpenBSD-Commit-ID: 3b64a640f8ce8c21d9314da9df7ce2420eefde3a commit ee9c0da8035b3168e8e57c1dedc2d1b0daf00eec Author: dtucker@openbsd.org Date: Fri Jan 22 02:44:58 2021 +0000 upstream: Rename PubkeyAcceptedKeyTypes keyword to PubkeyAcceptedAlgorithms. While the two were originally equivalent, this actually specifies the signature algorithms that are accepted. Some key types (eg RSA) can be used by multiple algorithms (eg ssh-rsa, rsa-sha2-512) so the old name is becoming increasingly misleading. The old name is retained as an alias. Prompted by bz#3253, help & ok djm@, man page help jmc@ OpenBSD-Commit-ID: 0346b2f73f54c43d4e001089759d149bfe402ca5 commit a8e798feabe36d02de292bcfd274712cae1d8d17 Author: dtucker@openbsd.org Date: Fri Jan 15 02:58:11 2021 +0000 upstream: Change types in convtime() unit test to int to match change its new type. Add tests for boundary conditions and fix convtime to work up to INT_MAX. ok djm@ OpenBSD-Regress-ID: ba2b81e9a3257fff204b020affe85b604a44f97e commit 9bde1a420626da5007bf7ab499fa2159b9eddf72 Author: dtucker@openbsd.org Date: Fri Jan 15 04:31:25 2021 +0000 upstream: Make output buffer larger to prevent potential truncation warnings from compilers not smart enough to know the strftime calls won't ever fully fill "to" and "from". ok djm@ OpenBSD-Commit-ID: 83733f1b01b82da88b9dd1769475952aff10bdd7 commit 02da325f10b214219eae2bb1bc2d3bf0c2f13f9f Author: dtucker@openbsd.org Date: Fri Jan 15 02:58:11 2021 +0000 upstream: Change types in convtime() unit test to int to match change its new type. Add tests for boundary conditions and fix convtime to work up to INT_MAX. ok djm@ OpenBSD-Commit-ID: 01dc0475f1484ac2f47facdfcf9221f9472145de commit 5339ab369c225b40bc64d5ec3374f5c91b3ad609 Author: dtucker@openbsd.org Date: Fri Jan 15 02:32:41 2021 +0000 upstream: In waitfd(), when poll returns early we are subtracting the elapsed time from the timeout each loop, so we only want to measure the elapsed time the poll() in that loop, not since the start of the function. Spotted by chris.xj.zhu at gmail.com, ok djm@ OpenBSD-Commit-ID: 199df060978ee9aa89b8041a3dfaf1bf7ae8dd7a commit a164862dfa863b54b7897f66e1dd75437f086c11 Author: rob@openbsd.org Date: Thu Jan 14 19:45:06 2021 +0000 upstream: Minor grammatical correction. OK jmc@ OpenBSD-Commit-ID: de0fad0581e212b2750751e479b79c18ff8cac02 commit 8635e7df7e3a3fbb4a4f6cd5a7202883b2506087 Author: Darren Tucker Date: Wed Jan 13 18:00:57 2021 +1100 Merge Mac OS X targets into a single config. commit ac112ade990585c511048ed4edaf2d9fc92b61f0 Author: Darren Tucker Date: Tue Jan 12 19:22:47 2021 +1100 Add Mac OS X test targets. commit 1050109b4b2884bf50fd1b3aa084c7fd0a42ae90 Author: anatasluo Date: Mon Jan 11 13:51:39 2021 +0000 Remove duplicated declaration in fatal.c . commit 7d0f8a3369579dfe398536eb4e3da7bc15da9599 Author: dtucker@openbsd.org Date: Mon Jan 11 04:48:22 2021 +0000 upstream: Correct spelling of persourcenetblocksize in config-dump mode. OpenBSD-Commit-ID: ecdc49e2b6bde6b6b0e52163d621831f6ac7b13d commit ba328bd7a6774f30daaf90b83f1933cc4afc866c Author: dtucker@openbsd.org Date: Sat Jan 9 12:31:46 2021 +0000 upstream: Adjust kexfuzz to addr.c/addrmatch.c split. OpenBSD-Regress-ID: 1d8d23bb548078020be2fb52c4c643efb190f0eb commit b08ef25552443e94c0857d5e3806dd019ccc55d7 Author: dtucker@openbsd.org Date: Sat Jan 9 12:24:30 2021 +0000 upstream: Update unittests for addr.c/addrmatch.c split. OpenBSD-Regress-ID: de2b415fb7af084a91c6ef147a90482d8f771eef commit 6d30673fedec2d251f4962c526fd0451f70c4d97 Author: dtucker@openbsd.org Date: Mon Jan 11 02:12:57 2021 +0000 upstream: Change convtime() from returning long to returning int. On platforms where sizeof(int) != sizeof(long), convtime could accept values >MAX_INT which subsequently truncate when stored in an int during config parsing. bz#3250, ok djm@ OpenBSD-Commit-ID: 8fc932683d6b4660d52f50911d62bd6639c5db31 commit 7a57adb8b07b2ad0aead4b2e09ee18edc04d0481 Author: jmc@openbsd.org Date: Sat Jan 9 12:51:12 2021 +0000 upstream: add a comma to previous; OpenBSD-Commit-ID: 9139433701c0aa86a0d3a6c7afe10d1c9c2e0869 commit 3a923129534b007c2e24176a8655dec74eca9c46 Author: dtucker@openbsd.org Date: Sat Jan 9 12:10:02 2021 +0000 upstream: Add PerSourceMaxStartups and PerSourceNetBlockSize options which provide more fine grained MaxStartups limits. Man page help jmc@, feedback & ok djm@ OpenBSD-Commit-ID: e2f68664e3d02c0895b35aa751c48a2af622047b commit d9a2bc71693ea27461a78110005d5a2d8b0c6a50 Author: dtucker@openbsd.org Date: Sat Jan 9 11:58:50 2021 +0000 upstream: Move address handling functions out into their own file in order to reuse them for per-source maxstartups limiting. Supplement with some additional functions from djm's flowtools that we'll also need. ok djm@ (as part of a larger diff). OpenBSD-Commit-ID: e3e7d9ccc6c9b82e25cfef0ec83598e8e2327cbf commit b744914fcb76d70761f1b667de95841b3fc80a56 Author: Darren Tucker Date: Sat Jan 9 00:36:05 2021 +1100 Add test against Graphene hardened malloc. commit 6cb52d5bf771f6769b630fce35a8e9b8e433044f Author: djm@openbsd.org Date: Fri Jan 8 04:49:13 2021 +0000 upstream: make CheckHostIP default to 'no'. It doesn't provide any perceptible value and makes it much harder for hosts to change host keys, particularly ones that use IP-based load-balancing. ok dtucker@ OpenBSD-Commit-ID: 0db98413e82074f78c7d46784b1286d08aee78f0 commit 309b642e1442961b5e57701f095bcd4acd2bfb5f Author: Darren Tucker Date: Fri Jan 8 15:50:41 2021 +1100 Run tests with sudo for better coverage. commit c336644351fa3c715a08b7a292e309e72792e71e Author: Darren Tucker Date: Fri Jan 8 14:26:32 2021 +1100 Add Ubuntu 16.04 and 20.04 test targets. commit 4c7af01f9dcc1606dec033e7665a042cb0d8ec52 Author: djm@openbsd.org Date: Fri Jan 8 02:57:24 2021 +0000 upstream: If a signature operation on a FIDO key fails with a "incorrect PIN" reason and no PIN was initially requested from the user, then request a PIN and retry the operation. This smoothes over a few corner cases including FIDO devices that require PINs for all hosted credentials, biometric FIDO devices that fall back to requiring PIN when reading the biometric failed, devices that don't implement reading credProtect status for downloaded keys and probably a few more cases that I haven't though of yet. ok dtucker@ OpenBSD-Commit-ID: 176db8518933d6a5bbf81a2e3cf62447158dc878 commit 64ddd0fe68c4a7acf99b78624f8af45e919cd317 Author: djm@openbsd.org Date: Fri Jan 8 02:44:14 2021 +0000 upstream: don't try to use timespeccmp(3) directly as a qsort(3) comparison function - it returns 0/1 and not the -1/0/1 that qsort expectes. fixes sftp "ls -ltr" under some circumstances. Based on patch by Masahiro Matsuya via bz3248. OpenBSD-Commit-ID: 65b5e9f18bb0d10573868c3516de6e5170adb163 commit 599df78f3008cf78af21f8977be3e1dd085f8e2e Author: dtucker@openbsd.org Date: Fri Jan 8 02:33:13 2021 +0000 upstream: Update the sntrup761 creation script and generated code: - remove unneeded header files and typedefs and rely on crypto_api.h - add defines to map types used to the crypto_api ones instead of typedefs. This prevents typedef name collisions in -portable. - remove CRYPTO_NAMESPACE entirely instead of making it a no-op - delete unused functions and make the remaining ones that aren't exported static. ok djm@ OpenBSD-Commit-ID: 7b9d0cf3acd5a3c1091da8afe00c904d38cf5783 commit 16448ff529affda7e2a15ee7c3200793abde0759 Author: djm@openbsd.org Date: Fri Jan 8 02:19:24 2021 +0000 upstream: mention that DisableForwarding is valid in a sshd_config Match block reported by Fredrik Eriksson in bz3239 OpenBSD-Commit-ID: 3a71c3d84b597f5e43e4b40d5232797daf0993f6 commit 91bac5e95b1b0debf9b2b4f05c20dcfa96b368b9 Author: dtucker@openbsd.org Date: Mon Jan 4 21:58:58 2021 +0000 upstream: estructure sntrup761.sh to process all files in a single list, which will make it easier to reorder. Re-inline int32_MINMAX. ok tobhe@ OpenBSD-Commit-ID: d145c6c19b08bb93c9e14bfaa7af589d90f144c0 commit 4d96a3ebab2224f17e639a15078e03be1ad3736d Author: tobhe@openbsd.org Date: Sun Jan 3 18:05:21 2021 +0000 upstream: Prevent redefinition of `crypto_int32' error with gcc3. Fixes compilation on luna88k. Feedback millert@ Found by and ok aoyama@ OpenBSD-Commit-ID: f305ddfe575a26cc53431af3fde3f4aeebed9ba6 commit a23954eeb930ccc8a66a2710153730769dba31b6 Author: Darren Tucker Date: Fri Jan 1 22:00:49 2021 +1100 Undef int32 after sort routines. This prevents typedef'ing crypto_int32 twice, in sntrup761.c and crypto_api.h, which some compilers (at least some GCCs) don't accept. commit 148b8a661c3f93e4b6d049ee902de3d521261fbc Author: Damien Miller Date: Thu Dec 31 12:47:22 2020 +1100 fix: missing pieces of previous commit commit 3d999be7b987c848feda718cfcfcdc005ddf670d Author: tobhe@openbsd.org Date: Wed Dec 30 14:13:28 2020 +0000 upstream: Use int64_t for intermediate values in int32_MINMAX to prevent signed 32-bit integer overflow. Found by and ok djm@ ok markus@ OpenBSD-Commit-ID: 4f0704768e34cf45fdd792bac4011c6971881bb3 commit 5c1953bf98732da5a76c706714ac066dbfa015ac Author: Damien Miller Date: Tue Dec 29 12:40:54 2020 +1100 adapt KEX fuzzer to PQ kex change commit 659864fe81dbc57eeed3769c462679d83e026640 Author: djm@openbsd.org Date: Tue Dec 29 01:02:15 2020 +0000 upstream: Adapt to replacement of sntrup4591761x25519-sha512@tinyssh.org with sntrup761x25519-sha512@openssh.com. Also test sntrup761x25519-sha512@openssh.com in unittests/kex OpenBSD-Regress-ID: cfa3506b2b077a9cac1877fb521efd2641b6030c commit 2c71cec020219d69df84055c59eba5799a1233ec Author: djm@openbsd.org Date: Tue Dec 29 00:59:15 2020 +0000 upstream: Update/replace the experimental post-quantim hybrid key exchange method based on Streamlined NTRU Prime (coupled with X25519). The previous sntrup4591761x25519-sha512@tinyssh.org method is replaced with sntrup761x25519-sha512@openssh.com. Per the authors, sntrup4591761 was replaced almost two years ago by sntrup761. The sntrup761 implementaion, like sntrup4591761 before it, is public domain code extracted from the SUPERCOP cryptography benchmark suite (https://bench.cr.yp.to/supercop.html). Thanks for Daniel J Bernstein for guidance on algorithm selection. Patch from Tobias Heider; feedback & ok markus@ and myself (note this both the updated method and the one that it replaced are disabled by default) OpenBSD-Commit-ID: 2bf582b772d81ee24e911bb6f4b2aecfd39338ae commit 09d070ccc3574ae0d7947d212ed53c7268ef7e1f Author: jmc@openbsd.org Date: Tue Dec 22 07:40:26 2020 +0000 upstream: tweak the description of KnownHostsCommand in ssh_conf.5, and add entries for it to the -O list in scp.1 and sftp.1; ok djm OpenBSD-Commit-ID: aba31ebea03f38f8d218857f7ce16a500c3e4aff commit 931c93389a80e32272712459b1102d303844453d Author: Damien Miller Date: Tue Dec 22 19:43:55 2020 +1100 whitespace at EOL commit 397b1c4d393f97427283a4717e9015a2bd31b8a5 Author: Damien Miller Date: Tue Dec 22 19:42:37 2020 +1100 whitespace at EOL commit 33fa3ac547e5349ca34681cce6727b2f933dff0a Author: Darren Tucker Date: Tue Dec 22 19:21:26 2020 +1100 Improve AIX text. commit 0f2e21c9dca89598b694932b5b05848380a23ec0 Author: Darren Tucker Date: Tue Dec 22 18:56:54 2020 +1100 Include stdio.h for FILE in misc.h. Fixes build on at least OpenBSD. commit 3e9811e57b57ee66b0f70d99d7258da3153b0e8a Author: Damien Miller Date: Tue Dec 22 18:31:50 2020 +1100 ensure $LOGNAME is set in tests commit 3eb647cbb34d87a063aa7714256c6e56103fffda Author: djm@openbsd.org Date: Tue Dec 22 06:47:24 2020 +0000 upstream: more detail for failing tests OpenBSD-Regress-ID: c68c0e5a521cad7e7f68e54c54ebf86d6c10ee1d commit 2873f19570d4d8758be24dbf78332be9a779009b Author: djm@openbsd.org Date: Tue Dec 22 06:03:36 2020 +0000 upstream: regress test for KnownHostsCommand OpenBSD-Regress-ID: ffc77464320b6dabdcfa0a72e0df02659233a38a commit 0121aa87bab9ad2365de2d07f2832b56d5ff9871 Author: tb@openbsd.org Date: Tue Dec 22 03:05:31 2020 +0000 upstream: Remove lines accidentally left behind in the ProxyJump parsing fix r1.345. ok djm OpenBSD-Commit-ID: fe767c108c8117bea33767b080ff62eef2c55f5c commit da4bf0db942b5f0278f33238b86235e5813d7a5a Author: djm@openbsd.org Date: Tue Dec 22 00:15:22 2020 +0000 upstream: add a ssh_config KnownHostsCommand that allows the client to obtain known_hosts data from a command in addition to the usual files. The command accepts bunch of %-expansions, including details of the connection and the offered server host key. Note that the command may be invoked up to three times per connection (see the manpage for details). ok markus@ OpenBSD-Commit-ID: 2433cff4fb323918ae968da6ff38feb99b4d33d0 commit a34e14a5a0071de2036826a00197ce38c8b4ba8b Author: djm@openbsd.org Date: Tue Dec 22 00:12:22 2020 +0000 upstream: move subprocess() from auth.c to misc.c make privilege dropping optional but allow it via callbacks (to avoid need to link uidswap.c everywhere) add some other flags (keep environment, disable strict path safety check) that make this more useful for client-side use. feedback & ok markus@ OpenBSD-Commit-ID: a80ea9fdcc156f1a18e9c166122c759fae1637bf commit 649205fe388b56acb3481a1b2461f6b5b7c6efa6 Author: dtucker@openbsd.org Date: Mon Dec 21 22:48:41 2020 +0000 upstream: Remove explicit rijndael-cbc@lysator.liu.se test since the cipher was removed. OpenBSD-Regress-ID: aa93cddb4ecd9bc21446a79008a1a53050e64f17 commit 03e93c753d7c223063ad8acaf9a30aa511e5f931 Author: dtucker@openbsd.org Date: Mon Dec 21 11:09:32 2020 +0000 upstream: Remove the pre-standardization cipher rijndael-cbc@lysator.liu.se. It is an alias for aes256-cbc which was standardized in RFC4253 (2006), has been deprecated and disabled by default since OpenSSH 7.2 (2016) and was only briefly documented in ssh.1 in 2001. This will reduce the amount of work the cipher/kex regression tests need to do by a little bit. ok markus@ djm@ OpenBSD-Commit-ID: fb460acc18290a998fd70910b19c29b4e4f199ad commit a11ca015879eab941add8c6bdaaec7d41107c6f5 Author: djm@openbsd.org Date: Mon Dec 21 09:19:53 2020 +0000 upstream: properly fix ProxyJump parsing; Thanks to tb@ for pointing out my error (parse_ssh_uri() can return -1/0/1, that I missed). Reported by Raf Czlonka via bugs@ ok tb@ OpenBSD-Commit-ID: a2991a3794bcaf1ca2b025212cce11cdb5f6b7d6 commit d97fb879724f1670bf55d9adfea7278a93c33ae2 Author: djm@openbsd.org Date: Mon Dec 21 01:31:06 2020 +0000 upstream: adapt to API change in hostkeys_foreach()/load_hostkeys() OpenBSD-Regress-ID: dcb468514f32da49a446372453497dc6eeafdbf3 commit bf7eb3c266b7fd4ddda108fcf72b860af2af6406 Author: djm@openbsd.org Date: Fri Oct 16 14:02:24 2020 +0000 upstream: few more things needs match.c and addrmatch.c now that log.c calls match_pattern_list() OpenBSD-Regress-ID: f7c95c76b150d0aeb00a67858b9579b7d1b2db74 commit 2c64f24e27a5e72a7f59e515fc4f4985355237ae Author: Darren Tucker Date: Mon Dec 21 14:02:56 2020 +1100 Pull in missing rev 1.2. commit 0f504f592d15d8047e466eb7453067a6880992a8 Author: djm@openbsd.org Date: Sun Dec 20 23:40:19 2020 +0000 upstream: plumb ssh_conn_info through to sshconnect.c; feedback/ok markus@ OpenBSD-Commit-ID: e8d14a09cda3f1dc55df08f8a4889beff74e68b0 commit 729b05f59ded35483acef90a6f88aa03eae33b29 Author: djm@openbsd.org Date: Sun Dec 20 23:38:00 2020 +0000 upstream: allow UserKnownHostsFile=none; feedback and ok markus@ OpenBSD-Commit-ID: c46d515eac94a35a1d50d5fd71c4b1ca53334b48 commit b4c7cd1185c5dc0593d47eafcc1a34fda569dd1d Author: djm@openbsd.org Date: Sun Dec 20 23:36:51 2020 +0000 upstream: load_hostkeys()/hostkeys_foreach() variants for FILE* Add load_hostkeys_file() and hostkeys_foreach_file() that accept a FILE* argument instead of opening the file directly. Original load_hostkeys() and hostkeys_foreach() are implemented using these new interfaces. Add a u_int note field to the hostkey_entry and hostkey_foreach_line structs that is passed directly from the load_hostkeys() and hostkeys_foreach() call. This is a lightweight way to annotate results between different invocations of load_hostkeys(). ok markus@ OpenBSD-Commit-ID: 6ff6db13ec9ee4edfa658b2c38baad0f505d8c20 commit 06fbb386bed666581095cb9cbc7a900e02bfe1b7 Author: tobhe@openbsd.org Date: Sat Dec 19 22:09:21 2020 +0000 upstream: Print client kem key with correct length. ok markus@ OpenBSD-Commit-ID: 91689e14a4fc6c270e265a32d1c8faba63a45755 commit 0ebead6593e2441e4af2735bbe2cd097607cd0d3 Author: djm@openbsd.org Date: Thu Dec 17 23:28:50 2020 +0000 upstream: fix possible error("%s", NULL) on error paths OpenBSD-Commit-ID: 0b3833c2cb985453ecca1d76803ebb8f3b736a11 commit d060bc7f6e6244f001e658208f53e3e2ecbbd382 Author: djm@openbsd.org Date: Thu Dec 17 23:26:11 2020 +0000 upstream: refactor client percent_expand() argument passing; consolidate the common arguments into a single struct and pass that around instead of using a bunch of globals. ok markus@ OpenBSD-Commit-ID: 035e6d7ca9145ad504f6af5a021943f1958cd19b commit 43026da035cd266db37df1f723d5575056150744 Author: djm@openbsd.org Date: Thu Dec 17 23:10:27 2020 +0000 upstream: prepare readconf.c for fuzzing; remove fatal calls and fix some (one-off) memory leaks; ok markus@ OpenBSD-Commit-ID: 91c6aec57b0e7aae9190de188e9fe8933aad5ec5 commit bef92346c4a808f33216e54d6f4948f9df2ad7c1 Author: djm@openbsd.org Date: Mon Dec 14 03:13:12 2020 +0000 upstream: use _PATH_SSH_USER_DIR instead of hardcoded .ssh in path OpenBSD-Commit-ID: 5c1048468813107baa872f5ee33ba51623630e01 commit a5ab499bd2644b4026596fc2cb24a744fa310666 Author: Damien Miller Date: Fri Dec 4 14:01:27 2020 +1100 basic KEX fuzzer; adapted from Markus' unittest commit 021ff33e383c77b11badd60cec5b141a3e3fa532 Author: Damien Miller Date: Fri Dec 4 13:57:43 2020 +1100 use options that work with recent clang commit e4d1a0b40add800b6e9352b40c2223e44acc3a45 Author: djm@openbsd.org Date: Fri Dec 4 02:41:10 2020 +0000 upstream: shuffle a few utility functions into sftp-client.c; from Jakub Jelen OpenBSD-Commit-ID: fdeb1aae1f6149b193f12cd2af158f948c514a2a commit ace12dc64f8e3a2496ca48d36b53cb3c0a090755 Author: djm@openbsd.org Date: Fri Dec 4 02:29:56 2020 +0000 upstream: make ssh_free(NULL) a no-op OpenBSD-Commit-ID: 42cb285d94789cefe6608db89c63040ab0a80fa0 commit 3b98b6e27f8a122dbfda9966b1afeb3e371cce91 Author: djm@openbsd.org Date: Fri Dec 4 02:29:25 2020 +0000 upstream: memleak of DH public bignum; found with libfuzzer OpenBSD-Commit-ID: 0e913b542c3764b100b1571fdb0d0e5cc086fe97 commit 553b90feedd7da5b90901d73005f86705456d686 Author: djm@openbsd.org Date: Fri Dec 4 02:27:57 2020 +0000 upstream: fix minor memleak of kex->hostkey_alg on rekex OpenBSD-Commit-ID: 2c3969c74966d4ccdfeff5e5f0df0791919aef50 commit ac0364b85e66eb53da2f9618f699ba6bd195ceea Author: djm@openbsd.org Date: Fri Dec 4 02:27:08 2020 +0000 upstream: typos: s/hex/kex/ in error messages OpenBSD-Commit-ID: 43a026c9571dd779ec148de1829cf5a6b6651905 commit ee22db7c5885a1d90219202c0695bc621aa0409b Author: djm@openbsd.org Date: Fri Dec 4 02:25:13 2020 +0000 upstream: make program name be const OpenBSD-Commit-ID: ece25680ec637fdf20502721ccb0276691df5384 commit 2bcbf679de838bb77a8bd7fa18e100df471a679c Author: dtucker@openbsd.org Date: Mon Nov 30 05:36:39 2020 +0000 upstream: Ignore comments at the end of config lines in ssh_config, similar to what we already do for sshd_config. bz#2320, with & ok djm@ OpenBSD-Commit-ID: bdbf9fc5bc72b1a14266f5f61723ed57307a6db4 commit b755264e7d3cdf1de34e18df1af4efaa76a3c015 Author: dtucker@openbsd.org Date: Sat Nov 28 12:52:32 2020 +0000 upstream: Include cipher.h for declaration of cipher_by_name. OpenBSD-Commit-ID: ddfebbca03ca0e14e00bbad9d35f94b99655d032 commit 022def7bd16c3426a95e25f57cb259d54468341c Author: djm@openbsd.org Date: Sat Nov 28 03:27:59 2020 +0000 upstream: check result of strchr() against NULL rather than searched-for characters; from zhongjubin@huawei.com OpenBSD-Commit-ID: e6f57de1d4a4d25f8db2d44e8d58d847e247a4fe commit 57bf03f0217554afb8980f6697a7a0b88658d0a9 Author: dtucker@openbsd.org Date: Fri Nov 27 10:12:30 2020 +0000 upstream: Document ssh-keygen -Z, sanity check its argument earlier and provide a better error message if it's not correct. Prompted by bz#2879, ok djm@ jmc@ OpenBSD-Commit-ID: 484178a173e92230fb1803fb4f206d61f7b58005 commit 33313ebc1c7135085676db62189e3520341d6b73 Author: djm@openbsd.org Date: Fri Nov 27 00:49:58 2020 +0000 upstream: Set the specified TOS/DSCP for interactive use prior to TCP connect. The connection phase of the SSH session is time-sensitive (due to server side login grace periods) and is frequently interactive (e.g. entering passwords). The ultimate interactive/bulk TOS/DSCP will be set after authentication completes. ok dtucker@ OpenBSD-Commit-ID: f31ab10d9233363a6d2c9996007083ba43a093f1 commit b2bcec13f17ce9174238a704e91d52203e916432 Author: djm@openbsd.org Date: Fri Nov 27 00:37:10 2020 +0000 upstream: clean up passing of struct passwd from monitor to preauth privsep process. No longer copy entire struct w/ pointer addresses, but pass remaining scalar fields explicitly, Prompted by Yuichiro NAITO, feedback Thorsten Glaser; ok dtucker@ OpenBSD-Commit-ID: 9925df75a56732c43f3663e70dd15ff413ab3e53 commit 19af04e2231155d513e24fdc81fbec2217ae36a6 Author: djm@openbsd.org Date: Sun Nov 22 22:38:26 2020 +0000 upstream: when loading PKCS#11 keys, include the key fingerprints and provider/slot information in debug output. OpenBSD-Commit-ID: 969a089575d0166a9a364a9901bb6a8d9b8a1431 commit 9b9465ea856e15b9e9890b4ecb4110d7106e7766 Author: djm@openbsd.org Date: Sun Nov 22 22:37:11 2020 +0000 upstream: when mentioning that the host key has changed, don't report the type because it is ambiguous as to whether it referred to the known or new host key. bz3216; ok dtucker@ OpenBSD-Commit-ID: 2d5ce4a83dbcf44e340a572e361decad8aab7bad commit 637017a7dd3281d3f2df804993cc27c30dbfda47 Author: Darren Tucker Date: Wed Nov 25 17:38:46 2020 +1100 Use "=" not "==" in string test. POSIX says "=" is string comparison and some shells (eg HP-UX) will complain about "==". commit 9880f3480f9768897f3b8e714d5317fb993bc5b3 Author: Darren Tucker Date: Fri Nov 20 17:16:51 2020 +1100 Restore correct flags during localtime_r check. We were restoring the wrong thing CPPFLAGS (we used CFLAGS) for any platform that doesn't have localtime_r. commit 41935882f4e82de60dbd6e033eabe79e1b963518 Author: dtucker@openbsd.org Date: Fri Nov 20 03:16:56 2020 +0000 upstream: When doing an sftp recursive upload or download of a read-only directory, ensure that the directory is created with write and execute permissions in the interim so that we can actually complete the transfer, then set the directory permission as the final step. (The execute bit is only likely to be an issue with a non-POSIX server). bz#3222, ok djm@ OpenBSD-Commit-ID: a82606212f2796e31f0e1af94a63355a7ad5d903 commit 0f90440ca70abab947acbd77795e9f130967956c Author: Darren Tucker Date: Fri Nov 20 13:37:54 2020 +1100 Add new pselect6_time64 syscall on ARM. This is apparently needed on armhfp/armv7hl. bz#3232, patch from jjelen at redhat.com. commit 3a7c46c72b6a1f643b1fc3589cd20d8320c3d9e1 Author: dtucker@openbsd.org Date: Fri Nov 20 02:14:16 2020 +0000 upstream: Explicitly initialize all members of the find_by_key_ctx struct. Initializing a single member should be enough (the spec says the remainder should be initialized as per the static rules) but some GCCs warn on this which prevents us testing with -Werror on those. ok deraadt@ djm@ OpenBSD-Commit-ID: 687126e60a27d30f02614760ef3c3ae4e8d6af28 commit 076cb616b87d1ea1d292973fcd0ba38c08ea6832 Author: dtucker@openbsd.org Date: Thu Nov 19 23:05:05 2020 +0000 upstream: draft-ietf-secsh-architecture is now RFC4251. OpenBSD-Commit-ID: cb0bb58c2711fb5ed519507659be1dcf179ed403 commit 85cceda21f1471548e04111aefe2c4943131c1c8 Author: dtucker@openbsd.org Date: Tue Nov 17 11:23:58 2020 +0000 upstream: Specify that the KDF function is bcrypt. Based on github PR#214 from rafork, ok markus@, mdoc correction jmc@ OpenBSD-Commit-ID: d8f2853e7edbcd483f31b50da77ab80ffa18b4ef commit 5b9720f9adbd70ba5a994f407fe07a7d016d8d65 Author: djm@openbsd.org Date: Sun Nov 15 22:34:58 2020 +0000 upstream: revert r1.341; it breaks ProxyJump; reported by sthen@ OpenBSD-Commit-ID: 6ac2f945b26cb86d936eed338f77861d6da8356a commit 04088725ec9c44880c01799b588cd4ba47b3e8bc Author: djm@openbsd.org Date: Fri Nov 13 07:30:44 2020 +0000 upstream: scrub keyboard-interactive authentication prompts coming from the server through asmprintf() prior to display; suggested by and ok dtucker@ OpenBSD-Commit-ID: 31fe93367645c37fbfe4691596bf6cf1e3972a58 commit 5442b491d0ee4bb82f6341ad0ee620ef3947f8c5 Author: djm@openbsd.org Date: Fri Nov 13 04:53:12 2020 +0000 upstream: prefix keyboard interactive prompts with (user@host) to make it easier to determine which connection they are associated with in cases like scp -3, ProxyJump, etc. bz#3224 ok dtucker OpenBSD-Commit-ID: 67e6189b04b46c867662f8a6759cf3ecb5f59170 commit 2992e4e7014ac1047062acfdbbf6feb156fef616 Author: Darren Tucker Date: Fri Nov 13 17:56:11 2020 +1100 Remove use of TIME_WITH_SYS_TIME. It was only set by the recently removed AC_HEADER_TIME macro, replace with simple inclusions of both sys/time.h and time.h. Should prevent mis-detection of struct timespec. commit e3f27006f15abacb7e89fda3f5e9a0bd420b7e38 Author: Damien Miller Date: Fri Nov 13 14:20:43 2020 +1100 Revert "detect Linux/X32 systems" This reverts commit 5b56bd0affea7b02b540bdbc4d1d271b0e4fc885. The approach used was incorrect; discussion in bz#3085 commit e51dc7fab61df36e43f3bc64b673f88d388cab91 Author: Damien Miller Date: Fri Nov 13 13:22:15 2020 +1100 SELinux has deprecated security_context_t (it was only ever a char* anyway) commit b79add37d118276d67f3899987b9f0629c9449c3 Author: Darren Tucker Date: Fri Nov 13 13:43:30 2020 +1100 Remove obsolete AC_HEADER_TIME macro. AC_HEADER_TIME is marked as obsolete in autoconf-2.70 and as far as I can tell everything we have that might be old enough to need it doesn't. commit d5d05cdb3d4efd4a618aa52caab5bec73097c163 Author: djm@openbsd.org Date: Thu Nov 12 22:56:00 2020 +0000 upstream: when prompting the user to accept a new hostkey, display any other host names/addresses already associated with the key. E.g. > The authenticity of host 'test (10.0.0.1)' can't be established. > ECDSA key fingerprint is SHA256:milU4MODXm8iJQI18wlsbPG7Yup+34fuNNmV08qDnax. > This host key is known by the following other names/addresses: > ~/.ssh/known_hosts:1: host.example.org,10.0.0.1 > ~/.ssh/known_hosts:2: [hashed name] > ~/.ssh/known_hosts:3: [hashed name] > ~/.ssh/known_hosts:4: host > ~/.ssh/known_hosts:5: [host]:2222 > Are you sure you want to continue connecting (yes/no/[fingerprint])? feedback and ok markus@ OpenBSD-Commit-ID: f6f58a77b49f1368b5883b3a1f776447cfcc7ef4 commit 819b44e8b9af6ce18d3ec7505b9f461bf7991a1f Author: dtucker@openbsd.org Date: Thu Nov 12 22:38:57 2020 +0000 upstream: Prevent integer overflow when ridiculously large ConnectTimeout is specified, capping the effective value (for most platforms) at 24 days. bz#3229, ok djm@ OpenBSD-Commit-ID: 62d4c4b7b87d111045f8e9f28b5b532d17ac5bc0 commit add926dd1bbe3c4db06e27cab8ab0f9a3d00a0c2 Author: djm@openbsd.org Date: Wed Nov 11 05:22:32 2020 +0000 upstream: fix logic error that broke URI parsing in ProxyJump directives; ok dtucker@ OpenBSD-Commit-ID: 96d48839b1704882a0e9a77898f5e14b2d222705 commit 4340dd43928dfe746cb7e75fe920b63c0d909a9a Author: claudio@openbsd.org Date: Tue Nov 10 07:46:20 2020 +0000 upstream: Free the previously allocated msg buffer after writing it out. OK djm@ OpenBSD-Commit-ID: 18c055870fc75e4cb9f926c86c7543e2e21d7fa4 commit fcf429a4c69d30d8725612a55b37181594da8ddf Author: Darren Tucker Date: Wed Nov 11 12:30:46 2020 +1100 Prevent excessively long username going to PAM. This is a mitigation for a buffer overflow in Solaris' PAM username handling (CVE-2020-14871), and is only enabled for Sun-derived PAM implementations. This is not a problem in sshd itself, it only prevents sshd from being used as a vector to attack Solaris' PAM. It does not prevent the bug in PAM from being exploited via some other PAM application. Based on github PR#212 from Mike Scott but implemented slightly differently. ok tim@ djm@ commit 10dce8ff68ef615362cfcab0c0cc33ce524e7682 Author: djm@openbsd.org Date: Sun Nov 8 23:19:03 2020 +0000 upstream: unbreak; missing NULL check OpenBSD-Commit-ID: 6613dfab488123f454d348ef496824476b8c11c0 commit d5a0cd4fc430c8eda213a4010a612d4778867cd9 Author: djm@openbsd.org Date: Sun Nov 8 22:37:24 2020 +0000 upstream: when requesting a security key touch on stderr, inform the user once the touch has been recorded; requested by claudio@ ok markus@ OpenBSD-Commit-ID: 3b76ee444490e546b9ea7f879e4092ee0d256233 commit 292bcb2479deb27204e3ff796539c003975a5f7a Author: Darren Tucker Date: Mon Nov 9 00:33:35 2020 +1100 Remove preprocessor directive from log macro calls. Preprocessor directives inside macro calls, such as the new log macros, are undefined behaviour and do not work with, eg old GCCs. Put the entire log call inside the ifdef for OPENSSL_HAS_NISTP521. commit 71693251b7cbb7dd89aaac18815147124732d0d3 Author: dtucker@openbsd.org Date: Sun Nov 8 12:10:20 2020 +0000 upstream: Add a comment documenting the source of the moduli group sizes. OpenBSD-Commit-ID: aec0725ce607630caaa62682624c6763b350391c commit 4d94b031ff88b015f0db57e140f481bff7ae1a91 Author: dtucker@openbsd.org Date: Sun Nov 8 11:46:12 2020 +0000 upstream: Replace WITH_OPENSSL ifdefs in log calls with a macro. The log calls are themselves now macros, and preprocessor directives inside macro arguments are undefined behaviour which some compilers (eg old GCCs) choke on. It also makes the code tidier. ok deraadt@ OpenBSD-Commit-ID: cc12a9029833d222043aecd252d654965c351a69 commit 6d2564b94e51184eb0b73b97d13a36ad50b4f810 Author: Darren Tucker Date: Fri Nov 6 17:11:16 2020 +1100 Fix function body for variadic macro test. AC_LANG_PROGRAM puts its second argument inside main() so we don't need to do it ourselves. commit 586f9bd2f5980e12f8cf0d3c2a761fa63175da52 Author: Darren Tucker Date: Fri Nov 6 16:53:24 2020 +1100 Remove AC_PROC_CC_C99 obsoleted in autoconf 2.70. Since we only use it to make sure we can handle variadic macros, explicitly check only for that. with & ok djm@ commit a019e353df04de1b2ca78d91b39c393256044ad7 Author: Darren Tucker Date: Fri Nov 6 13:56:41 2020 +1100 Replace AC_TRY_COMPILE obsoleted in autoconf 2.70. Replace with the equivalent AC_COMPILE_IFELSE. commit 771b7795c0ef6a2fb43b4c6c66b615c2085cb9cd Author: Darren Tucker Date: Fri Nov 6 13:55:33 2020 +1100 Move AC_PROG_CC_C99 to immediately afer AC_PROG_CC. This puts the related C version selection output in the same place. commit e5591161f21ab493c6284a85ac3c0710ad94998f Author: Darren Tucker Date: Fri Nov 6 13:54:17 2020 +1100 AC_CHECK_HEADER() is obsoleted in autoconf 2.70. Replace with the non-obsoleted AC_CHECK_HEADERS(). commit 05bcd0cadf160fd4826a2284afa7cba6ec432633 Author: djm@openbsd.org Date: Tue Nov 3 22:53:12 2020 +0000 upstream: fold consecutive '*' wildcards to mitigate combinatorial explosion of recursive searches; ok dtucker OpenBSD-Commit-ID: d18bcb39c40fb8a1ab61153db987e7d11dd3792b commit 7d680448db5858dc76307663f78d0b8d3c2b4a3d Author: djm@openbsd.org Date: Fri Oct 30 01:50:07 2020 +0000 upstream: print reason in fatal error message when kex_assemble_namelist() fails OpenBSD-Commit-ID: a9975ee8db6c98d6f32233d88051b2077ca63dab commit 95d1109fec7e89ad21f2a97e92bde1305d32a353 Author: djm@openbsd.org Date: Thu Oct 29 03:13:06 2020 +0000 upstream: fix sshd_config SetEnv directive inside Match blocks; part of github PR#201 from github user manuelm OpenBSD-Commit-ID: 9772e3748abff3ad65ae8fc43d026ed569b1d2bc commit b12b835dc022ba161afe68348e05a83dfbcb1515 Author: djm@openbsd.org Date: Thu Oct 29 03:01:18 2020 +0000 upstream: fix type of nid in type_bits_valid(); github PR#202 from github user thingsconnected OpenBSD-Commit-ID: 769d2b040dec7ab32d323daf54b854dd5dcb5485 commit 1a14c13147618144d1798c36a588397ba9008fcc Author: djm@openbsd.org Date: Thu Oct 29 02:52:43 2020 +0000 upstream: whitespace; no code change OpenBSD-Commit-ID: efefc1c47e880887bdee8cd2127ca93177eaad79 commit 815209abfdd2991fb92ad7d2e33374916cdcbcf4 Author: djm@openbsd.org Date: Thu Oct 29 02:47:23 2020 +0000 upstream: UpdateHostkeys: fixed/better detection of host keys that exist under other names and addresses; spotted by and debugged with lots of help from jca@ OpenBSD-Commit-ID: 5113d7f550bbd48243db1705afbf16b63792d4b7 commit a575cf44e59a65506c67bddb62a712208a7a279c Author: Duncan Eastoe Date: Wed Oct 21 10:11:10 2020 +0100 session.c: use "denylist" terminology Follow upstream (6d755706a0059eb9e2d63517f288b75cbc3b4701) language improvements in this portable-specific code. commit 33267feaffd5d98aa56d2f0b3a99ec352effe938 Author: Damien Miller Date: Tue Oct 27 16:46:31 2020 +1100 Remove checks for strict POSIX mkdtemp() We needed a mkdtemp() that accepted template paths that did not end in XXXXXX a long time ago for KRB4, but that code is long deprecated. We no longer need to replace mkdtemp() for strictly following POSIX. ok dtucker@ commit 492d70e18bad5a8c97d05f5eddac817171e88d2c Author: dtucker@openbsd.org Date: Mon Oct 26 00:39:04 2020 +0000 upstream: Minor man page fixes (capitalization, commas) identified by the manpage-l10n project via bz#3223. feedback deraadt@, ok jmc@ OpenBSD-Commit-ID: ab83af0daf18369244a72daaec6c4a58a9eb7e2c commit eab2888cfc6cc4e2ef24bd017da9835a0f365f3f Author: dtucker@openbsd.org Date: Mon Oct 19 22:49:23 2020 +0000 upstream: Adapt XMSS to new logging infrastructure. With markus@, ok djm@. OpenBSD-Commit-ID: 9c35ec3aa0f710e4e3325187ceff4fa3791686de commit f7bd11e4941620991f3e727cd0131b01f0311a58 Author: djm@openbsd.org Date: Mon Oct 19 08:07:08 2020 +0000 upstream: fix SEGV on fatal() errors spotted by dtucker@ OpenBSD-Commit-ID: 75f155a1ac61e364ed00dc379e2c42df81067ce2 commit 7715a3b171049afa1feffb1d5a1245dfac36ce99 Author: Darren Tucker Date: Mon Oct 19 10:54:41 2020 +1100 Use fatal_fr not fatal_r when passing r. Caught by the PAM -Werror tinderbox build. commit 816036f142ecd284c12bb3685ae316a68d2ef190 Author: djm@openbsd.org Date: Sun Oct 18 11:32:01 2020 +0000 upstream: use the new variant log macros instead of prepending __func__ and appending ssh_err(r) manually; ok markus@ OpenBSD-Commit-ID: 1f14b80bcfa85414b2a1a6ff714fb5362687ace8 commit 9e2c4f64224f68fb84c49b5182e449f94b0dc985 Author: djm@openbsd.org Date: Sun Oct 18 11:21:59 2020 +0000 upstream: variants of the log methods that append a ssherr.h string from a supplied error code; ok markus@ OpenBSD-Commit-ID: aed98c4435d48d036ae6740300f6a8357b7cc0bf commit 28cb0a4b03940d1ee576eb767a81a4113bdc917e Author: djm@openbsd.org Date: Sun Oct 18 11:14:27 2020 +0000 upstream: remove a level of macro indirection; ok markus@ OpenBSD-Commit-ID: 0c529d06e902c5d1a6b231e1bec6157f76dc67c9 commit 9cac1db52e6c4961c447910fe02cd68a3b2f9460 Author: djm@openbsd.org Date: Sun Oct 18 11:13:45 2020 +0000 upstream: add some variant log.h calls that prepend the calling function name; ok markus@ OpenBSD-Commit-ID: 4be1b2e2455b271ddb7457bc195c5367644f4e48 commit d55dfed34ef6ef1f028d552a90d5f3dba8dd6f7b Author: Damien Miller Date: Sat Oct 17 22:55:24 2020 +1100 missing header commit 999d7cb79a3a73d92a6dfbf174c33da0d984c7a2 Author: Damien Miller Date: Sat Oct 17 22:47:52 2020 +1100 sync regress/misc/sk-dummy/fatal.c commit 3554b4afa38b3483a3302f1be18eaa6f843bb260 Author: djm@openbsd.org Date: Sat Oct 17 01:28:20 2020 +0000 upstream: make the log functions that exit (sshlogdie(), sshfatal(), etc) have identical signatures. Makes things a bit more consistent... OpenBSD-Commit-ID: bd0ae124733389d7c0042e135c71ee9091362eb9 commit 616029a85ad7529b24bb8c4631d9607c0d6e7afe Author: jmc@openbsd.org Date: Fri Oct 16 14:34:33 2020 +0000 upstream: add space between macro arg and punctuation; OpenBSD-Commit-ID: bb81e2ed5a77832fe62ab30a915ae67cda57633e commit f812a36cee5727147bc897d34ab9af068dd4561e Author: Damien Miller Date: Sat Oct 17 12:03:34 2020 +1100 check for and require a C99 capable compiler recent logging changes use __VA_ARGS__. commit f9ea6515202b59a1e2d5b885cafc1b12eff33016 Author: Damien Miller Date: Sat Oct 17 11:51:20 2020 +1100 logging is now macros, remove function pointers commit 0f938f998626e8359324f803157cd7c9f8f403e2 Author: Damien Miller Date: Sat Oct 17 11:42:26 2020 +1100 adapt sk-dummy's fatal implementation to changes commit afbd9ec9e2dbad04834ce7ce53e58740434f32a5 Author: Damien Miller Date: Sat Oct 17 11:33:13 2020 +1100 fix netcat build problem commit 793b583d097381730adaf6f68bed3c343139a013 Author: djm@openbsd.org Date: Fri Oct 16 13:26:13 2020 +0000 upstream: LogVerbose keyword for ssh and sshd Allows forcing maximum debug logging by file/function/line pattern- lists. ok markus@ OpenBSD-Commit-ID: c294c25732d1b4fe7e345cb3e044df00531a6356 commit 752250caabda3dd24635503c4cd689b32a650794 Author: djm@openbsd.org Date: Fri Oct 16 13:24:45 2020 +0000 upstream: revised log infrastructure for OpenSSH log functions receive function, filename and line number of caller. We can use this to selectively enable logging via pattern-lists. ok markus@ OpenBSD-Commit-ID: 51a472610cbe37834ce6ce4a3f0e0b1ccc95a349 commit acadbb3402b70f72f14d9a6930ad41be97c2f9dc Author: djm@openbsd.org Date: Fri Oct 16 02:37:12 2020 +0000 upstream: use do_log2 instead of function pointers to different log functions OpenBSD-Commit-ID: 88077b826d348c58352a6b394755520f4e484480 commit 95b0bcfd1531d59e056ae8af27bb741391f26ab0 Author: djm@openbsd.org Date: Wed Oct 14 00:55:17 2020 +0000 upstream: make UpdateHostkeys still more conservative: refuse to proceed if one of the keys offered by the server is already in known_hosts under another name. This avoid collisions between address entries for different host aliases when CheckHostIP=yes Also, do not attempt to fix known_hosts with incomplete host/ip matches when there are no new or deprecated hostkeys. OpenBSD-Commit-ID: 95c19842f7c41f9bd9c92aa6441a278c0fd0c4a3 commit a336ce8c2c55547cc00e0070a18c55f30bb53fb6 Author: kn@openbsd.org Date: Mon Oct 12 08:36:36 2020 +0000 upstream: Zap unused family parameter from ssh_connect_direct() sshconnect.c r1.241 from 2013 made it unused; found while reading code. OK djm OpenBSD-Commit-ID: 219ba6d7f9925d0b7992918612680399d86712b5 commit e545d94b713effab8e6c7dfabbfb76c1d84d7498 Author: Philip Hands Date: Sun Oct 4 00:15:46 2020 +0200 shift contents of long $() into filter_ids() This was prompted by the fact that posh does not deal with $() that contains comments where the comment includes an odd number of single-quotes. It seems to get befuddled into trying to find the matching quote. Regardless, making a function for filtering the unneeded ids seems much neater than avoiding apostrophes, so that's what I've done. SSH-Copy-ID-Upstream: 3dab3366a584427045c8a690a93282f02c09cf24 commit fd360174596047b52aa1cddda74d85012a03ca4b Author: Philip Hands Date: Sat Oct 3 23:15:16 2020 +0200 combine if/elif to avoid duplication of the action SSH-Copy-ID-Upstream: 42aeb1cc53d3f7f6e78edc210fb121fda0834914 commit f7c3a39b016dd77709ecbf18da8282f967b86cd7 Author: Philip Hands Date: Sat Oct 3 21:45:16 2020 +0200 shellcheck tidyage SSH-Copy-ID-Upstream: 5b08f840e78ac544288b3983010a1b0585e966fd commit 108676c3f26be6c873db0dd8754063699908727b Author: Philip Hands Date: Sat Oct 3 21:10:03 2020 +0200 tidy up test of $SCRATCH_DIR creation SSH-Copy-ID-Upstream: 2d8b22d96c105d87743ffe8874887b06f8989b93 commit a9c9e91a82bc1a2cf801b4e3ef27a941dbd27717 Author: Philip Hands Date: Wed Sep 16 16:13:30 2020 +0200 add -s flag: to install keys via SFTP This is prompted by: https://bugzilla.mindrot.org/show_bug.cgi?id=3201 Thanks go to Matthias Blümel for the idea, and the helpful patch, from which this patch grew. SSH-Copy-ID-Upstream: f7c76dc64427cd20287a6868f672423b62057614 commit f92424970c02b78852ff149378c7f2616ada4ccf Author: djm@openbsd.org Date: Sun Oct 11 22:14:38 2020 +0000 upstream: UpdateHostkeys: check for keys under other names Stop UpdateHostkeys from automatically removing deprecated keys from known_hosts files if the same keys exist under a different name or address to the host that is being connected to. This avoids UpdateHostkeys from making known_hosts inconsistent in some cases. For example, multiple host aliases sharing address-based known_hosts on different lines, or hosts that resolves to multiple addresses. ok markus@ OpenBSD-Commit-ID: 6444a705ba504c3c8ccddccd8d1b94aa33bd11c1 commit d98f14b5328922ae3085e07007d820c4f655b57a Author: djm@openbsd.org Date: Sun Oct 11 22:13:37 2020 +0000 upstream: UpdateHostkeys: better CheckHostIP handling When preparing to update the known_hosts file, fully check both entries for both the host and the address (if CheckHostIP enabled) and ensure that, at the end of the operation, entries for both are recorded. Make sure this works with HashKnownHosts too, which requires maintaining a list of entry-types seen across the whole file for each key. ok markus@ OpenBSD-Commit-ID: 374dc263103f6b343d9671f87dbf81ffd0d6abdd commit af5941ae9b013aac12585e84c4cf494f3728982f Author: djm@openbsd.org Date: Sun Oct 11 22:12:44 2020 +0000 upstream: UpdateHostkeys: better detect manual host entries Disable UpdateHostkeys if the known_hosts line has more than two entries in the pattern-list. ssh(1) only writes "host" or "host,ip" lines so anything else was added by a different tool or by a human. ok markus@ OpenBSD-Commit-ID: e434828191fb5f3877d4887c218682825aa59820 commit 6247812c76f70b2245f3c23f5074665b3d436cae Author: djm@openbsd.org Date: Thu Oct 8 01:15:16 2020 +0000 upstream: don't misdetect comma-separated hostkey names as wildcards; spotted by naddy@ OpenBSD-Commit-ID: 4b874edfec7fc324a21b130bdb42f912177739ce commit 67146c7d022a170be3cdad2f5f40259a663fb266 Author: wangxp006 Date: Thu Oct 8 17:49:59 2020 +0800 fix TEST_MALLOC_OPTIONS var commit 3205eaa3f8883a34fa4559ddef6c90d1067c5cce Author: djm@openbsd.org Date: Thu Oct 8 00:31:05 2020 +0000 upstream: clarify conditions for UpdateHostkeys OpenBSD-Commit-ID: 9cba714cf6aeed769f998ccbe8c483077a618e27 commit e8dfca9bfeff05de87160407fb3e6a5717fa3dcb Author: djm@openbsd.org Date: Wed Oct 7 06:38:16 2020 +0000 upstream: remove GlobalKnownHostsFile for this test after UpdateHostkeys change OpenBSD-Regress-ID: a940ad79d59343319613ba8fc46b6ef24aa3f8e1 commit 4aa2717d7517cff4bc423a6cfba3a2defb055aea Author: djm@openbsd.org Date: Wed Oct 7 02:26:28 2020 +0000 upstream: Disable UpdateHostkeys when hostkey checking fails If host key checking fails (i.e. a wrong host key is recorded for the server) and the user elects to continue (via StrictHostKeyChecking=no), then disable UpdateHostkeys for the session. reminded by Mark D. Baushke; ok markus@ OpenBSD-Commit-ID: 98b524f121f4252309dd21becd8c4cacb0c6042a commit 04c06d04475f1f673e9d9743710d194453fe3888 Author: djm@openbsd.org Date: Wed Oct 7 02:25:43 2020 +0000 upstream: Fix UpdateHostkeys/HashKnownHosts/CheckHostIP bug When all of UpdateHostkeys, HashKnownHosts and ChechHostIP were enabled and new host keys were learned, known_hosts IP entries were not being recorded for new host keys. reported by matthieu@ ok markus@ OpenBSD-Commit-ID: a654a8290bd1c930aac509e8158cf85e42e49cb7 commit b70e33711291f3081702133175a41cccafc0212a Author: djm@openbsd.org Date: Wed Oct 7 02:24:51 2020 +0000 upstream: don't UpdateHostkeys when the hostkey is verified by the GlobalKnownHostsFile file, support only UserKnownHostsFile matches suggested by Mark D. Baushke; feedback and ok markus@ OpenBSD-Commit-ID: eabb771a6add676c398d38a143a1aff5f04abbb9 commit aa623142e426ca1ab9db77b06dcc9b1b70bd102b Author: djm@openbsd.org Date: Wed Oct 7 02:22:23 2020 +0000 upstream: revert kex->flags cert hostkey downgrade back to a plain key (commitid VtF8vozGOF8DMKVg). We now do this a simpler way that needs less plumbing. ok markus@ OpenBSD-Commit-ID: fb92d25b216bff8c136da818ac2221efaadf18ed commit f4f14e023cafee1cd9ebe4bb0db4029e6e1fafac Author: djm@openbsd.org Date: Wed Oct 7 02:20:35 2020 +0000 upstream: simply disable UpdateHostkeys when a certificate successfully authenticated the host; simpler than the complicated plumbing via kex->flags we have now. ok markus@ OpenBSD-Commit-ID: 80e39644eed75717d563a7f177e8117a0e14f42c commit e79957e877db42c4c68fabcf6ecff2268e53acb5 Author: djm@openbsd.org Date: Wed Oct 7 02:18:45 2020 +0000 upstream: disable UpdateHostkeys by default if VerifyHostKeyDNS is enabled; suggested by Mark D. Baushke OpenBSD-Commit-ID: 85a1b88592c81bc85df7ee7787dbbe721a0542bf commit 3d4c2016bae1a6f14b48c1150a4c79ca4c9968bd Author: dtucker@openbsd.org Date: Tue Oct 6 07:12:04 2020 +0000 upstream: Agent protocol draft is now at rev 4. ok djm@ OpenBSD-Commit-ID: 8c01ea3aae48aab45e01b7421b0fca2dad5e7837 commit af889a40ffc113af9105c03d7b32131eb4372d50 Author: djm@openbsd.org Date: Sun Oct 4 09:45:01 2020 +0000 upstream: when ordering host key algorithms in the client, consider the ECDSA key subtype; ok markus@ OpenBSD-Commit-ID: 3097686f853c61ff61772ea35f8b699931392ece commit 2d39fc9f7e039351daa3d6aead1538ac29258add Author: dtucker@openbsd.org Date: Sun Oct 4 03:04:02 2020 +0000 upstream: Allow full range of UIDs and GIDs for sftp chown and chgrp on 32bit platforms instead of being limited by LONG_MAX. bz#3206, found by booking00 at sina.cn, ok markus@ OpenBSD-Commit-ID: 373b7bbf1f15ae482d39567ce30d18b51c9229b5 commit 396d32f3a1a16e54df2a76b2a9b237868580dcbe Author: djm@openbsd.org Date: Sat Oct 3 09:22:26 2020 +0000 upstream: There are lots of place where we want to redirect stdin, stdout and/or stderr to /dev/null. Factor all these out to a single stdfd_devnull() function that allows selection of which of these to redirect. ok markus@ OpenBSD-Commit-ID: 3033ba5a4c47cacfd5def020d42cabc52fad3099 commit 1286981d08b8429a64613215ce8bff3f6b32488a Author: djm@openbsd.org Date: Sat Oct 3 08:30:47 2020 +0000 upstream: enable UpdateHostkeys by default when the configuration has not overridden UserKnownHostsFile; ok markus@ "The timing is perfect" deraadt@ OpenBSD-Commit-ID: 62df71c9c5242da5763cb473c2a2deefbd0cef60 commit 332f21537293d66508f7342dc643bc7fe45f0f69 Author: djm@openbsd.org Date: Sat Oct 3 08:12:59 2020 +0000 upstream: disable UpdateHostkeys when a wildcard hostname pattern is encountered or when a certificate host key is in use. feedback/ok markus@ OpenBSD-Commit-ID: b6e5575af7e6732322be82ec299e09051a5413bd commit 13cee44ef907824083d89cb9395adbbd552e46c1 Author: djm@openbsd.org Date: Sat Oct 3 08:11:28 2020 +0000 upstream: record when the host key checking code downgrades a certificate host key to a plain key. This occurs when the user connects to a host with a certificate host key but no corresponding CA key configured in known_hosts; feedback and ok markus@ OpenBSD-Commit-ID: 2ada81853ff9ee7824c62f440bcf4ad62030c901 commit 12ae8f95e2e0c273e9e7ef930b01a028ef796a3f Author: djm@openbsd.org Date: Sat Oct 3 04:15:06 2020 +0000 upstream: prefer ed25519 signature algorithm variants to ECDSA; ok markus@ OpenBSD-Commit-ID: 82187926fca96d35a5b5afbc091afa84e0966e5b commit e5ed753add7aa8eed6b167e44db6240a76404db2 Author: djm@openbsd.org Date: Sat Oct 3 03:40:38 2020 +0000 upstream: want time.h here too OpenBSD-Commit-ID: fafee8f1108c64ad8b282f9a1ed5ea830d8c58a7 commit 66bd9fdf8b7762eb6a85cabbb1ae4ed955679f60 Author: deraadt@openbsd.org Date: Sat Oct 3 02:18:33 2020 +0000 upstream: split introductory paragraph, and insert ominous words about the glob issue, which cannot be fully fixed and really requires completely replacing scp with a completely different subsystem. team effort to find the right words.. OpenBSD-Commit-ID: 58e1f72d292687f63eb357183036ee242513691c commit 86cc8ce002ea10e88a4c5d622a8fdfab8a7d261f Author: Damien Miller Date: Sat Oct 3 13:38:55 2020 +1000 use relative rather than system include here commit 922cfac5ed5ead9f796f7d39f012dd653dc5c173 Author: Damien Miller Date: Sat Oct 3 13:38:41 2020 +1000 add some openbsd-compat licenses we missed commit ce941c75ea9cd6c358508a5b206809846c8d9240 Author: Philip Hands Date: Sat Oct 3 00:20:07 2020 +0200 un-nest $() to make ksh cheerful commit 18ea5f4b88e303677d2003b95e5cb864b439e442 Author: Philip Hands Date: Fri Oct 2 21:30:10 2020 +0200 ksh doesn't grok 'local' and AFAICT it's not actually doing anything useful in the code, so let's see how things go without it. commit d9e727dcc04a52caaac87543ea1d230e9e6b5604 Author: Oleg Date: Thu Oct 1 12:09:08 2020 +0300 Fix `EOF: command not found` error in ssh-copy-id commit a1a856d50c89be3206f320baa4bfb32fff4e826f Author: dtucker@openbsd.org Date: Wed Sep 30 09:11:39 2020 +0000 upstream: Regen moduli. OpenBSD-Commit-ID: 04967f8c43e9854ac34b917bcd6f5ac96c53a693 commit fa1fe3ead7069d90d3c67d62137ad66acfcc9f48 Author: HARUYAMA Seigo Date: Sun Sep 27 20:06:20 2020 +0900 Restore first section title of INSTALL commit 279261e1ea8150c7c64ab5fe7cb4a4ea17acbb29 Author: Damien Miller Date: Sun Sep 27 17:25:01 2020 +1000 update version numbers commit 58ca6ab6ff035ed12b5078e3e9c7199fe72c8587 Author: djm@openbsd.org Date: Sun Sep 27 07:22:05 2020 +0000 upstream: openssh 8.4 OpenBSD-Commit-ID: a29e5b372d2c00e297da8a35a3b87c9beb3b4a58 commit 9bb8a303ce05ff13fb421de991b495930be103c3 Author: Damien Miller Date: Tue Sep 22 10:07:43 2020 +1000 sync with upstream ssh-copy-id rev f0da1a1b7 commit 0a4a5571ada76b1b012bec9cf6ad1203fc19ec8d Author: djm@openbsd.org Date: Mon Sep 21 07:29:09 2020 +0000 upstream: close stdin when forking after authentication too; ok markus OpenBSD-Commit-ID: 43db17e4abc3e6b4a7b033aa8cdab326a7cb6c24 commit d14fe25e6c3b89f8af17e2894046164ac3b45688 Author: djm@openbsd.org Date: Sun Sep 20 23:31:46 2020 +0000 upstream: close stdout/stderr after "ssh -f ..." forking bz#3137, ok markus OpenBSD-Commit-ID: e2d83cc4dea1665651a7aa924ad1ed6bcaaab3e2 commit 53a33a0d745179c02108589e1722457ca8ae4372 Author: Damien Miller Date: Sun Sep 20 15:57:09 2020 +1000 .depend commit 107eb3eeafcd390e1fa7cc7672a05e994d14013e Author: djm@openbsd.org Date: Sun Sep 20 05:47:25 2020 +0000 upstream: cap channel input buffer size at 16MB; avoids high memory use when peer advertises a large window but is slow to consume the data we send (e.g. because of a slow network) reported by Pierre-Yves David fix with & ok markus@ OpenBSD-Commit-ID: 1452771f5e5e768876d3bfe2544e3866d6ade216 commit acfe2ac5fe033e227ad3a56624fbbe4af8b5da04 Author: Damien Miller Date: Fri Sep 18 22:02:53 2020 +1000 libfido2 1.5.0 is recommended commit 52a03e9fca2d74eef953ddd4709250f365ca3975 Author: djm@openbsd.org Date: Fri Sep 18 08:16:38 2020 +0000 upstream: handle multiple messages in a single read() PR#183 by Dennis Kaarsemaker; feedback and ok markus@ OpenBSD-Commit-ID: 8570bb4d02d00cf70b98590716ea6a7d1cce68d1 commit dc098405b2939146e17567a25b08fc6122893cdf Author: pedro martelletto Date: Fri Sep 18 08:57:29 2020 +0200 configure.ac: add missing includes when testing, make sure to include the relevant header files that declare the types of the functions used by the test: - stdio.h for printf(); - stdlib.h for exit(); - string.h for strcmp(); - unistd.h for unlink(), _exit(), fork(), getppid(), sleep(). commit b3855ff053f5078ec3d3c653cdaedefaa5fc362d Author: djm@openbsd.org Date: Fri Sep 18 05:23:03 2020 +0000 upstream: tweak the client hostkey preference ordering algorithm to prefer the default ordering if the user has a key that matches the best-preference default algorithm. feedback and ok markus@ OpenBSD-Commit-ID: a92dd7d7520ddd95c0a16786a7519e6d0167d35f commit f93b187ab900c7d12875952cc63350fe4de8a0a8 Author: Damien Miller Date: Fri Sep 18 14:55:48 2020 +1000 control over the colours in gnome-ssh-askpass[23] Optionally set the textarea colours via $GNOME_SSH_ASKPASS_FG_COLOR and $GNOME_SSH_ASKPASS_BG_COLOR. These accept the usual three or six digit hex colours. commit 9d3d36bdb10b66abd1af42e8655502487b6ba1fa Author: Damien Miller Date: Fri Sep 18 14:50:38 2020 +1000 focus improvement for gnome-ssh-askpass[23] When serving a SSH_ASKPASS_PROMPT=none information dialog, ensure then doesn't immediately close the dialog. Instead, require an explicit to reach the close button, or . commit d6f507f37e6c75a899db0ef8224e72797c5563b6 Author: dtucker@openbsd.org Date: Wed Sep 16 03:07:31 2020 +0000 upstream: Remove unused buf, last user was removed when switching to the sshbuf API. Patch from Sebastian Andrzej Siewior. OpenBSD-Commit-ID: 250fa17f0cec01039cc4abd95917d9746e24c889 commit c3c786c3a0973331ee0922b2c51832a3b8d7f20f Author: djm@openbsd.org Date: Wed Sep 9 21:57:27 2020 +0000 upstream: For the hostkey confirmation message: > Are you sure you want to continue connecting (yes/no/[fingerprint])? compare the fingerprint case sensitively; spotted Patrik Lundin ok dtucker OpenBSD-Commit-ID: 73097afee1b3a5929324e345ba4a4a42347409f2 commit f2950baf0bafe6aa20dfe2e8d1ca4b23528df617 Author: Darren Tucker Date: Fri Sep 11 14:45:23 2020 +1000 New config-build-time dependency on automake. commit 600c1c27abd496372bd0cf83d21a1c119dfdf9a5 Author: Darren Tucker Date: Sun Sep 6 21:56:36 2020 +1000 Add aclocal.m4 and config.h.in~ to .gitignore. aclocal.m4 is now generated by autoreconf. commit 4bf7e1d00b1dcd3a6b3239f77465c019e61c6715 Author: Sebastian Andrzej Siewior Date: Sat Sep 5 17:50:03 2020 +0200 Quote the definition of OSSH_CHECK_HEADER_FOR_FIELD autoreconf complains about underquoted definition of OSSH_CHECK_HEADER_FOR_FIELD after aclocal.m4 has been and now is beeing recreated. Quote OSSH_CHECK_HEADER_FOR_FIELD as suggested. Signed-off-by: Sebastian Andrzej Siewior commit a2f3ae386b5f7938ed3c565ad71f30c4f7f010f1 Author: Sebastian Andrzej Siewior Date: Sat Sep 5 17:50:02 2020 +0200 Move the local m4 macros The `aclocal' step is skipped during `autoreconf' because aclocal.m4 is present. Move the current aclocal.m4 which contains local macros into the m4/ folder. With this change the aclocal.m4 will be re-created during changes to the m4/ macro. This is needed so the `aclocal' can fetch m4 macros from the system if they are references in the configure script. This is a prerequisite to use PKG_CHECK_MODULES. Signed-off-by: Sebastian Andrzej Siewior commit 8372bff3a895b84fd78a81dc39da10928b662f5a Author: Sebastian Andrzej Siewior Date: Sat Sep 5 17:50:01 2020 +0200 Remove HAVE_MMAP and BROKEN_MMAP BROKEN_MMAP is no longer defined since commit 1cfd5c06efb12 ("Remove portability support for mmap") this commit also removed other HAVE_MMAP user. I didn't find anything that defines HAVE_MMAP. The check does not trigger because compression on server side is by default COMP_DELAYED (2) so it never triggers. Remove remaining HAVE_MMAP and BROKEN_MMAP bits. Signed-off-by: Sebastian Andrzej Siewior commit bbf20ac8065905f9cb9aeb8f1df57fcab52ee2fb Author: djm@openbsd.org Date: Wed Sep 9 03:10:21 2020 +0000 upstream: adapt to SSH_SK_VERSION_MAJOR crank OpenBSD-Regress-ID: 0f3e76bdc8f9dbd9d22707c7bdd86051d5112ab8 commit 9afe2a150893b20bdf9eab764978d817b9a7b783 Author: dtucker@openbsd.org Date: Fri Aug 28 03:17:13 2020 +0000 upstream: Ensure that address/mask mismatches are flagged at config-check time. ok djm@ OpenBSD-Regress-ID: 8f5f4c2c0bf00e6ceae7a1755a444666de0ea5c2 commit c76773524179cb654ff838dd43ba1ddb155bafaa Author: djm@openbsd.org Date: Wed Sep 9 03:08:01 2020 +0000 upstream: when writing an attestation blob for a FIDO key, record all the data needed to verify the attestation. Previously we were missing the "authenticator data" that is included in the signature. spotted by Ian Haken feedback Pedro Martelletto and Ian Haken; ok markus@ OpenBSD-Commit-ID: 8439896e63792b2db99c6065dd9a45eabbdb7e0a commit c1c44eeecddf093a7983bd91e70b446de789b363 Author: pedro martelletto Date: Tue Sep 1 17:01:55 2020 +0200 configure.ac: fix libfido2 back-compat - HAVE_FIDO_CRED_PROD -> HAVE_FIDO_CRED_PROT; - check for fido_dev_get_touch_begin(), so that HAVE_FIDO_DEV_GET_TOUCH_BEGIN gets defined. commit 785f0f315bf7ac5909e988bb1ac3e019fb5e1594 Author: djm@openbsd.org Date: Mon Aug 31 04:33:17 2020 +0000 upstream: refuse to add verify-required (PINful) FIDO keys to ssh-agent until the agent supports them properly OpenBSD-Commit-ID: 125bd55a8df32c87c3ec33c6ebe437673a3d037e commit 39e88aeff9c7cb6862b37ad1a87a03ebbb38c233 Author: djm@openbsd.org Date: Mon Aug 31 00:17:41 2020 +0000 upstream: Add RCS IDs to the few files that are missing them; from Pedro Martelletto OpenBSD-Commit-ID: 39aa37a43d0c75ec87f1659f573d3b5867e4a3b3 commit 72730249b38a676da94a1366b54a6e96e6928bcb Author: dtucker@openbsd.org Date: Fri Aug 28 03:15:52 2020 +0000 upstream: Check that the addresses supplied to Match Address and Match LocalAddress are valid when parsing in config-test mode. This will catch address/mask mismatches before they cause problems at runtime. Found by Daniel Stocker, ok djm@ OpenBSD-Commit-ID: 2d0b10c69fad5d8fda4c703e7c6804935289378b commit 2a3a9822311a565a9df48ed3b6a3c972f462bd7d Author: jmc@openbsd.org Date: Thu Aug 27 12:34:00 2020 +0000 upstream: sentence fix; from pedro martelletto OpenBSD-Commit-ID: f95b84a1e94e9913173229f3787448eea2f8a575 commit ce178be0d954b210c958bc2b9e998cd6a7aa73a9 Author: Damien Miller Date: Thu Aug 27 20:01:52 2020 +1000 tweak back-compat for older libfido2 commit d6f45cdde031acdf434bbb27235a1055621915f4 Author: djm@openbsd.org Date: Thu Aug 27 09:46:04 2020 +0000 upstream: debug()-print a little info about FIDO-specific key fields via "ssh-keygen -vyf /path/key" OpenBSD-Commit-ID: cf315c4fe77db43947d111b00155165cb6b577cf commit b969072cc3d62d05cb41bc6d6f3c22c764ed932f Author: djm@openbsd.org Date: Thu Aug 27 09:43:28 2020 +0000 upstream: skip a bit more FIDO token selection logic when only a single token is attached. with Pedro Martelletto OpenBSD-Commit-ID: e4a324bd9814227ec1faa8cb619580e661cca9ac commit 744df42a129d7d7db26947b7561be32edac89f88 Author: jmc@openbsd.org Date: Thu Aug 27 06:15:22 2020 +0000 upstream: tweak previous; OpenBSD-Commit-ID: 92714b6531e244e4da401b2defaa376374e24be7 commit e32479645ce649b444ba5c6e7151304306a09654 Author: djm@openbsd.org Date: Thu Aug 27 03:55:22 2020 +0000 upstream: adapt to API changes OpenBSD-Regress-ID: 5f147990cb67094fe554333782ab268a572bb2dd commit bbcc858ded3fbc46abfa7760e40389e3ca93884c Author: Damien Miller Date: Thu Aug 27 12:37:12 2020 +1000 degrade semi-gracefully when libfido2 is too old commit 9cbbdc12cb6a2ab1e9ffe9974cca91d213c185c2 Author: djm@openbsd.org Date: Thu Aug 27 01:15:36 2020 +0000 upstream: dummy firmware needs to match API version numner crank (for verify-required resident keys) even though it doesn't implement this feature OpenBSD-Regress-ID: 86579ea2891e18e822e204413d011b2ae0e59657 commit c1e76c64956b424ba260fd4eec9970e5b5859039 Author: djm@openbsd.org Date: Thu Aug 27 02:11:09 2020 +0000 upstream: remove unreachable code I forgot to delete in r1.334 OpenBSD-Commit-ID: 9ed6078251a0959ee8deda443b9ae42484fd8b18 commit 0caff05350bd5fc635674c9e051a0322faba5ae3 Author: djm@openbsd.org Date: Thu Aug 27 01:08:45 2020 +0000 upstream: Request PIN ahead of time for certain FIDO actions When we know that a particular action will require a PIN, such as downloading resident keys or generating a verify-required key, request the PIN before attempting it. joint work with Pedro Martelletto; ok markus@ OpenBSD-Commit-ID: 863182d38ef075bad1f7d20ca485752a05edb727 commit b649b3daa6d4b8ebe1bd6de69b3db5d2c03c9af0 Author: djm@openbsd.org Date: Thu Aug 27 01:08:19 2020 +0000 upstream: preserve verify-required for resident FIDO keys When downloading a resident, verify-required key from a FIDO token, preserve the verify-required in the private key that is written to disk. Previously we weren't doing that because of lack of support in the middleware API. from Pedro Martelletto; ok markus@ and myself OpenBSD-Commit-ID: 201c46ccdd227cddba3d64e1bdbd082afa956517 commit 642e06d0df983fa2af85126cf4b23440bb2985bf Author: djm@openbsd.org Date: Thu Aug 27 01:07:51 2020 +0000 upstream: major rework of FIDO token selection logic When PINs are in use and multiple FIDO tokens are attached to a host, we cannot just blast requests at all attached tokens with the PIN specified as this will cause the per-token PIN failure counter to increment. If this retry counter hits the token's limit (usually 3 attempts), then the token will lock itself and render all (web and SSH) of its keys invalid. We don't want this. So this reworks the key selection logic for the specific case of multiple keys being attached. When multiple keys are attached and the operation requires a PIN, then the user must touch the key that they wish to use first in order to identify it. This may require multiple touches, but only if there are multiple keys attached AND (usually) the operation requires a PIN. The usual case of a single key attached should be unaffected. Work by Pedro Martelletto; ok myself and markus@ OpenBSD-Commit-ID: 637d3049ced61b7a9ee796914bbc4843d999a864 commit 801c9f095e6d8b7b91aefd98f5001c652ea13488 Author: djm@openbsd.org Date: Thu Aug 27 01:07:09 2020 +0000 upstream: support for requiring user verified FIDO keys in sshd This adds a "verify-required" authorized_keys flag and a corresponding sshd_config option that tells sshd to require that FIDO keys verify the user identity before completing the signing/authentication attempt. Whether or not user verification was performed is already baked into the signature made on the FIDO token, so this is just plumbing that flag through and adding ways to require it. feedback and ok markus@ OpenBSD-Commit-ID: 3a2313aae153e043d57763d766bb6d55c4e276e6 commit 9b8ad93824c682ce841f53f3b5762cef4e7cc4dc Author: djm@openbsd.org Date: Thu Aug 27 01:06:18 2020 +0000 upstream: support for user-verified FIDO keys FIDO2 supports a notion of "user verification" where the user is required to demonstrate their identity to the token before particular operations (e.g. signing). Typically this is done by authenticating themselves using a PIN that has been set on the token. This adds support for generating and using user verified keys where the verification happens via PIN (other options might be added in the future, but none are in common use now). Practically, this adds another key generation option "verify-required" that yields a key that requires a PIN before each authentication. feedback markus@ and Pedro Martelletto; ok markus@ OpenBSD-Commit-ID: 57fd461e4366f87c47502c5614ec08573e6d6a15 commit 1196d7f49d4fbc90f37e550de3056561613b0960 Author: cheloha@openbsd.org Date: Wed Aug 12 01:23:45 2020 +0000 upstream: ssh-keyscan(1): simplify conloop() with timercmp(3), timersub(3); ok djm@ OpenBSD-Commit-ID: a102acb544f840d33ad73d40088adab4a687fa27 commit d0a195c89e26766d3eb8f3e4e2a00ebc98b57795 Author: djm@openbsd.org Date: Tue Aug 11 09:49:57 2020 +0000 upstream: let ssh_config(5)'s AddKeysToAgent keyword accept a time limit for keys in addition to its current flag options. Time-limited keys will automatically be removed from ssh-agent after their expiry time has passed; ok markus@ OpenBSD-Commit-ID: 792e71cacbbc25faab5424cf80bee4a006119f94 commit e9c2002891a7b8e66f4140557a982978f372e5a3 Author: djm@openbsd.org Date: Tue Aug 11 09:45:54 2020 +0000 upstream: let the "Confirm user presence for key ..." ssh-askpass notification respect $SSH_ASKPASS_REQUIRE; ok markus@ OpenBSD-Commit-ID: 7c1a616b348779bda3b9ad46bf592741f8e206c1 commit eaf8672b1b52db2815a229745f4e4b08681bed6d Author: Darren Tucker Date: Fri Aug 21 00:04:13 2020 +1000 Remove check for 'ent' command. It was added in 8d1fd57a9 for measuring entropy of ssh_prng_cmds which has long since been removed and there are no other references to it. commit 05c215de8d224e094a872d97d45f37f60c06206b Author: Darren Tucker Date: Mon Aug 17 21:34:32 2020 +1000 Wrap stdint.h include in ifdef HAVE_STDINT_H. commit eaf2765efe8bc74feba85c34295d067637fc6635 Author: Damien Miller Date: Mon Aug 10 13:24:09 2020 +1000 sync memmem.c with OpenBSD commit ed6bef77f5bb5b8f9ca2914478949e29f2f0a780 Author: Darren Tucker Date: Fri Aug 7 17:12:16 2020 +1000 Always send any PAM account messages. If the PAM account stack reaturns any messages, send them to the user not just if the check succeeds. bz#2049, ok djm@ commit a09e98dcae1e26f026029b7142b0e0d10130056f Author: Darren Tucker Date: Fri Aug 7 15:37:37 2020 +1000 Output test debug logs on failure. commit eb122b1eebe58b29a83a507ee814cbcf8aeded1b Author: Darren Tucker Date: Fri Aug 7 15:11:42 2020 +1000 Add ability to specify exact test target. commit c2ec7a07f8caabb4d8e00c66e7cd46bf2cd1e922 Author: Darren Tucker Date: Fri Aug 7 14:21:15 2020 +1000 Document --without-openssl and --without-zlib. commit 651bb3a31949bbdc3a78b2ede95a77bce0c72984 Author: Darren Tucker Date: Fri Aug 7 14:15:11 2020 +1000 Add without-openssl without-zlib test target. commit 9499f2bb01dc1032ae155999b2d7764b9491341f Author: Stefan Schindler Date: Wed Aug 5 19:00:52 2020 +0200 Add CI with prepare script * Only use heimdal kerberos implementation * Fetch yubico/libfido2 (see: https://github.com/Yubico/libfido2) * Add one target for * all features * each feature alone * no features commit ea1f649046546a860f68b97ddc3015b7e44346ca Author: Damien Miller Date: Wed Aug 5 08:58:57 2020 +1000 support NetBSD's utmpx.ut_ss address field bz#960, ok dtucker commit 32c63e75a70a0ed9d6887a55fcb0e4531a6ad617 Author: Damien Miller Date: Tue Aug 4 14:59:21 2020 +1000 wrap a declaration in the same ifdefs as its use avoids warnings on NetBSD commit c9e3be9f4b41fda32a2a0138d54c7a6b563bc94d Author: Damien Miller Date: Tue Aug 4 14:58:46 2020 +1000 undef TAILQ_CONCAT and friends Needed for NetBSD. etc that supply these macros commit 2d8a3b7e8b0408dfeb933ac5cfd3a58f5bac49af Author: djm@openbsd.org Date: Mon Aug 3 02:53:51 2020 +0000 upstream: ensure that certificate extensions are lexically sorted. Previously if the user specified a custom extension then the everything would be in order except the custom ones. bz3198 ok dtucker markus OpenBSD-Commit-ID: d97deb90587b06cb227c66ffebb2d9667bf886f0 commit a8732d74cb8e72f0c6366015687f1e649f60be87 Author: djm@openbsd.org Date: Mon Aug 3 02:43:41 2020 +0000 upstream: allow -A to explicitly enable agent forwarding in scp and sftp. The default remains to not forward an agent, even when ssh_config enables it. ok jmc dtucker markus OpenBSD-Commit-ID: 36cc526aa3b0f94e4704b8d7b969dd63e8576822 commit ab9105470a83ed5d8197959a1b1f367399958ba1 Author: deraadt@openbsd.org Date: Mon Aug 3 02:42:49 2020 +0000 upstream: clang -Wimplicit-fallthrough does not recognise /* FALLTHROUGH */ comments, which is the style we currently use, and gives too many boring warnings. ok djm OpenBSD-Commit-ID: 07b5031e9f49f2b69ac5e85b8da4fc9e393992a0 commit ced327b9fb78c94d143879ef4b2a02cbc5d38690 Author: dtucker@openbsd.org Date: Fri Jul 31 04:19:37 2020 +0000 upstream: Also compare username when checking for JumpHost loops. bz#3057, ok djm@ OpenBSD-Commit-ID: 9bbc1d138adb34c54f3c03a15a91f75dbf418782 commit ae7527010c44b3376b85d036a498f136597b2099 Author: Darren Tucker Date: Fri Jul 31 15:19:04 2020 +1000 Remove AC_REVISION. It hasn't been useful since we switched to git in 2014. ok djm@ commit 89fc3f414be0ce4e8008332a9739a7d721269e50 Author: Darren Tucker Date: Tue Jul 28 19:40:30 2020 +1000 Use argv in OSSH_CHECK_CFLAG_COMPILE test. configure.ac is not detecting -Wextra in compilers that implement the option. The problem is that -Wextra implies -Wunused-parameter, and the C excerpt used by aclocal.m4 does not use argv. Patch from pedro at ambientworks.net, ok djm@ commit 62c81ef531b0cc7ff655455dd34f5f0c94f48e82 Author: Darren Tucker Date: Mon Jul 20 22:12:07 2020 +1000 Skip ECDSA-SK webauthn test when built w/out ECC commit 3ec9a6d7317236a9994887d8bd5d246af403a00d Author: Damien Miller Date: Mon Jul 20 13:09:25 2020 +1000 Add ssh-sk-helper and manpage to RPM spec file Based on patch from Fabio Pedretti commit a2855c048b3f4b17d8787bd3f24232ec0cd79abe Author: dtucker@openbsd.org Date: Fri Jul 17 07:09:24 2020 +0000 upstream: Add %k to the TOKENs for Match Exec for consistency with the other keywords that recently got %k. OpenBSD-Commit-ID: 1857d1c40f270cbc254fca91e66110641dddcfdb commit 69860769fa9f4529d8612ec055ae11912f7344cf Author: jmc@openbsd.org Date: Fri Jul 17 05:59:05 2020 +0000 upstream: fix macro slip in previous; OpenBSD-Commit-ID: 624e47ab209450ad9ad5c69f54fa69244de5ed9a commit 40649bd0822883b684183854b16d0b8461d5697b Author: dtucker@openbsd.org Date: Fri Jul 17 07:10:24 2020 +0000 upstream: Add test for '%k' (HostKeyAlias) TOKEN. OpenBSD-Regress-ID: 8ed1ba1a811790031aad3fcea860a34ad7910456 commit 6736fe680704a3518cb4f3f8f6723b00433bd3dd Author: dtucker@openbsd.org Date: Fri Jul 17 03:26:58 2020 +0000 upstream: Add tests for expansions on UserKnownHostsFile. OpenBSD-Regress-ID: bccf8060306c841bbcceb1392644f906a4d6ca51 commit 287dc6396e0f9cb2393f901816dbd7f2a7dfbb5f Author: djm@openbsd.org Date: Fri Jul 17 03:51:32 2020 +0000 upstream: log error message for process_write() write failures OpenBSD-Commit-ID: f733d7b3b05e3c68967dc18dfe39b9e8fad29851 commit 8df5774a42d2eaffe057bd7f293fc6a4b1aa411c Author: dtucker@openbsd.org Date: Fri Jul 17 03:43:42 2020 +0000 upstream: Add a '%k' TOKEN that expands to the effective HostKey of the destination. This allows, eg, keeping host keys in individual files using "UserKnownHostsFile ~/.ssh/known_hosts.d/%k". bz#1654, ok djm@, jmc@ (man page bits) OpenBSD-Commit-ID: 7084d723c9cc987a5c47194219efd099af5beadc commit c4f239944a4351810fd317edf408bdcd5c0102d9 Author: dtucker@openbsd.org Date: Fri Jul 17 03:23:10 2020 +0000 upstream: Add %-TOKEN, environment variable and tilde expansion to UserKnownHostsFile, allowing the file to be automagically split up in the configuration (eg bz#1654). ok djm@, man page parts jmc@ OpenBSD-Commit-ID: 7e1b406caf147638bb51558836a72d6cc0bd1b18 commit dbaaa01daedb423c38124a72c471982fb08a16fb Author: solene@openbsd.org Date: Wed Jul 15 07:50:46 2020 +0000 upstream: - Add [-a rounds] in ssh-keygen man page and usage() - Reorder parameters list in the first usage() case - Sentence rewording ok dtucker@ jmc@ noticed usage() missed -a flag too OpenBSD-Commit-ID: f06b9afe91cc96f260b929a56e9930caecbde246 commit 69924a92c3af7b99a7541aa544a2334ec0fb092c Author: jmc@openbsd.org Date: Wed Jul 15 05:40:05 2020 +0000 upstream: start sentence with capital letter; OpenBSD-Commit-ID: ab06581d51b2b4cc1b4aab781f7f3cfa56cad973 commit 5b56bd0affea7b02b540bdbc4d1d271b0e4fc885 Author: Damien Miller Date: Fri Jul 17 13:15:50 2020 +1000 detect Linux/X32 systems This is a frankenstein monster of AMD64 instructions/calling conventions but with a 4GB address space. Allegedly deprecated but people still run into it causing weird sandbox failures, e.g. bz#3085 commit 9c9ddc1391d6af8d09580a2424ab467d0a5df3c7 Author: dtucker@openbsd.org Date: Wed Jul 15 06:43:16 2020 +0000 upstream: Fix previous by calling the correct function. OpenBSD-Regress-ID: 821cdd1dff9c502cceff4518b6afcb81767cad5a commit f1a4798941b4372bfe5e46f1c0f8672fe692d9e4 Author: dtucker@openbsd.org Date: Wed Jul 15 05:36:50 2020 +0000 upstream: Update test to match recent change in match.c OpenBSD-Regress-ID: 965bda1f95f09a765050707340c73ad755f41167 commit d7e71be4fd57b7c7e620d733cdf2333b27bfa924 Author: Darren Tucker Date: Wed Jul 15 15:30:43 2020 +1000 Adjust portable code to match changes in 939d787d, commit fec89f32a84fd0aa1afc81deec80a460cbaf451a Author: dtucker@openbsd.org Date: Wed Jul 15 04:27:34 2020 +0000 upstream: Add default for number of rounds (-a). ok djm@ OpenBSD-Commit-ID: cb7e9aa04ace01a98e63e4bd77f34a42ab169b15 commit aaa8b609a7b332be836cd9a3b782422254972777 Author: djm@openbsd.org Date: Tue Jul 14 23:57:01 2020 +0000 upstream: allow some additional control over the use of ssh-askpass via $SSH_ASKPASS_REQUIRE, including force-enable/disable. bz#69 ok markus@ OpenBSD-Commit-ID: 3a1e6cbbf6241ddc4405c4246caa2c249f149eb2 commit 6368022cd4dd508671c4999a59ec5826df098530 Author: deraadt@openbsd.org Date: Tue Jul 7 02:47:21 2020 +0000 upstream: correct recently broken comments OpenBSD-Commit-ID: 964d9a88f7de1d0eedd3f8070b43fb6e426351f1 commit 6d755706a0059eb9e2d63517f288b75cbc3b4701 Author: djm@openbsd.org Date: Sun Jul 5 23:59:45 2020 +0000 upstream: some language improvements; ok markus OpenBSD-Commit-ID: 939d787d571b4d5da50b3b721fd0b2ac236acaa8 commit b0c1e8384d5e136ebdf895d1434aea7dd8661a1c Author: markus@openbsd.org Date: Fri Jul 3 10:12:26 2020 +0000 upstream: update setproctitle after re-exec; ok djm OpenBSD-Commit-ID: bc92d122f9184ec2a9471ade754b80edd034ce8b commit cd119a5ec2bf0ed5df4daff3bd14f8f7566dafd3 Author: markus@openbsd.org Date: Fri Jul 3 10:11:33 2020 +0000 upstream: keep ignoring HUP after fork+exec; ok djm OpenBSD-Commit-ID: 7679985a84ee5ceb09839905bb6f3ddd568749a2 commit 8af4a743693ccbea3e15fc9e93edbeb610fa94f4 Author: markus@openbsd.org Date: Fri Jul 3 10:10:17 2020 +0000 upstream: don't exit the listener on send_rexec_state errors; ok djm OpenBSD-Commit-ID: 57cbd757d130d3f45b7d41310b3a15eeec137d5c commit 03da4c2b70468f04ed1c08518ea0a70e67232739 Author: dtucker@openbsd.org Date: Wed Jul 15 04:55:47 2020 +0000 upstream: Use $OBJ to find key files. Fixes test when run on an obj directory (on OpenBSD) or out of tree (in Portable). OpenBSD-Regress-ID: 938fa8ac86adaa527d64a305bd2135cfbb1c0a17 commit 73f20f195ad18f1cf633eb7d8be95dc1b6111eea Author: Darren Tucker Date: Sat Jul 4 23:11:23 2020 +1000 Wrap stdint.h in ifdef HAVE_STDINT_H. commit aa6fa4bf3023fa0e5761cd8f4b2cd015d2de74dd Author: djm@openbsd.org Date: Fri Jul 3 07:25:18 2020 +0000 upstream: put back the mux_ctx memleak fix, but only for channels of type SSH_CHANNEL_MUX_LISTENER; Specifically SSH_CHANNEL_MUX_PROXY channels should not have this structure freed. OpenBSD-Commit-ID: f3b213ae60405f77439e2b06262f054760c9d325 commit d8195914eb43b20b13381f4e5a74f9f8a14f0ded Author: djm@openbsd.org Date: Fri Jul 3 07:17:35 2020 +0000 upstream: revert r1.399 - the lifetime of c->mux_ctx is more complex; simply freeing it here causes other problems OpenBSD-Commit-ID: c6fee8ca94e2485faa783839541962be2834c5ed commit 20b5fab9f773b3d3c7f06cb15b8f69a2c081ee80 Author: djm@openbsd.org Date: Fri Jul 3 07:02:37 2020 +0000 upstream: avoid tilde_expand_filename() in expanding ~/.ssh/rc - if sshd is in chroot mode, the likely absence of a password database will cause tilde_expand_filename() to fatal; ok dtucker@ OpenBSD-Commit-ID: e20aee6159e8b79190d18dba1513fc1b7c8b7ee1 commit c8935081db35d73ee6355999142fa0776a2af912 Author: djm@openbsd.org Date: Fri Jul 3 06:46:41 2020 +0000 upstream: when redirecting sshd's log output to a file, undo this redirection after the session child process is forked(); ok dtucker@ OpenBSD-Commit-ID: 6df86dd653c91f5bc8ac1916e7680d9d24690865 commit 183c4aaef944af3a1a909ffa01058c65bac55748 Author: djm@openbsd.org Date: Fri Jul 3 06:29:57 2020 +0000 upstream: start ClientAliveInterval bookkeeping before first pass through select() loop; fixed theoretical case where busy sshd may ignore timeouts from client; inspired by and ok dtucker OpenBSD-Commit-ID: 96bfc4b1f86c7da313882a84755b2b47eb31957f commit 6fcfd303d67f16695198cf23d109a988e40eefb6 Author: Damien Miller Date: Fri Jul 3 15:28:27 2020 +1000 add check for fido_cred_set_prot() to configure commit f11b23346309e4d5138e733a49321aedd6eeaa2f Author: dtucker@openbsd.org Date: Fri Jul 3 05:09:06 2020 +0000 upstream: Only reset the serveralive check when we receive traffic from the server and ignore traffic from a port forwarding client, preventing a client from keeping a connection alive when it should be terminated. Based on a patch from jxraynor at gmail.com via openssh-unix-dev and bz#2265, ok djm@ OpenBSD-Commit-ID: a941a575a5cbc244c0ef5d7abd0422bbf02c2dcd commit adfdbf1211914b631c038f0867a447db7b519937 Author: Damien Miller Date: Fri Jul 3 15:15:15 2020 +1000 sync sys-queue.h with OpenBSD upstream needed for TAILQ_CONCAT commit 1b90ddde49e2ff377204082b6eb130a096411dc1 Author: djm@openbsd.org Date: Fri Jul 3 05:08:41 2020 +0000 upstream: fix memory leak of mux_ctx; patch from Sergiy Lozovsky via bz3189 ok dtucker OpenBSD-Commit-ID: db249bd4526fd42d0f4f43f72f7b8b7705253bde commit 55ef3e9cbd5b336bd0f89205716924886fcf86de Author: markus@openbsd.org Date: Wed Jul 1 16:28:31 2020 +0000 upstream: free kex in ssh_packet_close; ok djm semarie OpenBSD-Commit-ID: dbc181e90d3d32fd97b10d75e68e374270e070a2 commit e1c401109b61f7dbc199b5099933d579e7fc5dc9 Author: bket@openbsd.org Date: Sat Jun 27 13:39:09 2020 +0000 upstream: Replace TAILQ concatenation loops with TAILQ_CONCAT OK djm@ OpenBSD-Commit-ID: 454b40e09a117ddb833794358970a65b14c431ef commit 14beca57ac92d62830c42444c26ba861812dc837 Author: semarie@openbsd.org Date: Fri Jun 26 11:26:01 2020 +0000 upstream: backout 1.293 fix kex mem-leak in ssh_packet_close at markus request the change introduced a NULL deref in sshpkt_vfatal() (uses of ssh->kex after calling ssh_packet_clear_keys()) OpenBSD-Commit-ID: 9c9a6721411461b0b1c28dc00930d7251a798484 commit 598c3a5e3885080ced0d7c40fde00f1d5cdbb32b Author: Damien Miller Date: Fri Jun 26 16:07:12 2020 +1000 document a PAM spec problem in a frustrated comment commit 976c4f86286d52a0cb2aadf4a095d379c0da752e Author: djm@openbsd.org Date: Fri Jun 26 05:42:16 2020 +0000 upstream: avoid spurious error message when ssh-keygen creates files outside ~/.ssh; with dtucker@ OpenBSD-Commit-ID: ac0c662d44607e00ec78c266ee60752beb1c7e08 commit 32b2502a9dfdfded1ccdc1fd6dc2b3fe41bfc205 Author: Damien Miller Date: Fri Jun 26 15:30:06 2020 +1000 missing ifdef SELINUX; spotted by dtucker commit e073106f370cdd2679e41f6f55a37b491f0e82fe Author: 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 Date: Wed Jun 24 15:16:23 2020 +0000 upstream: add test for mux w/-Oproxy; ok djm OpenBSD-Regress-ID: 764d5c696e2a259f1316a056e225e50023abb027 commit 3d06ff4bbd3dca8054c238d2a94c0da563ef7eee Author: djm@openbsd.org Date: Fri Jun 26 05:16:38 2020 +0000 upstream: handle EINTR in waitfd() and timeout_connect() helpers; bz#3071; ok dtucker@ OpenBSD-Commit-ID: 08fa87be50070bd8b754d9b1ebb1138d7bc9d8ee commit fe2ec0b9c19adeab0cd9f04b8152dc17f31c31e5 Author: djm@openbsd.org Date: Fri Jun 26 05:04:07 2020 +0000 upstream: allow "ssh-add -d -" to read keys to be deleted from stdin bz#3180; ok dtucker@ OpenBSD-Commit-ID: 15c7f10289511eb19fce7905c9cae8954e3857ff commit a3e0c376ffc11862fa3568b28188bd12965973e1 Author: djm@openbsd.org Date: Fri Jun 26 05:03:36 2020 +0000 upstream: constify a few things; ok dtucker (as part of another diff) OpenBSD-Commit-ID: 7c17fc987085994d752304bd20b1ae267a9bcdf6 commit 74344c3ca42c3f53b00b025daf09ae7f6aa38076 Author: dtucker@openbsd.org Date: Fri Jun 26 05:02:03 2020 +0000 upstream: Defer creation of ~/.ssh by ssh(1) until we attempt to write to it so we don't leave an empty .ssh directory when it's not needed. Use the same function to replace the code in ssh-keygen that does the same thing. bz#3156, ok djm@ OpenBSD-Commit-ID: 59c073b569be1a60f4de36f491a4339bc4ae870f commit c9e24daac6324fcbdba171392c325bf9ccc3c768 Author: dtucker@openbsd.org Date: Fri Jun 26 04:45:11 2020 +0000 upstream: Expand path to ~/.ssh/rc rather than relying on it being relative to the current directory, so that it'll still be found if the shell startup changes its directory. Since the path is potentially longer, make the cmd buffer that uses it dynamically sized. bz#3185, with & ok djm@ OpenBSD-Commit-ID: 36e33ff01497af3dc8226d0c4c1526fc3a1e46bf commit 07f5f369a25e228a7357ef6c57205f191f073d99 Author: markus@openbsd.org Date: Wed Jun 24 15:12:09 2020 +0000 upstream: fix kex mem-leak in ssh_packet_close; ok djm OpenBSD-Commit-ID: e2e9533f393620383afd0b68ef435de8d5e8abe4 commit e35995088cd6691a712bfd586bae8084a3a922ba Author: markus@openbsd.org Date: Wed Jun 24 15:10:38 2020 +0000 upstream: fix ssh -O proxy w/mux which got broken by no longer making ssh->kex optional in packet.c revision 1.278 ok djm@ OpenBSD-Commit-ID: 2b65df04a064c2c6277359921d2320c90ab7d917 commit 250246fef22b87a54a63211c60a2def9be431fbd Author: markus@openbsd.org Date: Wed Jun 24 15:09:53 2020 +0000 upstream: support loading big sshd_config files w/o realloc; ok djm OpenBSD-Commit-ID: ba9238e810074ac907f0cf8cee1737ac04983171 commit 89b54900ac61986760452f132bbe3fb7249cfdac Author: markus@openbsd.org Date: Wed Jun 24 15:08:53 2020 +0000 upstream: allow sshd_config longer than 256k; ok djm OpenBSD-Commit-ID: 83f40dd5457a64c1d3928eb4364461b22766beb3 commit e3fa6249e6d9ceb57c14b04dd4c0cfab12fa7cd5 Author: markus@openbsd.org Date: Wed Jun 24 15:07:33 2020 +0000 upstream: only call sshkey_xmss_init() once for KEY_XMSS_CERT; ok djm OpenBSD-Commit-ID: d0002ffb7f20f538b014d1d0735facd5a81ff096 commit 37f2da069c0619f2947fb92785051d82882876d7 Author: djm@openbsd.org Date: Mon Jun 22 23:44:27 2020 +0000 upstream: some clarifying comments OpenBSD-Commit-ID: 5268479000fd97bfa30ab819f3517139daa054a2 commit b659319a5bc9e8adf3c4facc51f37b670d2a7426 Author: jmc@openbsd.org Date: Mon Jun 22 06:37:38 2020 +0000 upstream: updated argument name for -P in first synopsis was missed in previous; OpenBSD-Commit-ID: 8d84dc3050469884ea91e29ee06a371713f2d0b7 commit 02a9222cbce7131d639984c2f6c71d1551fc3333 Author: jmc@openbsd.org Date: Mon Jun 22 06:36:40 2020 +0000 upstream: supply word missing in previous; OpenBSD-Commit-ID: 16a38b049f216108f66c8b699aa046063381bd23 commit 5098b3b6230852a80ac6cef5d53a785c789a5a56 Author: Damien Miller Date: Mon Jun 22 16:54:02 2020 +1000 missing files for webauthn/sshsig unit test commit 354535ff79380237924ac8fdc98f8cdf83e67da6 Author: djm@openbsd.org Date: Mon Jun 22 06:00:06 2020 +0000 upstream: add support for verification of webauthn sshsig signature, and example HTML/JS to generate webauthn signatures in SSH formats (also used to generate the testdata/* for the test). OpenBSD-Regress-ID: dc575be5bb1796fdf4b8aaee0ef52a6671a0f6fb commit bb52e70fa5330070ec9a23069c311d9e277bbd6f Author: djm@openbsd.org Date: Mon Jun 22 05:58:35 2020 +0000 upstream: Add support for FIDO webauthn (verification only). webauthn is a standard for using FIDO keys in web browsers. webauthn signatures are a slightly different format to plain FIDO signatures - this support allows verification of these. Feedback and ok markus@ OpenBSD-Commit-ID: ab7e3a9fb5782d99d574f408614d833379e564ad commit 64bc121097f377142f1387ffb2df7592c49935af Author: djm@openbsd.org Date: Mon Jun 22 05:56:23 2020 +0000 upstream: refactor ECDSA-SK verification a little ahead of adding support for FIDO webauthn signature verification support; ok markus@ OpenBSD-Commit-ID: c9f478fd8e0c1bd17e511ce8694f010d8e32043e commit 12848191f8fe725af4485d3600e0842d92f8637f Author: djm@openbsd.org Date: Mon Jun 22 05:54:10 2020 +0000 upstream: support for RFC4648 base64url encoding; ok markus OpenBSD-Commit-ID: 0ef22c55e772dda05c112c88412c0797fec66eb4 commit 473b4af43db12127137c7fc1a10928313f5a16d2 Author: djm@openbsd.org Date: Mon Jun 22 05:53:26 2020 +0000 upstream: better terminology for permissions; feedback & ok markus@ OpenBSD-Commit-ID: ff2a71803b5ea57b83cc3fa9b3be42b70e462fb9 commit fc270baf264248c3ee3050b13a6c8c0919e6559f Author: djm@openbsd.org Date: Mon Jun 22 05:52:05 2020 +0000 upstream: better terminology for permissions; feedback & ok markus@ OpenBSD-Commit-ID: ffb220b435610741dcb4de0e7fc68cbbdc876d2c commit 00531bb42f1af17ddabea59c3d9c4b0629000d27 Author: dtucker@openbsd.org Date: Fri Jun 19 07:21:42 2020 +0000 upstream: Correct synopsis and usage for the options accepted when passing a command to ssh-agent. ok jmc@ OpenBSD-Commit-ID: b36f0679cb0cac0e33b361051b3406ade82ea846 commit b4556c8ad7177e379f0b60305a0cd70f12180e7c Author: Darren Tucker Date: Fri Jun 19 19:22:00 2020 +1000 Add OPENBSD ORIGINAL marker to bcrypt_pbkdf. commit 1babb8bb14c423011ca34c2f563bb1c51c8fbf1d Author: Darren Tucker Date: Fri Jun 19 19:10:47 2020 +1000 Extra brackets around sizeof() in bcrypt. Prevents following warning from clang 10: bcrypt_pbkdf.c:94:40: error: expression does not compute the number of elements in this array; element type is ´uint32_tÂ[...] place parentheses around the ´sizeof(uint64_t)´ expression to silence this warning commit 9e065729592633290e5ddb6852792913b2286545 Author: Darren Tucker Date: Fri Jun 19 18:47:56 2020 +1000 Add includes.h to new test. Fixes warnings eg "´bounded´ attribute directive ignor" from gcc. commit e684b1ea365e070433f282a3c1dabc3e2311ce49 Author: Darren Tucker Date: Fri Jun 19 18:38:39 2020 +1000 Skip OpenSSL specific tests w/out OpenSSL. Allows unit tests to pass when configure'ed --without-openssl. commit 80610e97a76407ca982e62fd051c9be03622fe7b Author: Darren Tucker Date: Fri Jun 19 17:15:27 2020 +1000 Hook sshsig tests up to Portable Makefiles. commit 5dba1fcabacaab46693338ec829b42a1293d1f52 Author: dtucker@openbsd.org Date: Fri Jun 19 05:07:09 2020 +0000 upstream: Test that ssh-agent exits when running as as subprocess of a specified command (ie "ssh-agent command"). Would have caught bz#3181. OpenBSD-Regress-ID: 895b4765ba5153eefaea3160a7fe08ac0b6db8b3 commit 68e8294f6b04f9590ea227e63d3e129398a49e27 Author: djm@openbsd.org Date: Fri Jun 19 04:34:21 2020 +0000 upstream: run sshsig unit tests OpenBSD-Regress-ID: 706ef17e2b545b64873626e0e35553da7c06052a commit 5edfa1690e9a75048971fd8775f7c16d153779db Author: djm@openbsd.org Date: Fri Jun 19 04:32:09 2020 +0000 upstream: basic unit test for sshsig.[ch], including FIDO keys verification only so far OpenBSD-Regress-ID: fb1f946c8fc59206bc6a6666e577b5d5d7e45896 commit e95c0a0e964827722d29b4bc00d5c0ff4afe0ed2 Author: djm@openbsd.org Date: Fri Jun 19 03:48:49 2020 +0000 upstream: basic unit test for FIDO kep parsing OpenBSD-Regress-ID: 8089b88393dd916d7c95422b442a6fd4cfe00c82 commit 7775819c6de3e9547ac57b87c7dd2bfd28cefcc5 Author: djm@openbsd.org Date: Thu Jun 18 23:34:19 2020 +0000 upstream: check public host key matches private; ok markus@ (as part of previous diff) OpenBSD-Commit-ID: 65a4f66436028748b59fb88b264cb8c94ce2ba63 commit c514f3c0522855b4d548286eaa113e209051a6d2 Author: djm@openbsd.org Date: Thu Jun 18 23:33:38 2020 +0000 upstream: avoid spurious "Unable to load host key" message when sshd can load a private key but no public counterpart; with & ok markus@ OpenBSD-Commit-ID: 0713cbdf9aa1ff8ac7b1f78b09ac911af510f81b commit 7fafaeb5da365f4a408fec355dac04a774f27193 Author: djm@openbsd.org Date: Fri Jun 12 05:26:37 2020 +0000 upstream: correct RFC number; from HARUYAMA Seigo via GH PR191 OpenBSD-Commit-ID: 8d03b6c96ca98bfbc23d3754c3c33e1fe0852e10 commit 3a7f654d5bcb20df24a134b6581b0d235da4564a Author: djm@openbsd.org Date: Fri Jun 5 06:18:07 2020 +0000 upstream: unbreak "sshd -ddd" - close of config passing fd happened too early. ok markus@ OpenBSD-Commit-ID: 49346e945c6447aca3e904e65fc400128d2f8ed0 commit 3de02be39e5c0c2208d9682a3844991651620fcc Author: Andreas Schwab Date: Mon May 25 11:10:44 2020 +0200 Add support for AUDIT_ARCH_RISCV64 commit ea547eb0329c2f8da77a4ac05f6c330bd49bdaab Author: djm@openbsd.org Date: Fri Jun 5 03:25:35 2020 +0000 upstream: make sshbuf_putb(b, NULL) a no-op OpenBSD-Commit-ID: 976fdc99b500e347023d430df372f31c1dd128f7 commit 69796297c812640415c6cea074ea61afc899cbaa Author: djm@openbsd.org Date: Fri Jun 5 03:24:36 2020 +0000 upstream: make sshbuf_dump() args const OpenBSD-Commit-ID: b4a5accae750875d665b862504169769bcf663bd commit 670428895739d1f79894bdb2457891c3afa60a59 Author: djm@openbsd.org Date: Fri Jun 5 03:24:16 2020 +0000 upstream: wrap long line OpenBSD-Commit-ID: ed405a12bd27bdc9c52e169bc5ff3529b4ebbbb2 commit 2f648cf222882719040906722b3593b01df4ad1a Author: dtucker@openbsd.org Date: Fri Jun 5 03:15:26 2020 +0000 upstream: Correct historical comment: provos@ modified OpenSSH to work with SSLeay (very quickly replaced by OpenSSL) not SSL in general. ok deraadt, historical context markus@ OpenBSD-Commit-ID: 7209e07a2984b50411ed8ca5a4932da5030d2b90 commit 56548e4efcc3e3e8093c2eba30c75b23e561b172 Author: dtucker@openbsd.org Date: Wed Jun 3 08:23:18 2020 +0000 upstream: Import regenerated moduli file. OpenBSD-Commit-ID: 52ff0e3205036147b2499889353ac082e505ea54 commit 8da801f585dd9c534c0cbe487a3b1648036bf2fb Author: Darren Tucker Date: Fri Jun 5 13:20:10 2020 +1000 Test fallthrough in OSSH_CHECK_CFLAG_COMPILE. clang 10's -Wimplicit-fallthrough does not understand /* FALLTHROUGH */ comments and we don't use the __attribute__((fallthrough)) that it's looking for. This has the effect of turning off -Wimplicit-fallthrough where it does not currently help (particularly with -Werror). ok djm@ commit 049297de975b92adcc2db77e3fb7046c0e3c695d Author: dtucker@openbsd.org Date: Wed Jun 3 08:23:18 2020 +0000 upstream: Import regenerated moduli file. OpenBSD-Commit-ID: 52ff0e3205036147b2499889353ac082e505ea54 commit b458423a38a3140ac022ffcffcb332609faccfe3 Author: dtucker@openbsd.org Date: Mon Jun 1 07:11:38 2020 +0000 upstream: Remove now-unused proto_spec and associated definitions. ok djm@ OpenBSD-Commit-ID: 2e2b18e3aa6ee22a7b69c39f2d3bd679ec35c362 commit 5ad3c3a33ef038b55a14ebd31faeeec46073db2c Author: millert@openbsd.org Date: Fri May 29 21:22:02 2020 +0000 upstream: Fix error message on close(2) and add printf format attributes. From Christos Zoulas, OK markus@ OpenBSD-Commit-ID: 41523c999a9e3561fcc7082fd38ea2e0629ee07e commit 712ac1efb687a945a89db6aa3e998c1a17b38653 Author: dtucker@openbsd.org Date: Fri May 29 11:17:56 2020 +0000 upstream: Make dollar_expand variadic and pass a real va_list to vdollar_percent_expand. Fixes build error on arm64 spotted by otto@. OpenBSD-Commit-ID: 181910d7ae489f40ad609b4cf4a20f3d068a7279 commit 837ffa9699a9cba47ae7921d2876afaccc027133 Author: Darren Tucker Date: Fri May 29 20:39:00 2020 +1000 Omit ToS setting if we don't have IPV6_TCLASS too. Fixes tests on old BSDs. commit f85b118d2150847cc333895296bc230e367be6b5 Author: dtucker@openbsd.org Date: Fri May 29 09:02:44 2020 +0000 upstream: Pass a NULL instead of zeroed out va_list from dollar_expand. The original intent was in case there's some platform where va_list is not a pointer equivalent, but on i386 this chokes on the memset. This unbreaks that build, but will require further consideration. OpenBSD-Commit-ID: 7b90afcd8e1137a1d863204060052aef415baaf7 commit ec1d50b01c84ff667240ed525f669454c4ebc8e9 Author: jmc@openbsd.org Date: Fri May 29 05:48:39 2020 +0000 upstream: remove a stray .El; OpenBSD-Commit-ID: 58ddfe6f8a15fe10209db6664ecbe7896f1d167c commit 058674a62ffe33f01d871d46e624bc2a2c22d91f Author: dtucker@openbsd.org Date: Fri May 29 04:32:26 2020 +0000 upstream: Add regression and unit tests for ${ENV} style environment variable expansion in various keywords (bz#3140). ok djm@ OpenBSD-Regress-ID: 4d9ceb95d89365b7b674bc26cf064c15a5bbb197 commit 0b15892fc47d6840eba1291a6be9be1a70bc8972 Author: dtucker@openbsd.org Date: Fri May 29 01:21:35 2020 +0000 upstream: Unit test for convtime. ok djm@ OpenBSD-Regress-ID: cec4239efa2fc4c7062064f07a847e1cbdbcd5dd commit 188e332d1c8f9f24e5b6659e9680bf083f837df9 Author: djm@openbsd.org Date: Fri May 29 05:37:03 2020 +0000 upstream: mention that wildcards are processed in lexical order; bz#3165 OpenBSD-Commit-ID: 8856f3d1612bd42e9ee606d89386cae456dd165c commit 4a1b46e6d032608b7ec00ae51c4e25b82f460b05 Author: dtucker@openbsd.org Date: Fri May 29 04:25:40 2020 +0000 upstream: Allow some keywords to expand shell-style ${ENV} environment variables on the client side. The supported keywords are CertificateFile, ControlPath, IdentityAgent and IdentityFile, plus LocalForward and RemoteForward when used for Unix domain socket paths. This would for example allow forwarding of Unix domain socket paths that change at runtime. bz#3140, ok djm@ OpenBSD-Commit-ID: a4a2e801fc2d4df2fe0e58f50d9c81b03822dffa commit c9bab1d3a9e183cef3a3412f57880a0374cc8cb2 Author: Damien Miller Date: Fri May 29 14:49:16 2020 +1000 depend commit 0b0d219313bf9239ca043f20b1a095db0245588f Author: sobrado Date: Thu Sep 3 23:06:28 2015 +0000 partial sync of regress/netcat.c with upstream synchronize synopsis and usage. commit 0f04c8467f589f85a523e19fd684c4f6c4ed9482 Author: chl Date: Sun Jul 26 19:12:28 2015 +0000 partial sync of regress/netcat.c with upstream remove unused variable ok tedu@ commit d6a81050ace2630b06c3c6dd39bb4eef5d1043f8 Author: tobias Date: Thu Mar 26 21:22:50 2015 +0000 partial sync of regress/netcat.c with upstream The code in socks.c writes multiple times in a row to a socket. If the socket becomes invalid between these calls (e.g. connection closed), write will throw SIGPIPE. With this patch, SIGPIPE is ignored so we can handle write's -1 return value (errno will be EPIPE). Ultimately, it leads to program exit, too -- but with nicer error message. :) with input by and ok djm commit bf3893dddd35e16def04bf48ed2ee1ad695b8f82 Author: tobias Date: Thu Mar 26 10:36:03 2015 +0000 partial sync of regress/netcat.c with upstream Check for short writes in fdpass(). Clean up while at it. ok djm commit e18435fec124b4c08eb6bbbbee9693dc04f4befb Author: jca Date: Sat Feb 14 22:40:22 2015 +0000 partial sync of regress/netcat.c with upstream Support for nc -T on IPv6 addresses. ok sthen@ commit 4c607244054a036ad3b2449a6cb4c15feb846a76 Author: djm@openbsd.org Date: Fri May 29 03:14:02 2020 +0000 upstream: fix compilation on !HAVE_DLOPEN platforms; stub function was not updated to match API change. From Dale Rahn via beck@ ok markus@ OpenBSD-Commit-ID: 2b8d054afe34c9ac85e417dae702ef981917b836 commit 224418cf55611869a4ace1b8b07bba0dff77a9c3 Author: djm@openbsd.org Date: Fri May 29 03:11:54 2020 +0000 upstream: fix exit status for downloading of FIDO resident keys; from Pedro Martelletto, ok markus@ OpenBSD-Commit-ID: 0da77dc24a1084798eedd83c39a002a9d231faef commit 1001dd148ed7c57bccf56afb40cb77482ea343a6 Author: dtucker@openbsd.org Date: Fri May 29 01:20:46 2020 +0000 upstream: Fix multiplier in convtime when handling seconds after other units. bz#3171, spotted by ronf at timeheart.net, ok djm@. OpenBSD-Commit-ID: 95b7a848e1083974a65fbb6ccb381d438e1dd5be commit 7af1e92cd289b7eaa9a683e9a6f2fddd98f37a01 Author: djm@openbsd.org Date: Wed May 27 22:37:53 2020 +0000 upstream: fix Include before Match in sshd_config; bz#3122 patch from Jakub Jelen OpenBSD-Commit-ID: 1b0aaf135fe6732b5d326946042665dd3beba5f4 commit 0a9a611619b0a1fecd0195ec86a9885f5d681c84 Author: djm@openbsd.org Date: Wed May 27 21:59:11 2020 +0000 upstream: Do not call process_queued_listen_addrs() for every included file from sshd_config; patch from Jakub Jelen OpenBSD-Commit-ID: 0ff603d6f06a7fab4881f12503b53024799d0a49 commit 16ea1fdbe736648f79a827219134331f8d9844fb Author: djm@openbsd.org Date: Wed May 27 21:25:18 2020 +0000 upstream: fix crash in recallocarray when deleting SendEnv variables; spotted by & ok sthen@ OpenBSD-Commit-ID: b881e8e849edeec5082b5c0a87d8d7cff091a8fd commit 47adfdc07f4f8ea0064a1495500244de08d311ed Author: djm@openbsd.org Date: Wed May 27 22:35:19 2020 +0000 upstream: two new tests for Include in sshd_config, checking whether Port directives are processed correctly and handling of Include directives that appear before Match. Both tests currently fail. bz#3122 and bz#3169 - patch from Jakub Jelen OpenBSD-Regress-ID: 8ad5a4a385a63f0a1c59c59c763ff029b45715df commit 47faad8f794516c33864d866aa1b55d88416f94c Author: Darren Tucker Date: Wed May 27 23:26:23 2020 +1000 Document that libfido2 >= 1.4.0 is needed. commit 4be563994c0cbe9856e7dd3078909f41beae4a9c Author: djm@openbsd.org Date: Tue May 26 01:59:46 2020 +0000 upstream: fix memleak of signature; from Pedro Martelletto OpenBSD-Commit-ID: d0a6eb07e77c001427d738b220dd024ddc64b2bb commit 0c111eb84efba7c2a38b2cc3278901a0123161b9 Author: djm@openbsd.org Date: Tue May 26 01:26:58 2020 +0000 upstream: Restrict ssh-agent from signing web challenges for FIDO keys. When signing messages in ssh-agent using a FIDO key that has an application string that does not start with "ssh:", ensure that the message being signed is one of the forms expected for the SSH protocol (currently pubkey authentication and sshsig signatures). This prevents ssh-agent forwarding on a host that has FIDO keys attached granting the ability for the remote side to sign challenges for web authentication using those keys too. Note that the converse case of web browsers signing SSH challenges is already precluded because no web RP can have the "ssh:" prefix in the application string that we require. ok markus@ OpenBSD-Commit-ID: 9ab6012574ed0352d2f097d307f4a988222d1b19 commit 9c5f64b6cb3a68b99915202d318b842c6c76cf14 Author: djm@openbsd.org Date: Tue May 26 01:09:05 2020 +0000 upstream: improve logging for MaxStartups connection throttling: have sshd log when it starts and stops throttling and periodically while in this state. bz#3055 ok markus@ OpenBSD-Commit-ID: 2e07a09a62ab45d790d3d2d714f8cc09a9ac7ab9 commit 756c6f66aee83a5862a6f936a316f761532f3320 Author: djm@openbsd.org Date: Tue May 26 01:06:52 2020 +0000 upstream: add fmt_timeframe() (from bgpd) to format a time interval in a human- friendly format. Switch copyright for this file from BSD to MIT to make it easier to add Henning's copyright for this function. ok markus@ OpenBSD-Commit-ID: 414a831c662df7e68893e5233e86f2cac081ccf9 commit 2a63ce5cd6d0e782783bf721462239b03757dd49 Author: djm@openbsd.org Date: Mon May 18 04:29:35 2020 +0000 upstream: avoid possible NULL deref; from Pedro Martelletto OpenBSD-Commit-ID: e6099c3fbb70aa67eb106e84d8b43f1fa919b721 commit 4b307faf2fb0e63e51a550b37652f7f972df9676 Author: markus@openbsd.org Date: Fri May 15 08:34:03 2020 +0000 upstream: sshd listener must not block if reexecd sshd exits in write(2) on config_s[0] if the forked child exits early before finishing recv_rexec_state (e.g. with fatal()) because config_s[1] stays open in the parent. this prevents the parent from accepting new connections. ok djm, deraadt OpenBSD-Commit-ID: 92ccfeb939ccd55bda914dc3fe84582158c4a9ef commit af8b16fb2cce880341c0ee570ceb0d84104bdcc0 Author: djm@openbsd.org Date: Fri May 15 03:57:33 2020 +0000 upstream: fix off-by-one error that caused sftp downloads to make one more concurrent request that desired. This prevented using sftp(1) in unpipelined request/response mode, which is useful when debugging. Patch from Stephen Goetze in bz#3054 OpenBSD-Commit-ID: 41b394ebe57037dbc43bdd0eef21ff0511191f28 commit d7d753e2979f2d3c904b03a08d30856cd2a6e892 Author: deraadt@openbsd.org Date: Wed May 13 22:38:41 2020 +0000 upstream: we are still aiming for pre-C99 ... OpenBSD-Commit-ID: a240fc9cbe60bc4e6c3d24d022eb4ab01fe1cb38 commit 2ad7b7e46408dbebf2a4efc4efd75a9544197d57 Author: djm@openbsd.org Date: Wed May 13 10:08:02 2020 +0000 upstream: Enable credProtect extension when generating a resident key. The FIDO 2.1 Client to Authenticator Protocol introduced a "credProtect" feature to better protect resident keys. This option allows (amone other possibilities) requiring a PIN prior to all operations that may retrieve the key handle. Patch by Pedro Martelletto; ok djm and markus OpenBSD-Commit-ID: 013bc06a577dcaa66be3913b7f183eb8cad87e73 commit 1e70dc3285fc9b4f6454975acb81e8702c23dd89 Author: djm@openbsd.org Date: Wed May 13 09:57:17 2020 +0000 upstream: always call fido_init(); previous behaviour only called fido_init() when SK_DEBUG was defined. Harmless with current libfido2, but this isn't guaranteed in the future. OpenBSD-Commit-ID: c7ea20ff2bcd98dd12015d748d3672d4f01f0864 commit f2d84f1b3fa68d77c99238d4c645d0266fae2a74 Author: djm@openbsd.org Date: Wed May 13 09:55:57 2020 +0000 upstream: preserve group/world read permission on known_hosts file across runs of "ssh-keygen -Rf /path". The old behaviour was to remove all rights for group/other. bz#3146 ok dtucker@ OpenBSD-Commit-ID: dc369d0e0b5dd826430c63fd5f4b269953448a8a commit 05a651400da6fbe12296c34e3d3bcf09f034fbbf Author: djm@openbsd.org Date: Wed May 13 09:52:41 2020 +0000 upstream: when ordering the hostkey algorithms to request from a server, prefer certificate types if the known_hosts files contain a key marked as a @cert-authority; bz#3157 ok markus@ OpenBSD-Commit-ID: 8f194573e5bb7c01b69bbfaabc68f27c9fa5e0db commit 829451815ec207e14bd54ff5cf7e22046816f042 Author: djm@openbsd.org Date: Tue May 12 01:41:32 2020 +0000 upstream: fix non-ASCII quote that snuck in; spotted by Gabriel Kihlman OpenBSD-Commit-ID: 04bcde311de2325d9e45730c744c8de079b49800 commit 5a442cec92c0efd6fffb4af84bf99c70af248ef3 Author: djm@openbsd.org Date: Mon May 11 02:11:29 2020 +0000 upstream: clarify role of FIDO tokens in multi-factor authentictation; mostly from Pedro Martelletto OpenBSD-Commit-ID: fbe05685a1f99c74b1baca7130c5a03c2df7c0ac commit ecb2c02d994b3e21994f31a70ff911667c262f1f Author: djm@openbsd.org Date: Fri May 8 05:13:14 2020 +0000 upstream: fix compilation with DEBUG_KEXDH; bz#3160 ok dtucker@ OpenBSD-Commit-ID: 832e771948fb45f2270e8b8895aac36d176ba17a commit 3ab6fccc3935e9b778ff52f9c8d40f215d58e01d Author: Damien Miller Date: Thu May 14 12:22:09 2020 +1000 prefer ln to cp for temporary copy of sshd I saw failures on the reexec fallback test on Darwin 19.4 where fork()ed children of a process that had it's executable removed would instantly fail. Using ln to preserve the inode avoids this. commit f700d316c6b15a9cfbe87230d2dca81a5d916279 Author: Darren Tucker Date: Wed May 13 15:24:51 2020 +1000 Actually skip pty tests when needed. commit 08ce6b2210f46f795e7db747809f8e587429dfd2 Author: Darren Tucker Date: Wed May 13 13:56:45 2020 +1000 Skip building sk-dummy library if no SK support. commit 102d106bc2e50347d0e545fad6ff5ce408d67247 Author: Damien Miller Date: Wed May 13 12:08:34 2020 +1000 explicitly manage .depend and .depend.bak Bring back removal of .depend to give the file a known state before running makedepend, but manually move aside the current .depend file and restore it as .depend.bak afterwards so the stale .depend check works as expected. commit 83a6dc6ba1e03b3fa39d12a8522b8b0e68dd6390 Author: Damien Miller Date: Wed May 13 12:03:42 2020 +1000 make depend commit 7c0bbed967abed6301a63e0267cc64144357a99a Author: Damien Miller Date: Wed May 13 12:01:10 2020 +1000 revert removal of .depend before makedepend Commit 83657eac4 started removing .depend before running makedepend to reset the contents of .depend to a known state. Unfortunately this broke the depend-check step as now .depend.bak would only ever be created as an empty file. ok dtucker commit 58ad004acdcabf3b9f40bc3aaa206b25d998db8c Author: Damien Miller Date: Tue May 12 12:58:46 2020 +1000 prepare for 8.3 release commit 4fa9e048c2af26beb7dc2ee9479ff3323e92a7b5 Author: Darren Tucker Date: Fri May 8 21:50:43 2020 +1000 Ensure SA_SIGNAL test only signals itself. When the test's child signals its parent and it exits the result of getppid changes. On Ubuntu 20.04 this results in the ppid being that of the GDM session, causing it to exit. Analysis and testing from pedro at ambientworks.net commit dc2da29aae76e170d22f38bb36f1f5d1edd5ec2b Author: Damien Miller Date: Fri May 8 13:31:53 2020 +1000 sync config.guess/config.sub with latest versions ok dtucker@ commit a8265bd64c14881fc7f4fa592f46dfc66b911f17 Author: djm@openbsd.org Date: Wed May 6 20:58:01 2020 +0000 upstream: openssh-8.3; ok deraadt@ OpenBSD-Commit-ID: c8831ec88b9c750f5816aed9051031fb535d22c1 commit 955854cafca88e0cdcd3d09ca1ad4ada465364a1 Author: djm@openbsd.org Date: Wed May 6 20:57:38 2020 +0000 upstream: another case where a utimes() failure could make scp send a desynchronising error; reminded by Aymeric Vincent ok deraadt markus OpenBSD-Commit-ID: 2ea611d34d8ff6d703a7a8bf858aa5dbfbfa7381 commit 59d531553fd90196946743da391f3a27cf472f4e Author: Darren Tucker Date: Thu May 7 15:34:12 2020 +1000 Check if -D_REENTRANT is needed for localtime_r. On at least HP-UX 11.11, the localtime_r declararation is behind ifdef _REENTRANT. Check for and add if needed. commit c13403e55de8cdbb9da628ed95017b1d4c0f205f Author: Darren Tucker Date: Tue May 5 11:32:43 2020 +1000 Skip security key tests if ENABLE_SK not set. commit 4da393f87cd52d788c84112ee3f2191c9bcaaf30 Author: djm@openbsd.org Date: Fri May 1 04:03:14 2020 +0000 upstream: sure enough, some of the test data that we though were in new format were actually in the old format; fix from Michael Forney OpenBSD-Regress-ID: a41a5c43a61b0f0b1691994dbf16dfb88e8af933 commit 15bfafc1db4c8792265ada9623a96f387990f732 Author: djm@openbsd.org Date: Fri May 1 04:00:29 2020 +0000 upstream: make mktestdata.sh generate old/new format keys that we expect. This script was written before OpenSSH switched to new-format private keys by default and was never updated to the change (until now) From Michael Forney OpenBSD-Regress-ID: 38cf354715c96852e5b71c2393fb6e7ad28b7ca7 commit 7882d2eda6ad3eb82220a85294de545d20ef82db Author: djm@openbsd.org Date: Fri May 1 03:58:02 2020 +0000 upstream: portability fix for sed that always emil a newline even if the input does not contain one; from Michael Forney OpenBSD-Regress-ID: 9190c3ddf0d2562ccc02c4a95fce0e392196bfc7 commit 8074f9499e454df0acdacea33598858a1453a357 Author: djm@openbsd.org Date: Fri May 1 03:36:25 2020 +0000 upstream: remove obsolete RSA1 test keys; spotted by Michael Forney OpenBSD-Regress-ID: 6384ba889594e217d166908ed8253718ab0866da commit c697e46c314aa94574af0d393d80f23e0ebc9748 Author: Darren Tucker Date: Sat May 2 18:34:47 2020 +1000 Update .depend. commit 83657eac42941f270c4b02b2c46d9a21f616ef99 Author: Darren Tucker Date: Sat May 2 18:29:40 2020 +1000 Remove use of tail for 'make depend'. Not every tail supports +N and we can do with out it so just remove it. Prompted by mforney at mforney.org. commit d25d630d24c5a1c64d4e646510e79dc22d6d7b88 Author: djm@openbsd.org Date: Sat May 2 07:19:43 2020 +0000 upstream: we have a sshkey_save_public() function to save public keys; use it and save a bunch of redundant code. Patch from loic AT venez.fr; ok markus@ djm@ OpenBSD-Commit-ID: f93e030a0ebcd0fd9054ab30db501ec63454ea5f commit e9dc9863723e111ae05e353d69df857f0169544a Author: Darren Tucker Date: Fri May 1 18:32:25 2020 +1000 Use LONG_LONG_MAX and friends if available. If we don't have LLONG_{MIN,MAX} but do have LONG_LONG_{MIN,MAX} then use those instead. We do calculate these values in configure, but it turns out that at least one compiler (old HP ANSI C) can't parse "-9223372036854775808LL" without mangling it. (It can parse "-9223372036854775807LL" which is presumably why its limits.h defines LONG_LONG_MIN as the latter minus 1.) Fixes rekey test when compiled with the aforementioned compiler. commit aad87b88fc2536b1ea023213729aaf4eaabe1894 Author: djm@openbsd.org Date: Fri May 1 06:31:42 2020 +0000 upstream: when receving a file in sink(), be careful to send at most a single error response after the file has been opened. Otherwise the source() and sink() can become desyncronised. Reported by Daniel Goujot, Georges-Axel Jaloyan, Ryan Lahfa, and David Naccache. ok deraadt@ markus@ OpenBSD-Commit-ID: 6c14d233c97349cb811a8f7921ded3ae7d9e0035 commit 31909696c4620c431dd55f6cd15db65c4e9b98da Author: djm@openbsd.org Date: Fri May 1 06:28:52 2020 +0000 upstream: expose vasnmprintf(); ok (as part of other commit) markus deraadt OpenBSD-Commit-ID: 2e80cea441c599631a870fd40307d2ade5a7f9b5 commit 99ce9cefbe532ae979744c6d956b49f4b02aff82 Author: djm@openbsd.org Date: Fri May 1 04:23:11 2020 +0000 upstream: avoid NULL dereference when attempting to convert invalid ssh.com private keys using "ssh-keygen -i"; spotted by Michael Forney OpenBSD-Commit-ID: 2e56e6d26973967d11d13f56ea67145f435bf298 commit 6c6072ba8b079e6f5caa38b011a6f4570c14ed38 Author: Darren Tucker Date: Fri May 1 15:09:26 2020 +1000 See if SA_RESTART signals will interrupt select(). On some platforms (at least older HP-UXes such as 11.11, possibly others) setting SA_RESTART on signal handers will cause it to not interrupt select(), at least for calls that do not specify a timeout. Try to detect this and if found, don't use SA_RESTART. POSIX says "If SA_RESTART has been set for the interrupting signal, it is implementation-dependent whether select() restarts or returns with [EINTR]" so this behaviour is within spec. commit 90a0b434ed41f9c505662dba8782591818599cb3 Author: Damien Miller Date: Fri May 1 13:55:03 2020 +1000 fix reversed test commit c0dfd18dd1c2107c73d18f70cd164f7ebd434b08 Author: Damien Miller Date: Fri May 1 13:29:16 2020 +1000 wrap sha2.h inclusion in #ifdef HAVE_SHA2_H commit a01817a9f63dbcbbc6293aacc4019993a4cdc7e3 Author: djm@openbsd.org Date: Tue Apr 28 04:59:29 2020 +0000 upstream: adapt dummy FIDO middleware to API change; ok markus@ OpenBSD-Regress-ID: 8bb84ee500c2eaa5616044314dd0247709a1790f commit 261571ddf02ea38fdb5e4a97c69ee53f847ca5b7 Author: jmc@openbsd.org Date: Thu Apr 30 18:28:37 2020 +0000 upstream: tweak previous; ok markus OpenBSD-Commit-ID: 41895450ce2294ec44a5713134491cc31f0c09fd commit 5de21c82e1d806d3e401b5338371e354b2e0a66f Author: markus@openbsd.org Date: Thu Apr 30 17:12:20 2020 +0000 upstream: bring back debug() removed in rev 1.74; noted by pradeep kumar OpenBSD-Commit-ID: 8d134d22ab25979078a3b48d058557d49c402e65 commit ea14103ce9a5e13492e805f7e9277516ff5a4273 Author: markus@openbsd.org Date: Thu Apr 30 17:07:10 2020 +0000 upstream: run the 2nd ssh with BatchMode for scp -3 OpenBSD-Commit-ID: 77994fc8c7ca02d88e6d0d06d0f0fe842a935748 commit 59d2de956ed29aa5565ed5e5947a7abdb27ac013 Author: djm@openbsd.org Date: Tue Apr 28 04:02:29 2020 +0000 upstream: when signing a challenge using a FIDO toke, perform the hashing in the middleware layer rather than in ssh code. This allows middlewares that call APIs that perform the hashing implicitly (including Microsoft's AFAIK). ok markus@ OpenBSD-Commit-ID: c9fc8630aba26c75d5016884932f08a5a237f37d commit c9d10dbc0ccfb1c7568bbb784f7aeb7a0b5ded12 Author: dtucker@openbsd.org Date: Sun Apr 26 09:38:14 2020 +0000 upstream: Fix comment typo. Patch from mforney at mforney.org. OpenBSD-Commit-ID: 3565f056003707a5e678e60e03f7a3efd0464a2b commit 4d2c87b4d1bde019cdd0f00552fcf97dd8b39940 Author: dtucker@openbsd.org Date: Sat Apr 25 06:59:36 2020 +0000 upstream: We've standardized on memset over bzero, replace a couple that had slipped in. ok deraadt markus djm. OpenBSD-Commit-ID: f5be055554ee93e6cc66b0053b590bef3728dbd6 commit 7f23f42123d64272a7b00754afa6b0841d676691 Author: Darren Tucker Date: Fri May 1 12:21:58 2020 +1000 Include sys/byteorder.h for htons and friends. These are usually in netinet/in.h but on HP-UX they are not defined if _XOPEN_SOURCE_EXTENDED is set. Only needed for netcat in the regression tests. commit d27cba58c972d101a5de976777e518f34ac779cb Author: Darren Tucker Date: Fri May 1 09:21:52 2020 +1000 Fix conditional for openssl-based chacha20. Fixes warnings or link errors when building against older OpenSSLs. ok djm commit 20819b962dc1467cd6fad5486a7020c850efdbee Author: Darren Tucker Date: Fri Apr 24 15:07:55 2020 +1000 Error out if given RDomain if unsupported. If the config contained 'RDomain %D' on a platform that did not support it, the error would not be detected until runtime resulting in a broken sshd. Detect this earlier and error out if found. bz#3126, based on a patch from jjelen at redhat.com, tweaks and ok djm@ commit 2c1690115a585c624eed2435075a93a463a894e2 Author: dtucker@openbsd.org Date: Fri Apr 24 03:33:21 2020 +0000 upstream: Fix incorrect error message for "too many known hosts files." bz#3149, patch from jjelen at redhat.com. OpenBSD-Commit-ID: e0fcb07ed5cf7fd54ce340471a747c24454235e5 commit 3beb7276e7a8aedd3d4a49f9c03b97f643448c92 Author: dtucker@openbsd.org Date: Fri Apr 24 02:19:40 2020 +0000 upstream: Remove leave_non_blocking() which is now dead code because nothing sets in_non_blocking_mode any more. Patch from michaael.meeks at collabora.com, ok djm@ OpenBSD-Commit-ID: c403cefe97a5a99eca816e19cc849cdf926bd09c commit 8654e3561772f0656e7663a0bd6a1a8cb6d43300 Author: jmc@openbsd.org Date: Thu Apr 23 21:28:09 2020 +0000 upstream: ce examples of "Ar arg Ar arg" with "Ar arg arg" and stop the spread; OpenBSD-Commit-ID: af0e952ea0f5e2019c2ce953ed1796eca47f0705 commit 67697e4a8246dd8423e44b8785f3ee31fee72d07 Author: Darren Tucker Date: Fri Apr 24 11:10:18 2020 +1000 Update .depend. commit d6cc76176216fe3fac16cd20d148d75cb9c50876 Author: Darren Tucker Date: Wed Apr 22 14:07:00 2020 +1000 Mailing list is now closed to non-subscribers. While there, add a reference to the bugzilla. ok djm@ commit cecde6a41689d0ae585ec903b190755613a6de79 Author: Darren Tucker Date: Wed Apr 22 12:09:40 2020 +1000 Put the values from env vars back. This merges the values from the recently removed environment into make's command line arguments since we actually need those. commit 300c4322b92e98d3346efa0aec1c094c94d0f964 Author: Darren Tucker Date: Wed Apr 22 11:33:15 2020 +1000 Pass configure's egrep through to test-exec.sh. Use it to create a wrapper function to call it from tests. Fixes the keygen-comment test on platforms with impoverished default egrep (eg Solaris). commit c8d9796cfe046f00eb8b2096d2b7028d6a523a84 Author: Darren Tucker Date: Wed Apr 22 10:56:44 2020 +1000 Remove unneeded env vars from t-exec invocation. commit 01d4cdcd4514e99a4b6eb9523cd832bbf008d1d7 Author: dtucker@openbsd.org Date: Tue Apr 21 23:14:58 2020 +0000 upstream: Backslash '$' at then end of string. Prevents warning on some shells. OpenBSD-Regress-ID: 5dc27ab624c09d34078fd326b10e38c1ce9c741f commit 8854724ccefc1fa16f10b37eda2e759c98148caa Author: Darren Tucker Date: Tue Apr 21 18:27:23 2020 +1000 Sync rev 1.49. Prevent infinite for loop since i went from ssize_t to size_t. Patch from eagleoflqj via OpenSSH github PR#178, ok djm@, feedback & ok millert@ commit d00d07b6744d3b4bb7aca46c734ecd670148da23 Author: djm@openbsd.org Date: Mon Apr 20 04:44:47 2020 +0000 upstream: regression test for printing of private key fingerprints and key comments, mostly by loic AT venez.fr (slightly tweaked for portability) ok dtucker@ OpenBSD-Regress-ID: 8dc6c4feaf4fe58b6d634cd89afac9a13fd19004 commit a98d5ba31e5e7e01317352f85fa63b846a960f8c Author: djm@openbsd.org Date: Mon Apr 20 04:43:57 2020 +0000 upstream: fix a bug I introduced in r1.406: when printing private key fingerprint of old-format key, key comments were not being displayed. Spotted by loic AT venez.fr, ok dtucker OpenBSD-Commit-ID: 2d98e4f9eb168eea733d17e141e1ead9fe26e533 commit 32f2d0aad42c15e19bd3b07496076ca891573a58 Author: djm@openbsd.org Date: Fri Apr 17 07:16:07 2020 +0000 upstream: repair private key fingerprint printing to also print comment after regression caused by my recent pubkey loading refactor. Reported by loic AT venez.fr, ok dtucker@ OpenBSD-Commit-ID: f8db49acbee6a6ccb2a4259135693b3cceedb89e commit 094dd513f4b42e6a3cebefd18d1837eb709b4d99 Author: djm@openbsd.org Date: Fri Apr 17 07:15:11 2020 +0000 upstream: refactor out some duplicate private key loading code; based on patch from loic AT venez.fr, ok dtucker@ OpenBSD-Commit-ID: 5eff2476b0d8d0614924c55e350fb7bb9c84f45e commit 4e04f46f248f1708e39b900b76c9693c820eff68 Author: jmc@openbsd.org Date: Fri Apr 17 06:12:41 2020 +0000 upstream: add space beteen macro arg and punctuation; OpenBSD-Commit-ID: c93a6cbb4bf9468fc4c13e64bc1fd4efee201a44 commit 44ae009a0112081d0d541aeaa90088bedb6f21ce Author: djm@openbsd.org Date: Fri Apr 17 04:27:03 2020 +0000 upstream: auth2-pubkey r1.89 changed the order of operations to checking AuthorizedKeysFile first and falling back to AuthorizedKeysCommand if no key was found in a file. Document this order here; bz3134 OpenBSD-Commit-ID: afce0872cbfcfc1d4910ad7722e50f792a1dce12 commit f96f17f920f38ceea6f3c5cb0b075c46b8929fdc Author: Damien Miller Date: Fri Apr 17 14:07:15 2020 +1000 sys/sysctl.h is only used on OpenBSD so change the preprocessor test used to include it to check __OpenBSD__, matching the code that uses the symbols it declares. commit 54688e937a69c7aebef8a3d50cbd4c6345bab2ca Author: djm@openbsd.org Date: Fri Apr 17 03:38:47 2020 +0000 upstream: fix reversed test that caused IdentitiesOnly=yes to not apply to keys loaded from a PKCS11Provider; bz3141, ok dtucker@ OpenBSD-Commit-ID: e3dd6424b94685671fe84c9b9dbe352fb659f677 commit 267cbc87b5b6e78973ac4d3c7a6f807ed226928c Author: djm@openbsd.org Date: Fri Apr 17 03:34:42 2020 +0000 upstream: mention that /etc/hosts.equiv and /etc/shosts.equiv are not considered for HostbasedAuthentication when the target user is root; bz3148 OpenBSD-Commit-ID: fe4c1256929e53f23af17068fbef47852f4bd752 commit c90f72d29e84b4a2709078bf5546a72c29a65177 Author: djm@openbsd.org Date: Fri Apr 17 03:30:05 2020 +0000 upstream: make IgnoreRhosts a tri-state option: "yes" ignore rhosts/shosts, "no" allow rhosts/shosts or (new) "shosts-only" to allow .shosts files but not .rhosts. ok dtucker@ OpenBSD-Commit-ID: d08d6930ed06377a80cf53923c1955e9589342e9 commit 321c7147079270f3a154f91b59e66219aac3d514 Author: djm@openbsd.org 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 Date: Sat Apr 11 20:20:09 2020 +0000 upstream: add space between macro arg and punctuation; OpenBSD-Commit-ID: e579e4d95eef13059c30931ea1f09ed8296b819c commit 8af0244d7b4a65eed2e62f9c89141c7c8e63f09d Author: Darren Tucker Date: Wed Apr 15 10:58:02 2020 +1000 Add sys/syscall.h for syscall numbers. In some architecture/libc configurations we need to explicitly include sys/syscall.h for the syscall number (__NR_xxx) definitions. bz#3085, patch from blowfist at xroutine.net. commit 3779b50ee952078018a5d9e1df20977f4355df17 Author: djm@openbsd.org Date: Sat Apr 11 10:16:11 2020 +0000 upstream: Refactor private key parsing. Eliminates a fair bit of duplicated code and fixes oss-fuzz#20074 (NULL deref) caused by a missing key type check in the ECDSA_CERT parsing path. feedback and ok markus@ OpenBSD-Commit-ID: 4711981d88afb7196d228f7baad9be1d3b20f9c9 commit b6a4013647db67ec622c144a9e05dd768f1966b3 Author: dtucker@openbsd.org Date: Fri Apr 10 00:54:03 2020 +0000 upstream: Add tests for TOKEN expansion of LocalForward and RemoteForward. OpenBSD-Regress-ID: 90fcbc60d510eb114a2b6eaf4a06ff87ecd80a89 commit abc3e0a5179c13c0469a1b11fe17d832abc39999 Author: dtucker@openbsd.org Date: Mon Apr 6 09:43:55 2020 +0000 upstream: Add utf8.c for asmprintf used by krl.c OpenBSD-Regress-ID: 433708d11165afdb189fe635151d21659dd37a37 commit 990687a0336098566c3a854d23cce74a31ec6fe2 Author: dtucker@openbsd.org Date: Fri Apr 10 00:52:07 2020 +0000 upstream: Add TOKEN percent expansion to LocalFoward and RemoteForward when used for Unix domain socket forwarding. Factor out the code for the config keywords that use the most common subset of TOKENS into its own function. bz#3014, ok jmc@ (man page bits) djm@ OpenBSD-Commit-ID: bffc9f7e7b5cf420309a057408bef55171fd0b97 commit 2b13d3934d5803703c04803ca3a93078ecb5b715 Author: djm@openbsd.org Date: Wed Apr 8 00:10:37 2020 +0000 upstream: let sshkey_try_load_public() load public keys from the unencrypted envelope of private key files if not sidecar public key file is present. ok markus@ OpenBSD-Commit-ID: 252a0a580e10b9a6311632530d63b5ac76592040 commit d01f39304eaab0352793b490a25e1ab5f59a5366 Author: djm@openbsd.org Date: Wed Apr 8 00:09:24 2020 +0000 upstream: simplify sshkey_try_load_public() ok markus@ OpenBSD-Commit-ID: 05a5d46562aafcd70736c792208b1856064f40ad commit f290ab0833e44355fc006e4e67b92446c14673ef Author: djm@openbsd.org Date: Wed Apr 8 00:08:46 2020 +0000 upstream: add sshkey_parse_pubkey_from_private_fileblob_type() Extracts a public key from the unencrypted envelope of a new-style OpenSSH private key. ok markus@ OpenBSD-Commit-ID: 44d7ab446e5e8c686aee96d5897b26b3939939aa commit 8d514eea4ae089626a55e11c7bc1745c8d9683e4 Author: djm@openbsd.org Date: Wed Apr 8 00:07:19 2020 +0000 upstream: simplify sshkey_parse_private_fileblob_type() Try new format parser for all key types first, fall back to PEM parser only for invalid format errors. ok markus@ OpenBSD-Commit-ID: 0173bbb3a5cface77b0679d4dca0e15eb5600b77 commit 421169d0e758351b105eabfcebf42378ebf17217 Author: djm@openbsd.org Date: Wed Apr 8 00:05:59 2020 +0000 upstream: check private key type against requested key type in new-style private decoding; ok markus@ OpenBSD-Commit-ID: 04d44b3a34ce12ce5187fb6f6e441a88c8c51662 commit 6aabfb6d22b36d07f584cba97f4cdc4363a829da Author: djm@openbsd.org Date: Wed Apr 8 00:04:32 2020 +0000 upstream: check that pubkey in private key envelope matches actual private key (this public key is currently unusued) ok markus@ OpenBSD-Commit-ID: 634a60b5e135d75f48249ccdf042f3555112049c commit c0f5b2294796451001fd328c44f0d00f1114eddf Author: djm@openbsd.org Date: Wed Apr 8 00:01:52 2020 +0000 upstream: refactor private key parsing a little Split out the base64 decoding and private section decryption steps in to separate functions. This will make the decryption step easier to fuzz as well as making it easier to write a "load public key from new-format private key" function. ok markus@ OpenBSD-Commit-ID: 7de31d80fb9062aa01901ddf040c286b64ff904e - -commit 8461a5b3db34ed0b5a4a18d82f64fd5ac8693ea8 -Author: Darren Tucker -Date: Mon Apr 6 20:54:34 2020 +1000 - - Include openssl-compat.h before checking ifdefs. - - Fixes problem where unsuitable chacha20 code in libressl would be used - unintentionally. - -commit 931c50c5883a9910ea1ae9a371e4e815ec56b035 -Author: Damien Miller -Date: Mon Apr 6 10:04:56 2020 +1000 - - fix inverted test for LibreSSL version - -commit d1d5f728511e2338b7c994968d301d8723012264 -Author: dtucker@openbsd.org -Date: Sat Apr 4 23:04:41 2020 +0000 - - upstream: Indicate if we're using a cached key in trace output. - - OpenBSD-Regress-ID: 409a7b0e59d1272890fda507651c0c3d2d3c0d89 - -commit a398251a4627367c78bc483c70c2ec973223f82c -Author: Darren Tucker -Date: Sun Apr 5 08:43:57 2020 +1000 - - Use /usr/bin/xp4g/id if necessary. - - Solaris' native "id" doesn't support the options we use but the one - in /usr/bin/xp4g does, so use that instead. - -commit db0fdd48335b5b01114f78c1a73a195235910f81 -Author: dtucker@openbsd.org -Date: Sat Apr 4 22:14:26 2020 +0000 - - upstream: Some platforms don't have "hostname -s", so use cut to trim - - short hostname instead. - - OpenBSD-Regress-ID: ebcf36a6fdf287c9336b0d4f6fc9f793c05307a7 - -commit e7e59a9cc8eb7fd5944ded28f4d7e3ae0a5fdecd -Author: dtucker@openbsd.org -Date: Fri Apr 3 07:53:10 2020 +0000 - - upstream: Compute hash locally and re-enable %C tests. - - OpenBSD-Regress-ID: 94d1366e8105274858b88a1f9ad2e62801e49770 - -commit abe2b245b3ac6c4801e99bc0f13289cd28211e22 -Author: Damien Miller -Date: Fri Apr 3 17:25:46 2020 +1100 - - prefer libcrypto chacha20-poly1305 where possible - -commit bc5c5d01ad668981f9e554e62195383bc12e8528 -Author: dtucker@openbsd.org -Date: Fri Apr 3 05:43:11 2020 +0000 - - upstream: Temporarily remove tests for '%C' since the hash contains the - - local hostname and it doesn't work on any machine except mine... spotted by - djm@ - - OpenBSD-Regress-ID: 2d4c3585b9fcbbff14f4a5a5fde51dbd0d690401 - -commit 81624026989654955a657ebf2a1fe8b9994f3c87 -Author: djm@openbsd.org -Date: Fri Apr 3 06:07:57 2020 +0000 - - upstream: r1.522 deleted one too many lines; repair - - OpenBSD-Commit-ID: 1af8851fd7a99e4a887b19aa8f4c41a6b3d25477 - -commit 668cb3585ce829bd6e34d4a962c489bda1d16370 -Author: jmc@openbsd.org -Date: Fri Apr 3 05:53:52 2020 +0000 - - upstream: sort -N and add it to usage(); - - OpenBSD-Commit-ID: 5b00e8db37c2b0a54c7831fed9e5f4db53ada332 - -commit 338ccee1e7fefa47f3d128c2541e94c5270abe0c -Author: djm@openbsd.org -Date: Fri Apr 3 05:48:57 2020 +0000 - - upstream: avoid another compiler warning spotted in -portable - - OpenBSD-Commit-ID: 1d29c51ac844b287c4c8bcaf04c63c7d9ba3b8c7 - -commit 9f8a42340bd9af86a99cf554dc39ecdf89287544 -Author: djm@openbsd.org -Date: Fri Apr 3 04:07:48 2020 +0000 - - upstream: this needs utf8.c too - - OpenBSD-Regress-ID: 445040036cec714d28069a20da25553a04a28451 - -commit 92115ea7c3a834374720c350841fc729e7d5c8b2 -Author: dtucker@openbsd.org -Date: Fri Apr 3 03:14:03 2020 +0000 - - upstream: Add percent_expand test for 'Match Exec'. - - OpenBSD-Regress-ID: a41c14fd6a0b54d66aa1e9eebfb9ec962b41232f - -commit de34a440276ae855c38deb20f926d46752c62c9d -Author: djm@openbsd.org -Date: Fri Apr 3 04:43:24 2020 +0000 - - upstream: fix format string (use %llu for uint64, not %lld). spotted by - - Darren and his tinderbox tests - - OpenBSD-Commit-ID: 3b4587c3d9d46a7be9bdf028704201943fba96c2 - -commit 9cd40b829a5295cc81fbea8c7d632b2478db6274 -Author: djm@openbsd.org -Date: Fri Apr 3 04:34:15 2020 +0000 - - upstream: Add a flag to re-enable verbose output when in batch - - mode; requested in bz3135; ok dtucker - - OpenBSD-Commit-ID: 5ad2ed0e6440562ba9c84b666a5bbddc1afe2e2b - -commit 6ce51a5da5d333a44e7c74c027f3571f70c39b24 -Author: djm@openbsd.org -Date: Fri Apr 3 04:32:21 2020 +0000 - - upstream: chacha20-poly1305 AEAD using libcrypto EVP_chacha20 - - Based on patch from Yuriy M. Kaminskiy. ok + lots of assistance along the - way at a2k20 tb@ - - OpenBSD-Commit-ID: 5e08754c13d31258bae6c5e318cc96219d6b10f0 - -commit eba523f0a130f1cce829e6aecdcefa841f526a1a -Author: djm@openbsd.org -Date: Fri Apr 3 04:27:03 2020 +0000 - - upstream: make Chacha20-POLY1305 context struct opaque; ok tb@ as - - part of a larger diff at a2k20 - - OpenBSD-Commit-ID: a4609b7263284f95c9417ef60ed7cdbb7bf52cfd - -commit ebd29e90129cf18fedfcfe1de86e324228669295 -Author: djm@openbsd.org -Date: Fri Apr 3 04:06:26 2020 +0000 - - upstream: fix debug statement - - OpenBSD-Commit-ID: 42c6edeeda5ce88b51a20d88c93be3729ce6b916 - -commit 7b4d8999f2e1a0cb7b065e3efa83e6edccfc7d82 -Author: djm@openbsd.org -Date: Fri Apr 3 04:03:51 2020 +0000 - - upstream: the tunnel-forwarding vs ExitOnForwardFailure fix that I - - committed earlier had an off-by-one. Fix this and add some debugging that - would have made it apparent sooner. - - OpenBSD-Commit-ID: 082f8f72b1423bd81bbdad750925b906e5ac6910 - -commit eece243666d44ceb710d004624c5c7bdc05454bc -Author: dtucker@openbsd.org -Date: Fri Apr 3 03:12:11 2020 +0000 - - upstream: %C expansion just added to Match Exec should include - - remote user not local user. - - OpenBSD-Commit-ID: 80f1d976938f2a55ee350c11d8b796836c8397e2 - -commit d5318a784d016478fc8da90a38d9062c51c10432 -Author: dtucker@openbsd.org -Date: Fri Apr 3 02:33:31 2020 +0000 - - upstream: Add regression test for percent expansions where possible. - - OpenBSD-Regress-ID: 7283be8b2733ac1cbefea3048a23d02594485288 - -commit 663e84bb53de2a60e56a44d538d25b8152b5c1cc -Author: djm@openbsd.org -Date: Fri Apr 3 02:40:32 2020 +0000 - - upstream: make failures when establishing "Tunnel" forwarding terminate - - the connection when ExitOnForwardFailure is enabled; bz3116; ok dtucker - - OpenBSD-Commit-ID: ef4b4808de0a419c17579b1081da768625c1d735 - -commit ed833da176611a39d3376d62154eb88eb440d31c -Author: dtucker@openbsd.org -Date: Fri Apr 3 02:27:12 2020 +0000 - - upstream: Make with config keywords support which - - percent_expansions more consistent. - %C is moved into its own function and - added to Match Exec. - move the common (global) options into a macro. This - is ugly but it's the least-ugly way I could come up with. - move - IdentityAgent and ForwardAgent percent expansion to before the config dump - to make it regression-testable. - document all of the above - - ok jmc@ for man page bits, "makes things less terrible" djm@ for the rest. - - OpenBSD-Commit-ID: 4b65664bd6d8ae2a9afaf1a2438ddd1b614b1d75 - -commit 6ec7457171468da2bbd908b8cd63d298b0e049ea -Author: djm@openbsd.org -Date: Fri Apr 3 02:26:56 2020 +0000 - - upstream: give ssh-keygen the ability to dump the contents of a - - binary key revocation list: ssh-keygen -lQf /path bz#3132; ok dtucker - - OpenBSD-Commit-ID: b76afc4e3b74ab735dbde4e5f0cfa1f02356033b - -commit af628b8a6c3ef403644d83d205c80ff188c97f0c -Author: djm@openbsd.org -Date: Fri Apr 3 02:25:21 2020 +0000 - - upstream: add allocating variant of the safe utf8 printer; ok - - dtucker as part of a larger diff - - OpenBSD-Commit-ID: 037e2965bd50eacc2ffb49889ecae41552744fa0 - -commit d8ac9af645f5519ac5211e9e1e4dc1ed00e9cced -Author: dtucker@openbsd.org -Date: Mon Mar 16 02:17:02 2020 +0000 - - upstream: Cast lifetime to u_long for comparison to prevent unsigned - - comparison warning on 32bit arches. Spotted by deraadt, ok djm. - - OpenBSD-Commit-ID: 7a75b2540bff5ab4fa00b4d595db1df13bb0515a - -commit 0eaca933ae08b0a515edfccd5cc4a6b667034813 -Author: Darren Tucker -Date: Sat Mar 14 20:58:46 2020 +1100 - - Include fido.h when checking for fido/credman.h. - - It's required for fido_dev_t, otherwise configure fails with - when given --with-security-key-builtin. - -commit c7c099060f82ffe6a36d8785ecf6052e12fd92f0 -Author: djm@openbsd.org -Date: Fri Mar 13 03:18:45 2020 +0000 - - upstream: some more speeling mistakes from - - OpenBSD-Regress-ID: 02471c079805471c546b7a69d9ab1d34e9a57443 - -commit 1d89232a4aa97fe935cd60b8d24d75c2f70d56c5 -Author: djm@openbsd.org -Date: Fri Mar 13 04:16:27 2020 +0000 - - upstream: improve error messages for some common PKCS#11 C_Login - - failure cases; based on patch from Jacob Hoffman-Andrews in bz3130; ok - dtucker - - OpenBSD-Commit-ID: b8b849621b4a98e468942efd0a1c519c12ce089e - -commit 5becbec023f2037394987f85ed7f74b9a28699e0 -Author: djm@openbsd.org -Date: Fri Mar 13 04:01:56 2020 +0000 - - upstream: use sshpkt_fatal() for kex_exchange_identification() - - errors. This ensures that the logged errors are consistent with other - transport- layer errors and that the relevant IP addresses are logged. bz3129 - ok dtucker@ - - OpenBSD-Commit-ID: 2c22891f0b9e1a6cd46771cedbb26ac96ec2e6ab - -commit eef88418f9e5e51910af3c5b23b5606ebc17af55 -Author: dtucker@openbsd.org -Date: Fri Mar 13 03:24:49 2020 +0000 - - upstream: Don't clear alarm timers in listening sshd. Previously - - these timers were used for regenerating the SSH1 ephemeral host keys but - those are now gone so there's no need to clear the timers either. ok - deraadt@ - - OpenBSD-Commit-ID: 280d2b885e4a1ce404632e8cc38fcb17be7dafc0 - -commit d081f017c20a3564255873ed99fd7d024cac540f -Author: djm@openbsd.org -Date: Fri Mar 13 03:17:07 2020 +0000 - - upstream: spelling errors in comments; no code change from - - OpenBSD-Commit-ID: 166ea64f6d84f7bac5636dbd38968592cb5eb924 - -commit c084a2d040f160bc2b83f13297e3e3ca3f5dbac6 -Author: djm@openbsd.org -Date: Fri Mar 13 03:12:17 2020 +0000 - - upstream: when downloading FIDO2 resident keys from a token, don't - - prompt for a PIN until the token has told us that it needs one. Avoids - double-prompting on devices that implement on-device authentication (e.g. a - touchscreen PIN pad on the Trezor Model T). ok dtucker@ - - OpenBSD-Commit-ID: 38b78903dd4422d7d3204095a31692fb69130817 - -commit 955c4cf4c6a1417c28d4e1040702c4d9bf63645b -Author: Damien Miller -Date: Fri Mar 13 14:30:16 2020 +1100 - - sync fnmatch.c with upstream to fix another typo - -commit 397f217e8640e75bb719a8e87111b4bd848fb3df -Author: Damien Miller -Date: Fri Mar 13 14:24:23 2020 +1100 - - another spelling error in comment - -commit def31bc5427579ec3f7f2ce99f2da1338fdc0c9f -Author: Damien Miller -Date: Fri Mar 13 14:23:07 2020 +1100 - - spelling mistakes - - from https://fossies.org/linux/misc/openssh-8.2p1.tar.gz/codespell.html - -commit 8bdc3bb7cf4c82c3344cfcb82495a43406e87e83 -Author: markus@openbsd.org -Date: Fri Mar 6 18:29:54 2020 +0000 - - upstream: fix relative includes in sshd_config; ok djm - - OpenBSD-Commit-ID: fa29b0da3c93cbc3a1d4c6bcd58af43c00ffeb5b - -commit e32ef97a56ae03febfe307688858badae3a70e5a -Author: markus@openbsd.org -Date: Fri Mar 6 18:29:14 2020 +0000 - - upstream: fix use-after-free in do_download_sk; ok djm - - OpenBSD-Commit-ID: 96b49623d297797d4fc069f1f09e13c8811f8863 - -commit 5732d58020309364bf31fa125354e399361006db -Author: markus@openbsd.org -Date: Fri Mar 6 18:28:50 2020 +0000 - - upstream: do not leak oprincipals; ok djm - - OpenBSD-Commit-ID: 4691d9387eab36f8fda48f5d8009756ed13a7c4c - -commit 8fae395f34c2c52cdaf9919aa261d1848b4bb00b -Author: markus@openbsd.org -Date: Fri Mar 6 18:28:27 2020 +0000 - - upstream: initialize seconds for debug message; ok djm - - OpenBSD-Commit-ID: 293fbefe6d00b4812a180ba02e26170e4c855b81 - -commit 46e5c4c8ffcd1569bcd5d04803abaa2ecf3e4cff -Author: markus@openbsd.org -Date: Fri Mar 6 18:27:50 2020 +0000 - - upstream: correct return code; ok djm - - OpenBSD-Commit-ID: 319d09e3b7f4b2bc920c67244d9ff6426b744810 - -commit 31c39e7840893f1bfdcbe4f813b20d1d7e69ec3e -Author: markus@openbsd.org -Date: Fri Mar 6 18:27:15 2020 +0000 - - upstream: principalsp is optional, pubkey required; ok djm - - OpenBSD-Commit-ID: 2cc3ea5018c28ed97edaccd7f17d2cc796f01024 - -commit e26a31757c5df2f58687cb9a4853d1418f39728e -Author: markus@openbsd.org -Date: Fri Mar 6 18:26:21 2020 +0000 - - upstream: remove unused variables in ssh-pkcs11-helper; ok djm - - OpenBSD-Commit-ID: 13e572846d0d1b28f1251ddd2165e9cf18135ae1 - -commit 1b378c0d982d6ab522eda634b0e88cf1fca5e352 -Author: markus@openbsd.org -Date: Fri Mar 6 18:25:48 2020 +0000 - - upstream: return correct error in sshsk_ed25519_sig; ok djm - - OpenBSD-Commit-ID: 52bf733df220303c260fee4f165ec64b4a977625 - -commit fbff605e637b068061ab6784ff03e3874890c092 -Author: markus@openbsd.org -Date: Fri Mar 6 18:25:12 2020 +0000 - - upstream: fix possible null-deref in check_key_not_revoked; ok - - djm - - OpenBSD-Commit-ID: 80855e9d7af42bb6fcc16c074ba69876bfe5e3bf - -commit bc30b446841fc16e50ed6e75c56ccfbd37b9f281 -Author: markus@openbsd.org -Date: Fri Mar 6 18:24:39 2020 +0000 - - upstream: ssh_fetch_identitylist() returns the return value from - - ssh_request_reply() so we should also check against != 0 ok djm - - OpenBSD-Commit-ID: 28d0028769d03e665688c61bb5fd943e18614952 - -commit 7b4f70ddeb59f35283d77d8d9c834ca58f8cf436 -Author: markus@openbsd.org -Date: Fri Mar 6 18:23:17 2020 +0000 - - upstream: sshkey_cert_check_authority requires reason to be set; - - ok djm - - OpenBSD-Commit-ID: 6f7a6f19540ed5749763c2f9530c0897c94aa552 - -commit 05efe270df1e925db0af56a806d18b5063db4b6d -Author: markus@openbsd.org -Date: Fri Mar 6 18:21:28 2020 +0000 - - upstream: passphrase depends on kdfname, not ciphername (possible - - null-deref); ok djm - - OpenBSD-Commit-ID: 0d39668edf5e790b5837df4926ee1141cec5471c - -commit 1ddf5682f3992bdacd29164891abb71a19c2cf61 -Author: markus@openbsd.org -Date: Fri Mar 6 18:20:44 2020 +0000 - - upstream: consistently check packet_timeout_ms against 0; ok djm - - OpenBSD-Commit-ID: e8fb8cb2c96c980f075069302534eaf830929928 - -commit 31f1ee54968ad84eb32375e4412e0318766b586b -Author: markus@openbsd.org -Date: Fri Mar 6 18:20:02 2020 +0000 - - upstream: initialize cname in case ai_canonname is NULL or too - - long; ok djm - - OpenBSD-Commit-ID: c27984636fdb1035d1642283664193e91aab6e37 - -commit a6134b02b5264b2611c8beae98bb392329452bba -Author: markus@openbsd.org -Date: Fri Mar 6 18:19:21 2020 +0000 - - upstream: fix uninitialized pointers for forward_cancel; ok djm - - OpenBSD-Commit-ID: 612778e6d87ee865d0ba97d0a335f141cee1aa37 - -commit 16d4f9961c75680aab374dee762a5baa0ad507af -Author: markus@openbsd.org -Date: Fri Mar 6 18:16:21 2020 +0000 - - upstream: exit on parse failures in input_service_request; ok djm - - OpenBSD-Commit-ID: 6a7e1bfded26051d5aa893c030229b1ee6a0d5d2 - -commit 5f25afe5216ba7f8921e04f79aa4ca0624eca820 -Author: markus@openbsd.org -Date: Fri Mar 6 18:15:38 2020 +0000 - - upstream: fix null-deref on calloc failure; ok djm - - OpenBSD-Commit-ID: a313519579b392076b7831ec022dfdefbec8724a - -commit ff2acca039aef16a15fce409163df404858f7aa5 -Author: markus@openbsd.org -Date: Fri Mar 6 18:15:04 2020 +0000 - - upstream: exit if ssh_krl_revoke_key_sha256 fails; ok djm - - OpenBSD-Commit-ID: 0864ad4fe8bf28ab21fd1df766e0365c11bbc0dc - -commit 31c860a0212af2d5b6a129e3e8fcead51392ee1d -Author: markus@openbsd.org -Date: Fri Mar 6 18:14:13 2020 +0000 - - upstream: pkcs11_register_provider: return < 0 on error; ok djm - - OpenBSD-Commit-ID: cfc8321315b787e4d40da4bdb2cbabd4154b0d97 - -commit 15be29e1e3318737b0768ca37d5b4a3fbe868ef0 -Author: markus@openbsd.org -Date: Fri Mar 6 18:13:29 2020 +0000 - - upstream: sshsig: return correct error, fix null-deref; ok djm - - OpenBSD-Commit-ID: 1d1af7cd538b8b23e621cf7ab84f11e7a923edcd - -commit 6fb6f186cb62a6370fba476b6a03478a1e95c30d -Author: markus@openbsd.org -Date: Fri Mar 6 18:12:55 2020 +0000 - - upstream: vasnmprintf allocates str and returns -1; ok djm - - OpenBSD-Commit-ID: dae4c9e83d88471bf3b3f89e3da7a107b44df11c - -commit 714e1cbca17daa13f4f98978cf9e0695d4b2e0a4 -Author: markus@openbsd.org -Date: Fri Mar 6 18:11:10 2020 +0000 - - upstream: sshpkt_fatal() does not return; ok djm - - OpenBSD-Commit-ID: 7dfe847e28bd78208eb227b37f29f4a2a0929929 - -commit 9b47bd7b09d191991ad9e0506bb66b74bbc93d34 -Author: djm@openbsd.org -Date: Fri Feb 28 01:07:28 2020 +0000 - - upstream: no-touch-required certificate option should be an - - extension, not a critical option. - - OpenBSD-Commit-ID: 626b22c5feb7be8a645e4b9a9bef89893b88600d - -commit dd992520bed35387fc010239abe1bdc0c2665e38 -Author: djm@openbsd.org -Date: Fri Feb 28 01:06:05 2020 +0000 - - upstream: better error message when trying to use a FIDO key - - function and SecurityKeyProvider is empty - - OpenBSD-Commit-ID: e56602c2ee8c82f835d30e4dc8ee2e4a7896be24 - -commit b81e66dbe0345aef4717911abcb4f589fff33a0a -Author: dtucker@openbsd.org -Date: Thu Feb 27 02:32:37 2020 +0000 - - upstream: Drop leading space from line count that was confusing - - ssh-keygen's screen mode. - - OpenBSD-Commit-ID: 3bcae7a754db3fc5ad3cab63dd46774edb35b8ae - -commit d5ba1c03278eb079438bb038266d80d7477d49cb -Author: jsg@openbsd.org -Date: Wed Feb 26 13:40:09 2020 +0000 - - upstream: change explicit_bzero();free() to freezero() - - While freezero() returns early if the pointer is NULL the tests for - NULL in callers are left to avoid warnings about passing an - uninitialised size argument across a function boundry. - - ok deraadt@ djm@ - - OpenBSD-Commit-ID: 2660fa334fcc7cd05ec74dd99cb036f9ade6384a - -commit 9e3220b585c5be19a7431ea4ff8884c137b3a81c -Author: dtucker@openbsd.org -Date: Wed Feb 26 11:46:51 2020 +0000 - - upstream: Have sftp reject "-1" in the same way as ssh(1) and - - scp(1) do instead of accepting and silently ignoring it since protocol 1 - support has been removed. Spotted by shivakumar2696 at gmail.com, ok - deraadt@ - - OpenBSD-Commit-ID: b79f95559a1c993214f4ec9ae3c34caa87e9d5de - -commit ade8e67bb0f07b12e5e47e7baeafbdc898de639f -Author: dtucker@openbsd.org -Date: Wed Feb 26 01:31:47 2020 +0000 - - upstream: Remove obsolete XXX comment. ok deraadt@ - - OpenBSD-Commit-ID: bc462cc843947feea26a2e21c750b3a7469ff01b - -commit 7eb903f51eba051d7f65790bab92a28970ac1ccc -Author: dtucker@openbsd.org -Date: Mon Feb 24 04:27:58 2020 +0000 - - upstream: Fix typo. Patch from itoama at live.jp via github PR#173. - - OpenBSD-Commit-ID: 5cdaafab38bbdea0d07e24777d00bfe6f972568a diff --git a/crypto/openssh/Makefile.in b/crypto/openssh/Makefile.in index 065bf91e3fcc..7250d3f315e1 100644 --- a/crypto/openssh/Makefile.in +++ b/crypto/openssh/Makefile.in @@ -1,781 +1,780 @@ -# uncomment if you run a non bourne compatible shell. Ie. csh -#SHELL = @SH@ +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@ K5LIBS=@K5LIBS@ GSSLIBS=@GSSLIBS@ SSHDLIBS=@SSHDLIBS@ LIBEDIT=@LIBEDIT@ LIBFIDO2=@LIBFIDO2@ AR=@AR@ AWK=@AWK@ RANLIB=@RANLIB@ INSTALL=@INSTALL@ SED=@SED@ XAUTH_PATH=@XAUTH_PATH@ LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ LDFLAGS_NOPIE=-L. -Lopenbsd-compat/ @LDFLAGS_NOPIE@ EXEEXT=@EXEEXT@ MANFMT=@MANFMT@ MKDIR_P=@MKDIR_P@ .SUFFIXES: .lo TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) XMSS_OBJS=\ ssh-xmss.o \ sshkey-xmss.o \ xmss_commons.o \ xmss_fast.o \ xmss_hash.o \ xmss_hash_address.o \ xmss_wots.o LIBOPENSSH_OBJS=\ ssh_api.o \ ssherr.o \ sshbuf.o \ sshkey.o \ sshbuf-getput-basic.o \ sshbuf-misc.o \ sshbuf-getput-crypto.o \ krl.o \ bitmap.o \ ${XMSS_OBJS} LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ authfd.o authfile.o \ canohost.o channels.o cipher.o cipher-aes.o cipher-aesctr.o \ cipher-ctr.o cleanup.o \ compat.o fatal.o hostfile.o \ log.o match.o moduli.o nchan.o packet.o \ readpass.o ttymodes.o xmalloc.o addr.o addrmatch.o \ atomicio.o dispatch.o mac.o misc.o utf8.o \ monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-ecdsa-sk.o \ ssh-ed25519-sk.o ssh-rsa.o dh.o \ msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ ssh-pkcs11.o smult_curve25519_ref.o \ poly1305.o chacha.o cipher-chachapoly.o cipher-chachapoly-libcrypto.o \ ssh-ed25519.o digest-openssl.o digest-libc.o \ hmac.o sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o \ kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ kexgexc.o kexgexs.o \ kexsntrup761x25519.o sntrup761.o kexgen.o \ sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ sshbuf-io.o SKOBJS= ssh-sk-client.o SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ sshconnect.o sshconnect2.o mux.o $(SKOBJS) SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \ audit.o audit-bsm.o audit-linux.o platform.o \ sshpty.o sshlogin.o servconf.o serverloop.o \ auth.o auth2.o auth-options.o session.o \ auth2-chall.o groupaccess.o \ auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \ auth2-none.o auth2-passwd.o auth2-pubkey.o \ monitor.o monitor_wrap.o auth-krb5.o \ auth2-gss.o gss-serv.o gss-serv-krb5.o \ loginrec.o auth-pam.o auth-shadow.o auth-sia.o \ 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) MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out ssh-sk-helper.8.out sshd_config.5.out ssh_config.5.out MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 ssh-sk-helper.8 sshd_config.5 ssh_config.5 MANTYPE = @MANTYPE@ CONFIGFILES=sshd_config.out ssh_config.out moduli.out CONFIGFILES_IN=sshd_config ssh_config moduli PATHSUBS = \ -e 's|/etc/ssh/ssh_config|$(sysconfdir)/ssh_config|g' \ -e 's|/etc/ssh/ssh_known_hosts|$(sysconfdir)/ssh_known_hosts|g' \ -e 's|/etc/ssh/sshd_config|$(sysconfdir)/sshd_config|g' \ -e 's|/usr/libexec|$(libexecdir)|g' \ -e 's|/etc/shosts.equiv|$(sysconfdir)/shosts.equiv|g' \ -e 's|/etc/ssh/ssh_host_key|$(sysconfdir)/ssh_host_key|g' \ -e 's|/etc/ssh/ssh_host_ecdsa_key|$(sysconfdir)/ssh_host_ecdsa_key|g' \ -e 's|/etc/ssh/ssh_host_dsa_key|$(sysconfdir)/ssh_host_dsa_key|g' \ -e 's|/etc/ssh/ssh_host_rsa_key|$(sysconfdir)/ssh_host_rsa_key|g' \ -e 's|/etc/ssh/ssh_host_ed25519_key|$(sysconfdir)/ssh_host_ed25519_key|g' \ -e 's|/var/run/sshd.pid|$(piddir)/sshd.pid|g' \ -e 's|/etc/moduli|$(sysconfdir)/moduli|g' \ -e 's|/etc/ssh/moduli|$(sysconfdir)/moduli|g' \ -e 's|/etc/ssh/sshrc|$(sysconfdir)/sshrc|g' \ -e 's|/usr/X11R6/bin/xauth|$(XAUTH_PATH)|g' \ -e 's|/var/empty|$(PRIVSEP_PATH)|g' \ -e 's|/usr/bin:/bin:/usr/sbin:/sbin|@user_path@|g' FIXPATHSCMD = $(SED) $(PATHSUBS) FIXALGORITHMSCMD= $(SHELL) $(srcdir)/fixalgorithms $(SED) \ @UNSUPPORTED_ALGORITHMS@ all: configure-check $(CONFIGFILES) $(MANPAGES) $(TARGETS) $(LIBSSH_OBJS): Makefile.in config.h $(SSHOBJS): Makefile.in config.h $(SSHDOBJS): Makefile.in config.h configure-check: $(srcdir)/configure $(srcdir)/configure: configure.ac $(srcdir)/m4/*.m4 @echo "ERROR: configure is out of date; please run ${AUTORECONF} (and configure)" 1>&2 @exit 1 .c.o: $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ LIBCOMPAT=openbsd-compat/libopenbsd-compat.a $(LIBCOMPAT): always (cd openbsd-compat && $(MAKE)) always: libssh.a: $(LIBSSH_OBJS) $(AR) rv $@ $(LIBSSH_OBJS) $(RANLIB) $@ ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(GSSLIBS) sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) scp$(EXEEXT): $(LIBCOMPAT) libssh.a $(SCP_OBJS) $(LD) -o $@ $(SCP_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHADD_OBJS) $(LD) -o $@ $(SSHADD_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHAGENT_OBJS) $(LD) -o $@ $(SSHAGENT_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHKEYGEN_OBJS) $(LD) -o $@ $(SSHKEYGEN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHKEYSIGN_OBJS) $(LD) -o $@ $(SSHKEYSIGN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a $(P11HELPER_OBJS) $(LD) -o $@ $(P11HELPER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) ssh-sk-helper$(EXEEXT): $(LIBCOMPAT) libssh.a $(SKHELPER_OBJS) $(LD) -o $@ $(SKHELPER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) $(LIBFIDO2) ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHKEYSCAN_OBJS) $(LD) -o $@ $(SSHKEYSCAN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a $(SFTPSERVER_OBJS) $(LD) -o $@ $(SFTPSERVER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -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) regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c $(REGRESSLIBS) $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/modpipe.c \ $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) regress/setuid-allowed$(EXEEXT): $(srcdir)/regress/setuid-allowed.c $(REGRESSLIBS) $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/setuid-allowed.c \ $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) regress/netcat$(EXEEXT): $(srcdir)/regress/netcat.c $(REGRESSLIBS) $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/netcat.c \ $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) regress/check-perm$(EXEEXT): $(srcdir)/regress/check-perm.c $(REGRESSLIBS) $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/check-perm.c \ $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) regress/mkdtemp$(EXEEXT): $(srcdir)/regress/mkdtemp.c $(REGRESSLIBS) $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/mkdtemp.c \ $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) UNITTESTS_TEST_HELPER_OBJS=\ regress/unittests/test_helper/test_helper.o \ regress/unittests/test_helper/fuzz.o regress/unittests/test_helper/libtest_helper.a: ${UNITTESTS_TEST_HELPER_OBJS} $(AR) rv $@ $(UNITTESTS_TEST_HELPER_OBJS) $(RANLIB) $@ UNITTESTS_TEST_SSHBUF_OBJS=\ regress/unittests/sshbuf/tests.o \ regress/unittests/sshbuf/test_sshbuf.o \ regress/unittests/sshbuf/test_sshbuf_getput_basic.o \ regress/unittests/sshbuf/test_sshbuf_getput_crypto.o \ regress/unittests/sshbuf/test_sshbuf_misc.o \ regress/unittests/sshbuf/test_sshbuf_fuzz.o \ regress/unittests/sshbuf/test_sshbuf_getput_fuzz.o \ regress/unittests/sshbuf/test_sshbuf_fixed.o regress/unittests/sshbuf/test_sshbuf$(EXEEXT): ${UNITTESTS_TEST_SSHBUF_OBJS} \ regress/unittests/test_helper/libtest_helper.a libssh.a $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_SSHBUF_OBJS) \ regress/unittests/test_helper/libtest_helper.a \ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) UNITTESTS_TEST_SSHKEY_OBJS=\ regress/unittests/sshkey/test_fuzz.o \ regress/unittests/sshkey/tests.o \ regress/unittests/sshkey/common.o \ regress/unittests/sshkey/test_file.o \ regress/unittests/sshkey/test_sshkey.o \ $(SKOBJS) regress/unittests/sshkey/test_sshkey$(EXEEXT): ${UNITTESTS_TEST_SSHKEY_OBJS} \ regress/unittests/test_helper/libtest_helper.a libssh.a $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_SSHKEY_OBJS) \ regress/unittests/test_helper/libtest_helper.a \ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) UNITTESTS_TEST_SSHSIG_OBJS=\ sshsig.o \ regress/unittests/sshsig/tests.o \ $(SKOBJS) regress/unittests/sshsig/test_sshsig$(EXEEXT): ${UNITTESTS_TEST_SSHSIG_OBJS} \ regress/unittests/test_helper/libtest_helper.a libssh.a $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_SSHSIG_OBJS) \ regress/unittests/test_helper/libtest_helper.a \ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) UNITTESTS_TEST_BITMAP_OBJS=\ regress/unittests/bitmap/tests.o regress/unittests/bitmap/test_bitmap$(EXEEXT): ${UNITTESTS_TEST_BITMAP_OBJS} \ regress/unittests/test_helper/libtest_helper.a libssh.a $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_BITMAP_OBJS) \ regress/unittests/test_helper/libtest_helper.a \ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) UNITTESTS_TEST_AUTHOPT_OBJS=\ regress/unittests/authopt/tests.o \ auth-options.o \ $(SKOBJS) regress/unittests/authopt/test_authopt$(EXEEXT): \ ${UNITTESTS_TEST_AUTHOPT_OBJS} \ regress/unittests/test_helper/libtest_helper.a libssh.a $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_AUTHOPT_OBJS) \ regress/unittests/test_helper/libtest_helper.a \ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) UNITTESTS_TEST_CONVERSION_OBJS=\ regress/unittests/conversion/tests.o regress/unittests/conversion/test_conversion$(EXEEXT): \ ${UNITTESTS_TEST_CONVERSION_OBJS} \ regress/unittests/test_helper/libtest_helper.a libssh.a $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_CONVERSION_OBJS) \ regress/unittests/test_helper/libtest_helper.a \ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) UNITTESTS_TEST_KEX_OBJS=\ regress/unittests/kex/tests.o \ regress/unittests/kex/test_kex.o \ $(SKOBJS) regress/unittests/kex/test_kex$(EXEEXT): ${UNITTESTS_TEST_KEX_OBJS} \ regress/unittests/test_helper/libtest_helper.a libssh.a $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_KEX_OBJS) \ regress/unittests/test_helper/libtest_helper.a \ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) UNITTESTS_TEST_HOSTKEYS_OBJS=\ regress/unittests/hostkeys/tests.o \ regress/unittests/hostkeys/test_iterate.o \ $(SKOBJS) regress/unittests/hostkeys/test_hostkeys$(EXEEXT): \ ${UNITTESTS_TEST_HOSTKEYS_OBJS} \ regress/unittests/test_helper/libtest_helper.a libssh.a $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_HOSTKEYS_OBJS) \ regress/unittests/test_helper/libtest_helper.a \ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) UNITTESTS_TEST_MATCH_OBJS=\ regress/unittests/match/tests.o regress/unittests/match/test_match$(EXEEXT): \ ${UNITTESTS_TEST_MATCH_OBJS} \ regress/unittests/test_helper/libtest_helper.a libssh.a $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_MATCH_OBJS) \ regress/unittests/test_helper/libtest_helper.a \ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) UNITTESTS_TEST_MISC_OBJS=\ regress/unittests/misc/tests.o \ regress/unittests/misc/test_parse.o \ regress/unittests/misc/test_expand.o \ regress/unittests/misc/test_convtime.o \ regress/unittests/misc/test_argv.o \ regress/unittests/misc/test_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) UNITTESTS_TEST_UTF8_OBJS=\ regress/unittests/utf8/tests.o regress/unittests/utf8/test_utf8$(EXEEXT): \ ${UNITTESTS_TEST_UTF8_OBJS} \ regress/unittests/test_helper/libtest_helper.a libssh.a $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_UTF8_OBJS) \ regress/unittests/test_helper/libtest_helper.a \ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) # These all need to be compiled -fPIC, so they are treated differently. SK_DUMMY_OBJS=\ regress/misc/sk-dummy/sk-dummy.lo \ regress/misc/sk-dummy/fatal.lo \ ed25519.lo hash.lo ge25519.lo fe25519.lo sc25519.lo verify.lo SK_DUMMY_LIBRARY=@SK_DUMMY_LIBRARY@ .c.lo: Makefile.in config.h $(CC) $(CFLAGS_NOPIE) $(PICFLAG) $(CPPFLAGS) -c $< -o $@ regress/misc/sk-dummy/sk-dummy.so: $(SK_DUMMY_OBJS) - $(CC) $(CFLAGS) $(CPPFLAGS) -fPIC -shared -o $@ $(SK_DUMMY_OBJS) \ + $(CC) $(CFLAGS) $(CPPFLAGS) $(PICFLAG) -shared -o $@ $(SK_DUMMY_OBJS) \ -L. -Lopenbsd-compat -lopenbsd-compat $(LDFLAGS_NOPIE) $(LIBS) regress-binaries: regress-prep $(LIBCOMPAT) \ regress/modpipe$(EXEEXT) \ regress/setuid-allowed$(EXEEXT) \ regress/netcat$(EXEEXT) \ regress/check-perm$(EXEEXT) \ regress/mkdtemp$(EXEEXT) \ $(SK_DUMMY_LIBRARY) regress-unit-binaries: regress-prep $(REGRESSLIBS) \ regress/unittests/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 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/crypto/openssh/auth.c b/crypto/openssh/auth.c index faa1a4d3c666..ad5a14e05ae8 100644 --- a/crypto/openssh/auth.c +++ b/crypto/openssh/auth.c @@ -1,1075 +1,1031 @@ /* $OpenBSD: auth.c,v 1.154 2022/02/23 11:17:10 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" __RCSID("$FreeBSD$"); #include #include #include #include #include #include #include #include #ifdef HAVE_PATHS_H # include #endif #include #ifdef HAVE_LOGIN_H #include #endif #ifdef USE_SHADOW #include #endif #include #include #include #include #include #include #include #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" #include "blacklist_client.h" /* import */ extern ServerOptions options; extern struct include_list includes; extern int use_privsep; extern struct sshbuf *loginmsg; extern struct passwd *privsep_pw; extern struct sshauthopt *auth_opts; /* Debugging messages */ static struct sshbuf *auth_debug; /* * Check if the user is allowed to log in via ssh. If user is listed * in DenyUsers or one of user's groups is listed in DenyGroups, false * will be returned. If AllowUsers isn't empty and user isn't listed * there, or if AllowGroups isn't empty and one of user's groups isn't * listed there, false will be returned. * If the user's shell is not executable, false will be returned. * Otherwise true is returned. */ int allowed_user(struct ssh *ssh, struct passwd * pw) { struct stat st; - const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL; + const char *hostname = NULL, *ipaddr = NULL; u_int i; int r; -#ifdef USE_SHADOW - struct spwd *spw = NULL; -#endif /* Shouldn't be called if pw is NULL, but better safe than sorry... */ if (!pw || !pw->pw_name) return 0; -#ifdef USE_SHADOW - if (!options.use_pam) - spw = getspnam(pw->pw_name); -#ifdef HAS_SHADOW_EXPIRE - if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw)) + if (!options.use_pam && platform_locked_account(pw)) { + logit("User %.100s not allowed because account is locked", + pw->pw_name); return 0; -#endif /* HAS_SHADOW_EXPIRE */ -#endif /* USE_SHADOW */ - - /* grab passwd field for locked account check */ - passwd = pw->pw_passwd; -#ifdef USE_SHADOW - if (spw != NULL) -#ifdef USE_LIBIAF - passwd = get_iaf_password(pw); -#else - passwd = spw->sp_pwdp; -#endif /* USE_LIBIAF */ -#endif - - /* check for locked account */ - if (!options.use_pam && passwd && *passwd) { - int locked = 0; - -#ifdef LOCKED_PASSWD_STRING - if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0) - locked = 1; -#endif -#ifdef LOCKED_PASSWD_PREFIX - if (strncmp(passwd, LOCKED_PASSWD_PREFIX, - strlen(LOCKED_PASSWD_PREFIX)) == 0) - locked = 1; -#endif -#ifdef LOCKED_PASSWD_SUBSTR - if (strstr(passwd, LOCKED_PASSWD_SUBSTR)) - locked = 1; -#endif -#ifdef USE_LIBIAF - free((void *) passwd); -#endif /* USE_LIBIAF */ - if (locked) { - logit("User %.100s not allowed because account is locked", - pw->pw_name); - return 0; - } } /* * Deny if shell does not exist or is not executable unless we * are chrooting. */ if (options.chroot_directory == NULL || strcasecmp(options.chroot_directory, "none") == 0) { char *shell = xstrdup((pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */ if (stat(shell, &st) == -1) { logit("User %.100s not allowed because shell %.100s " "does not exist", pw->pw_name, shell); free(shell); return 0; } if (S_ISREG(st.st_mode) == 0 || (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) { logit("User %.100s not allowed because shell %.100s " "is not executable", pw->pw_name, shell); free(shell); return 0; } free(shell); } if (options.num_deny_users > 0 || options.num_allow_users > 0 || options.num_deny_groups > 0 || options.num_allow_groups > 0) { hostname = auth_get_canonical_hostname(ssh, options.use_dns); ipaddr = ssh_remote_ipaddr(ssh); } /* Return false if user is listed in DenyUsers */ if (options.num_deny_users > 0) { for (i = 0; i < options.num_deny_users; i++) { r = match_user(pw->pw_name, hostname, ipaddr, options.deny_users[i]); if (r < 0) { fatal("Invalid DenyUsers pattern \"%.100s\"", options.deny_users[i]); } else if (r != 0) { logit("User %.100s from %.100s not allowed " "because listed in DenyUsers", pw->pw_name, hostname); return 0; } } } /* Return false if AllowUsers isn't empty and user isn't listed there */ if (options.num_allow_users > 0) { for (i = 0; i < options.num_allow_users; i++) { r = match_user(pw->pw_name, hostname, ipaddr, options.allow_users[i]); if (r < 0) { fatal("Invalid AllowUsers pattern \"%.100s\"", options.allow_users[i]); } else if (r == 1) break; } /* i < options.num_allow_users iff we break for loop */ if (i >= options.num_allow_users) { logit("User %.100s from %.100s not allowed because " "not listed in AllowUsers", pw->pw_name, hostname); return 0; } } if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { /* Get the user's group access list (primary and supplementary) */ if (ga_init(pw->pw_name, pw->pw_gid) == 0) { logit("User %.100s from %.100s not allowed because " "not in any group", pw->pw_name, hostname); return 0; } /* Return false if one of user's groups is listed in DenyGroups */ if (options.num_deny_groups > 0) if (ga_match(options.deny_groups, options.num_deny_groups)) { ga_free(); logit("User %.100s from %.100s not allowed " "because a group is listed in DenyGroups", pw->pw_name, hostname); return 0; } /* * Return false if AllowGroups isn't empty and one of user's groups * isn't listed there */ if (options.num_allow_groups > 0) if (!ga_match(options.allow_groups, options.num_allow_groups)) { ga_free(); logit("User %.100s from %.100s not allowed " "because none of user's groups are listed " "in AllowGroups", pw->pw_name, hostname); return 0; } ga_free(); } #ifdef CUSTOM_SYS_AUTH_ALLOWED_USER if (!sys_auth_allowed_user(pw, loginmsg)) return 0; #endif /* We found no reason not to let this user try to log on... */ return 1; } /* * Formats any key left in authctxt->auth_method_key for inclusion in * auth_log()'s message. Also includes authxtct->auth_method_info if present. */ static char * format_method_key(Authctxt *authctxt) { const struct sshkey *key = authctxt->auth_method_key; const char *methinfo = authctxt->auth_method_info; char *fp, *cafp, *ret = NULL; if (key == NULL) return NULL; if (sshkey_is_cert(key)) { fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); cafp = sshkey_fingerprint(key->cert->signature_key, options.fingerprint_hash, SSH_FP_DEFAULT); xasprintf(&ret, "%s %s ID %s (serial %llu) CA %s %s%s%s", sshkey_type(key), fp == NULL ? "(null)" : fp, key->cert->key_id, (unsigned long long)key->cert->serial, sshkey_type(key->cert->signature_key), cafp == NULL ? "(null)" : cafp, methinfo == NULL ? "" : ", ", methinfo == NULL ? "" : methinfo); free(fp); free(cafp); } else { fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); xasprintf(&ret, "%s %s%s%s", sshkey_type(key), fp == NULL ? "(null)" : fp, methinfo == NULL ? "" : ", ", methinfo == NULL ? "" : methinfo); free(fp); } return ret; } void auth_log(struct ssh *ssh, int authenticated, int partial, const char *method, const char *submethod) { Authctxt *authctxt = (Authctxt *)ssh->authctxt; int level = SYSLOG_LEVEL_VERBOSE; const char *authmsg; char *extra = NULL; if (use_privsep && !mm_is_monitor() && !authctxt->postponed) return; /* Raise logging level */ if (authenticated == 1 || !authctxt->valid || authctxt->failures >= options.max_authtries / 2 || strcmp(method, "password") == 0) level = SYSLOG_LEVEL_INFO; if (authctxt->postponed) authmsg = "Postponed"; else if (partial) authmsg = "Partial"; else { authmsg = authenticated ? "Accepted" : "Failed"; if (authenticated) BLACKLIST_NOTIFY(ssh, BLACKLIST_AUTH_OK, "ssh"); } 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 HAVE_AUTH_HOSTOK const char *from_host, *from_ip; #endif #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) { BLACKLIST_NOTIFY(ssh, BLACKLIST_BAD_USER, user); 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 HAVE_AUTH_HOSTOK from_host = auth_get_canonical_hostname(ssh, options.use_dns); from_ip = ssh_remote_ipaddr(ssh); if (!auth_hostok(lc, from_host, from_ip)) { debug("Denied connection for %.200s from %.200s [%.200s].", pw->pw_name, from_host, from_ip); return (NULL); } #endif /* HAVE_AUTH_HOSTOK */ #ifdef HAVE_AUTH_TIMEOK if (!auth_timeok(lc, time(NULL))) { debug("LOGIN %.200s REFUSED (TIME)", pw->pw_name); return (NULL); } #endif /* HAVE_AUTH_TIMEOK */ #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(); 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/crypto/openssh/auth2-pubkey.c b/crypto/openssh/auth2-pubkey.c index 9c2298fc887d..d297a5c3d975 100644 --- a/crypto/openssh/auth2-pubkey.c +++ b/crypto/openssh/auth2-pubkey.c @@ -1,1094 +1,1094 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.112 2021/12/19 22:12:30 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.113 2022/02/27 01:33:59 naddy 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 #include #include #include #include #ifdef HAVE_PATHS_H # include #endif #include #include #include #include #include #include #include #include #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("key type %s not in PubkeyAcceptedAlgorithms", - sshkey_ssh_name(key)); + 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; } 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, struct sshkey_cert *cert, struct sshauthopt **authoptsp) { FILE *f; int success; if (authoptsp != NULL) *authoptsp = NULL; temporarily_use_uid(pw); debug("trying authorized principals file %s", file); if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { restore_uid(); return 0; } success = process_principals(ssh, f, file, cert, authoptsp); fclose(f); restore_uid(); return success; } /* * Checks whether principal is allowed in output of command. * returns 1 if the principal is allowed or 0 otherwise. */ static int match_principals_command(struct ssh *ssh, struct passwd *user_pw, const struct sshkey *key, struct sshauthopt **authoptsp) { struct passwd *runas_pw = NULL; const struct sshkey_cert *cert = key->cert; FILE *f = NULL; int r, ok, found_principal = 0; int i, ac = 0, uid_swapped = 0; pid_t pid; char *tmp, *username = NULL, *command = NULL, **av = NULL; char *ca_fp = NULL, *key_fp = NULL, *catext = NULL, *keytext = NULL; char serial_s[32], uidstr[32]; void (*osigchld)(int); if (authoptsp != NULL) *authoptsp = NULL; if (options.authorized_principals_command == NULL) return 0; if (options.authorized_principals_command_user == NULL) { error("No user for AuthorizedPrincipalsCommand specified, " "skipping"); return 0; } /* * NB. all returns later this function should go via "out" to * ensure the original SIGCHLD handler is restored properly. */ osigchld = ssh_signal(SIGCHLD, SIG_DFL); /* Prepare and verify the user for the command */ username = percent_expand(options.authorized_principals_command_user, "u", user_pw->pw_name, (char *)NULL); runas_pw = getpwnam(username); if (runas_pw == NULL) { error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s", username, strerror(errno)); goto out; } /* Turn the command into an argument vector */ if (argv_split(options.authorized_principals_command, &ac, &av, 0) != 0) { error("AuthorizedPrincipalsCommand \"%s\" contains " "invalid quotes", options.authorized_principals_command); goto out; } if (ac == 0) { error("AuthorizedPrincipalsCommand \"%s\" yielded no arguments", options.authorized_principals_command); goto out; } if ((ca_fp = sshkey_fingerprint(cert->signature_key, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { error_f("sshkey_fingerprint failed"); goto out; } if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { error_f("sshkey_fingerprint failed"); goto out; } if ((r = sshkey_to_base64(cert->signature_key, &catext)) != 0) { error_fr(r, "sshkey_to_base64 failed"); goto out; } if ((r = sshkey_to_base64(key, &keytext)) != 0) { error_fr(r, "sshkey_to_base64 failed"); goto out; } snprintf(serial_s, sizeof(serial_s), "%llu", (unsigned long long)cert->serial); snprintf(uidstr, sizeof(uidstr), "%llu", (unsigned long long)user_pw->pw_uid); for (i = 1; i < ac; i++) { tmp = percent_expand(av[i], "U", uidstr, "u", user_pw->pw_name, "h", user_pw->pw_dir, "t", sshkey_ssh_name(key), "T", sshkey_ssh_name(cert->signature_key), "f", key_fp, "F", ca_fp, "k", keytext, "K", catext, "i", cert->key_id, "s", serial_s, (char *)NULL); if (tmp == NULL) fatal_f("percent_expand failed"); free(av[i]); av[i] = tmp; } /* Prepare a printable command for logs, etc. */ command = argv_assemble(ac, av); if ((pid = subprocess("AuthorizedPrincipalsCommand", command, ac, av, &f, SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD, runas_pw, temporarily_use_uid, restore_uid)) == 0) goto out; uid_swapped = 1; temporarily_use_uid(runas_pw); ok = process_principals(ssh, f, "(command)", cert, authoptsp); fclose(f); f = NULL; if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command, 0) != 0) goto out; /* Read completed successfully */ found_principal = ok; out: if (f != NULL) fclose(f); ssh_signal(SIGCHLD, osigchld); for (i = 0; i < ac; i++) free(av[i]); free(av); if (uid_swapped) restore_uid(); free(command); free(username); free(ca_fp); free(key_fp); free(catext); free(keytext); return found_principal; } /* * Check a single line of an authorized_keys-format file. Returns 0 if key * matches, -1 otherwise. Will return key/cert options via *authoptsp * on success. "loc" is used as file/line location in log messages. */ static int check_authkey_line(struct ssh *ssh, struct passwd *pw, struct sshkey *key, char *cp, const char *loc, struct sshauthopt **authoptsp) { int want_keytype = sshkey_is_cert(key) ? KEY_UNSPEC : key->type; struct sshkey *found = NULL; struct sshauthopt *keyopts = NULL, *certopts = NULL, *finalopts = NULL; char *key_options = NULL, *fp = NULL; const char *reason = NULL; int ret = -1; if (authoptsp != NULL) *authoptsp = NULL; if ((found = sshkey_new(want_keytype)) == NULL) { debug3_f("keytype %d failed", want_keytype); goto out; } /* XXX djm: peek at key type in line and skip if unwanted */ if (sshkey_read(found, &cp) != 0) { /* no key? check for options */ debug2("%s: check options: '%s'", loc, cp); key_options = cp; if (sshkey_advance_past_options(&cp) != 0) { reason = "invalid key option string"; goto fail_reason; } skip_space(&cp); if (sshkey_read(found, &cp) != 0) { /* still no key? advance to next line*/ debug2("%s: advance: '%s'", loc, cp); goto out; } } /* Parse key options now; we need to know if this is a CA key */ if ((keyopts = sshauthopt_parse(key_options, &reason)) == NULL) { debug("%s: bad key options: %s", loc, reason); auth_debug_add("%s: bad key options: %s", loc, reason); goto out; } /* Ignore keys that don't match or incorrectly marked as CAs */ if (sshkey_is_cert(key)) { /* Certificate; check signature key against CA */ if (!sshkey_equal(found, key->cert->signature_key) || !keyopts->cert_authority) goto out; } else { /* Plain key: check it against key found in file */ if (!sshkey_equal(found, key) || keyopts->cert_authority) goto out; } /* We have a candidate key, perform authorisation checks */ if ((fp = sshkey_fingerprint(found, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) fatal_f("fingerprint failed"); debug("%s: matching %s found: %s %s", loc, sshkey_is_cert(key) ? "CA" : "key", sshkey_type(found), fp); if (auth_authorise_keyopts(ssh, pw, keyopts, sshkey_is_cert(key), loc) != 0) { reason = "Refused by key options"; goto fail_reason; } /* That's all we need for plain keys. */ if (!sshkey_is_cert(key)) { verbose("Accepted key %s %s found at %s", sshkey_type(found), fp, loc); finalopts = keyopts; keyopts = NULL; goto success; } /* * Additional authorisation for certificates. */ /* Parse and check options present in certificate */ if ((certopts = sshauthopt_from_cert(key)) == NULL) { reason = "Invalid certificate options"; goto fail_reason; } if (auth_authorise_keyopts(ssh, pw, certopts, 0, loc) != 0) { reason = "Refused by certificate options"; goto fail_reason; } if ((finalopts = sshauthopt_merge(keyopts, certopts, &reason)) == NULL) goto fail_reason; /* * If the user has specified a list of principals as * a key option, then prefer that list to matching * their username in the certificate principals list. */ if (keyopts->cert_principals != NULL && !match_principals_option(keyopts->cert_principals, key->cert)) { reason = "Certificate does not contain an authorized principal"; goto fail_reason; } if (sshkey_cert_check_authority_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, struct sshauthopt **authoptsp) { char *ca_fp, *principals_file = NULL; const char *reason; struct sshauthopt *principals_opts = NULL, *cert_opts = NULL; struct sshauthopt *final_opts = NULL; int r, ret = 0, found_principal = 0, use_authorized_principals; if (authoptsp != NULL) *authoptsp = NULL; if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL) return 0; if ((ca_fp = sshkey_fingerprint(key->cert->signature_key, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) return 0; if ((r = sshkey_in_file(key->cert->signature_key, options.trusted_user_ca_keys, 1, 0)) != 0) { debug2_fr(r, "CA %s %s is not listed in %s", sshkey_type(key->cert->signature_key), ca_fp, options.trusted_user_ca_keys); goto out; } /* * If AuthorizedPrincipals is in use, then compare the certificate * principals against the names in that file rather than matching * against the username. */ if ((principals_file = authorized_principals_file(pw)) != NULL) { if (match_principals_file(ssh, pw, principals_file, key->cert, &principals_opts)) found_principal = 1; } /* Try querying command if specified */ if (!found_principal && match_principals_command(ssh, pw, key, &principals_opts)) found_principal = 1; /* If principals file or command is specified, then require a match */ use_authorized_principals = principals_file != NULL || options.authorized_principals_command != NULL; 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) { reason = "Refused by certificate options"; goto fail_reason; } if (principals_opts == NULL) { final_opts = cert_opts; cert_opts = NULL; } else { if (auth_authorise_keyopts(ssh, pw, principals_opts, 0, "principals") != 0) { reason = "Refused by certificate principals options"; goto fail_reason; } if ((final_opts = sshauthopt_merge(principals_opts, cert_opts, &reason)) == NULL) { fail_reason: error("%s", reason); auth_debug_add("%s", reason); goto out; } } /* Success */ verbose("Accepted certificate ID \"%s\" (serial %llu) signed by " "%s CA %s via %s", key->cert->key_id, (unsigned long long)key->cert->serial, sshkey_type(key->cert->signature_key), ca_fp, options.trusted_user_ca_keys); if (authoptsp != NULL) { *authoptsp = final_opts; final_opts = NULL; } ret = 1; out: sshauthopt_free(principals_opts); sshauthopt_free(cert_opts); sshauthopt_free(final_opts); free(principals_file); free(ca_fp); return ret; } /* * Checks whether key is allowed in file. * returns 1 if the key is allowed or 0 otherwise. */ static int user_key_allowed2(struct ssh *ssh, struct passwd *pw, struct sshkey *key, char *file, struct sshauthopt **authoptsp) { FILE *f; int found_key = 0; if (authoptsp != NULL) *authoptsp = NULL; /* Temporarily use the user's uid. */ temporarily_use_uid(pw); debug("trying public key file %s", file); if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) { found_key = check_authkeys_file(ssh, pw, f, file, key, authoptsp); fclose(f); } restore_uid(); return found_key; } /* * Checks whether key is allowed in output of command. * returns 1 if the key is allowed or 0 otherwise. */ static int user_key_command_allowed2(struct ssh *ssh, struct passwd *user_pw, struct sshkey *key, struct sshauthopt **authoptsp) { struct passwd *runas_pw = NULL; FILE *f = NULL; int r, ok, found_key = 0; int i, uid_swapped = 0, ac = 0; pid_t pid; char *username = NULL, *key_fp = NULL, *keytext = NULL; char uidstr[32], *tmp, *command = NULL, **av = NULL; void (*osigchld)(int); if (authoptsp != NULL) *authoptsp = NULL; if (options.authorized_keys_command == NULL) return 0; if (options.authorized_keys_command_user == NULL) { error("No user for AuthorizedKeysCommand specified, skipping"); return 0; } /* * NB. all returns later this function should go via "out" to * ensure the original SIGCHLD handler is restored properly. */ osigchld = ssh_signal(SIGCHLD, SIG_DFL); /* Prepare and verify the user for the command */ username = percent_expand(options.authorized_keys_command_user, "u", user_pw->pw_name, (char *)NULL); runas_pw = getpwnam(username); if (runas_pw == NULL) { error("AuthorizedKeysCommandUser \"%s\" not found: %s", username, strerror(errno)); goto out; } /* Prepare AuthorizedKeysCommand */ if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { error_f("sshkey_fingerprint failed"); goto out; } if ((r = sshkey_to_base64(key, &keytext)) != 0) { error_fr(r, "sshkey_to_base64 failed"); goto out; } /* Turn the command into an argument vector */ if (argv_split(options.authorized_keys_command, &ac, &av, 0) != 0) { error("AuthorizedKeysCommand \"%s\" contains invalid quotes", options.authorized_keys_command); goto out; } if (ac == 0) { error("AuthorizedKeysCommand \"%s\" yielded no arguments", options.authorized_keys_command); goto out; } snprintf(uidstr, sizeof(uidstr), "%llu", (unsigned long long)user_pw->pw_uid); for (i = 1; i < ac; i++) { tmp = percent_expand(av[i], "U", uidstr, "u", user_pw->pw_name, "h", user_pw->pw_dir, "t", sshkey_ssh_name(key), "f", key_fp, "k", keytext, (char *)NULL); if (tmp == NULL) fatal_f("percent_expand failed"); free(av[i]); av[i] = tmp; } /* Prepare a printable command for logs, etc. */ command = argv_assemble(ac, av); /* * If AuthorizedKeysCommand was run without arguments * then fall back to the old behaviour of passing the * target username as a single argument. */ if (ac == 1) { av = xreallocarray(av, ac + 2, sizeof(*av)); av[1] = xstrdup(user_pw->pw_name); av[2] = NULL; /* Fix up command too, since it is used in log messages */ free(command); xasprintf(&command, "%s %s", av[0], av[1]); } if ((pid = subprocess("AuthorizedKeysCommand", command, ac, av, &f, SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD, runas_pw, temporarily_use_uid, restore_uid)) == 0) goto out; uid_swapped = 1; temporarily_use_uid(runas_pw); ok = check_authkeys_file(ssh, user_pw, f, options.authorized_keys_command, key, authoptsp); fclose(f); f = NULL; if (exited_cleanly(pid, "AuthorizedKeysCommand", command, 0) != 0) goto out; /* Read completed successfully */ found_key = ok; out: if (f != NULL) fclose(f); ssh_signal(SIGCHLD, osigchld); for (i = 0; i < ac; i++) free(av[i]); free(av); if (uid_swapped) restore_uid(); free(command); free(username); free(key_fp); free(keytext); return found_key; } /* * Check whether key authenticates and authorises the user. */ int user_key_allowed(struct ssh *ssh, struct passwd *pw, struct sshkey *key, int auth_attempt, struct sshauthopt **authoptsp) { u_int success = 0, i; char *file; struct sshauthopt *opts = NULL; if (authoptsp != NULL) *authoptsp = NULL; if (auth_key_is_revoked(key)) return 0; if (sshkey_is_cert(key) && auth_key_is_revoked(key->cert->signature_key)) return 0; for (i = 0; !success && i < options.num_authkeys_files; i++) { if (strcasecmp(options.authorized_keys_files[i], "none") == 0) continue; file = expand_authorized_keys( options.authorized_keys_files[i], pw); success = user_key_allowed2(ssh, pw, key, file, &opts); free(file); if (!success) { sshauthopt_free(opts); opts = NULL; } } if (success) goto out; if ((success = user_cert_trusted_ca(ssh, pw, key, &opts)) != 0) goto out; sshauthopt_free(opts); opts = NULL; if ((success = user_key_command_allowed2(ssh, pw, key, &opts)) != 0) goto out; sshauthopt_free(opts); opts = NULL; out: if (success && authoptsp != NULL) { *authoptsp = opts; opts = NULL; } sshauthopt_free(opts); return success; } Authmethod method_pubkey = { "publickey", "publickey-hostbound-v00@openssh.com", userauth_pubkey, &options.pubkey_authentication }; diff --git a/crypto/openssh/channels.c b/crypto/openssh/channels.c index 73e93c032765..d47af7911f04 100644 --- a/crypto/openssh/channels.c +++ b/crypto/openssh/channels.c @@ -1,5119 +1,5138 @@ -/* $OpenBSD: channels.c,v 1.413 2022/02/17 10:58:27 djm Exp $ */ +/* $OpenBSD: channels.c,v 1.416 2022/04/11 22:52:08 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , 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 #include #include #include #include #ifdef HAVE_SYS_TIME_H # include #endif #include #include #include #include #include #include #ifdef HAVE_POLL_H #include #endif #include #ifdef HAVE_STDINT_H # include #endif #include #include #include #include #include #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) { 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) { c->restore_block |= CHANNEL_RESTORE_RFD; set_nonblock(rfd); } if (wfd != -1 && !isatty(wfd) && fcntl(wfd, F_GETFL) == 0) { c->restore_block |= CHANNEL_RESTORE_WFD; set_nonblock(wfd); } if (efd != -1 && !isatty(efd) && fcntl(efd, F_GETFL) == 0) { 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. */ Channel * channel_new(struct ssh *ssh, char *ctype, int type, int rfd, int wfd, int efd, u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock) { struct ssh_channels *sc = ssh->chanctxt; u_int i, found; Channel *c; int r; /* Try to find a free slot where to put the new channel. */ for (i = 0; i < sc->channels_alloc; i++) { if (sc->channels[i] == NULL) { /* Found a free slot. */ found = i; break; } } if (i >= sc->channels_alloc) { /* * There are no free slots. Take last+1 slot and expand * the array. */ found = sc->channels_alloc; if (sc->channels_alloc > CHANNELS_MAX_CHANNELS) fatal_f("internal error: channels_alloc %d too big", sc->channels_alloc); sc->channels = xrecallocarray(sc->channels, sc->channels_alloc, sc->channels_alloc + 10, sizeof(*sc->channels)); sc->channels_alloc += 10; debug2("channel: expanding %d", sc->channels_alloc); } /* Initialize and return new channel. */ c = sc->channels[found] = xcalloc(1, sizeof(Channel)); if ((c->input = sshbuf_new()) == NULL || (c->output = sshbuf_new()) == NULL || (c->extended = sshbuf_new()) == NULL) fatal_f("sshbuf_new failed"); if ((r = sshbuf_set_max_size(c->input, CHAN_INPUT_MAX)) != 0) fatal_fr(r, "sshbuf_set_max_size"); c->ostate = CHAN_OUTPUT_OPEN; c->istate = CHAN_INPUT_OPEN; channel_register_fds(ssh, c, rfd, wfd, efd, extusage, nonblock, 0); c->self = found; c->type = type; c->ctype = ctype; c->local_window = window; c->local_window_max = window; c->local_maxpacket = maxpack; c->remote_name = xstrdup(remote_name); c->ctl_chan = -1; c->delayed = 1; /* prevent call to channel_post handler */ TAILQ_INIT(&c->status_confirms); debug("channel %d: new [%s]", found, remote_name); return c; } 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; 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_f("channel %d: rfd r%d w%d e%d s%d " - "pfd[%u].fd=%d want 0x%02x ev 0x%02x ready 0x%02x rev 0x%02x", - c->self, c->rfd, c->wfd, c->efd, c->sock, pollfd_offset, pfd->fd, - c->io_want, pfd->events, c->io_ready, pfd->revents); + 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 p = *next_pollfd; + 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->pollfd_offset = -1; + 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) { - if (c->pollfd_offset == -1) - c->pollfd_offset = p; - pfd[p].fd = c->rfd; - pfd[p].events = 0; + ev = 0; if ((c->io_want & SSH_CHAN_IO_RFD) != 0) - pfd[p].events |= POLLIN; + ev |= POLLIN; /* rfd == wfd */ - if (c->wfd == c->rfd && - (c->io_want & SSH_CHAN_IO_WFD) != 0) - pfd[p].events |= POLLOUT; + if (c->wfd == c->rfd) { + if ((c->io_want & SSH_CHAN_IO_WFD) != 0) + ev |= POLLOUT; + } /* rfd == efd */ - if (c->efd == c->rfd && - (c->io_want & SSH_CHAN_IO_EFD_R) != 0) - pfd[p].events |= POLLIN; - if (c->efd == c->rfd && - (c->io_want & SSH_CHAN_IO_EFD_W) != 0) - pfd[p].events |= POLLOUT; + 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 && - (c->io_want & SSH_CHAN_IO_SOCK_R) != 0) - pfd[p].events |= POLLIN; - if (c->sock == c->rfd && - (c->io_want & SSH_CHAN_IO_SOCK_W) != 0) - pfd[p].events |= POLLOUT; - dump_channel_poll(__func__, "rfd", c, p, &pfd[p]); - p++; - } - /* prepare c->wfd (if not already handled above) */ + 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) { - if (c->pollfd_offset == -1) - c->pollfd_offset = p; - pfd[p].fd = c->wfd; - pfd[p].events = 0; - if ((c->io_want & SSH_CHAN_IO_WFD) != 0) - pfd[p].events = POLLOUT; - dump_channel_poll(__func__, "wfd", c, p, &pfd[p]); - p++; - } - /* prepare c->efd (if not already handled above) */ + 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) { - if (c->pollfd_offset == -1) - c->pollfd_offset = p; - pfd[p].fd = c->efd; - pfd[p].events = 0; + ev = 0; if ((c->io_want & SSH_CHAN_IO_EFD_R) != 0) - pfd[p].events |= POLLIN; + ev |= POLLIN; if ((c->io_want & SSH_CHAN_IO_EFD_W) != 0) - pfd[p].events |= POLLOUT; - dump_channel_poll(__func__, "efd", c, p, &pfd[p]); - p++; + 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 not already handled above) */ + /* prepare c->sock if wanting IO and not already handled above */ if (c->sock != -1 && c->rfd != c->sock) { - if (c->pollfd_offset == -1) - c->pollfd_offset = p; - pfd[p].fd = c->sock; - pfd[p].events = 0; + ev = 0; if ((c->io_want & SSH_CHAN_IO_SOCK_R) != 0) - pfd[p].events |= POLLIN; + ev |= POLLIN; if ((c->io_want & SSH_CHAN_IO_SOCK_W) != 0) - pfd[p].events |= POLLOUT; - dump_channel_poll(__func__, "sock", c, p, &pfd[p]); - p++; + 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; 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, u_int p, struct pollfd *pfds, int fd, +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, p; + u_int i; + int p; Channel *c; #ifdef DEBUG_CHANNEL_POLL - for (p = 0; p < npfd; p++) { + 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 || c->pollfd_offset < 0) + if (c == NULL) continue; - if ((u_int)c->pollfd_offset >= npfd) { - /* shouldn't happen */ - fatal_f("channel %d: (before) bad pfd %u (max %u)", - c->self, c->pollfd_offset, npfd); - } /* 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; - p = c->pollfd_offset; /* rfd, potentially shared with wfd, efd and sock */ - if (c->rfd != -1) { - fd_ready(c, p, pfd, c->rfd, "rfd", POLLIN, - SSH_CHAN_IO_RFD); + 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, c->wfd, "wfd/r", POLLOUT, - SSH_CHAN_IO_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, c->efd, "efdr/r", POLLIN, - SSH_CHAN_IO_EFD_R); - fd_ready(c, p, pfd, c->efd, "efdw/r", POLLOUT, - SSH_CHAN_IO_EFD_W); + 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, c->sock, "sockr/r", POLLIN, - SSH_CHAN_IO_SOCK_R); - fd_ready(c, p, pfd, c->sock, "sockw/r", POLLOUT, - SSH_CHAN_IO_SOCK_W); + 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); } - p++; + dump_channel_poll(__func__, "rfd", c, p, pfd); } /* wfd */ - if (c->wfd != -1 && c->wfd != c->rfd) { - fd_ready(c, p, pfd, c->wfd, "wfd", POLLOUT, - SSH_CHAN_IO_WFD); - p++; + 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) { - fd_ready(c, p, pfd, c->efd, "efdr", POLLIN, - SSH_CHAN_IO_EFD_R); - fd_ready(c, p, pfd, c->efd, "efdw", POLLOUT, - SSH_CHAN_IO_EFD_W); - p++; + 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) { - fd_ready(c, p, pfd, c->sock, "sockr", POLLIN, - SSH_CHAN_IO_SOCK_R); - fd_ready(c, p, pfd, c->sock, "sockw", POLLOUT, - SSH_CHAN_IO_SOCK_W); - p++; - } - - if (p > npfd) { - /* shouldn't happen */ - fatal_f("channel %d: (after) bad pfd %u (max %u)", - c->self, c->pollfd_offset, npfd); + 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, "", -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"); continue; } break; default: continue; } if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype, cctx->ai->ai_protocol)) == -1) { if (cctx->ai->ai_next == NULL) error("socket: %.100s", strerror(errno)); else verbose("socket: %.100s", strerror(errno)); continue; } if (set_nonblock(sock) == -1) fatal_f("set_nonblock(%d)", sock); if (connect(sock, cctx->ai->ai_addr, cctx->ai->ai_addrlen) == -1 && errno != EINPROGRESS) { debug("connect_next: host %.100s ([%.100s]:%s): " "%.100s", cctx->host, ntop, strport, strerror(errno)); saved_errno = errno; close(sock); errno = saved_errno; continue; /* fail -- try next */ } if (cctx->ai->ai_family != AF_UNIX) set_nodelay(sock); debug("connect_next: host %.100s ([%.100s]:%s) " "in progress, fd=%d", cctx->host, ntop, strport, sock); cctx->ai = cctx->ai->ai_next; return sock; } return -1; } static void channel_connect_ctx_free(struct channel_connect *cctx) { free(cctx->host); if (cctx->aitop) { if (cctx->aitop->ai_family == AF_UNIX) free(cctx->aitop); else freeaddrinfo(cctx->aitop); } memset(cctx, 0, sizeof(*cctx)); } /* * Return connecting socket to remote host:port or local socket path, * passing back the failure reason if appropriate. */ static int connect_to_helper(struct ssh *ssh, const char *name, int port, int socktype, char *ctype, char *rname, struct channel_connect *cctx, int *reason, const char **errmsg) { struct addrinfo hints; int gaierr; int sock = -1; char strport[NI_MAXSERV]; if (port == PORT_STREAMLOCAL) { struct sockaddr_un *sunaddr; struct addrinfo *ai; if (strlen(name) > sizeof(sunaddr->sun_path)) { error("%.100s: %.100s", name, strerror(ENAMETOOLONG)); return -1; } /* * Fake up a struct addrinfo for AF_UNIX connections. * channel_connect_ctx_free() must check ai_family * and use free() not freeaddirinfo() for AF_UNIX. */ ai = xmalloc(sizeof(*ai) + sizeof(*sunaddr)); memset(ai, 0, sizeof(*ai) + sizeof(*sunaddr)); ai->ai_addr = (struct sockaddr *)(ai + 1); ai->ai_addrlen = sizeof(*sunaddr); ai->ai_family = AF_UNIX; ai->ai_socktype = socktype; ai->ai_protocol = PF_UNSPEC; sunaddr = (struct sockaddr_un *)ai->ai_addr; sunaddr->sun_family = AF_UNIX; strlcpy(sunaddr->sun_path, name, sizeof(sunaddr->sun_path)); cctx->aitop = ai; } else { memset(&hints, 0, sizeof(hints)); hints.ai_family = ssh->chanctxt->IPv4or6; hints.ai_socktype = socktype; snprintf(strport, sizeof strport, "%d", port); if ((gaierr = getaddrinfo(name, strport, &hints, &cctx->aitop)) != 0) { if (errmsg != NULL) *errmsg = ssh_gai_strerror(gaierr); if (reason != NULL) *reason = SSH2_OPEN_CONNECT_FAILED; error("connect_to %.100s: unknown host (%s)", name, ssh_gai_strerror(gaierr)); return -1; } } cctx->host = xstrdup(name); cctx->port = port; cctx->ai = cctx->aitop; if ((sock = connect_next(cctx)) == -1) { error("connect to %.100s port %d failed: %s", name, port, strerror(errno)); return -1; } return sock; } /* Return CONNECTING channel to remote host:port or local socket path */ static Channel * connect_to(struct ssh *ssh, const char *host, int port, char *ctype, char *rname) { struct channel_connect cctx; Channel *c; int sock; memset(&cctx, 0, sizeof(cctx)); sock = connect_to_helper(ssh, host, port, SOCK_STREAM, ctype, rname, &cctx, NULL, NULL); if (sock == -1) { channel_connect_ctx_free(&cctx); return NULL; } c = channel_new(ssh, ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1); c->host_port = port; c->path = xstrdup(host); c->connect_ctx = cctx; return c; } /* * returns either the newly connected channel or the downstream channel * that needs to deal with this connection. */ Channel * channel_connect_by_listen_address(struct ssh *ssh, const char *listen_host, u_short listen_port, char *ctype, char *rname) { struct ssh_channels *sc = ssh->chanctxt; struct permission_set *pset = &sc->local_perms; u_int i; struct permission *perm; for (i = 0; i < pset->num_permitted_user; i++) { perm = &pset->permitted_user[i]; if (open_listen_match_tcpip(perm, listen_host, listen_port, 1)) { if (perm->downstream) return perm->downstream; if (perm->port_to_connect == 0) return rdynamic_connect_prepare(ssh, ctype, rname); return connect_to(ssh, perm->host_to_connect, perm->port_to_connect, ctype, rname); } } error("WARNING: Server requests forwarding for unknown listen_port %d", listen_port); return NULL; } Channel * channel_connect_by_listen_path(struct ssh *ssh, const char *path, char *ctype, char *rname) { struct ssh_channels *sc = ssh->chanctxt; struct permission_set *pset = &sc->local_perms; u_int i; struct permission *perm; for (i = 0; i < pset->num_permitted_user; i++) { perm = &pset->permitted_user[i]; if (open_listen_match_streamlocal(perm, path)) { return connect_to(ssh, perm->host_to_connect, perm->port_to_connect, ctype, rname); } } error("WARNING: Server requests forwarding for unknown path %.100s", path); return NULL; } /* Check if connecting to that port is permitted and connect. */ Channel * channel_connect_to_port(struct ssh *ssh, const char *host, u_short port, char *ctype, char *rname, int *reason, const char **errmsg) { struct ssh_channels *sc = ssh->chanctxt; struct permission_set *pset = &sc->local_perms; struct channel_connect cctx; Channel *c; u_int i, permit, permit_adm = 1; int sock; struct permission *perm; permit = pset->all_permitted; if (!permit) { for (i = 0; i < pset->num_permitted_user; i++) { perm = &pset->permitted_user[i]; if (open_match(perm, host, port)) { permit = 1; break; } } } if (pset->num_permitted_admin > 0) { permit_adm = 0; for (i = 0; i < pset->num_permitted_admin; i++) { perm = &pset->permitted_admin[i]; if (open_match(perm, host, port)) { permit_adm = 1; break; } } } if (!permit || !permit_adm) { logit("Received request from %.100s port %d to connect to " "host %.100s port %d, but the request was denied.", ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), host, port); if (reason != NULL) *reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED; return NULL; } memset(&cctx, 0, sizeof(cctx)); sock = connect_to_helper(ssh, host, port, SOCK_STREAM, ctype, rname, &cctx, reason, errmsg); if (sock == -1) { channel_connect_ctx_free(&cctx); return NULL; } c = channel_new(ssh, ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1); c->host_port = port; c->path = xstrdup(host); c->connect_ctx = cctx; return c; } /* Check if connecting to that path is permitted and connect. */ Channel * channel_connect_to_path(struct ssh *ssh, const char *path, char *ctype, char *rname) { struct ssh_channels *sc = ssh->chanctxt; struct permission_set *pset = &sc->local_perms; u_int i, permit, permit_adm = 1; struct permission *perm; permit = pset->all_permitted; if (!permit) { for (i = 0; i < pset->num_permitted_user; i++) { perm = &pset->permitted_user[i]; if (open_match(perm, path, PORT_STREAMLOCAL)) { permit = 1; break; } } } if (pset->num_permitted_admin > 0) { permit_adm = 0; for (i = 0; i < pset->num_permitted_admin; i++) { perm = &pset->permitted_admin[i]; if (open_match(perm, path, PORT_STREAMLOCAL)) { permit_adm = 1; break; } } } if (!permit || !permit_adm) { logit("Received request to connect to path %.100s, " "but the request was denied.", path); return NULL; } return connect_to(ssh, path, PORT_STREAMLOCAL, ctype, rname); } void channel_send_window_changes(struct ssh *ssh) { struct ssh_channels *sc = ssh->chanctxt; struct winsize ws; int r; u_int i; for (i = 0; i < sc->channels_alloc; i++) { if (sc->channels[i] == NULL || !sc->channels[i]->client_tty || sc->channels[i]->type != SSH_CHANNEL_OPEN) continue; if (ioctl(sc->channels[i]->rfd, TIOCGWINSZ, &ws) == -1) continue; channel_request_start(ssh, i, "window-change", 0); if ((r = sshpkt_put_u32(ssh, (u_int)ws.ws_col)) != 0 || (r = sshpkt_put_u32(ssh, (u_int)ws.ws_row)) != 0 || (r = sshpkt_put_u32(ssh, (u_int)ws.ws_xpixel)) != 0 || (r = sshpkt_put_u32(ssh, (u_int)ws.ws_ypixel)) != 0 || (r = sshpkt_send(ssh)) != 0) fatal_fr(r, "channel %u; send window-change", i); } } /* Return RDYNAMIC_OPEN channel: channel allows SOCKS, but is not connected */ static Channel * rdynamic_connect_prepare(struct ssh *ssh, char *ctype, char *rname) { Channel *c; int r; c = channel_new(ssh, ctype, SSH_CHANNEL_RDYNAMIC_OPEN, -1, -1, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1); c->host_port = 0; c->path = NULL; /* * We need to open the channel before we have a FD, * so that we can get SOCKS header from peer. */ if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 || (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || (r = sshpkt_put_u32(ssh, c->self)) != 0 || (r = sshpkt_put_u32(ssh, c->local_window)) != 0 || (r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) fatal_fr(r, "channel %i; confirm", c->self); return c; } /* Return CONNECTING socket to remote host:port or local socket path */ static int rdynamic_connect_finish(struct ssh *ssh, Channel *c) { struct ssh_channels *sc = ssh->chanctxt; struct permission_set *pset = &sc->local_perms; struct permission *perm; struct channel_connect cctx; u_int i, permit_adm = 1; int sock; if (pset->num_permitted_admin > 0) { permit_adm = 0; for (i = 0; i < pset->num_permitted_admin; i++) { perm = &pset->permitted_admin[i]; if (open_match(perm, c->path, c->host_port)) { permit_adm = 1; break; } } } if (!permit_adm) { debug_f("requested forward not permitted"); return -1; } memset(&cctx, 0, sizeof(cctx)); sock = connect_to_helper(ssh, c->path, c->host_port, SOCK_STREAM, NULL, NULL, &cctx, NULL, NULL); if (sock == -1) channel_connect_ctx_free(&cctx); else { /* similar to SSH_CHANNEL_CONNECTING but we've already sent the open */ c->type = SSH_CHANNEL_RDYNAMIC_FINISH; c->connect_ctx = cctx; channel_register_fds(ssh, c, sock, sock, -1, 0, 1, 0); } return sock; } /* -- X11 forwarding */ /* * Creates an internet domain socket for listening for X11 connections. * Returns 0 and a suitable display number for the DISPLAY variable * stored in display_numberp , or -1 if an error occurs. */ int x11_create_display_inet(struct ssh *ssh, int x11_display_offset, int x11_use_localhost, int single_connection, u_int *display_numberp, int **chanids) { Channel *nc = NULL; int display_number, sock; u_short port; struct addrinfo hints, *ai, *aitop; char strport[NI_MAXSERV]; int gaierr, n, num_socks = 0, socks[NUM_SOCKS]; if (chanids == NULL) return -1; for (display_number = x11_display_offset; display_number < MAX_DISPLAYS; display_number++) { port = 6000 + display_number; memset(&hints, 0, sizeof(hints)); hints.ai_family = ssh->chanctxt->IPv4or6; hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; snprintf(strport, sizeof strport, "%d", port); if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) { error("getaddrinfo: %.100s", ssh_gai_strerror(gaierr)); return -1; } for (ai = aitop; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) continue; sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock == -1) { if ((errno != EINVAL) && (errno != EAFNOSUPPORT) #ifdef EPFNOSUPPORT && (errno != EPFNOSUPPORT) #endif ) { error("socket: %.100s", strerror(errno)); freeaddrinfo(aitop); return -1; } else { debug("x11_create_display_inet: Socket family %d not supported", ai->ai_family); continue; } } if (ai->ai_family == AF_INET6) sock_set_v6only(sock); if (x11_use_localhost) set_reuseaddr(sock); if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) { debug2_f("bind port %d: %.100s", port, strerror(errno)); close(sock); for (n = 0; n < num_socks; n++) close(socks[n]); num_socks = 0; break; } socks[num_socks++] = sock; if (num_socks == NUM_SOCKS) break; } freeaddrinfo(aitop); if (num_socks > 0) break; } if (display_number >= MAX_DISPLAYS) { error("Failed to allocate internet-domain X11 display socket."); return -1; } /* Start listening for connections on the socket. */ for (n = 0; n < num_socks; n++) { sock = socks[n]; if (listen(sock, SSH_LISTEN_BACKLOG) == -1) { error("listen: %.100s", strerror(errno)); close(sock); return -1; } } /* Allocate a channel for each socket. */ *chanids = xcalloc(num_socks + 1, sizeof(**chanids)); for (n = 0; n < num_socks; n++) { sock = socks[n]; nc = channel_new(ssh, "x11 listener", SSH_CHANNEL_X11_LISTENER, sock, sock, -1, CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "X11 inet listener", 1); nc->single_connection = single_connection; (*chanids)[n] = nc->self; } (*chanids)[n] = -1; /* Return the display number for the DISPLAY environment variable. */ *display_numberp = display_number; return 0; } static int connect_local_xsocket_path(const char *pathname) { int sock; struct sockaddr_un addr; sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock == -1) error("socket: %.100s", strerror(errno)); memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strlcpy(addr.sun_path, pathname, sizeof addr.sun_path); if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) return sock; close(sock); error("connect %.100s: %.100s", addr.sun_path, strerror(errno)); return -1; } static int connect_local_xsocket(u_int dnr) { char buf[1024]; snprintf(buf, sizeof buf, _PATH_UNIX_X, dnr); return connect_local_xsocket_path(buf); } #ifdef __APPLE__ static int is_path_to_xsocket(const char *display, char *path, size_t pathlen) { struct stat sbuf; if (strlcpy(path, display, pathlen) >= pathlen) { error("%s: display path too long", __func__); return 0; } if (display[0] != '/') return 0; if (stat(path, &sbuf) == 0) { return 1; } else { char *dot = strrchr(path, '.'); if (dot != NULL) { *dot = '\0'; if (stat(path, &sbuf) == 0) { return 1; } } } return 0; } #endif int x11_connect_display(struct ssh *ssh) { u_int display_number; const char *display; char buf[1024], *cp; struct addrinfo hints, *ai, *aitop; char strport[NI_MAXSERV]; int gaierr, sock = 0; /* Try to open a socket for the local X server. */ display = getenv("DISPLAY"); if (!display) { error("DISPLAY not set."); return -1; } /* * Now we decode the value of the DISPLAY variable and make a * connection to the real X server. */ #ifdef __APPLE__ /* Check if display is a path to a socket (as set by launchd). */ { char path[PATH_MAX]; if (is_path_to_xsocket(display, path, sizeof(path))) { debug("x11_connect_display: $DISPLAY is launchd"); /* Create a socket. */ sock = connect_local_xsocket_path(path); if (sock < 0) return -1; /* OK, we now have a connection to the display. */ return sock; } } #endif /* * Check if it is a unix domain socket. Unix domain displays are in * one of the following formats: unix:d[.s], :d[.s], ::d[.s] */ if (strncmp(display, "unix:", 5) == 0 || display[0] == ':') { /* Connect to the unix domain socket. */ if (sscanf(strrchr(display, ':') + 1, "%u", &display_number) != 1) { error("Could not parse display number from DISPLAY: " "%.100s", display); return -1; } /* Create a socket. */ sock = connect_local_xsocket(display_number); if (sock < 0) return -1; /* OK, we now have a connection to the display. */ return sock; } /* * Connect to an inet socket. The DISPLAY value is supposedly * hostname:d[.s], where hostname may also be numeric IP address. */ strlcpy(buf, display, sizeof(buf)); cp = strchr(buf, ':'); if (!cp) { error("Could not find ':' in DISPLAY: %.100s", display); return -1; } *cp = 0; /* * buf now contains the host name. But first we parse the * display number. */ if (sscanf(cp + 1, "%u", &display_number) != 1) { error("Could not parse display number from DISPLAY: %.100s", display); return -1; } /* Look up the host address */ memset(&hints, 0, sizeof(hints)); hints.ai_family = ssh->chanctxt->IPv4or6; hints.ai_socktype = SOCK_STREAM; snprintf(strport, sizeof strport, "%u", 6000 + display_number); if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { error("%.100s: unknown host. (%s)", buf, ssh_gai_strerror(gaierr)); return -1; } for (ai = aitop; ai; ai = ai->ai_next) { /* Create a socket. */ sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock == -1) { debug2("socket: %.100s", strerror(errno)); continue; } /* Connect it to the display. */ if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) { debug2("connect %.100s port %u: %.100s", buf, 6000 + display_number, strerror(errno)); close(sock); continue; } /* Success */ break; } freeaddrinfo(aitop); if (!ai) { error("connect %.100s port %u: %.100s", buf, 6000 + display_number, strerror(errno)); return -1; } set_nodelay(sock); return sock; } /* * Requests forwarding of X11 connections, generates fake authentication * data, and enables authentication spoofing. * This should be called in the client only. */ void x11_request_forwarding_with_spoofing(struct ssh *ssh, int client_session_id, const char *disp, const char *proto, const char *data, int want_reply) { struct ssh_channels *sc = ssh->chanctxt; u_int data_len = (u_int) strlen(data) / 2; u_int i, value; const char *cp; char *new_data; int r, screen_number; if (sc->x11_saved_display == NULL) sc->x11_saved_display = xstrdup(disp); else if (strcmp(disp, sc->x11_saved_display) != 0) { error("x11_request_forwarding_with_spoofing: different " "$DISPLAY already forwarded"); return; } cp = strchr(disp, ':'); if (cp) cp = strchr(cp, '.'); if (cp) screen_number = (u_int)strtonum(cp + 1, 0, 400, NULL); else screen_number = 0; if (sc->x11_saved_proto == NULL) { /* Save protocol name. */ sc->x11_saved_proto = xstrdup(proto); /* Extract real authentication data. */ sc->x11_saved_data = xmalloc(data_len); for (i = 0; i < data_len; i++) { if (sscanf(data + 2 * i, "%2x", &value) != 1) { fatal("x11_request_forwarding: bad " "authentication data: %.100s", data); } sc->x11_saved_data[i] = value; } sc->x11_saved_data_len = data_len; /* Generate fake data of the same length. */ sc->x11_fake_data = xmalloc(data_len); arc4random_buf(sc->x11_fake_data, data_len); sc->x11_fake_data_len = data_len; } /* Convert the fake data into hex. */ new_data = tohex(sc->x11_fake_data, data_len); /* Send the request packet. */ channel_request_start(ssh, client_session_id, "x11-req", want_reply); if ((r = sshpkt_put_u8(ssh, 0)) != 0 || /* bool: single connection */ (r = sshpkt_put_cstring(ssh, proto)) != 0 || (r = sshpkt_put_cstring(ssh, new_data)) != 0 || (r = sshpkt_put_u32(ssh, screen_number)) != 0 || (r = sshpkt_send(ssh)) != 0 || (r = ssh_packet_write_wait(ssh)) != 0) fatal_fr(r, "send x11-req"); free(new_data); } diff --git a/crypto/openssh/channels.h b/crypto/openssh/channels.h index 82f33ba2ff14..dfb82f8ce262 100644 --- a/crypto/openssh/channels.h +++ b/crypto/openssh/channels.h @@ -1,383 +1,383 @@ -/* $OpenBSD: channels.h,v 1.141 2022/01/22 00:49:34 djm Exp $ */ +/* $OpenBSD: channels.h,v 1.142 2022/03/30 21:10:25 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , 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 pollfd_offset; /* base offset into pollfd array (or -1) */ + 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); 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/crypto/openssh/config.h b/crypto/openssh/config.h index 543e1f6ec724..456966f2c0be 100644 --- a/crypto/openssh/config.h +++ b/crypto/openssh/config.h @@ -1,2114 +1,2121 @@ /* config.h. Generated from config.h.in by configure. */ /* 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 */ #define BROKEN_GLOB 1 /* 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 */ #define BROKEN_STRNVIS 1 /* 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 */ #define DISABLE_LASTLOG 1 /* 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 */ #define DISABLE_UTMP 1 /* Define if you don't want to use utmpx */ /* #undef DISABLE_UTMPX */ /* Define if you don't want to use wtmp */ #define DISABLE_WTMP 1 /* Define if you don't want to use wtmpx */ #define DISABLE_WTMPX 1 /* Enable for PKCS#11 support */ #define ENABLE_PKCS11 /**/ /* Enable for U2F/FIDO support */ #define 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 */ #define GETPGRP_VOID 1 /* Conflicting defs for getspnam */ /* #undef GETSPNAM_CONFLICTING_DEFS */ /* Define if your system glob() function has the GLOB_ALTDIRFUNC extension */ #define GLOB_HAS_ALTDIRFUNC 1 /* Define if your system glob() function has gl_matchc options in glob_t */ #define GLOB_HAS_GL_MATCHC 1 /* 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. */ #define HAVE_ARC4RANDOM 1 /* Define to 1 if you have the `arc4random_buf' function. */ #define HAVE_ARC4RANDOM_BUF 1 /* Define to 1 if you have the `arc4random_stir' function. */ /* #undef HAVE_ARC4RANDOM_STIR */ /* Define to 1 if you have the `arc4random_uniform' function. */ #define HAVE_ARC4RANDOM_UNIFORM 1 /* Define to 1 if you have the `asprintf' function. */ #define HAVE_ASPRINTF 1 /* OpenBSD's gcc has bounded */ /* #undef HAVE_ATTRIBUTE__BOUNDED__ */ /* Have attribute nonnull */ #define HAVE_ATTRIBUTE__NONNULL__ 1 /* 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 `auth_hostok' function. */ #define HAVE_AUTH_HOSTOK 1 /* Define to 1 if you have the `auth_timeok' function. */ #define HAVE_AUTH_TIMEOK 1 /* 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. */ #define HAVE_BASENAME 1 /* Define to 1 if you have the `bcopy' function. */ #define HAVE_BCOPY 1 /* Define to 1 if you have the `bcrypt_pbkdf' function. */ /* #undef HAVE_BCRYPT_PBKDF */ /* Define to 1 if you have the `bindresvport_sa' function. */ #define HAVE_BINDRESVPORT_SA 1 /* Define to 1 if you have the `blf_enc' function. */ /* #undef HAVE_BLF_ENC */ /* Define to 1 if you have the 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. */ #define HAVE_BN_IS_PRIME_EX 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_BSD_LIBUTIL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_BSM_AUDIT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_BSTRING_H */ /* Define to 1 if you have the `bzero' function. */ #define HAVE_BZERO 1 /* calloc(0, x) returns NULL */ #define HAVE_CALLOC 1 /* Define to 1 if you have the `cap_rights_limit' function. */ #define HAVE_CAP_RIGHTS_LIMIT 1 /* Define to 1 if you have the `clock' function. */ #define HAVE_CLOCK 1 /* Have clock_gettime */ #define HAVE_CLOCK_GETTIME 1 /* define if you have clock_t data type */ #define HAVE_CLOCK_T 1 /* Define to 1 if you have the `closefrom' function. */ #define HAVE_CLOSEFROM 1 /* Define to 1 if you have the `close_range' function. */ #define HAVE_CLOSE_RANGE 1 /* Define if gai_strerror() returns const char * */ #define HAVE_CONST_GAI_STRERROR_PROTO 1 /* Define if your system uses ancillary data style file descriptor passing */ #define HAVE_CONTROL_IN_MSGHDR 1 /* Define to 1 if you have the `crypt' function. */ #define HAVE_CRYPT 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_CRYPTO_SHA2_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_CRYPT_H */ /* Define if you are on Cygwin */ /* #undef HAVE_CYGWIN */ /* Define if your libraries define daemon() */ #define HAVE_DAEMON 1 /* Define to 1 if you have the declaration of `AI_NUMERICSERV', and to 0 if you don't. */ #define HAVE_DECL_AI_NUMERICSERV 1 /* 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. */ #define HAVE_DECL_BZERO 1 +/* Define to 1 if you have the declaration of `ftruncate', and to 0 if you + don't. */ +#define HAVE_DECL_FTRUNCATE 1 + /* Define to 1 if you have the declaration of `getpeereid', and to 0 if you don't. */ #define HAVE_DECL_GETPEEREID 1 /* Define to 1 if you have the declaration of `GLOB_NOMATCH', and to 0 if you don't. */ #define HAVE_DECL_GLOB_NOMATCH 1 /* 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. */ #define HAVE_DECL_HOWMANY 1 /* Define to 1 if you have the declaration of `h_errno', and to 0 if you don't. */ #define HAVE_DECL_H_ERRNO 1 /* 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. */ #define HAVE_DECL_MAXSYMLINKS 1 /* Define to 1 if you have the declaration of `memmem', and to 0 if you don't. */ #define HAVE_DECL_MEMMEM 1 /* Define to 1 if you have the declaration of `NFDBITS', and to 0 if you don't. */ #define HAVE_DECL_NFDBITS 1 /* Define to 1 if you have the declaration of `offsetof', and to 0 if you don't. */ #define HAVE_DECL_OFFSETOF 1 /* Define to 1 if you have the declaration of `O_NONBLOCK', and to 0 if you don't. */ #define HAVE_DECL_O_NONBLOCK 1 /* 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. */ #define HAVE_DECL_READV 1 /* 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. */ #define HAVE_DECL_SHUT_RD 1 /* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you don't. */ #define HAVE_DECL_UINT32_MAX 1 /* Define to 1 if you have the declaration of `writev', and to 0 if you don't. */ #define HAVE_DECL_WRITEV 1 /* Define to 1 if you have the declaration of `_getlong', and to 0 if you don't. */ #define HAVE_DECL__GETLONG 0 /* Define to 1 if you have the declaration of `_getshort', and to 0 if you don't. */ #define HAVE_DECL__GETSHORT 0 /* Define to 1 if you have the `DES_crypt' function. */ #define HAVE_DES_CRYPT 1 /* 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. */ #define HAVE_DH_GET0_KEY 1 /* Define to 1 if you have the `DH_get0_pqg' function. */ #define HAVE_DH_GET0_PQG 1 /* Define to 1 if you have the `DH_set0_key' function. */ #define HAVE_DH_SET0_KEY 1 /* Define to 1 if you have the `DH_set0_pqg' function. */ #define HAVE_DH_SET0_PQG 1 /* Define to 1 if you have the `DH_set_length' function. */ #define HAVE_DH_SET_LENGTH 1 /* Define to 1 if you have the header file. */ #define HAVE_DIRENT_H 1 /* Define to 1 if you have the `dirfd' function. */ #define HAVE_DIRFD 1 /* Define to 1 if you have the `dirname' function. */ #define HAVE_DIRNAME 1 /* Define to 1 if you have the `dlopen' function. */ #define HAVE_DLOPEN 1 /* Define to 1 if you have the `DSA_generate_parameters_ex' function. */ #define HAVE_DSA_GENERATE_PARAMETERS_EX 1 /* Define to 1 if you have the `DSA_get0_key' function. */ #define HAVE_DSA_GET0_KEY 1 /* Define to 1 if you have the `DSA_get0_pqg' function. */ #define HAVE_DSA_GET0_PQG 1 /* Define to 1 if you have the `DSA_set0_key' function. */ #define HAVE_DSA_SET0_KEY 1 /* Define to 1 if you have the `DSA_set0_pqg' function. */ #define HAVE_DSA_SET0_PQG 1 /* Define to 1 if you have the `DSA_SIG_get0' function. */ #define HAVE_DSA_SIG_GET0 1 /* Define to 1 if you have the `DSA_SIG_set0' function. */ #define HAVE_DSA_SIG_SET0 1 /* Define to 1 if you have the `ECDSA_SIG_get0' function. */ #define HAVE_ECDSA_SIG_GET0 1 /* Define to 1 if you have the `ECDSA_SIG_set0' function. */ #define HAVE_ECDSA_SIG_SET0 1 /* Define to 1 if you have the `EC_KEY_METHOD_new' function. */ #define HAVE_EC_KEY_METHOD_NEW 1 /* Define to 1 if you have the header file. */ #define HAVE_ELF_H 1 /* Define to 1 if you have the `endgrent' function. */ #define HAVE_ENDGRENT 1 /* Define to 1 if you have the 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. */ #define HAVE_ENDUTXENT 1 /* Define to 1 if you have the `err' function. */ #define HAVE_ERR 1 /* Define to 1 if you have the `errx' function. */ #define HAVE_ERRX 1 /* Define to 1 if you have the header file. */ #define HAVE_ERR_H 1 /* Define if your system has /etc/default/login */ /* #undef HAVE_ETC_DEFAULT_LOGIN */ /* Define to 1 if you have the `EVP_chacha20' function. */ #define HAVE_EVP_CHACHA20 1 /* Define to 1 if you have the `EVP_CIPHER_CTX_ctrl' function. */ #define HAVE_EVP_CIPHER_CTX_CTRL 1 /* 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. */ #define HAVE_EVP_CIPHER_CTX_IV 1 /* Define to 1 if you have the `EVP_CIPHER_CTX_iv_noconst' function. */ #define HAVE_EVP_CIPHER_CTX_IV_NOCONST 1 /* 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. */ #define HAVE_EVP_DIGESTFINAL_EX 1 /* Define to 1 if you have the `EVP_DigestInit_ex' function. */ #define HAVE_EVP_DIGESTINIT_EX 1 /* 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. */ #define HAVE_EVP_MD_CTX_COPY_EX 1 /* Define to 1 if you have the `EVP_MD_CTX_free' function. */ #define HAVE_EVP_MD_CTX_FREE 1 /* 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. */ #define HAVE_EVP_MD_CTX_NEW 1 /* Define to 1 if you have the `EVP_PKEY_get0_RSA' function. */ #define HAVE_EVP_PKEY_GET0_RSA 1 /* Define to 1 if you have the `EVP_sha256' function. */ #define HAVE_EVP_SHA256 1 /* Define to 1 if you have the `EVP_sha384' function. */ #define HAVE_EVP_SHA384 1 /* Define to 1 if you have the `EVP_sha512' function. */ #define HAVE_EVP_SHA512 1 /* Define if you have ut_exit in utmp.h */ /* #undef HAVE_EXIT_IN_UTMP */ /* Define to 1 if you have the `explicit_bzero' function. */ #define HAVE_EXPLICIT_BZERO 1 /* Define to 1 if you have the `explicit_memset' function. */ /* #undef HAVE_EXPLICIT_MEMSET */ /* Define to 1 if you have the `fchmod' function. */ #define HAVE_FCHMOD 1 /* Define to 1 if you have the `fchmodat' function. */ #define HAVE_FCHMODAT 1 /* Define to 1 if you have the `fchown' function. */ #define HAVE_FCHOWN 1 /* Define to 1 if you have the `fchownat' function. */ #define HAVE_FCHOWNAT 1 /* Use F_CLOSEM fcntl for closefrom */ /* #undef HAVE_FCNTL_CLOSEM */ /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if the system has the type `fd_mask'. */ #define HAVE_FD_MASK 1 /* Define to 1 if you have the 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_supports_cred_prot' function. */ /* #undef HAVE_FIDO_DEV_SUPPORTS_CRED_PROT */ /* Define to 1 if you have the header file. */ #define HAVE_FLOATINGPOINT_H 1 /* Define to 1 if you have the `flock' function. */ #define HAVE_FLOCK 1 /* Define to 1 if you have the `fmt_scaled' function. */ /* #undef HAVE_FMT_SCALED */ /* Define to 1 if you have the `fnmatch' function. */ #define HAVE_FNMATCH 1 /* Define to 1 if you have the header file. */ #define HAVE_FNMATCH_H 1 /* Define to 1 if you have the `freeaddrinfo' function. */ #define HAVE_FREEADDRINFO 1 /* Define to 1 if you have the `freezero' function. */ /* #undef HAVE_FREEZERO */ /* Define to 1 if the system has the type `fsblkcnt_t'. */ #define HAVE_FSBLKCNT_T 1 /* Define to 1 if the system has the type `fsfilcnt_t'. */ #define HAVE_FSFILCNT_T 1 /* Define to 1 if you have the `fstatfs' function. */ #define HAVE_FSTATFS 1 /* Define to 1 if you have the `fstatvfs' function. */ #define HAVE_FSTATVFS 1 /* Define to 1 if you have the `futimes' function. */ #define HAVE_FUTIMES 1 /* Define to 1 if you have the `gai_strerror' function. */ #define HAVE_GAI_STRERROR 1 /* Define to 1 if you have the `getaddrinfo' function. */ #define HAVE_GETADDRINFO 1 /* 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. */ #define HAVE_GETCWD 1 /* Define to 1 if you have the `getgrouplist' function. */ #define HAVE_GETGROUPLIST 1 /* 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. */ #define HAVE_GETLINE 1 /* Define to 1 if you have the `getluid' function. */ /* #undef HAVE_GETLUID */ /* Define to 1 if you have the `getnameinfo' function. */ #define HAVE_GETNAMEINFO 1 /* Define to 1 if you have the `getopt' function. */ #define HAVE_GETOPT 1 /* Define to 1 if you have the header file. */ #define HAVE_GETOPT_H 1 /* Define if your getopt(3) defines and uses optreset */ #define HAVE_GETOPT_OPTRESET 1 /* Define if your libraries define getpagesize() */ #define HAVE_GETPAGESIZE 1 /* Define to 1 if you have the `getpeereid' function. */ #define HAVE_GETPEEREID 1 /* Define to 1 if you have the `getpeerucred' function. */ /* #undef HAVE_GETPEERUCRED */ /* Define to 1 if you have the `getpgid' function. */ #define HAVE_GETPGID 1 /* Define to 1 if you have the `getpgrp' function. */ #define HAVE_GETPGRP 1 /* Define to 1 if you have the `getpwanam' function. */ /* #undef HAVE_GETPWANAM */ /* Define to 1 if you have the `getrandom' function. */ #define HAVE_GETRANDOM 1 /* Define to 1 if you have the `getrlimit' function. */ #define HAVE_GETRLIMIT 1 /* 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. */ #define HAVE_GETSID 1 /* Define to 1 if you have the `gettimeofday' function. */ #define HAVE_GETTIMEOFDAY 1 /* Define to 1 if you have the `getttyent' function. */ #define HAVE_GETTTYENT 1 /* 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. */ #define HAVE_GETUTXENT 1 /* Define to 1 if you have the `getutxid' function. */ #define HAVE_GETUTXID 1 /* Define to 1 if you have the `getutxline' function. */ #define HAVE_GETUTXLINE 1 /* Define to 1 if you have the `getutxuser' function. */ #define HAVE_GETUTXUSER 1 /* 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. */ #define HAVE_GLOB 1 /* Define to 1 if you have the header file. */ #define HAVE_GLOB_H 1 /* Define to 1 if you have the `group_from_gid' function. */ #define HAVE_GROUP_FROM_GID 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GENERIC_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_KRB5_H */ /* Define if HEADER.ad exists in arpa/nameser.h */ #define HAVE_HEADER_AD 1 /* 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 */ #define HAVE_HOST_IN_UTMPX 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_IAF_H */ /* Define to 1 if you have the 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 */ #define HAVE_ID_IN_UTMPX 1 /* Define to 1 if you have the header file. */ #define HAVE_IFADDRS_H 1 /* Define to 1 if you have the `inet_aton' function. */ #define HAVE_INET_ATON 1 /* Define to 1 if you have the `inet_ntoa' function. */ #define HAVE_INET_NTOA 1 /* Define to 1 if you have the `inet_ntop' function. */ #define HAVE_INET_NTOP 1 /* Define to 1 if you have the `innetgr' function. */ #define HAVE_INNETGR 1 /* define if you have int64_t data type */ #define HAVE_INT64_T 1 /* Define to 1 if the system has the type `intmax_t'. */ #define HAVE_INTMAX_T 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* define if you have intxx_t data type */ #define HAVE_INTXX_T 1 /* Define to 1 if the system has the type `in_addr_t'. */ #define HAVE_IN_ADDR_T 1 /* Define to 1 if the system has the type `in_port_t'. */ #define HAVE_IN_PORT_T 1 /* Define if you have isblank(3C). */ #define HAVE_ISBLANK 1 +/* Define to 1 if you have the `killpg' function. */ +#define HAVE_KILLPG 1 + /* 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 header file. */ #define HAVE_LANGINFO_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_LASTLOG_H */ /* Define if you want ldns support */ /* #undef HAVE_LDNS */ /* Define to 1 if you have the 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). */ #define HAVE_LIBDL 1 /* Define to 1 if you have the header file. */ #define HAVE_LIBGEN_H 1 /* 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). */ #define HAVE_LIBPAM 1 /* Define to 1 if you have the 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 header file. */ #define HAVE_LIBUTIL_H 1 /* Define to 1 if you have the `xnet' library (-lxnet). */ /* #undef HAVE_LIBXNET */ /* Define to 1 if you have the `z' library (-lz). */ #define HAVE_LIBZ 1 /* Define to 1 if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_LINUX_AUDIT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LINUX_FILTER_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LINUX_IF_TUN_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LINUX_SECCOMP_H */ /* Define to 1 if you have the `llabs' function. */ #define HAVE_LLABS 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define to 1 if you have the `localtime_r' function. */ #define HAVE_LOCALTIME_R 1 /* Define to 1 if you have the `login' function. */ /* #undef HAVE_LOGIN */ /* Define to 1 if you have the header file. */ #define HAVE_LOGIN_CAP_H 1 /* Define to 1 if you have the `login_getcapbool' function. */ #define HAVE_LOGIN_GETCAPBOOL 1 /* Define to 1 if you have the `login_getpwclass' function. */ #define HAVE_LOGIN_GETPWCLASS 1 /* Define to 1 if you have the 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'. */ #define HAVE_LONG_DOUBLE 1 /* Define to 1 if the system has the type `long long'. */ #define HAVE_LONG_LONG 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_MAILLOCK_H */ /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #define HAVE_MALLOC 1 /* Define to 1 if you have the `mblen' function. */ #define HAVE_MBLEN 1 /* Define to 1 if you have the `mbtowc' function. */ #define HAVE_MBTOWC 1 /* Define to 1 if you have the `memmem' function. */ #define HAVE_MEMMEM 1 /* Define to 1 if you have the `memmove' function. */ #define HAVE_MEMMOVE 1 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `memset_s' function. */ #define HAVE_MEMSET_S 1 /* Define to 1 if you have the `mkdtemp' function. */ #define HAVE_MKDTEMP 1 /* define if you have mode_t data type */ #define HAVE_MODE_T 1 /* Some systems put nanosleep outside of libc */ #define HAVE_NANOSLEEP 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NETGROUP_H */ /* Define to 1 if you have the header file. */ #define HAVE_NET_IF_TUN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NET_ROUTE_H 1 /* Define if you are on NeXT */ /* #undef HAVE_NEXT */ /* Define to 1 if the system has the type `nfds_t'. */ #define HAVE_NFDS_T 1 /* Define to 1 if you have the `ngetaddrinfo' function. */ /* #undef HAVE_NGETADDRINFO */ /* Define to 1 if you have the `nl_langinfo' function. */ #define HAVE_NL_LANGINFO 1 /* 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. */ #define HAVE_OPENPTY 1 /* as a macro */ #define HAVE_OPENSSL_ADD_ALL_ALGORITHMS 1 /* Define to 1 if you have the `OPENSSL_init_crypto' function. */ #define HAVE_OPENSSL_INIT_CRYPTO 1 /* Define to 1 if you have the `OpenSSL_version' function. */ #define HAVE_OPENSSL_VERSION 1 /* Define to 1 if you have the `OpenSSL_version_num' function. */ #define HAVE_OPENSSL_VERSION_NUM 1 /* Define if you have Digital Unix Security Integration Architecture */ /* #undef HAVE_OSF_SIA */ /* Define to 1 if you have the `pam_getenvlist' function. */ #define HAVE_PAM_GETENVLIST 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_PAM_PAM_APPL_H */ /* Define to 1 if you have the `pam_putenv' function. */ #define HAVE_PAM_PUTENV 1 /* Define to 1 if you have the header file. */ #define HAVE_PATHS_H 1 /* Define if you have ut_pid in utmp.h */ /* #undef HAVE_PID_IN_UTMP */ /* define if you have pid_t data type */ #define HAVE_PID_T 1 /* Define to 1 if you have the `pledge' function. */ /* #undef HAVE_PLEDGE */ /* Define to 1 if you have the `poll' function. */ #define HAVE_POLL 1 /* Define to 1 if you have the header file. */ #define HAVE_POLL_H 1 /* Define to 1 if you have the `ppoll' function. */ #define HAVE_PPOLL 1 /* 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 header file. */ /* #undef HAVE_PRIV_H */ /* Define to 1 if you have the `procctl' function. */ #define HAVE_PROCCTL 1 /* 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. */ #define HAVE_PSELECT 1 /* Define to 1 if you have the `pstat' function. */ /* #undef HAVE_PSTAT */ /* Define to 1 if you have the 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. */ #define HAVE_PUTUTXLINE 1 /* Define to 1 if you have the `raise' function. */ #define HAVE_RAISE 1 /* Define to 1 if you have the `readpassphrase' function. */ #define HAVE_READPASSPHRASE 1 /* Define to 1 if you have the header file. */ #define HAVE_READPASSPHRASE_H 1 /* Define to 1 if your system has a GNU libc compatible `realloc' function, and to 0 otherwise. */ #define HAVE_REALLOC 1 /* Define to 1 if you have the `reallocarray' function. */ #define HAVE_REALLOCARRAY 1 /* Define to 1 if you have the `realpath' function. */ #define HAVE_REALPATH 1 /* Define to 1 if you have the `recallocarray' function. */ /* #undef HAVE_RECALLOCARRAY */ /* Define to 1 if you have the `recvmsg' function. */ #define HAVE_RECVMSG 1 /* sys/resource.h has RLIMIT_NPROC */ #define HAVE_RLIMIT_NPROC /**/ /* Define to 1 if you have the header file. */ #define HAVE_RPC_TYPES_H 1 /* Define to 1 if you have the `rresvport_af' function. */ #define HAVE_RRESVPORT_AF 1 /* Define to 1 if you have the `RSA_generate_key_ex' function. */ #define HAVE_RSA_GENERATE_KEY_EX 1 /* Define to 1 if you have the `RSA_get0_crt_params' function. */ #define HAVE_RSA_GET0_CRT_PARAMS 1 /* Define to 1 if you have the `RSA_get0_factors' function. */ #define HAVE_RSA_GET0_FACTORS 1 /* Define to 1 if you have the `RSA_get0_key' function. */ #define HAVE_RSA_GET0_KEY 1 /* Define to 1 if you have the `RSA_get_default_method' function. */ #define HAVE_RSA_GET_DEFAULT_METHOD 1 /* Define to 1 if you have the `RSA_meth_dup' function. */ #define HAVE_RSA_METH_DUP 1 /* Define to 1 if you have the `RSA_meth_free' function. */ #define HAVE_RSA_METH_FREE 1 /* Define to 1 if you have the `RSA_meth_get_finish' function. */ #define HAVE_RSA_METH_GET_FINISH 1 /* Define to 1 if you have the `RSA_meth_set1_name' function. */ #define HAVE_RSA_METH_SET1_NAME 1 /* Define to 1 if you have the `RSA_meth_set_finish' function. */ #define HAVE_RSA_METH_SET_FINISH 1 /* Define to 1 if you have the `RSA_meth_set_priv_dec' function. */ #define HAVE_RSA_METH_SET_PRIV_DEC 1 /* Define to 1 if you have the `RSA_meth_set_priv_enc' function. */ #define HAVE_RSA_METH_SET_PRIV_ENC 1 /* Define to 1 if you have the `RSA_set0_crt_params' function. */ #define HAVE_RSA_SET0_CRT_PARAMS 1 /* Define to 1 if you have the `RSA_set0_factors' function. */ #define HAVE_RSA_SET0_FACTORS 1 /* Define to 1 if you have the `RSA_set0_key' function. */ #define HAVE_RSA_SET0_KEY 1 /* Define to 1 if you have the 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 */ #define HAVE_SA_FAMILY_T 1 /* 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 header file. */ #define HAVE_SECURITY_PAM_APPL_H 1 /* Define to 1 if you have the `sendmsg' function. */ #define HAVE_SENDMSG 1 /* 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. */ #define HAVE_SETEGID 1 /* Define to 1 if you have the `setenv' function. */ #define HAVE_SETENV 1 /* Define to 1 if you have the `seteuid' function. */ #define HAVE_SETEUID 1 /* Define to 1 if you have the `setgroupent' function. */ #define HAVE_SETGROUPENT 1 /* Define to 1 if you have the `setgroups' function. */ #define HAVE_SETGROUPS 1 /* Define to 1 if you have the `setlinebuf' function. */ #define HAVE_SETLINEBUF 1 /* Define to 1 if you have the `setlogin' function. */ #define HAVE_SETLOGIN 1 /* Define to 1 if you have the `setluid' function. */ /* #undef HAVE_SETLUID */ /* Define to 1 if you have the `setpassent' function. */ #define HAVE_SETPASSENT 1 /* 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. */ #define HAVE_SETPROCTITLE 1 /* Define to 1 if you have the `setregid' function. */ #define HAVE_SETREGID 1 /* Define to 1 if you have the `setresgid' function. */ #define HAVE_SETRESGID 1 /* Define to 1 if you have the `setresuid' function. */ #define HAVE_SETRESUID 1 /* Define to 1 if you have the `setreuid' function. */ #define HAVE_SETREUID 1 /* Define to 1 if you have the `setrlimit' function. */ #define HAVE_SETRLIMIT 1 /* Define to 1 if you have the `setsid' function. */ #define HAVE_SETSID 1 /* Define to 1 if you have the `setutent' function. */ /* #undef HAVE_SETUTENT */ /* Define to 1 if you have the `setutxdb' function. */ #define HAVE_SETUTXDB 1 /* Define to 1 if you have the `setutxent' function. */ #define HAVE_SETUTXENT 1 /* Define to 1 if you have the `setvbuf' function. */ #define HAVE_SETVBUF 1 /* 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 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 header file. */ /* #undef HAVE_SHADOW_H */ /* Define to 1 if you have the `sigaction' function. */ #define HAVE_SIGACTION 1 /* Define to 1 if the system has the type `sighandler_t'. */ /* #undef HAVE_SIGHANDLER_T */ /* Define to 1 if you have the `sigvec' function. */ #define HAVE_SIGVEC 1 /* Define to 1 if the system has the type `sig_atomic_t'. */ #define HAVE_SIG_ATOMIC_T 1 /* define if you have size_t data type */ #define HAVE_SIZE_T 1 /* Define to 1 if you have the `snprintf' function. */ #define HAVE_SNPRINTF 1 /* Define to 1 if you have the `socketpair' function. */ #define HAVE_SOCKETPAIR 1 /* Have PEERCRED socket option */ /* #undef HAVE_SO_PEERCRED */ /* define if you have ssize_t data type */ #define HAVE_SSIZE_T 1 /* Fields in struct sockaddr_storage */ #define HAVE_SS_FAMILY_IN_SS 1 /* Define if you have ut_ss in utmpx.h */ /* #undef HAVE_SS_IN_UTMPX */ /* Define to 1 if you have the `statfs' function. */ #define HAVE_STATFS 1 /* Define to 1 if you have the `statvfs' function. */ #define HAVE_STATVFS 1 /* Define to 1 if you have the header file. */ #define HAVE_STDDEF_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strcasestr' function. */ #define HAVE_STRCASESTR 1 /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the `strftime' function. */ #define HAVE_STRFTIME 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strlcat' function. */ #define HAVE_STRLCAT 1 /* Define to 1 if you have the `strlcpy' function. */ #define HAVE_STRLCPY 1 /* Define to 1 if you have the `strmode' function. */ #define HAVE_STRMODE 1 /* Define to 1 if you have the `strndup' function. */ #define HAVE_STRNDUP 1 /* Define to 1 if you have the `strnlen' function. */ #define HAVE_STRNLEN 1 /* Define to 1 if you have the `strnvis' function. */ #define HAVE_STRNVIS 1 /* Define to 1 if you have the `strptime' function. */ #define HAVE_STRPTIME 1 /* Define to 1 if you have the `strsep' function. */ #define HAVE_STRSEP 1 /* Define to 1 if you have the `strsignal' function. */ #define HAVE_STRSIGNAL 1 /* Define to 1 if you have the `strtoll' function. */ #define HAVE_STRTOLL 1 /* Define to 1 if you have the `strtonum' function. */ #define HAVE_STRTONUM 1 /* Define to 1 if you have the `strtoul' function. */ #define HAVE_STRTOUL 1 /* Define to 1 if you have the `strtoull' function. */ #define HAVE_STRTOULL 1 /* define if you have struct addrinfo data type */ #define HAVE_STRUCT_ADDRINFO 1 /* define if you have struct in6_addr data type */ #define HAVE_STRUCT_IN6_ADDR 1 /* Define to 1 if `pw_change' is a member of `struct passwd'. */ #define HAVE_STRUCT_PASSWD_PW_CHANGE 1 /* Define to 1 if `pw_class' is a member of `struct passwd'. */ #define HAVE_STRUCT_PASSWD_PW_CLASS 1 /* Define to 1 if `pw_expire' is a member of `struct passwd'. */ #define HAVE_STRUCT_PASSWD_PW_EXPIRE 1 /* Define to 1 if `pw_gecos' is a member of `struct passwd'. */ #define HAVE_STRUCT_PASSWD_PW_GECOS 1 /* Define to 1 if `fd' is a member of `struct pollfd'. */ #define HAVE_STRUCT_POLLFD_FD 1 /* define if you have struct sockaddr_in6 data type */ #define HAVE_STRUCT_SOCKADDR_IN6 1 /* Define to 1 if `sin6_scope_id' is a member of `struct sockaddr_in6'. */ #define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1 /* define if you have struct sockaddr_storage data type */ #define HAVE_STRUCT_SOCKADDR_STORAGE 1 /* Define to 1 if `f_files' is a member of `struct statfs'. */ #define HAVE_STRUCT_STATFS_F_FILES 1 /* Define to 1 if `f_flags' is a member of `struct statfs'. */ #define HAVE_STRUCT_STATFS_F_FLAGS 1 /* Define to 1 if `st_blksize' is a member of `struct stat'. */ #define HAVE_STRUCT_STAT_ST_BLKSIZE 1 /* Define to 1 if `st_mtim' is a member of `struct stat'. */ #define HAVE_STRUCT_STAT_ST_MTIM 1 /* Define to 1 if `st_mtime' is a member of `struct stat'. */ #define HAVE_STRUCT_STAT_ST_MTIME 1 /* define if you have struct timespec */ #define HAVE_STRUCT_TIMESPEC 1 /* define if you have struct timeval */ #define HAVE_STRUCT_TIMEVAL 1 /* Define to 1 if you have the `swap32' function. */ /* #undef HAVE_SWAP32 */ /* Define to 1 if you have the `sysconf' function. */ #define HAVE_SYSCONF 1 /* Define if you have syslen in utmpx.h */ /* #undef HAVE_SYSLEN_IN_UTMPX */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_AUDIT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_BITYPES_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_BSDTTY_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_BYTEORDER_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_CAPSICUM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_CDEFS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_DIR_H 1 /* Define if your system defines sys_errlist[] */ #define HAVE_SYS_ERRLIST 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_FILE_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_LABEL_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_MMAN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_MOUNT_H 1 /* Define to 1 if you have the 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 header file. */ #define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_POLL_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_PRCTL_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_PROCCTL_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_PSTAT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_PTMS_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_PTRACE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_RANDOM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SELECT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STATVFS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_STREAM_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_STROPTS_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_STRTIO_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_SYSCTL_H 1 /* Force use of sys/syslog.h on Ultrix */ /* #undef HAVE_SYS_SYSLOG_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_SYSMACROS_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIMERS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_UN_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_VFS_H */ /* Define to 1 if you have the `tcgetpgrp' function. */ #define HAVE_TCGETPGRP 1 /* Define to 1 if you have the `tcsendbreak' function. */ #define HAVE_TCSENDBREAK 1 /* Define to 1 if you have the `time' function. */ #define HAVE_TIME 1 /* Define to 1 if you have the header file. */ #define HAVE_TIME_H 1 /* 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. */ #define HAVE_TIMINGSAFE_BCMP 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_TMPDIR_H */ /* Define to 1 if you have the `truncate' function. */ #define HAVE_TRUNCATE 1 /* Define to 1 if you have the header file. */ #define HAVE_TTYENT_H 1 /* Define if you have ut_tv in utmp.h */ /* #undef HAVE_TV_IN_UTMP */ /* Define if you have ut_tv in utmpx.h */ #define HAVE_TV_IN_UTMPX 1 /* Define if you have ut_type in utmp.h */ /* #undef HAVE_TYPE_IN_UTMP */ /* Define if you have ut_type in utmpx.h */ #define HAVE_TYPE_IN_UTMPX 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_UCRED_H */ /* Define to 1 if the system has the type `uintmax_t'. */ #define HAVE_UINTMAX_T 1 /* define if you have uintxx_t data type */ #define HAVE_UINTXX_T 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the `unsetenv' function. */ #define HAVE_UNSETENV 1 /* Define to 1 if the system has the type `unsigned long long'. */ #define HAVE_UNSIGNED_LONG_LONG 1 /* 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 header file. */ /* #undef HAVE_USERSEC_H */ /* Define to 1 if you have the `user_from_uid' function. */ #define HAVE_USER_FROM_UID 1 /* Define to 1 if you have the `usleep' function. */ #define HAVE_USLEEP 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_UTIL_H */ /* Define to 1 if you have the `utimensat' function. */ #define HAVE_UTIMENSAT 1 /* Define to 1 if you have the `utimes' function. */ #define HAVE_UTIMES 1 /* Define to 1 if you have the header file. */ #define HAVE_UTIME_H 1 /* 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 header file. */ #define HAVE_UTMPX_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_UTMP_H */ /* define if you have u_char data type */ #define HAVE_U_CHAR 1 /* define if you have u_int data type */ #define HAVE_U_INT 1 /* define if you have u_int64_t data type */ #define HAVE_U_INT64_T 1 /* define if you have u_intxx_t data type */ #define HAVE_U_INTXX_T 1 /* Define to 1 if you have the `vasprintf' function. */ #define HAVE_VASPRINTF 1 /* Define if va_copy exists */ #define HAVE_VA_COPY 1 /* Define to 1 if you have the header file. */ #define HAVE_VIS_H 1 /* Define to 1 if you have the `vsnprintf' function. */ #define HAVE_VSNPRINTF 1 /* Define to 1 if you have the `waitpid' function. */ #define HAVE_WAITPID 1 /* Define to 1 if you have the `warn' function. */ #define HAVE_WARN 1 /* Define to 1 if you have the header file. */ #define HAVE_WCHAR_H 1 /* Define to 1 if you have the `wcwidth' function. */ #define HAVE_WCWIDTH 1 /* Define to 1 if you have the `_getlong' function. */ #define HAVE__GETLONG 1 /* Define to 1 if you have the `_getpty' function. */ /* #undef HAVE__GETPTY */ /* Define to 1 if you have the `_getshort' function. */ #define HAVE__GETSHORT 1 /* Define if you have struct __res_state _res as an extern */ #define HAVE__RES_EXTERN 1 /* Define to 1 if you have the `__b64_ntop' function. */ #define HAVE___B64_NTOP 1 /* Define to 1 if you have the `__b64_pton' function. */ #define HAVE___B64_PTON 1 /* Define if compiler implements __FUNCTION__ */ #define HAVE___FUNCTION__ 1 /* Define if libc defines __progname */ #define HAVE___PROGNAME 1 /* Fields in struct sockaddr_storage */ /* #undef HAVE___SS_FAMILY_IN_SS */ /* Define if __va_copy exists */ #define HAVE___VA_COPY 1 /* Define if compiler implements __func__ */ #define HAVE___func__ 1 /* 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 if you want TCP Wrappers support */ /* #undef LIBWRAP */ /* 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) */ #define LOCKED_PASSWD_PREFIX "*LOCKED*" /* 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 */ #define OPENSSL_HAS_ECC 1 /* libcrypto has NID_X9_62_prime256v1 */ #define OPENSSL_HAS_NISTP256 1 /* libcrypto has NID_secp384r1 */ #define OPENSSL_HAS_NISTP384 1 /* libcrypto has NID_secp521r1 */ #define OPENSSL_HAS_NISTP521 1 /* libcrypto has EVP AES CTR */ #define OPENSSL_HAVE_EVPCTR 1 /* libcrypto has EVP AES GCM */ #define OPENSSL_HAVE_EVPGCM 1 /* libcrypto is missing AES 192 and 256 bit functions */ /* #undef OPENSSL_LOBOTOMISED_AES */ /* Define if you want the OpenSSL internally seeded PRNG only */ #define OPENSSL_PRNG_ONLY 1 /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "openssh-unix-dev@mindrot.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "OpenSSH" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "OpenSSH Portable" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "openssh" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "Portable" /* 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 */ #define SANDBOX_CAPSICUM 1 /* 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 */ #define SANDBOX_SKIP_RLIMIT_NOFILE 1 /* 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. */ #define SIZEOF_INT 4 /* The size of `long int', as computed by sizeof. */ #define SIZEOF_LONG_INT 8 /* The size of `long long int', as computed by sizeof. */ #define SIZEOF_LONG_LONG_INT 8 /* The size of `short int', as computed by sizeof. */ #define SIZEOF_SHORT_INT 2 /* The size of `time_t', as computed by sizeof. */ #define SIZEOF_TIME_T 8 /* Define as const if snprintf() can declare const char *fmt */ #define SNPRINTF_CONST 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 */ #define SSH_PRIVSEP_USER "sshd" /* Use tunnel device compatibility to OpenBSD */ /* #undef SSH_TUN_COMPAT_AF */ /* Open tunnel devices the FreeBSD way */ #define SSH_TUN_FREEBSD 1 /* 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 STDC_HEADERS 1 /* 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 */ #define USE_LIBEDIT 1 /* Use Linux audit module */ /* #undef USE_LINUX_AUDIT */ /* Enable OpenSSL engine support */ #define USE_OPENSSL_ENGINE 1 /* Define if you want to enable PAM support */ #define USE_PAM 1 /* 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 */ #define VARIABLE_DECLARATION_AFTER_CODE 1 /* compiler supports variable length arrays */ #define VARIABLE_LENGTH_ARRAYS 1 /* 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 */ #define WITH_OPENSSL 1 /* Define if you want SELinux support. */ /* #undef WITH_SELINUX */ /* Enable zlib */ #define WITH_ZLIB 1 /* 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 */ #define XAUTH_PATH "/usr/local/bin/xauth" /* 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 */ #define _PATH_PASSWD_PROG "/usr/bin/passwd" /* Specify location of ssh.pid */ #define _PATH_SSH_PIDDIR "/var/run" /* 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/crypto/openssh/configure.ac b/crypto/openssh/configure.ac index 5a66d99b80b1..d98ea1afce8d 100644 --- a/crypto/openssh/configure.ac +++ b/crypto/openssh/configure.ac @@ -1,5707 +1,5716 @@ # # 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]) 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_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 ]) AC_CHECK_DECL([LONG_LONG_MAX], [have_long_long_max=1], , [#include ]) AC_CHECK_DECL([SYSTR_POLICY_KILL], [have_systr_policy_kill=1], , [ #include #include #include ]) AC_CHECK_DECL([RLIMIT_NPROC], [AC_DEFINE([HAVE_RLIMIT_NPROC], [], [sys/resource.h has RLIMIT_NPROC])], , [ #include #include ]) AC_CHECK_DECL([PR_SET_NO_NEW_PRIVS], [have_linux_no_new_privs=1], , [ #include #include ]) 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 ]], [[ 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 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 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 ] ) fi fi AC_MSG_CHECKING([if compiler allows __attribute__ on return types]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[ #include __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 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 ]], [[ 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 ]], [[ 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 #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_LABEL_H # include #endif ]) # sys/capsicum.h requires sys/types.h AC_CHECK_HEADERS([sys/capsicum.h], [], [], [ #ifdef HAVE_SYS_TYPES_H # include #endif ]) # 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 #endif #include #include ]) # lastlog.h requires sys/time.h to be included first on Solaris AC_CHECK_HEADERS([lastlog.h], [], [], [ #ifdef HAVE_SYS_TIME_H # include #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 #endif ]) # login_cap.h requires sys/types.h on NetBSD AC_CHECK_HEADERS([login_cap.h], [], [], [ #include ]) # older BSDs need sys/param.h before sys/mount.h AC_CHECK_HEADERS([sys/mount.h], [], [], [ #include ]) # Android requires sys/socket.h to be included before sys/un.h AC_CHECK_HEADERS([sys/un.h], [], [], [ #include #include ]) # 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 ]) 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 ]], [[ (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 ] ) AC_CHECK_FUNCS([getgrset setauthdb]) AC_CHECK_DECL([F_CLOSEM], AC_DEFINE([HAVE_FCNTL_CLOSEM], [1], [Use F_CLOSEM fcntl for closefrom]), [], [ #include #include ] ) 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 #include 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 ] 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" 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 #endif ]) AC_CHECK_HEADERS([linux/seccomp.h linux/filter.h linux/audit.h], [], [], [#include ]) # 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 ;; 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 < ]], [[ 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 #include #include 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 ] ) 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]) AC_CHECK_HEADER([zlib.h], ,[AC_MSG_ERROR([*** zlib.h missing - please install first or check config.log ***])]) 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 #include #include ]], [[ 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]) ] ) 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 ]], [[ 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 #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_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 ]], [[ #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 ]) AC_CHECK_DECL([VIS_ALL], , AC_DEFINE(BROKEN_STRNVIS, 1, [missing VIS_ALL]), [#include ]) AC_MSG_CHECKING([whether struct dirent allocates space for d_name]) AC_RUN_IFELSE( [AC_LANG_PROGRAM([[ #include #include #include ]], [[ 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 TCP wrappers support TCPW_MSG="no" AC_ARG_WITH([tcp-wrappers], [ --with-tcp-wrappers[[=PATH]] Enable tcpwrappers support (optionally in PATH)], [ if test "x$withval" != "xno" ; then saved_LIBS="$LIBS" saved_LDFLAGS="$LDFLAGS" saved_CPPFLAGS="$CPPFLAGS" if test -n "${withval}" && \ test "x${withval}" != "xyes"; then if test -d "${withval}/lib"; then if test -n "${need_dash_r}"; then LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" else LDFLAGS="-L${withval}/lib ${LDFLAGS}" fi else if test -n "${need_dash_r}"; then LDFLAGS="-L${withval} -R${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 LIBS="-lwrap $LIBS" AC_MSG_CHECKING([for libwrap]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include #include #include int deny_severity = 0, allow_severity = 0; ]], [[ hosts_access(0); ]])], [ AC_MSG_RESULT([yes]) AC_DEFINE([LIBWRAP], [1], [Define if you want TCP Wrappers support]) SSHDLIBS="$SSHDLIBS -lwrap" TCPW_MSG="yes" ], [ AC_MSG_ERROR([*** libwrap missing]) ]) LIBS="$saved_LIBS" 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 #include #ifdef HAVE_STDINT_H # include #endif #include 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 #include ]], [[ 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 #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 ]], [[ 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([ \ auth_hostok \ auth_timeok \ 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 \ ]) 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 #include ]], [[ 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 ]], [[ 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 ] ) test "x$disable_sk" != "x" && enable_sk_internal="" AC_SEARCH_LIBS([dlopen], [dl]) AC_CHECK_FUNCS([dlopen]) AC_CHECK_DECL([RTLD_NOW], [], [], [#include ]) # 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 #include #include 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 ] ) ], [ #include ] ) dnl Make sure prototypes are defined for these before using them. AC_CHECK_DECL([strsep], [AC_CHECK_FUNCS([strsep])], [], [ #ifdef HAVE_STRING_H # include #endif ]) dnl tcsendbreak might be a macro AC_CHECK_DECL([tcsendbreak], [AC_DEFINE([HAVE_TCSENDBREAK])], [AC_CHECK_FUNCS([tcsendbreak])], [#include ] ) AC_CHECK_DECLS([h_errno], , ,[#include ]) AC_CHECK_DECLS([SHUT_RD, getpeereid], , , [ #include #include #include ]) AC_CHECK_DECLS([O_NONBLOCK], , , [ #include #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif ]) +AC_CHECK_DECLS([ftruncate], , , + [ +#include +#include + ]) + AC_CHECK_DECLS([readv, writev], , , [ #include #include #include ]) AC_CHECK_DECLS([MAXSYMLINKS], , , [ #include ]) AC_CHECK_DECLS([offsetof], , , [ #include ]) # extra bits for select(2) AC_CHECK_DECLS([howmany, NFDBITS], [], [], [[ #include #include #ifdef HAVE_SYS_SYSMACROS_H #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_UNISTD_H #include #endif ]]) AC_CHECK_TYPES([fd_mask], [], [], [[ #include #include #ifdef HAVE_SYS_SELECT_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_UNISTD_H #include #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 #include ]], [[ 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 #include ]], [[ 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 #include ]], [[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 #include ]], [[ 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 #include #include #include ]], [[ 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 #include #include 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 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 #include ]], [[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 #include #include #include #include #include ]], [[ 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 #include #include #include #include #include #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 #include #include #include #include #include #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 #include #include ]) 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 #include ]], [[ 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 #include #include #include #include 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 #endif #include #include #include #include #include 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 ] ) if test "x$openssl" = "xyes" ; then LIBS="-lcrypto $LIBS" 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 #include #include #include #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 #include #include #include #include #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. *) 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]) ] ) # Sanity check OpenSSL headers AC_MSG_CHECKING([whether OpenSSL's headers match the library]) AC_RUN_IFELSE( [AC_LANG_PROGRAM([[ #include #include #include #include ]], [[ #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 ]], [[ 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 ]], [[ ERR_load_crypto_strings(); ]])], [ AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([no]) LIBS="$saved_LIBS" ] ) ] ) AC_CHECK_FUNCS([ \ 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 \ ]) # 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 ]] ) ) # 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 ]], [[ 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 #include #include ]], [[ 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 #include #include ]], [[ 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 #include #include ]], [[ 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 #include #include ]], [[ 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 #include #include #include #include #include ]], [[ 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 #include #include #include #include #include ]], [[ 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 #include #include #include #include #include ]], [[ 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 #include #include #include #include #include #include ]],[[ 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]) 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="-lprivatefido2 -lprivatecbor" fi OTHERLIBS=`echo $LIBFIDO2 | sed 's/-lfido2//'` AC_CHECK_LIB([privatefido2], [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 libprivatefido2 found]) ], [ $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])) AC_CHECK_HEADER([fido/credman.h], [], AC_MSG_ERROR([missing fido/credman.h from libfido2]), [#include ] ) 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 #include #include ]], [[ 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 # 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 #if defined(HAVE_SECURITY_PAM_APPL_H) #include #elif defined (HAVE_PAM_PAM_APPL_H) #include #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 #include ]) fi if test "x$have_seccomp_filter" = "x1" ; then AC_MSG_CHECKING([kernel for seccomp_filter support]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include #include #include #include #include ]], [[ 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 # 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 ] ) # 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( [AC_LANG_PROGRAM([[ #include #ifdef HAVE_SYS_TIME_H # include #endif #include #ifdef HAVE_SYS_SELECT_H # include #endif #ifdef HAVE_POLL_H # include #elif HAVE_SYS_POLL_H # include #endif #include #include #include ]],[[ 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 yes]) - select_works_with_rlimit=yes] + [AC_MSG_WARN([cross compiling: assuming no]) + select_works_with_rlimit=no] ) AC_CHECK_MEMBERS([struct pollfd.fd], [], [], [[ #include #ifdef HAVE_POLL_H #include #endif #ifdef HAVE_SYS_POLL_H #include #endif ]]) AC_CHECK_TYPES([nfds_t], , , [ #include #ifdef HAVE_POLL_H #include #endif #ifdef HAVE_SYS_POLL_H #include #endif ]) AC_MSG_CHECKING([if setrlimit(RLIMIT_NOFILE,{0,0}) works]) AC_RUN_IFELSE( [AC_LANG_PROGRAM([[ #include #ifdef HAVE_SYS_TIME_H # include #endif #include #include #include ]],[[ 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_LANG_PROGRAM([[ #include #include #include ]],[[ 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])] ) 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 #ifdef HAVE_SYS_TIME_H # include #endif #ifdef HAVE_TIME_H # include #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 #include /* Why is this so damn hard? */ #ifdef __GNUC__ # undef __GNUC__ #endif #define __USE_ISOC99 #include #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 #endif #ifdef HAVE_LIMITS_H # include #endif #ifdef HAVE_STDINT_H # include #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 ]], [[ 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 ]], [[ 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 ]], [[ 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 #ifdef HAVE_STDINT_H # include #endif #include #ifdef HAVE_SYS_BITYPES_H # include #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 ]], [[ 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 ]], [[ 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 ]], [[ 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 ]], [[ 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 ]], [[ 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 ]], [[ 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 ]], [[ 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 ]], [[ 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 ]], [[ 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 #ifdef HAVE_STDINT_H # include #endif ]) TYPE_SOCKLEN_T AC_CHECK_TYPES([sig_atomic_t, sighandler_t], , , [#include ]) AC_CHECK_TYPES([fsblkcnt_t, fsfilcnt_t], , , [ #include #ifdef HAVE_SYS_BITYPES_H #include #endif #ifdef HAVE_SYS_STATFS_H #include #endif #ifdef HAVE_SYS_STATVFS_H #include #endif ]) AC_CHECK_MEMBERS([struct statfs.f_files, struct statfs.f_flags], [], [], [[ #include #include #ifdef HAVE_SYS_BITYPES_H #include #endif #ifdef HAVE_SYS_STATFS_H #include #endif #ifdef HAVE_SYS_STATVFS_H #include #endif #ifdef HAVE_SYS_VFS_H #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif ]]) AC_CHECK_TYPES([in_addr_t, in_port_t], , , [#include #include ]) AC_CACHE_CHECK([for size_t], ac_cv_have_size_t, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], [[ 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 ]], [[ 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 ]], [[ 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 #include ]], [[ sa_family_t foo; foo = 1235; ]])], [ ac_cv_have_sa_family_t="yes" ], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include #include #include ]], [[ 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 ]], [[ 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 ]], [[ 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 #include ]], [[ 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 #include ]], [[ 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 #include ]], [[ 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 #endif #include ]) fi AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include #include #include ]], [[ 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 ]], [[ 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 #endif #ifdef HAVE_TIME_H # include #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 #include #include #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 #include ]]) 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 #if HAVE_SYS_TYPES_H # include #endif #include #include #include ]]) 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 #include ]], [[ 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 #include ]], [[ 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 #include #include #include ]], [[ #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 #include #ifdef HAVE_SYS_TIME_H # include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #ifdef HAVE_SYS_STATVFS_H #include #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 #include ]], [[ 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 #include ]], [[ 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 #include #include #include ]], [[ #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 ]], [[ 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 ]], [[ 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 ]], [[ 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 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 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 ]], [[ 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 ]], [[ 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 ]], [[ 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 #include #include #include #include ]], [[ 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 #include #include #include #include ]], [[ 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 #include ]) AC_CHECK_MEMBER([HEADER.ad], [AC_DEFINE([HAVE_HEADER_AD], [1], [Define if HEADER.ad exists in arpa/nameser.h])], , [#include ]) ]) AC_MSG_CHECKING([if struct __res_state _res is an extern]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #if HAVE_SYS_TYPES_H # include #endif #include #include #include 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 ]], [[ 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 ]], [[ 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 ]], [[ 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 #elif defined(HAVE_GSSAPI_GSSAPI_H) # include #endif #ifdef HAVE_GSSAPI_GENERIC_H # include #elif defined(HAVE_GSSAPI_GSSAPI_GENERIC_H) # include #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]) # 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 #include #include #ifdef HAVE_PATHS_H #include #endif #ifdef HAVE_MAILLOCK_H #include #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 #include 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 #include #ifdef HAVE_PATHS_H # include #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 #include #include #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 #include #ifdef HAVE_LASTLOG_H # include #endif #ifdef HAVE_PATHS_H # include #endif #ifdef HAVE_LOGIN_H # include #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 #include #ifdef HAVE_LASTLOG_H # include #endif #ifdef HAVE_PATHS_H # include #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 #include #ifdef HAVE_PATHS_H # include #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 #include #ifdef HAVE_PATHS_H # include #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 #include #ifdef HAVE_UTMPX_H #include #endif #ifdef HAVE_PATHS_H # include #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 #endif #ifdef HAVE_UTMP_H #include #endif #ifdef HAVE_UTMPX_H #include #endif #ifdef HAVE_LASTLOG_H #include #endif ]) AC_CHECK_MEMBER([struct utmp.ut_line], [], [ AC_DEFINE([DISABLE_UTMP]) AC_DEFINE([DISABLE_WTMP]) ], [ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_UTMP_H #include #endif #ifdef HAVE_UTMPX_H #include #endif #ifdef HAVE_LASTLOG_H #include #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 " TCP Wrappers support: $TCPW_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 "${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/crypto/openssh/contrib/redhat/openssh.spec b/crypto/openssh/contrib/redhat/openssh.spec index 95ab2199b269..b8ba8bae0469 100644 --- a/crypto/openssh/contrib/redhat/openssh.spec +++ b/crypto/openssh/contrib/redhat/openssh.spec @@ -1,850 +1,850 @@ -%global ver 8.9p1 +%global ver 9.0p1 %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 - Remove remaining traces of --with-md5-passwords * Mon Jul 20 2020 Damien Miller - Add ssh-sk-helper and corresponding manual page. * Sat Feb 10 2018 Darren Tucker - 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 - 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 - test for skip_x11_askpass (line 77) should have been for no_x11_askpass * Mon Jun 2 2003 Damien Miller - Remove noip6 option. This may be controlled at run-time in client config file using new AddressFamily directive * Mon May 12 2003 Damien Miller - Don't install profile.d scripts when not building with GNOME/GTK askpass (patch from bet@rahul.net) * Tue Oct 01 2002 Damien Miller - Install ssh-agent setgid nobody to prevent ptrace() key theft attacks * Mon Sep 30 2002 Damien Miller - Use contrib/ Makefile for building askpass programs * Fri Jun 21 2002 Damien Miller - 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 - Merge in spec changes from RedHat, reorgansie a little - Add Privsep user, group and directory * Thu Mar 7 2002 Nalin Dahyabhai 3.1p1-2 - bump and grind (through the build system) * Thu Mar 7 2002 Nalin Dahyabhai 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 3.1p1-0 - update to 3.1p1 * Tue Mar 5 2002 Nalin Dahyabhai SNAP-20020305 - update to SNAP-20020305 - drop debug patch, fixed upstream * Wed Feb 20 2002 Nalin Dahyabhai 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 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 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 - adjust build dependencies so that build6x actually works right (fix from Hugo van der Kooij) * Tue Dec 4 2001 Nalin Dahyabhai 3.0.2p1-1 - update to 3.0.2p1 * Fri Nov 16 2001 Nalin Dahyabhai 3.0.1p1-1 - update to 3.0.1p1 * Tue Nov 13 2001 Nalin Dahyabhai - update to current CVS (not for use in distribution) * Thu Nov 8 2001 Nalin Dahyabhai 3.0p1-1 - merge some of Damien Miller changes from the upstream 3.0p1 spec file and init script * Wed Nov 7 2001 Nalin Dahyabhai - 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 2.9p2-9 - incorporate fix from Markus Friedl's advisory for IP-based authorization bugs * Thu Sep 13 2001 Bernhard Rosenkraenzer 2.9p2-8 - Merge changes to rescue build from current sysadmin survival cd * Thu Sep 6 2001 Nalin Dahyabhai 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 2.9p2-6 - add db1-devel as a BuildPrerequisite (noted by Hans Ecke) * Thu Aug 16 2001 Nalin Dahyabhai - pull cvs patch to fix remote port forwarding with protocol 2 * Thu Aug 9 2001 Nalin Dahyabhai - 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 - don't apply patches to code we don't intend to build (spotted by Matt Galgoci) * Mon Aug 6 2001 Nalin Dahyabhai - pass OPTIONS correctly to initlog (#50151) * Wed Jul 25 2001 Nalin Dahyabhai - switch to x11-ssh-askpass 1.2.2 * Wed Jul 11 2001 Nalin Dahyabhai - rebuild in new environment * Mon Jun 25 2001 Nalin Dahyabhai - disable the gssapi patch * Mon Jun 18 2001 Nalin Dahyabhai - update to 2.9p2 - refresh to a new version of the gssapi patch * Thu Jun 7 2001 Nalin Dahyabhai - 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 - 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 - 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 - 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 - update to 2.9 - drop various patches that came from or went upstream or to or from CVS * Wed Apr 18 2001 Nalin Dahyabhai - only require initscripts 5.00 on 6.2 (reported by Peter Bieringer) * Sun Apr 8 2001 Preston Brown - 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 - 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 - 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 - update to 2.5.2p2 - call setcred() again after initgroups, because the "creds" could actually be group memberships * Tue Mar 20 2001 Nalin Dahyabhai - 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 - remove dependency on openssl -- would need to be too precise * Fri Mar 2 2001 Nalin Dahyabhai - rebuild in new environment * Mon Feb 26 2001 Nalin Dahyabhai - 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 - 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 - 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 - 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 - 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 - 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 - i18n-tweak to initscript. * Tue Jan 23 2001 Nalin Dahyabhai - 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 - Finish with the gettextizing. * Thu Jan 18 2001 Nalin Dahyabhai - Fix a bug in auth2-pam.c (#23877) - Gettextize the init script. * Wed Dec 20 2000 Nalin Dahyabhai - Incorporate a switch for using PAM configs for 6.x, just in case. * Tue Dec 5 2000 Nalin Dahyabhai - Incorporate Bero's changes for a build specifically for rescue CDs. * Wed Nov 29 2000 Nalin Dahyabhai - 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 - 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 - Merge multiple PAM text messages into subsequent prompts when possible when doing keyboard-interactive authentication. * Sun Nov 26 2000 Nalin Dahyabhai - 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 - Use DESTDIR instead of %%makeinstall. - Remove /usr/X11R6/bin from the path-fixing patch. * Mon Nov 20 2000 Nalin Dahyabhai - 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 - 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 - Update to OpenSSH 2.3.0p1. - Update to x11-askpass 1.1.0. - Enable keyboard-interactive authentication. * Mon Oct 30 2000 Nalin Dahyabhai - Update to ssh-askpass-x11 1.0.3. - Change authentication related messages to be private (#19966). * Tue Oct 10 2000 Nalin Dahyabhai - Patch ssh-keygen to be able to list signatures for DSA public key files it generates. * Thu Oct 5 2000 Nalin Dahyabhai - 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 - 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 - Update to 2.2.0p1. (#17835) - Tweak the init script to allow proper restarting. (#18023) * Wed Aug 23 2000 Nalin Dahyabhai - Update to 20000823 snapshot. - Change subpackage requirements from %%{version} to %%{version}-%%{release} - Back out the pipe patch. * Mon Jul 17 2000 Nalin Dahyabhai - 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 - Update to 2.1.1p3, which includes fixes for X11 forwarding and strtok(). * Thu Jul 6 2000 Nalin Dahyabhai - 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 - Fix X11 forwarding, from mail post by Chan Shih-Ping Richard. * Sun Jul 2 2000 Nalin Dahyabhai - Update to 2.1.1p2. - Use of strtok() considered harmful. * Sat Jul 1 2000 Nalin Dahyabhai - Get the build root out of the man pages. * Thu Jun 29 2000 Nalin Dahyabhai - Add and use condrestart support in the init script. - Add newer initscripts as a prereq. * Tue Jun 27 2000 Nalin Dahyabhai - Build in new environment (release 2) - Move -clients subpackage to Applications/Internet group * Fri Jun 9 2000 Nalin Dahyabhai - Update to 2.2.1p1 * Sat Jun 3 2000 Nalin Dahyabhai - Patch to build with neither RSA nor RSAref. - Miscellaneous FHS-compliance tweaks. - Fix for possibly-compressed man pages. * Wed Mar 15 2000 Damien Miller - Updated for new location - Updated for new gnome-ssh-askpass build * Sun Dec 26 1999 Damien Miller - Added Jim Knoble's askpass * Mon Nov 15 1999 Damien Miller - Split subpackages further based on patch from jim knoble * Sat Nov 13 1999 Damien Miller - Added 'Obsoletes' directives * Tue Nov 09 1999 Damien Miller - Use make install - Subpackages * Mon Nov 08 1999 Damien Miller - Added links for slogin - Fixed perms on manpages * Sat Oct 30 1999 Damien Miller - Renamed init script * Fri Oct 29 1999 Damien Miller - Back to old binary names * Thu Oct 28 1999 Damien Miller - Use autoconf - New binary names * Wed Oct 27 1999 Damien Miller - Initial RPMification, based on Jan "Yenya" Kasprzak's spec. diff --git a/crypto/openssh/contrib/suse/openssh.spec b/crypto/openssh/contrib/suse/openssh.spec index 8df0ae3b0b44..28b9086f4cab 100644 --- a/crypto/openssh/contrib/suse/openssh.spec +++ b/crypto/openssh/contrib/suse/openssh.spec @@ -1,245 +1,245 @@ # Default values for additional components %define build_x11_askpass 1 # Define the UID/GID to use for privilege separation %define sshd_gid 65 %define sshd_uid 71 # The version of x11-ssh-askpass to use %define xversion 1.2.4.1 # Allow the ability to override defaults with -D skip_xxx=1 %{?skip_x11_askpass:%define build_x11_askpass 0} Summary: OpenSSH, a free Secure Shell (SSH) protocol implementation Name: openssh -Version: 8.9p1 +Version: 9.0p1 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 - Add ssh-sk-helper and corresponding manual page. * Wed Oct 26 2005 Iain Morgan - Removed accidental inclusion of --without-zlib-version-check * Tue Oct 25 2005 Iain Morgan - Overhaul to deal with newer versions of SuSE and OpenSSH * Mon Jun 12 2000 Damien Miller - Glob manpages to catch compressed files * Wed Mar 15 2000 Damien Miller - Updated for new location - Updated for new gnome-ssh-askpass build * Sun Dec 26 1999 Chris Saia - Made symlink to gnome-ssh-askpass called ssh-askpass * Wed Nov 24 1999 Chris Saia - 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 - 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 - 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 - Split subpackages further based on patch from jim knoble * Sat Nov 13 1999 Damien Miller - Added 'Obsoletes' directives * Tue Nov 09 1999 Damien Miller - Use make install - Subpackages * Mon Nov 08 1999 Damien Miller - Added links for slogin - Fixed perms on manpages * Sat Oct 30 1999 Damien Miller - Renamed init script * Fri Oct 29 1999 Damien Miller - Back to old binary names * Thu Oct 28 1999 Damien Miller - Use autoconf - New binary names * Wed Oct 27 1999 Damien Miller - Initial RPMification, based on Jan "Yenya" Kasprzak's 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/crypto/openssh/m4/openssh.m4 b/crypto/openssh/m4/openssh.m4 index 4f9c3792dc17..8c33c701b8b4 100644 --- a/crypto/openssh/m4/openssh.m4 +++ b/crypto/openssh/m4/openssh.m4 @@ -1,200 +1,203 @@ dnl OpenSSH-specific autoconf macros dnl dnl OSSH_CHECK_CFLAG_COMPILE(check_flag[, define_flag]) dnl Check that $CC accepts a flag 'check_flag'. If it is supported append dnl 'define_flag' to $CFLAGS. If 'define_flag' is not specified, then append dnl 'check_flag'. AC_DEFUN([OSSH_CHECK_CFLAG_COMPILE], [{ AC_MSG_CHECKING([if $CC supports compile flag $1]) saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $WERROR $1" _define_flag="$2" test "x$_define_flag" = "x" && _define_flag="$1" AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ #include #include +/* 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); } ]])], [ if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null then AC_MSG_RESULT([no]) CFLAGS="$saved_CFLAGS" else AC_MSG_RESULT([yes]) CFLAGS="$saved_CFLAGS $_define_flag" fi], [ AC_MSG_RESULT([no]) CFLAGS="$saved_CFLAGS" ] ) }]) dnl OSSH_CHECK_CFLAG_LINK(check_flag[, define_flag]) dnl Check that $CC accepts a flag 'check_flag'. If it is supported append dnl 'define_flag' to $CFLAGS. If 'define_flag' is not specified, then append dnl 'check_flag'. AC_DEFUN([OSSH_CHECK_CFLAG_LINK], [{ AC_MSG_CHECKING([if $CC supports compile flag $1 and linking succeeds]) saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $WERROR $1" _define_flag="$2" test "x$_define_flag" = "x" && _define_flag="$1" AC_LINK_IFELSE([AC_LANG_SOURCE([[ #include #include 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); } ]])], [ if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null then AC_MSG_RESULT([no]) CFLAGS="$saved_CFLAGS" else AC_MSG_RESULT([yes]) CFLAGS="$saved_CFLAGS $_define_flag" fi], [ AC_MSG_RESULT([no]) CFLAGS="$saved_CFLAGS" ] ) }]) dnl OSSH_CHECK_LDFLAG_LINK(check_flag[, define_flag]) dnl Check that $LD accepts a flag 'check_flag'. If it is supported append dnl 'define_flag' to $LDFLAGS. If 'define_flag' is not specified, then append dnl 'check_flag'. AC_DEFUN([OSSH_CHECK_LDFLAG_LINK], [{ AC_MSG_CHECKING([if $LD supports link flag $1]) saved_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $WERROR $1" _define_flag="$2" test "x$_define_flag" = "x" && _define_flag="$1" AC_LINK_IFELSE([AC_LANG_SOURCE([[ #include #include 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); } ]])], [ if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null then AC_MSG_RESULT([no]) LDFLAGS="$saved_LDFLAGS" else AC_MSG_RESULT([yes]) LDFLAGS="$saved_LDFLAGS $_define_flag" fi ], [ AC_MSG_RESULT([no]) LDFLAGS="$saved_LDFLAGS" ] ) }]) dnl OSSH_CHECK_HEADER_FOR_FIELD(field, header, symbol) dnl Does AC_EGREP_HEADER on 'header' for the string 'field' dnl If found, set 'symbol' to be defined. Cache the result. dnl TODO: This is not foolproof, better to compile and read from there AC_DEFUN([OSSH_CHECK_HEADER_FOR_FIELD], [ # look for field '$1' in header '$2' dnl This strips characters illegal to m4 from the header filename ossh_safe=`echo "$2" | sed 'y%./+-%__p_%'` dnl ossh_varname="ossh_cv_$ossh_safe""_has_"$1 AC_MSG_CHECKING(for $1 field in $2) AC_CACHE_VAL($ossh_varname, [ AC_EGREP_HEADER($1, $2, [ dnl eval "$ossh_varname=yes" dnl ], [ dnl eval "$ossh_varname=no" dnl ]) dnl ]) ossh_result=`eval 'echo $'"$ossh_varname"` if test -n "`echo $ossh_varname`"; then AC_MSG_RESULT($ossh_result) if test "x$ossh_result" = "xyes"; then AC_DEFINE($3, 1, [Define if you have $1 in $2]) fi else AC_MSG_RESULT(no) fi ]) dnl Check for socklen_t: historically on BSD it is an int, and in dnl POSIX 1g it is a type of its own, but some platforms use different dnl types for the argument to getsockopt, getpeername, etc. So we dnl have to test to find something that will work. AC_DEFUN([TYPE_SOCKLEN_T], [ AC_CHECK_TYPE([socklen_t], ,[ AC_MSG_CHECKING([for socklen_t equivalent]) AC_CACHE_VAL([curl_cv_socklen_t_equiv], [ # 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 AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ #include #include int getpeername (int, $arg2 *, $t *); ]], [[ $t len; getpeername(0,0,&len); ]]) ],[ curl_cv_socklen_t_equiv="$t" break ]) done done if test "x$curl_cv_socklen_t_equiv" = x; then AC_MSG_ERROR([Cannot find a type to use in place of socklen_t]) fi ]) AC_MSG_RESULT($curl_cv_socklen_t_equiv) AC_DEFINE_UNQUOTED(socklen_t, $curl_cv_socklen_t_equiv, [type to use in place of socklen_t if not defined])], [#include #include ]) ]) diff --git a/crypto/openssh/misc.c b/crypto/openssh/misc.c index 417498deb7a2..85d22369505d 100644 --- a/crypto/openssh/misc.c +++ b/crypto/openssh/misc.c @@ -1,2786 +1,2795 @@ -/* $OpenBSD: misc.c,v 1.174 2022/02/11 00:43:56 dtucker Exp $ */ +/* $OpenBSD: misc.c,v 1.175 2022/03/20 08:51:21 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005-2020 Damien Miller. All rights reserved. * Copyright (c) 2004 Henning Brauer * * 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 #include #include #include #include #include #include #include #ifdef HAVE_LIBGEN_H # include #endif #ifdef HAVE_POLL_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_PATHS_H # include #include #include #endif #ifdef SSH_TUN_OPENBSD #include #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: * 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("addargs: argument too long"); + fatal_f("argument too long"); nalloc = args->nalloc; if (args->list == NULL) { nalloc = 32; args->num = 0; - } else if (args->num+2 >= nalloc) + } 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->list = xrecallocarray(args->list, args->nalloc, + nalloc, sizeof(char *)); args->nalloc = nalloc; args->list[args->num++] = cp; args->list[args->num] = NULL; } void replacearg(arglist *args, u_int which, char *fmt, ...) { va_list ap; char *cp; int r; va_start(ap, fmt); r = vasprintf(&cp, fmt, ap); va_end(ap); if (r == -1) - fatal("replacearg: argument too long"); + fatal_f("argument too long"); + if (args->list == NULL || args->num >= args->nalloc) + fatal_f("arglist corrupt"); if (which >= args->num) - fatal("replacearg: tried to replace invalid arg %d >= %d", + 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->list != NULL) { + 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; } + 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; *tp = 0; /* * POSIX strptime says "The application shall ensure that there * is white-space or other non-alphanumeric characters between * any two conversion specifications" so arrange things this way. */ switch (strlen(s)) { case 8: /* YYYYMMDD */ fmt = "%Y-%m-%d"; snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6); break; case 12: /* YYYYMMDDHHMM */ fmt = "%Y-%m-%dT%H:%M"; snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s", s, s + 4, s + 6, s + 8, s + 10); break; case 14: /* YYYYMMDDHHMMSS */ fmt = "%Y-%m-%dT%H:%M:%S"; snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s", s, s + 4, s + 6, s + 8, s + 10, s + 12); break; default: return SSH_ERR_INVALID_FORMAT; } memset(&tm, 0, sizeof(tm)); if (strptime(buf, fmt, &tm) == NULL) return SSH_ERR_INVALID_FORMAT; if ((tt = mktime(&tm)) < 0) return SSH_ERR_INVALID_FORMAT; /* success */ *tp = (uint64_t)tt; return 0; } /* 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; } diff --git a/crypto/openssh/monitor.c b/crypto/openssh/monitor.c index c199cb9bc089..20b9f67b9349 100644 --- a/crypto/openssh/monitor.c +++ b/crypto/openssh/monitor.c @@ -1,1958 +1,1955 @@ -/* $OpenBSD: monitor.c,v 1.231 2022/01/28 06:18:42 guenther Exp $ */ +/* $OpenBSD: monitor.c,v 1.232 2022/02/25 02:09:27 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 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 #include #include #include #include #include #ifdef HAVE_PATHS_H #include #endif #include #include #ifdef HAVE_STDINT_H # include #endif #include #include #include #include #include #ifdef HAVE_POLL_H #include #else # ifdef HAVE_SYS_POLL_H # include # endif #endif #ifdef WITH_OPENSSL #include #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) { - char *username; struct passwd *pwent; int r, allowed = 0; u_int i; debug3_f("entering"); if (authctxt->attempt++ != 0) fatal_f("multiple attempts for getpwnam"); - if ((r = sshbuf_get_cstring(m, &username, NULL)) != 0) + if ((r = sshbuf_get_cstring(m, &authctxt->user, NULL)) != 0) fatal_fr(r, "parse"); - pwent = getpwnamallow(ssh, username); + pwent = getpwnamallow(ssh, authctxt->user); - authctxt->user = xstrdup(username); - setproctitle("%s [priv]", pwent ? username : "unknown"); - free(username); + 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/crypto/openssh/myproposal.h b/crypto/openssh/myproposal.h index f33d4a609cf8..6768d5ff8d09 100644 --- a/crypto/openssh/myproposal.h +++ b/crypto/openssh/myproposal.h @@ -1,118 +1,118 @@ -/* $OpenBSD: myproposal.h,v 1.70 2021/11/10 06:29:25 djm Exp $ */ +/* $OpenBSD: myproposal.h,v 1.71 2022/03/30 21:13:23 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. */ #define KEX_SERVER_KEX \ + "sntrup761x25519-sha512@openssh.com," \ "curve25519-sha256," \ "curve25519-sha256@libssh.org," \ "ecdh-sha2-nistp256," \ "ecdh-sha2-nistp384," \ "ecdh-sha2-nistp521," \ - "sntrup761x25519-sha512@openssh.com," \ "diffie-hellman-group-exchange-sha256," \ "diffie-hellman-group16-sha512," \ "diffie-hellman-group18-sha512," \ "diffie-hellman-group14-sha256" #define KEX_CLIENT_KEX KEX_SERVER_KEX #define KEX_DEFAULT_PK_ALG \ "ssh-ed25519-cert-v01@openssh.com," \ "ecdsa-sha2-nistp256-cert-v01@openssh.com," \ "ecdsa-sha2-nistp384-cert-v01@openssh.com," \ "ecdsa-sha2-nistp521-cert-v01@openssh.com," \ "sk-ssh-ed25519-cert-v01@openssh.com," \ "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com," \ "rsa-sha2-512-cert-v01@openssh.com," \ "rsa-sha2-256-cert-v01@openssh.com," \ "ssh-rsa-cert-v01@openssh.com," \ "ssh-ed25519," \ "ecdsa-sha2-nistp256," \ "ecdsa-sha2-nistp384," \ "ecdsa-sha2-nistp521," \ "sk-ssh-ed25519@openssh.com," \ "sk-ecdsa-sha2-nistp256@openssh.com," \ "rsa-sha2-512," \ "rsa-sha2-256," \ "ssh-rsa" #define KEX_SERVER_ENCRYPT \ "chacha20-poly1305@openssh.com," \ "aes128-ctr,aes192-ctr,aes256-ctr," \ "aes128-gcm@openssh.com,aes256-gcm@openssh.com" #define KEX_CLIENT_ENCRYPT KEX_SERVER_ENCRYPT #define KEX_SERVER_MAC \ "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" #define KEX_CLIENT_MAC KEX_SERVER_MAC /* Not a KEX value, but here so all the algorithm defaults are together */ #define SSH_ALLOWED_CA_SIGALGS \ "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" #define KEX_DEFAULT_COMP "none,zlib@openssh.com" #define KEX_DEFAULT_LANG "" #define KEX_CLIENT \ KEX_CLIENT_KEX, \ KEX_DEFAULT_PK_ALG, \ KEX_CLIENT_ENCRYPT, \ KEX_CLIENT_ENCRYPT, \ KEX_CLIENT_MAC, \ KEX_CLIENT_MAC, \ KEX_DEFAULT_COMP, \ KEX_DEFAULT_COMP, \ KEX_DEFAULT_LANG, \ KEX_DEFAULT_LANG #define KEX_SERVER \ KEX_SERVER_KEX, \ KEX_DEFAULT_PK_ALG, \ KEX_SERVER_ENCRYPT, \ KEX_SERVER_ENCRYPT, \ KEX_SERVER_MAC, \ KEX_SERVER_MAC, \ KEX_DEFAULT_COMP, \ KEX_DEFAULT_COMP, \ KEX_DEFAULT_LANG, \ KEX_DEFAULT_LANG diff --git a/crypto/openssh/openbsd-compat/arc4random.c b/crypto/openssh/openbsd-compat/arc4random.c index 80ff3c1801a1..ce5f054f1e23 100644 --- a/crypto/openssh/openbsd-compat/arc4random.c +++ b/crypto/openssh/openbsd-compat/arc4random.c @@ -1,346 +1,346 @@ /* OPENBSD ORIGINAL: lib/libc/crypto/arc4random.c */ /* $OpenBSD: arc4random.c,v 1.25 2013/10/01 18:34:57 markus Exp $ */ /* * Copyright (c) 1996, David Mazieres * Copyright (c) 2008, Damien Miller * Copyright (c) 2013, 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. */ /* * ChaCha based random number generator for OpenBSD. */ #include "includes.h" #include #include #include #include #include #ifdef HAVE_SYS_RANDOM_H # include #endif #ifndef HAVE_ARC4RANDOM #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) #ifdef WITH_OPENSSL #include #include #endif #include "log.h" #define KEYSTREAM_ONLY #include "chacha_private.h" #ifdef __GNUC__ #define inline __inline #else /* !__GNUC__ */ #define inline #endif /* !__GNUC__ */ /* OpenSSH isn't multithreaded */ #define _ARC4_LOCK() #define _ARC4_UNLOCK() #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 */ 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, 0); + 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)); } 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); } #endif /* WITH_OPENSSL */ static void _rs_stir(void) { u_char rnd[KEYSZ + IVSZ]; #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 (!rs_initialized) { rs_initialized = 1; _rs_init(rnd, sizeof(rnd)); } else _rs_rekey(rnd, sizeof(rnd)); explicit_bzero(rnd, sizeof(rnd)); /* invalidate rs_buf */ rs_have = 0; memset(rs_buf, 0, RSBUFSZ); rs_count = 1600000; } 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_stir(); } else rs_count -= len; } static inline void _rs_rekey(u_char *dat, size_t datlen) { #ifndef KEYSTREAM_ONLY memset(rs_buf, 0,RSBUFSZ); #endif /* fill rs_buf with the keystream */ chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ); /* mix in optional user provided data */ if (dat) { size_t i, m; m = MINIMUM(datlen, KEYSZ + IVSZ); for (i = 0; i < m; i++) 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; } static inline void _rs_random_buf(void *_buf, size_t n) { u_char *buf = (u_char *)_buf; 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); buf += m; n -= m; rs_have -= m; } if (rs_have == 0) _rs_rekey(NULL, 0); } } static inline void _rs_random_u32(u_int32_t *val) { _rs_stir_if_needed(sizeof(*val)); if (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; } 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 arc4random(void) { u_int32_t val; _ARC4_LOCK(); _rs_random_u32(&val); _ARC4_UNLOCK(); return val; } /* * 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(); } # 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 #include 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/crypto/openssh/openbsd-compat/bsd-misc.c b/crypto/openssh/openbsd-compat/bsd-misc.c index 059b6d3b3ec7..3b00ef6d240e 100644 --- a/crypto/openssh/openbsd-compat/bsd-misc.c +++ b/crypto/openssh/openbsd-compat/bsd-misc.c @@ -1,440 +1,448 @@ /* * 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. */ #include "includes.h" #include #ifdef HAVE_SYS_SELECT_H # include #endif #ifdef HAVE_SYS_TIME_H # include #endif #include #include #include #include #include #include #include #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(char *filename, struct timeval *tvp) +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 diff --git a/crypto/openssh/openbsd-compat/bsd-misc.h b/crypto/openssh/openbsd-compat/bsd-misc.h index 2206e1a82140..61ead1b7fad0 100644 --- a/crypto/openssh/openbsd-compat/bsd-misc.h +++ b/crypto/openssh/openbsd-compat/bsd-misc.h @@ -1,197 +1,197 @@ /* * 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. */ #ifndef _BSD_MISC_H #define _BSD_MISC_H #include "includes.h" char *ssh_get_progname(char *); int seed_from_prngd(unsigned char *, size_t); #ifndef HAVE_SETSID #define setsid() setpgrp(0, getpid()) #endif /* !HAVE_SETSID */ #ifndef HAVE_SETENV int setenv(const char *, const char *, int); #endif /* !HAVE_SETENV */ #ifndef HAVE_SETLOGIN int setlogin(const char *); #endif /* !HAVE_SETLOGIN */ #ifndef HAVE_INNETGR int innetgr(const char *, const char *, const char *, const char *); #endif /* HAVE_INNETGR */ #if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) int seteuid(uid_t); #endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */ #if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) int setegid(uid_t); #endif /* !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */ #if !defined(HAVE_STRERROR) && defined(HAVE_SYS_ERRLIST) && defined(HAVE_SYS_NERR) const char *strerror(int); #endif #if !defined(HAVE_SETLINEBUF) #define setlinebuf(a) (setvbuf((a), NULL, _IOLBF, 0)) #endif #ifndef HAVE_UTIMES #ifndef HAVE_STRUCT_TIMEVAL struct timeval { long tv_sec; long tv_usec; } #endif /* HAVE_STRUCT_TIMEVAL */ -int utimes(char *, struct timeval *); +int utimes(const char *, struct timeval *); #endif /* HAVE_UTIMES */ #ifndef AT_FDCWD # define AT_FDCWD (-2) #endif #ifndef HAVE_FCHMODAT int fchmodat(int, const char *, mode_t, int); #endif #ifndef HAVE_FCHOWNAT int fchownat(int, const char *, uid_t, gid_t, int); #endif #ifndef HAVE_TRUNCATE int truncate (const char *, off_t); #endif /* HAVE_TRUNCATE */ #ifndef HAVE_STRUCT_TIMESPEC struct timespec { time_t tv_sec; long tv_nsec; }; #endif /* !HAVE_STRUCT_TIMESPEC */ #if !defined(HAVE_NANOSLEEP) && !defined(HAVE_NSLEEP) # include int nanosleep(const struct timespec *, struct timespec *); #endif #ifndef HAVE_UTIMENSAT # include /* start with the high bits and work down to minimise risk of overlap */ # ifndef AT_SYMLINK_NOFOLLOW # define AT_SYMLINK_NOFOLLOW 0x80000000 # endif int utimensat(int, const char *, const struct timespec[2], int); #endif /* !HAVE_UTIMENSAT */ #ifndef HAVE_USLEEP int usleep(unsigned int useconds); #endif #ifndef HAVE_TCGETPGRP pid_t tcgetpgrp(int); #endif #ifndef HAVE_TCSENDBREAK int tcsendbreak(int, int); #endif #ifndef HAVE_UNSETENV int unsetenv(const char *); #endif #ifndef HAVE_ISBLANK int isblank(int); #endif #ifndef HAVE_GETPGID pid_t getpgid(pid_t); #endif #ifndef HAVE_PSELECT int pselect(int, fd_set *, fd_set *, fd_set *, const struct timespec *, const sigset_t *); #endif #ifndef HAVE_ENDGRENT # define endgrent() do { } while(0) #endif #ifndef HAVE_KRB5_GET_ERROR_MESSAGE # define krb5_get_error_message krb5_get_err_text #endif #ifndef HAVE_KRB5_FREE_ERROR_MESSAGE # define krb5_free_error_message(a,b) do { } while(0) #endif #ifndef HAVE_PLEDGE int pledge(const char *promises, const char *paths[]); #endif /* bsd-err.h */ #ifndef HAVE_ERR void err(int, const char *, ...) __attribute__((format(printf, 2, 3))); #endif #ifndef HAVE_ERRX void errx(int, const char *, ...) __attribute__((format(printf, 2, 3))); #endif #ifndef HAVE_WARN void warn(const char *, ...) __attribute__((format(printf, 1, 2))); #endif #ifndef HAVE_LLABS long long llabs(long long); #endif #if defined(HAVE_DECL_BZERO) && HAVE_DECL_BZERO == 0 void bzero(void *, size_t); #endif #ifndef HAVE_RAISE int raise(int); #endif #ifndef HAVE_GETSID pid_t getsid(pid_t); #endif #ifndef HAVE_FLOCK # define LOCK_SH 0x01 # define LOCK_EX 0x02 # define LOCK_NB 0x04 # define LOCK_UN 0x08 int flock(int, int); #endif #ifdef FFLUSH_NULL_BUG # define fflush(x) (_ssh_compat_fflush(x)) #endif #ifndef HAVE_LOCALTIME_R struct tm *localtime_r(const time_t *, struct tm *); #endif #ifndef HAVE_REALPATH #define realpath(x, y) (sftp_realpath((x), (y))) #endif #endif /* _BSD_MISC_H */ diff --git a/crypto/openssh/openbsd-compat/bsd-poll.c b/crypto/openssh/openbsd-compat/bsd-poll.c index 781ee978a651..9a9794f5863b 100644 --- a/crypto/openssh/openbsd-compat/bsd-poll.c +++ b/crypto/openssh/openbsd-compat/bsd-poll.c @@ -1,129 +1,129 @@ /* * Copyright (c) 2004, 2005, 2007 Darren Tucker (dtucker at zip com au). * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "includes.h" #if !defined(HAVE_PPOLL) || !defined(HAVE_POLL) || defined(BROKEN_POLL) #include #include #ifdef HAVE_SYS_PARAM_H # include #endif #ifdef HAVE_SYS_SELECT_H # include #endif #include #include #include #include #include "bsd-poll.h" #if !defined(HAVE_PPOLL) || defined(BROKEN_POLL) /* * A minimal implementation of ppoll(2), built on top of pselect(2). * * Only supports POLLIN, POLLOUT and POLLPRI flags in pfd.events and * revents. Notably POLLERR, POLLHUP and POLLNVAL are not supported. * * Supports pfd.fd = -1 meaning "unused" although it's not standard. */ int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmoutp, const sigset_t *sigmask) { nfds_t i; int saved_errno, ret, fd, maxfd = 0; fd_set *readfds = NULL, *writefds = NULL, *exceptfds = NULL; size_t nmemb; for (i = 0; i < nfds; i++) { fd = fds[i].fd; if (fd != -1 && fd >= FD_SETSIZE) { errno = EINVAL; return -1; } maxfd = MAX(maxfd, fd); } nmemb = howmany(maxfd + 1 , NFDBITS); if ((readfds = calloc(nmemb, sizeof(fd_mask))) == NULL || (writefds = calloc(nmemb, sizeof(fd_mask))) == NULL || (exceptfds = calloc(nmemb, sizeof(fd_mask))) == NULL) { saved_errno = ENOMEM; ret = -1; goto out; } /* populate event bit vectors for the events we're interested in */ for (i = 0; i < nfds; i++) { fd = fds[i].fd; if (fd == -1) continue; if (fds[i].events & POLLIN) FD_SET(fd, readfds); if (fds[i].events & POLLOUT) FD_SET(fd, writefds); if (fds[i].events & POLLPRI) FD_SET(fd, exceptfds); } ret = pselect(maxfd + 1, readfds, writefds, exceptfds, tmoutp, sigmask); saved_errno = errno; /* scan through select results and set poll() flags */ for (i = 0; i < nfds; i++) { fd = fds[i].fd; fds[i].revents = 0; if (fd == -1) continue; - if (FD_ISSET(fd, readfds)) + if ((fds[i].events & POLLIN) && FD_ISSET(fd, readfds)) fds[i].revents |= POLLIN; - if (FD_ISSET(fd, writefds)) + if ((fds[i].events & POLLOUT) && FD_ISSET(fd, writefds)) fds[i].revents |= POLLOUT; - if (FD_ISSET(fd, exceptfds)) + if ((fds[i].events & POLLPRI) && FD_ISSET(fd, exceptfds)) fds[i].revents |= POLLPRI; } out: free(readfds); free(writefds); free(exceptfds); if (ret == -1) errno = saved_errno; return ret; } #endif /* !HAVE_PPOLL || BROKEN_POLL */ #if !defined(HAVE_POLL) || defined(BROKEN_POLL) int poll(struct pollfd *fds, nfds_t nfds, int timeout) { struct timespec ts, *tsp = NULL; /* poll timeout is msec, ppoll is timespec (sec + nsec) */ if (timeout >= 0) { ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout % 1000) * 1000000; tsp = &ts; } return ppoll(fds, nfds, tsp, NULL); } #endif /* !HAVE_POLL || BROKEN_POLL */ #endif /* !HAVE_PPOLL || !HAVE_POLL || BROKEN_POLL */ diff --git a/crypto/openssh/openbsd-compat/chacha_private.h b/crypto/openssh/openbsd-compat/chacha_private.h index 7c3680fa6d64..cdcb78560825 100644 --- a/crypto/openssh/openbsd-compat/chacha_private.h +++ b/crypto/openssh/openbsd-compat/chacha_private.h @@ -1,222 +1,224 @@ +/* OPENBSD ORIGINAL: lib/libc/crypt/chacha_private.h */ + /* chacha-merged.c version 20080118 D. J. Bernstein Public domain. */ -/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */ +/* $OpenBSD: chacha_private.h,v 1.3 2022/02/28 21:56:29 dtucker Exp $ */ typedef unsigned char u8; typedef unsigned int u32; typedef struct { u32 input[16]; /* could be compressed */ } chacha_ctx; #define U8C(v) (v##U) #define U32C(v) (v##U) #define U8V(v) ((u8)(v) & U8C(0xFF)) #define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) #define ROTL32(v, n) \ (U32V((v) << (n)) | ((v) >> (32 - (n)))) #define U8TO32_LITTLE(p) \ (((u32)((p)[0]) ) | \ ((u32)((p)[1]) << 8) | \ ((u32)((p)[2]) << 16) | \ ((u32)((p)[3]) << 24)) #define U32TO8_LITTLE(p, v) \ do { \ (p)[0] = U8V((v) ); \ (p)[1] = U8V((v) >> 8); \ (p)[2] = U8V((v) >> 16); \ (p)[3] = U8V((v) >> 24); \ } while (0) #define ROTATE(v,c) (ROTL32(v,c)) #define XOR(v,w) ((v) ^ (w)) #define PLUS(v,w) (U32V((v) + (w))) #define PLUSONE(v) (PLUS((v),1)) #define QUARTERROUND(a,b,c,d) \ a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); static const char sigma[16] = "expand 32-byte k"; static const char tau[16] = "expand 16-byte k"; static void -chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits) +chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) { const char *constants; x->input[4] = U8TO32_LITTLE(k + 0); x->input[5] = U8TO32_LITTLE(k + 4); x->input[6] = U8TO32_LITTLE(k + 8); x->input[7] = U8TO32_LITTLE(k + 12); if (kbits == 256) { /* recommended */ k += 16; constants = sigma; } else { /* kbits == 128 */ constants = tau; } x->input[8] = U8TO32_LITTLE(k + 0); x->input[9] = U8TO32_LITTLE(k + 4); x->input[10] = U8TO32_LITTLE(k + 8); x->input[11] = U8TO32_LITTLE(k + 12); x->input[0] = U8TO32_LITTLE(constants + 0); x->input[1] = U8TO32_LITTLE(constants + 4); x->input[2] = U8TO32_LITTLE(constants + 8); x->input[3] = U8TO32_LITTLE(constants + 12); } static void chacha_ivsetup(chacha_ctx *x,const u8 *iv) { x->input[12] = 0; x->input[13] = 0; x->input[14] = U8TO32_LITTLE(iv + 0); x->input[15] = U8TO32_LITTLE(iv + 4); } static void chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) { u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; u8 *ctarget = NULL; u8 tmp[64]; u_int i; if (!bytes) return; j0 = x->input[0]; j1 = x->input[1]; j2 = x->input[2]; j3 = x->input[3]; j4 = x->input[4]; j5 = x->input[5]; j6 = x->input[6]; j7 = x->input[7]; j8 = x->input[8]; j9 = x->input[9]; j10 = x->input[10]; j11 = x->input[11]; j12 = x->input[12]; j13 = x->input[13]; j14 = x->input[14]; j15 = x->input[15]; for (;;) { if (bytes < 64) { for (i = 0;i < bytes;++i) tmp[i] = m[i]; m = tmp; ctarget = c; c = tmp; } x0 = j0; x1 = j1; x2 = j2; x3 = j3; x4 = j4; x5 = j5; x6 = j6; x7 = j7; x8 = j8; x9 = j9; x10 = j10; x11 = j11; x12 = j12; x13 = j13; x14 = j14; x15 = j15; for (i = 20;i > 0;i -= 2) { QUARTERROUND( x0, x4, x8,x12) QUARTERROUND( x1, x5, x9,x13) QUARTERROUND( x2, x6,x10,x14) QUARTERROUND( x3, x7,x11,x15) QUARTERROUND( x0, x5,x10,x15) QUARTERROUND( x1, x6,x11,x12) QUARTERROUND( x2, x7, x8,x13) QUARTERROUND( x3, x4, x9,x14) } x0 = PLUS(x0,j0); x1 = PLUS(x1,j1); x2 = PLUS(x2,j2); x3 = PLUS(x3,j3); x4 = PLUS(x4,j4); x5 = PLUS(x5,j5); x6 = PLUS(x6,j6); x7 = PLUS(x7,j7); x8 = PLUS(x8,j8); x9 = PLUS(x9,j9); x10 = PLUS(x10,j10); x11 = PLUS(x11,j11); x12 = PLUS(x12,j12); x13 = PLUS(x13,j13); x14 = PLUS(x14,j14); x15 = PLUS(x15,j15); #ifndef KEYSTREAM_ONLY x0 = XOR(x0,U8TO32_LITTLE(m + 0)); x1 = XOR(x1,U8TO32_LITTLE(m + 4)); x2 = XOR(x2,U8TO32_LITTLE(m + 8)); x3 = XOR(x3,U8TO32_LITTLE(m + 12)); x4 = XOR(x4,U8TO32_LITTLE(m + 16)); x5 = XOR(x5,U8TO32_LITTLE(m + 20)); x6 = XOR(x6,U8TO32_LITTLE(m + 24)); x7 = XOR(x7,U8TO32_LITTLE(m + 28)); x8 = XOR(x8,U8TO32_LITTLE(m + 32)); x9 = XOR(x9,U8TO32_LITTLE(m + 36)); x10 = XOR(x10,U8TO32_LITTLE(m + 40)); x11 = XOR(x11,U8TO32_LITTLE(m + 44)); x12 = XOR(x12,U8TO32_LITTLE(m + 48)); x13 = XOR(x13,U8TO32_LITTLE(m + 52)); x14 = XOR(x14,U8TO32_LITTLE(m + 56)); x15 = XOR(x15,U8TO32_LITTLE(m + 60)); #endif j12 = PLUSONE(j12); if (!j12) { j13 = PLUSONE(j13); /* stopping at 2^70 bytes per nonce is user's responsibility */ } U32TO8_LITTLE(c + 0,x0); U32TO8_LITTLE(c + 4,x1); U32TO8_LITTLE(c + 8,x2); U32TO8_LITTLE(c + 12,x3); U32TO8_LITTLE(c + 16,x4); U32TO8_LITTLE(c + 20,x5); U32TO8_LITTLE(c + 24,x6); U32TO8_LITTLE(c + 28,x7); U32TO8_LITTLE(c + 32,x8); U32TO8_LITTLE(c + 36,x9); U32TO8_LITTLE(c + 40,x10); U32TO8_LITTLE(c + 44,x11); U32TO8_LITTLE(c + 48,x12); U32TO8_LITTLE(c + 52,x13); U32TO8_LITTLE(c + 56,x14); U32TO8_LITTLE(c + 60,x15); if (bytes <= 64) { if (bytes < 64) { for (i = 0;i < bytes;++i) ctarget[i] = c[i]; } x->input[12] = j12; x->input[13] = j13; return; } bytes -= 64; c += 64; #ifndef KEYSTREAM_ONLY m += 64; #endif } } diff --git a/crypto/openssh/openbsd-compat/getrrsetbyname.c b/crypto/openssh/openbsd-compat/getrrsetbyname.c index dc6fe0533732..cc1f8ae519eb 100644 --- a/crypto/openssh/openbsd-compat/getrrsetbyname.c +++ b/crypto/openssh/openbsd-compat/getrrsetbyname.c @@ -1,610 +1,609 @@ /* $OpenBSD: getrrsetbyname.c,v 1.11 2007/10/11 18:36:41 jakob Exp $ */ /* * Copyright (c) 2001 Jakob Schlyter. 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. */ /* * Portions Copyright (c) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* OPENBSD ORIGINAL: lib/libc/net/getrrsetbyname.c */ #include "includes.h" #if !defined (HAVE_GETRRSETBYNAME) && !defined (HAVE_LDNS) #include #include #include #include #include "getrrsetbyname.h" #if defined(HAVE_DECL_H_ERRNO) && !HAVE_DECL_H_ERRNO extern int h_errno; #endif /* We don't need multithread support here */ #ifdef _THREAD_PRIVATE # undef _THREAD_PRIVATE #endif #define _THREAD_PRIVATE(a,b,c) (c) #ifndef HAVE__RES_EXTERN struct __res_state _res; #endif /* Necessary functions and macros */ /* * Inline versions of get/put short/long. Pointer is advanced. * * These macros demonstrate the property of C whereby it can be * portable or it can be elegant but rarely both. */ #ifndef INT32SZ # define INT32SZ 4 #endif #ifndef INT16SZ # define INT16SZ 2 #endif #ifndef GETSHORT #define GETSHORT(s, cp) { \ - register u_char *t_cp = (u_char *)(cp); \ + u_char *t_cp = (u_char *)(cp); \ (s) = ((u_int16_t)t_cp[0] << 8) \ | ((u_int16_t)t_cp[1]) \ ; \ (cp) += INT16SZ; \ } #endif #ifndef GETLONG #define GETLONG(l, cp) { \ - register u_char *t_cp = (u_char *)(cp); \ + u_char *t_cp = (u_char *)(cp); \ (l) = ((u_int32_t)t_cp[0] << 24) \ | ((u_int32_t)t_cp[1] << 16) \ | ((u_int32_t)t_cp[2] << 8) \ | ((u_int32_t)t_cp[3]) \ ; \ (cp) += INT32SZ; \ } #endif +/* + * If the system doesn't have _getshort/_getlong or that are not exactly what + * we need then use local replacements, avoiding name collisions. + */ +#if !defined(HAVE__GETSHORT) || !defined(HAVE__GETLONG) || \ + !defined(HAVE_DECL__GETSHORT) || HAVE_DECL__GETSHORT == 0 || \ + !defined(HAVE_DECL__GETLONG) || HAVE_DECL__GETLONG == 0 +#define _getshort(x) (_ssh_compat_getshort(x)) +#define _getlong(x) (_ssh_compat_getlong(x)) /* * Routines to insert/extract short/long's. */ - -#ifndef HAVE__GETSHORT static u_int16_t -_getshort(msgp) - register const u_char *msgp; +_getshort(const u_char *msgp) { - register u_int16_t u; + u_int16_t u; GETSHORT(u, msgp); return (u); } -#elif defined(HAVE_DECL__GETSHORT) && (HAVE_DECL__GETSHORT == 0) -u_int16_t _getshort(register const u_char *); -#endif -#ifndef HAVE__GETLONG static u_int32_t -_getlong(msgp) - register const u_char *msgp; +_getlong(const u_char *msgp) { - register u_int32_t u; + u_int32_t u; GETLONG(u, msgp); return (u); } -#elif defined(HAVE_DECL__GETLONG) && (HAVE_DECL__GETLONG == 0) -u_int32_t _getlong(register const u_char *); #endif /* ************** */ #define ANSWER_BUFFER_SIZE 0xffff struct dns_query { char *name; u_int16_t type; u_int16_t class; struct dns_query *next; }; struct dns_rr { char *name; u_int16_t type; u_int16_t class; u_int16_t ttl; u_int16_t size; void *rdata; struct dns_rr *next; }; struct dns_response { HEADER header; struct dns_query *query; struct dns_rr *answer; struct dns_rr *authority; struct dns_rr *additional; }; static struct dns_response *parse_dns_response(const u_char *, int); static struct dns_query *parse_dns_qsection(const u_char *, int, const u_char **, int); static struct dns_rr *parse_dns_rrsection(const u_char *, int, const u_char **, int); static void free_dns_query(struct dns_query *); static void free_dns_rr(struct dns_rr *); static void free_dns_response(struct dns_response *); static int count_dns_rr(struct dns_rr *, u_int16_t, u_int16_t); int getrrsetbyname(const char *hostname, unsigned int rdclass, unsigned int rdtype, unsigned int flags, struct rrsetinfo **res) { struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res); int result; struct rrsetinfo *rrset = NULL; struct dns_response *response = NULL; struct dns_rr *rr; struct rdatainfo *rdata; int length; unsigned int index_ans, index_sig; u_char answer[ANSWER_BUFFER_SIZE]; /* check for invalid class and type */ if (rdclass > 0xffff || rdtype > 0xffff) { result = ERRSET_INVAL; goto fail; } /* don't allow queries of class or type ANY */ if (rdclass == 0xff || rdtype == 0xff) { result = ERRSET_INVAL; goto fail; } /* don't allow flags yet, unimplemented */ if (flags) { result = ERRSET_INVAL; goto fail; } /* initialize resolver */ if ((_resp->options & RES_INIT) == 0 && res_init() == -1) { result = ERRSET_FAIL; goto fail; } #ifdef DEBUG _resp->options |= RES_DEBUG; #endif /* DEBUG */ #ifdef RES_USE_DNSSEC /* turn on DNSSEC if EDNS0 is configured */ if (_resp->options & RES_USE_EDNS0) _resp->options |= RES_USE_DNSSEC; #endif /* RES_USE_DNSEC */ /* make query */ length = res_query(hostname, (signed int) rdclass, (signed int) rdtype, answer, sizeof(answer)); if (length < 0) { switch(h_errno) { case HOST_NOT_FOUND: result = ERRSET_NONAME; goto fail; case NO_DATA: result = ERRSET_NODATA; goto fail; default: result = ERRSET_FAIL; goto fail; } } /* parse result */ response = parse_dns_response(answer, length); if (response == NULL) { result = ERRSET_FAIL; goto fail; } if (response->header.qdcount != 1) { result = ERRSET_FAIL; goto fail; } /* initialize rrset */ rrset = calloc(1, sizeof(struct rrsetinfo)); if (rrset == NULL) { result = ERRSET_NOMEMORY; goto fail; } rrset->rri_rdclass = response->query->class; rrset->rri_rdtype = response->query->type; rrset->rri_ttl = response->answer->ttl; rrset->rri_nrdatas = response->header.ancount; #ifdef HAVE_HEADER_AD /* check for authenticated data */ if (response->header.ad == 1) rrset->rri_flags |= RRSET_VALIDATED; #endif /* copy name from answer section */ rrset->rri_name = strdup(response->answer->name); if (rrset->rri_name == NULL) { result = ERRSET_NOMEMORY; goto fail; } /* count answers */ rrset->rri_nrdatas = count_dns_rr(response->answer, rrset->rri_rdclass, rrset->rri_rdtype); rrset->rri_nsigs = count_dns_rr(response->answer, rrset->rri_rdclass, T_RRSIG); /* allocate memory for answers */ rrset->rri_rdatas = calloc(rrset->rri_nrdatas, sizeof(struct rdatainfo)); if (rrset->rri_rdatas == NULL) { result = ERRSET_NOMEMORY; goto fail; } /* allocate memory for signatures */ if (rrset->rri_nsigs > 0) { rrset->rri_sigs = calloc(rrset->rri_nsigs, sizeof(struct rdatainfo)); if (rrset->rri_sigs == NULL) { result = ERRSET_NOMEMORY; goto fail; } } /* copy answers & signatures */ for (rr = response->answer, index_ans = 0, index_sig = 0; rr; rr = rr->next) { rdata = NULL; if (rr->class == rrset->rri_rdclass && rr->type == rrset->rri_rdtype) rdata = &rrset->rri_rdatas[index_ans++]; if (rr->class == rrset->rri_rdclass && rr->type == T_RRSIG) rdata = &rrset->rri_sigs[index_sig++]; if (rdata) { rdata->rdi_length = rr->size; rdata->rdi_data = malloc(rr->size); if (rdata->rdi_data == NULL) { result = ERRSET_NOMEMORY; goto fail; } memcpy(rdata->rdi_data, rr->rdata, rr->size); } } free_dns_response(response); *res = rrset; return (ERRSET_SUCCESS); fail: if (rrset != NULL) freerrset(rrset); if (response != NULL) free_dns_response(response); return (result); } void freerrset(struct rrsetinfo *rrset) { u_int16_t i; if (rrset == NULL) return; if (rrset->rri_rdatas) { for (i = 0; i < rrset->rri_nrdatas; i++) { if (rrset->rri_rdatas[i].rdi_data == NULL) break; free(rrset->rri_rdatas[i].rdi_data); } free(rrset->rri_rdatas); } if (rrset->rri_sigs) { for (i = 0; i < rrset->rri_nsigs; i++) { if (rrset->rri_sigs[i].rdi_data == NULL) break; free(rrset->rri_sigs[i].rdi_data); } free(rrset->rri_sigs); } if (rrset->rri_name) free(rrset->rri_name); free(rrset); } /* * DNS response parsing routines */ static struct dns_response * parse_dns_response(const u_char *answer, int size) { struct dns_response *resp; const u_char *cp; /* allocate memory for the response */ resp = calloc(1, sizeof(*resp)); if (resp == NULL) return (NULL); /* initialize current pointer */ cp = answer; /* copy header */ memcpy(&resp->header, cp, HFIXEDSZ); cp += HFIXEDSZ; /* fix header byte order */ resp->header.qdcount = ntohs(resp->header.qdcount); resp->header.ancount = ntohs(resp->header.ancount); resp->header.nscount = ntohs(resp->header.nscount); resp->header.arcount = ntohs(resp->header.arcount); /* there must be at least one query */ if (resp->header.qdcount < 1) { free_dns_response(resp); return (NULL); } /* parse query section */ resp->query = parse_dns_qsection(answer, size, &cp, resp->header.qdcount); if (resp->header.qdcount && resp->query == NULL) { free_dns_response(resp); return (NULL); } /* parse answer section */ resp->answer = parse_dns_rrsection(answer, size, &cp, resp->header.ancount); if (resp->header.ancount && resp->answer == NULL) { free_dns_response(resp); return (NULL); } /* parse authority section */ resp->authority = parse_dns_rrsection(answer, size, &cp, resp->header.nscount); if (resp->header.nscount && resp->authority == NULL) { free_dns_response(resp); return (NULL); } /* parse additional section */ resp->additional = parse_dns_rrsection(answer, size, &cp, resp->header.arcount); if (resp->header.arcount && resp->additional == NULL) { free_dns_response(resp); return (NULL); } return (resp); } static struct dns_query * parse_dns_qsection(const u_char *answer, int size, const u_char **cp, int count) { struct dns_query *head, *curr, *prev; int i, length; char name[MAXDNAME]; for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { /* allocate and initialize struct */ curr = calloc(1, sizeof(struct dns_query)); if (curr == NULL) { free_dns_query(head); return (NULL); } if (head == NULL) head = curr; if (prev != NULL) prev->next = curr; /* name */ length = dn_expand(answer, answer + size, *cp, name, sizeof(name)); if (length < 0) { free_dns_query(head); return (NULL); } curr->name = strdup(name); if (curr->name == NULL) { free_dns_query(head); return (NULL); } *cp += length; /* type */ curr->type = _getshort(*cp); *cp += INT16SZ; /* class */ curr->class = _getshort(*cp); *cp += INT16SZ; } return (head); } static struct dns_rr * parse_dns_rrsection(const u_char *answer, int size, const u_char **cp, int count) { struct dns_rr *head, *curr, *prev; int i, length; char name[MAXDNAME]; for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { /* allocate and initialize struct */ curr = calloc(1, sizeof(struct dns_rr)); if (curr == NULL) { free_dns_rr(head); return (NULL); } if (head == NULL) head = curr; if (prev != NULL) prev->next = curr; /* name */ length = dn_expand(answer, answer + size, *cp, name, sizeof(name)); if (length < 0) { free_dns_rr(head); return (NULL); } curr->name = strdup(name); if (curr->name == NULL) { free_dns_rr(head); return (NULL); } *cp += length; /* type */ curr->type = _getshort(*cp); *cp += INT16SZ; /* class */ curr->class = _getshort(*cp); *cp += INT16SZ; /* ttl */ curr->ttl = _getlong(*cp); *cp += INT32SZ; /* rdata size */ curr->size = _getshort(*cp); *cp += INT16SZ; /* rdata itself */ curr->rdata = malloc(curr->size); if (curr->rdata == NULL) { free_dns_rr(head); return (NULL); } memcpy(curr->rdata, *cp, curr->size); *cp += curr->size; } return (head); } static void free_dns_query(struct dns_query *p) { if (p == NULL) return; if (p->name) free(p->name); free_dns_query(p->next); free(p); } static void free_dns_rr(struct dns_rr *p) { if (p == NULL) return; if (p->name) free(p->name); if (p->rdata) free(p->rdata); free_dns_rr(p->next); free(p); } static void free_dns_response(struct dns_response *p) { if (p == NULL) return; free_dns_query(p->query); free_dns_rr(p->answer); free_dns_rr(p->authority); free_dns_rr(p->additional); free(p); } static int count_dns_rr(struct dns_rr *p, u_int16_t class, u_int16_t type) { int n = 0; while(p) { if (p->class == class && p->type == type) n++; p = p->next; } return (n); } #endif /* !defined (HAVE_GETRRSETBYNAME) && !defined (HAVE_LDNS) */ diff --git a/crypto/openssh/openbsd-compat/openbsd-compat.h b/crypto/openssh/openbsd-compat/openbsd-compat.h index c202e1429245..4316ab84bf89 100644 --- a/crypto/openssh/openbsd-compat/openbsd-compat.h +++ b/crypto/openssh/openbsd-compat/openbsd-compat.h @@ -1,366 +1,374 @@ /* * 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 #include #include #include /* 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 # 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 + #ifndef HAVE_GETLINE #include 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 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 # include # 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); #endif /* !HAVE_ARC4RANDOM */ #ifndef HAVE_ARC4RANDOM_BUF void arc4random_buf(void *, size_t); #endif #ifndef HAVE_ARC4RANDOM_UNIFORM u_int32_t arc4random_uniform(u_int32_t); #endif #ifndef HAVE_ASPRINTF int asprintf(char **, const char *, ...); #endif #ifndef HAVE_OPENPTY # include /* 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 #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 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 # if defined(__GNU_LIBRARY__) && defined(__GLIBC_PREREQ) # if __GLIBC_PREREQ(2, 15) && (_FORTIFY_SOURCE > 0) # include /* 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/crypto/openssh/platform.c b/crypto/openssh/platform.c index 44ba71dc5fcb..4fe8744ee887 100644 --- a/crypto/openssh/platform.c +++ b/crypto/openssh/platform.c @@ -1,199 +1,250 @@ /* * Copyright (c) 2006 Darren Tucker. 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 #include +#include #include #include "log.h" #include "misc.h" #include "servconf.h" #include "sshkey.h" #include "hostfile.h" #include "auth.h" #include "auth-pam.h" #include "platform.h" #include "openbsd-compat/openbsd-compat.h" extern int use_privsep; extern ServerOptions options; void platform_pre_listen(void) { #ifdef LINUX_OOM_ADJUST /* Adjust out-of-memory killer so listening process is not killed */ oom_adjust_setup(); #endif } void platform_pre_fork(void) { #ifdef USE_SOLARIS_PROCESS_CONTRACTS solaris_contract_pre_fork(); #endif } void platform_pre_restart(void) { #ifdef LINUX_OOM_ADJUST oom_adjust_restore(); #endif } void platform_post_fork_parent(pid_t child_pid) { #ifdef USE_SOLARIS_PROCESS_CONTRACTS solaris_contract_post_fork_parent(child_pid); #endif } void platform_post_fork_child(void) { #ifdef USE_SOLARIS_PROCESS_CONTRACTS solaris_contract_post_fork_child(); #endif #ifdef LINUX_OOM_ADJUST oom_adjust_restore(); #endif } /* return 1 if we are running with privilege to swap UIDs, 0 otherwise */ int platform_privileged_uidswap(void) { #ifdef HAVE_CYGWIN /* uid 0 is not special on Cygwin so always try */ return 1; #else return (getuid() == 0 || geteuid() == 0); #endif } /* * This gets called before switching UIDs, and is called even when sshd is * not running as root. */ void platform_setusercontext(struct passwd *pw) { #ifdef WITH_SELINUX /* Cache selinux status for later use */ (void)ssh_selinux_enabled(); #endif #ifdef USE_SOLARIS_PROJECTS /* * If solaris projects were detected, set the default now, unless * we are using PAM in which case it is the responsibility of the * PAM stack. */ if (!options.use_pam && (getuid() == 0 || geteuid() == 0)) solaris_set_default_project(pw); #endif #if defined(HAVE_LOGIN_CAP) && defined (__bsdi__) if (getuid() == 0 || geteuid() == 0) setpgid(0, 0); # endif #if defined(HAVE_LOGIN_CAP) && defined(USE_PAM) /* * If we have both LOGIN_CAP and PAM, we want to establish creds * before calling setusercontext (in session.c:do_setusercontext). */ if (getuid() == 0 || geteuid() == 0) { if (options.use_pam) { do_pam_setcred(use_privsep); } } # endif /* USE_PAM */ #if !defined(HAVE_LOGIN_CAP) && defined(HAVE_GETLUID) && defined(HAVE_SETLUID) if (getuid() == 0 || geteuid() == 0) { /* Sets login uid for accounting */ if (getluid() == -1 && setluid(pw->pw_uid) == -1) error("setluid: %s", strerror(errno)); } #endif } /* * This gets called after we've established the user's groups, and is only * called if sshd is running as root. */ void platform_setusercontext_post_groups(struct passwd *pw) { #if !defined(HAVE_LOGIN_CAP) && defined(USE_PAM) /* * PAM credentials may take the form of supplementary groups. * These will have been wiped by the above initgroups() call. * Reestablish them here. */ if (options.use_pam) { do_pam_setcred(use_privsep); } #endif /* USE_PAM */ #if !defined(HAVE_LOGIN_CAP) && (defined(WITH_IRIX_PROJECT) || \ defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY)) irix_setusercontext(pw); #endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */ #ifdef _AIX aix_usrinfo(pw); #endif /* _AIX */ #ifdef HAVE_SETPCRED /* * If we have a chroot directory, we set all creds except real * uid which we will need for chroot. If we don't have a * chroot directory, we don't override anything. */ { char **creds = NULL, *chroot_creds[] = { "REAL_USER=root", NULL }; if (options.chroot_directory != NULL && strcasecmp(options.chroot_directory, "none") != 0) creds = chroot_creds; if (setpcred(pw->pw_name, creds) == -1) fatal("Failed to set process credentials"); } #endif /* HAVE_SETPCRED */ #ifdef WITH_SELINUX ssh_selinux_setup_exec_context(pw->pw_name); #endif } char * platform_krb5_get_principal_name(const char *pw_name) { #ifdef USE_AIX_KRB_NAME return aix_krb5_get_principal_name(pw_name); #else return NULL; #endif } + +/* returns 1 if account is locked */ +int +platform_locked_account(struct passwd *pw) +{ + int locked = 0; + char *passwd = pw->pw_passwd; +#ifdef USE_SHADOW + struct spwd *spw = NULL; +#ifdef USE_LIBIAF + char *iaf_passwd = NULL; +#endif + + spw = getspnam(pw->pw_name); +#ifdef HAS_SHADOW_EXPIRE + if (spw != NULL && auth_shadow_acctexpired(spw)) + return 1; +#endif /* HAS_SHADOW_EXPIRE */ + + if (spw != NULL) +#ifdef USE_LIBIAF + iaf_passwd = passwd = get_iaf_password(pw); +#else + passwd = spw->sp_pwdp; +#endif /* USE_LIBIAF */ +#endif + + /* check for locked account */ + if (passwd && *passwd) { +#ifdef LOCKED_PASSWD_STRING + if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0) + locked = 1; +#endif +#ifdef LOCKED_PASSWD_PREFIX + if (strncmp(passwd, LOCKED_PASSWD_PREFIX, + strlen(LOCKED_PASSWD_PREFIX)) == 0) + locked = 1; +#endif +#ifdef LOCKED_PASSWD_SUBSTR + if (strstr(passwd, LOCKED_PASSWD_SUBSTR)) + locked = 1; +#endif + } +#ifdef USE_LIBIAF + if (iaf_passwd != NULL) + freezero(iaf_passwd, strlen(iaf_passwd)); +#endif /* USE_LIBIAF */ + + return locked; +} diff --git a/crypto/openssh/platform.h b/crypto/openssh/platform.h index ea4f9c584924..7fef8c983e5e 100644 --- a/crypto/openssh/platform.h +++ b/crypto/openssh/platform.h @@ -1,37 +1,38 @@ /* * Copyright (c) 2006 Darren Tucker. 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 #include void platform_pre_listen(void); void platform_pre_fork(void); void platform_pre_restart(void); void platform_post_fork_parent(pid_t child_pid); void platform_post_fork_child(void); int platform_privileged_uidswap(void); void platform_setusercontext(struct passwd *); void platform_setusercontext_post_groups(struct passwd *); char *platform_get_krb5_client(const char *); char *platform_krb5_get_principal_name(const char *); +int platform_locked_account(struct passwd *); int platform_sys_dir_uid(uid_t); void platform_disable_tracing(int); /* in platform-pledge.c */ void platform_pledge_agent(void); void platform_pledge_sftp_server(void); void platform_pledge_mux(void); diff --git a/crypto/openssh/scp.c b/crypto/openssh/scp.c index 519bffa1be1e..7a3851c5fdd1 100644 --- a/crypto/openssh/scp.c +++ b/crypto/openssh/scp.c @@ -1,2175 +1,2175 @@ -/* $OpenBSD: scp.c,v 1.245 2022/02/10 04:12:38 djm Exp $ */ +/* $OpenBSD: scp.c,v 1.247 2022/03/20 08:52:17 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 , Tatu Ylonen * * 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 #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_POLL_H #include #else # ifdef HAVE_SYS_POLL_H # include # endif #endif #ifdef HAVE_SYS_TIME_H # include #endif #include #include #include #include #include #include #ifdef HAVE_FNMATCH_H #include #endif #ifdef USE_SYSTEM_GLOB # include #else # include "openbsd-compat/glob.h" #endif #ifdef HAVE_LIBGEN_H #include #endif #include #include #include #include #include #ifdef HAVE_STDINT_H # include #endif #include #include #include #include #include #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) #include #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_SCP; 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 { - args.list = NULL; + 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) { error("failed to upload directory %s to %s", src, targ); errs = 1; } } else if (do_upload(conn, src, abs_dst, pflag, 0, 0) != 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) err = -1; } else { if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, pflag, 0, 0) == -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 "); 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/crypto/openssh/servconf.c b/crypto/openssh/servconf.c index e3c43c8cb487..6ab8e66f09e2 100644 --- a/crypto/openssh/servconf.c +++ b/crypto/openssh/servconf.c @@ -1,3054 +1,3055 @@ -/* $OpenBSD: servconf.c,v 1.383 2022/02/08 08:59:12 dtucker Exp $ */ +/* $OpenBSD: servconf.c,v 1.384 2022/03/18 04:04:11 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , 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" __RCSID("$FreeBSD$"); #include #include #include #ifdef __OpenBSD__ #include #endif #include #include #include #ifdef HAVE_NET_ROUTE_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_UTIL_H #include #endif #ifdef USE_SYSTEM_GLOB # include #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" #include "version.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->use_blacklist = -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); } static const char *defaultkey = "[default]"; void servconf_add_hostkey(const char *file, const int line, ServerOptions *options, const char *path, int userprovided) { char *apath = derelativise_path(path); if (file == defaultkey && access(path, R_OK) != 0) return; 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 = 1; /* Standard Options */ if (options->num_host_key_files == 0) { /* fill default hostkeys for protocols */ servconf_add_hostkey(defaultkey, 0, options, _PATH_HOST_RSA_KEY_FILE, 0); #ifdef OPENSSL_HAS_ECC servconf_add_hostkey(defaultkey, 0, options, _PATH_HOST_ECDSA_KEY_FILE, 0); #endif servconf_add_hostkey(defaultkey, 0, options, _PATH_HOST_ED25519_KEY_FILE, 0); #ifdef WITH_XMSS servconf_add_hostkey(defaultkey, 0, options, _PATH_HOST_XMSS_KEY_FILE, 0); #endif /* WITH_XMSS */ } if (options->num_host_key_files == 0) fatal("No host key files found"); /* 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; 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 = 1; 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 = 0; 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 = 1; 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(defaultkey, 0, "AuthorizedKeysFiles", &options->authorized_keys_files, &options->num_authkeys_files, _PATH_SSH_USER_PERMITTED_KEYS); opt_array_append(defaultkey, 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(SSH_VERSION_FREEBSD); 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->use_blacklist == -1) options->use_blacklist = 0; 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, sUseBlacklist, 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 }, { "useblacklist", sUseBlacklist, SSHCFG_GLOBAL }, { "useblocklist", sUseBlacklist, SSHCFG_GLOBAL }, /* alias */ { "noneenabled", sUnsupported, SSHCFG_ALL }, { "hpndisabled", sDeprecated, SSHCFG_ALL }, { "hpnbuffersize", sDeprecated, SSHCFG_ALL }, { "tcprcvbufpoll", sDeprecated, 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 : "", 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 : ""); 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 : ""); 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 : ""); 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 : ""); 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 : ""); 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 : ""); 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; 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 sUseBlacklist: intptr = &options->use_blacklist; goto parse_flag; 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); + 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); /* * 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) + 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); - process_queued_listen_addrs(options); + 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_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); dump_cfg_fmtint(sUseBlacklist, o->use_blacklist); /* 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/crypto/openssh/servconf.h b/crypto/openssh/servconf.h index 6094e85d99ca..6f87db44421a 100644 --- a/crypto/openssh/servconf.h +++ b/crypto/openssh/servconf.h @@ -1,314 +1,314 @@ -/* $OpenBSD: servconf.h,v 1.155 2021/07/02 05:11:21 dtucker Exp $ */ +/* $OpenBSD: servconf.h,v 1.156 2022/03/18 04:04:11 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , 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 #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 use_blacklist; } 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 *); + 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/crypto/openssh/sftp-client.c b/crypto/openssh/sftp-client.c index c75657553790..1b8ce6d78826 100644 --- a/crypto/openssh/sftp-client.c +++ b/crypto/openssh/sftp-client.c @@ -1,2675 +1,2795 @@ -/* $OpenBSD: sftp-client.c,v 1.161 2022/01/17 21:41:04 djm Exp $ */ +/* $OpenBSD: sftp-client.c,v 1.162 2022/03/31 03:07:03 djm Exp $ */ /* * Copyright (c) 2001-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. */ /* XXX: memleaks */ /* XXX: signed vs unsigned */ /* XXX: remove all logging, only return status codes */ /* XXX: copy between two remote sites */ #include "includes.h" #include #ifdef HAVE_SYS_STATVFS_H #include #endif #include "openbsd-compat/sys-queue.h" #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_SYS_TIME_H # include #endif #include #include #include #ifdef HAVE_POLL_H #include #else # ifdef HAVE_SYS_POLL_H # include # endif #endif #include #include #include #include #include #include #include #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 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; } 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) { 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); 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) { 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 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) 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) { 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) { 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); free(src_canon); return ret; } int do_upload(struct sftp_conn *conn, const char *local_path, const char *remote_path, int preserve_flag, int resume, int fsync_flag) { int r, local_fd; u_int status = SSH2_FX_OK; u_int id; u_char type; off_t offset, progress_counter; u_char *handle, *data; struct sshbuf *msg; struct stat sb; Attrib a, *c = NULL; u_int32_t startid; u_int32_t ackid; struct 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; } } /* 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) { 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; 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 (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 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) 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) { 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) { 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); 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; } 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/crypto/openssh/sftp-client.h b/crypto/openssh/sftp-client.h index 8851b23b89b5..282a4c70037d 100644 --- a/crypto/openssh/sftp-client.h +++ b/crypto/openssh/sftp-client.h @@ -1,198 +1,201 @@ -/* $OpenBSD: sftp-client.h,v 1.35 2022/01/01 01:55:30 jsg Exp $ */ +/* $OpenBSD: sftp-client.h,v 1.36 2022/03/31 03:07:03 djm Exp $ */ /* * Copyright (c) 2001-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. */ /* Client side of SSH2 filexfer protocol */ #ifndef _SFTP_CLIENT_H #define _SFTP_CLIENT_H #ifdef USE_SYSTEM_GLOB # include #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); /* * 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); /* * Upload 'local_path' to 'remote_path'. Preserve permissions and times * if 'pflag' is set */ int do_upload(struct sftp_conn *, const char *, const char *, int, int, int); /* * Recursively upload 'local_directory' to 'remote_directory'. Preserve * times if 'pflag' is set */ int upload_dir(struct sftp_conn *, const char *, const char *, int, int, int, int, 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); /* 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/crypto/openssh/sftp-glob.c b/crypto/openssh/sftp-glob.c index f573f98f01ec..764e99552d42 100644 --- a/crypto/openssh/sftp-glob.c +++ b/crypto/openssh/sftp-glob.c @@ -1,150 +1,150 @@ -/* $OpenBSD: sftp-glob.c,v 1.29 2019/11/13 04:47:52 deraadt Exp $ */ +/* $OpenBSD: sftp-glob.c,v 1.30 2022/02/25 09:46:24 dtucker Exp $ */ /* * Copyright (c) 2001-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. */ #include "includes.h" #include #ifdef HAVE_SYS_STAT_H # include #endif #include #include #include #include #include "xmalloc.h" #include "sftp.h" #include "sftp-common.h" #include "sftp-client.h" int remote_glob(struct sftp_conn *, const char *, int, int (*)(const char *, int), glob_t *); struct SFTP_OPENDIR { SFTP_DIRENT **dir; int offset; }; static struct { struct sftp_conn *conn; } cur; static void * fudge_opendir(const char *path) { struct SFTP_OPENDIR *r; r = xcalloc(1, sizeof(*r)); - if (do_readdir(cur.conn, (char *)path, &r->dir)) { + if (do_readdir(cur.conn, path, &r->dir)) { free(r); return(NULL); } r->offset = 0; return((void *)r); } static struct dirent * fudge_readdir(struct SFTP_OPENDIR *od) { /* Solaris needs sizeof(dirent) + path length (see below) */ static char buf[sizeof(struct dirent) + MAXPATHLEN]; struct dirent *ret = (struct dirent *)buf; #ifdef __GNU_LIBRARY__ static int inum = 1; #endif /* __GNU_LIBRARY__ */ if (od->dir[od->offset] == NULL) return(NULL); memset(buf, 0, sizeof(buf)); /* * Solaris defines dirent->d_name as a one byte array and expects * you to hack around it. */ #ifdef BROKEN_ONE_BYTE_DIRENT_D_NAME strlcpy(ret->d_name, od->dir[od->offset++]->filename, MAXPATHLEN); #else strlcpy(ret->d_name, od->dir[od->offset++]->filename, sizeof(ret->d_name)); #endif #ifdef __GNU_LIBRARY__ /* * Idiot glibc uses extensions to struct dirent for readdir with * ALTDIRFUNCs. Not that this is documented anywhere but the * source... Fake an inode number to appease it. */ ret->d_ino = inum++; if (!inum) inum = 1; #endif /* __GNU_LIBRARY__ */ return(ret); } static void fudge_closedir(struct SFTP_OPENDIR *od) { free_sftp_dirents(od->dir); free(od); } static int fudge_lstat(const char *path, struct stat *st) { Attrib *a; - if (!(a = do_lstat(cur.conn, (char *)path, 1))) + if (!(a = do_lstat(cur.conn, path, 1))) return(-1); attrib_to_stat(a, st); return(0); } static int fudge_stat(const char *path, struct stat *st) { Attrib *a; - if (!(a = do_stat(cur.conn, (char *)path, 1))) + if (!(a = do_stat(cur.conn, path, 1))) return(-1); attrib_to_stat(a, st); return(0); } int remote_glob(struct sftp_conn *conn, const char *pattern, int flags, int (*errfunc)(const char *, int), glob_t *pglob) { pglob->gl_opendir = fudge_opendir; pglob->gl_readdir = (struct dirent *(*)(void *))fudge_readdir; pglob->gl_closedir = (void (*)(void *))fudge_closedir; pglob->gl_lstat = fudge_lstat; pglob->gl_stat = fudge_stat; memset(&cur, 0, sizeof(cur)); cur.conn = conn; return(glob(pattern, flags | GLOB_ALTDIRFUNC, errfunc, pglob)); } diff --git a/crypto/openssh/sftp-server.c b/crypto/openssh/sftp-server.c index d4c6a3b4c39a..3dd19d4c81db 100644 --- a/crypto/openssh/sftp-server.c +++ b/crypto/openssh/sftp-server.c @@ -1,1926 +1,2018 @@ -/* $OpenBSD: sftp-server.c,v 1.139 2022/02/01 23:32:51 djm Exp $ */ +/* $OpenBSD: sftp-server.c,v 1.140 2022/03/31 03:05:49 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 #include #include #ifdef HAVE_SYS_TIME_H # include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #ifdef HAVE_SYS_STATVFS_H #include #endif #include #include #include #ifdef HAVE_POLL_H #include #endif #include #include #include #include #include #include #include +#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(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 }, { 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"); 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); 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(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/crypto/openssh/sftp.1 b/crypto/openssh/sftp.1 index 7eebeeacbf3f..39e7d6ed68a8 100644 --- a/crypto/openssh/sftp.1 +++ b/crypto/openssh/sftp.1 @@ -1,699 +1,711 @@ -.\" $OpenBSD: sftp.1,v 1.138 2021/07/02 05:11:21 dtucker Exp $ +.\" $OpenBSD: sftp.1,v 1.140 2022/03/31 17:27:27 naddy 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: July 2 2021 $ +.Dd $Mdocdate: March 31 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 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 +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 , chmod , chown , +.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 Connect directly to a local sftp server (rather than 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 .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 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/crypto/openssh/sftp.c b/crypto/openssh/sftp.c index 8cb5917a91f1..4efc025a504c 100644 --- a/crypto/openssh/sftp.c +++ b/crypto/openssh/sftp.c @@ -1,2585 +1,2598 @@ -/* $OpenBSD: sftp.c,v 1.212 2021/09/11 09:05:50 schwarze Exp $ */ +/* $OpenBSD: sftp.c,v 1.214 2022/03/31 03:07:03 djm Exp $ */ /* * Copyright (c) 2001-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. */ #include "includes.h" #include #include #ifdef HAVE_SYS_STAT_H # include #endif #include #include #ifdef HAVE_SYS_STATVFS_H #include #endif #include #include #ifdef HAVE_PATHS_H # include #endif #ifdef HAVE_LIBGEN_H #include #endif #ifdef HAVE_LOCALE_H # include #endif #ifdef USE_LIBEDIT #include #else typedef void EditLine; #endif #include #include #include #include #include #include #include #ifdef HAVE_UTIL_H # include #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" /* 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; }; /* 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 } }; /* 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 int process_get(struct sftp_conn *conn, const char *src, const char *dst, const char *pwd, int pflag, int rflag, int resume, int fflag) { char *abs_src = NULL; char *abs_dst = NULL; glob_t g; char *filename, *tmp=NULL; int i, r, err = 0; abs_src = xstrdup(src); abs_src = make_absolute(abs_src, pwd); memset(&g, 0, sizeof(g)); debug3("Looking up %s", abs_src); if ((r = remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) != 0) { if (r == GLOB_NOSPACE) { error("Too many matches for \"%s\".", abs_src); } else { error("File \"%s\" not found.", abs_src); } err = -1; goto out; } /* * If multiple matches then dst must be a directory or * unspecified. */ if (g.gl_matchc > 1 && dst != NULL && !local_is_dir(dst)) { error("Multiple source paths, but destination " "\"%s\" is not a directory", dst); err = -1; goto out; } for (i = 0; g.gl_pathv[i] && !interrupted; i++) { tmp = xstrdup(g.gl_pathv[i]); if ((filename = basename(tmp)) == NULL) { error("basename %s: %s", tmp, strerror(errno)); free(tmp); err = -1; goto out; } if (g.gl_matchc == 1 && dst) { if (local_is_dir(dst)) { abs_dst = path_append(dst, filename); } else { abs_dst = xstrdup(dst); } } else if (dst) { abs_dst = path_append(dst, filename); } else { abs_dst = xstrdup(filename); } free(tmp); resume |= global_aflag; if (!quiet && resume) mprintf("Resuming %s to %s\n", g.gl_pathv[i], abs_dst); else if (!quiet && !resume) mprintf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); /* 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) err = -1; } else { if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, pflag || global_pflag, resume, fflag || global_fflag) == -1) err = -1; } free(abs_dst); abs_dst = NULL; } out: free(abs_src); globfree(&g); return(err); } static int process_put(struct sftp_conn *conn, const char *src, const char *dst, const char *pwd, int pflag, int rflag, int resume, int fflag) { char *tmp_dst = NULL; char *abs_dst = NULL; char *tmp = NULL, *filename = NULL; glob_t g; int err = 0; int i, dst_is_dir = 1; struct stat sb; if (dst) { tmp_dst = xstrdup(dst); tmp_dst = make_absolute(tmp_dst, pwd); } memset(&g, 0, sizeof(g)); debug3("Looking up %s", src); if (glob(src, GLOB_NOCHECK | GLOB_MARK, NULL, &g)) { error("File \"%s\" not found.", src); err = -1; goto out; } /* If we aren't fetching to pwd then stash this status for later */ if (tmp_dst != NULL) dst_is_dir = remote_is_dir(conn, tmp_dst); /* If multiple matches, dst may be directory or unspecified */ if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) { error("Multiple paths match, but destination " "\"%s\" is not a directory", tmp_dst); err = -1; goto out; } for (i = 0; g.gl_pathv[i] && !interrupted; i++) { if (stat(g.gl_pathv[i], &sb) == -1) { err = -1; error("stat %s: %s", g.gl_pathv[i], strerror(errno)); continue; } tmp = xstrdup(g.gl_pathv[i]); if ((filename = basename(tmp)) == NULL) { error("basename %s: %s", tmp, strerror(errno)); free(tmp); err = -1; goto out; } if (g.gl_matchc == 1 && tmp_dst) { /* If directory specified, append filename */ if (dst_is_dir) abs_dst = path_append(tmp_dst, filename); else abs_dst = xstrdup(tmp_dst); } else if (tmp_dst) { abs_dst = path_append(tmp_dst, filename); } else { abs_dst = make_absolute(xstrdup(filename), pwd); } free(tmp); resume |= global_aflag; 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) err = -1; } else { if (do_upload(conn, g.gl_pathv[i], abs_dst, pflag || global_pflag, resume, fflag || global_fflag) == -1) err = -1; } } out: free(abs_dst); free(tmp_dst); globfree(&g); return(err); } static int sdirent_comp(const void *aa, const void *bb) { SFTP_DIRENT *a = *(SFTP_DIRENT **)aa; SFTP_DIRENT *b = *(SFTP_DIRENT **)bb; int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1; #define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1)) if (sort_flag & LS_NAME_SORT) return (rmul * strcmp(a->filename, b->filename)); else if (sort_flag & LS_TIME_SORT) return (rmul * NCMP(a->a.mtime, b->a.mtime)); else if (sort_flag & LS_SIZE_SORT) return (rmul * NCMP(a->a.size, b->a.size)); fatal("Unknown ls sort type"); } /* sftp ls.1 replacement for directories */ static int do_ls_dir(struct sftp_conn *conn, const char *path, const char *strip_path, int lflag) { int n; u_int c = 1, colspace = 0, columns = 1; SFTP_DIRENT **d; if ((n = do_readdir(conn, path, &d)) != 0) return (n); if (!(lflag & LS_SHORT_VIEW)) { u_int m = 0, width = 80; struct winsize ws; char *tmp; /* Count entries for sort and find longest filename */ for (n = 0; d[n] != NULL; n++) { if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL)) m = MAXIMUM(m, strlen(d[n]->filename)); } /* Add any subpath that also needs to be counted */ tmp = path_strip(path, strip_path); m += strlen(tmp); free(tmp); if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) width = ws.ws_col; columns = width / (m + 2); columns = MAXIMUM(columns, 1); colspace = width / columns; colspace = MINIMUM(colspace, width); } if (lflag & SORT_FLAGS) { for (n = 0; d[n] != NULL; n++) ; /* count entries */ sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT); qsort(d, n, sizeof(*d), sdirent_comp); } for (n = 0; d[n] != NULL && !interrupted; n++) { char *tmp, *fname; if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL)) continue; tmp = path_append(path, d[n]->filename); fname = path_strip(tmp, strip_path); free(tmp); if (lflag & LS_LONG_VIEW) { if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) { char *lname; struct stat sb; memset(&sb, 0, sizeof(sb)); attrib_to_stat(&d[n]->a, &sb); lname = ls_file(fname, &sb, 1, (lflag & LS_SI_UNITS)); mprintf("%s\n", lname); free(lname); } else mprintf("%s\n", d[n]->longname); } else { mprintf("%-*s", colspace, fname); if (c >= columns) { printf("\n"); c = 1; } else c++; } free(fname); } if (!(lflag & LS_LONG_VIEW) && (c != 1)) printf("\n"); free_sftp_dirents(d); return (0); } static int sglob_comp(const void *aa, const void *bb) { u_int a = *(const u_int *)aa; u_int b = *(const u_int *)bb; const char *ap = sort_glob->gl_pathv[a]; const char *bp = sort_glob->gl_pathv[b]; const struct stat *as = sort_glob->gl_statv[a]; const struct stat *bs = sort_glob->gl_statv[b]; int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1; #define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1)) if (sort_flag & LS_NAME_SORT) return (rmul * strcmp(ap, bp)); else if (sort_flag & LS_TIME_SORT) { #if defined(HAVE_STRUCT_STAT_ST_MTIM) if (timespeccmp(&as->st_mtim, &bs->st_mtim, ==)) return 0; return timespeccmp(&as->st_mtim, &bs->st_mtim, <) ? rmul : -rmul; #elif defined(HAVE_STRUCT_STAT_ST_MTIME) return (rmul * NCMP(as->st_mtime, bs->st_mtime)); #else return rmul * 1; #endif } else if (sort_flag & LS_SIZE_SORT) return (rmul * NCMP(as->st_size, bs->st_size)); fatal("Unknown ls sort type"); } /* sftp ls.1 replacement which handles path globs */ static int do_globbed_ls(struct sftp_conn *conn, const char *path, const char *strip_path, int lflag) { char *fname, *lname; glob_t g; int err, r; struct winsize ws; u_int i, j, nentries, *indices = NULL, c = 1; u_int colspace = 0, columns = 1, m = 0, width = 80; memset(&g, 0, sizeof(g)); if ((r = remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT|GLOB_NOSORT, NULL, &g)) != 0 || (g.gl_pathc && !g.gl_matchc)) { if (g.gl_pathc) globfree(&g); if (r == GLOB_NOSPACE) { error("Can't ls: Too many matches for \"%s\"", path); } else { error("Can't ls: \"%s\" not found", path); } return -1; } if (interrupted) goto out; /* * If the glob returns a single match and it is a directory, * then just list its contents. */ if (g.gl_matchc == 1 && g.gl_statv[0] != NULL && S_ISDIR(g.gl_statv[0]->st_mode)) { err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag); globfree(&g); return err; } if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) width = ws.ws_col; if (!(lflag & LS_SHORT_VIEW)) { /* Count entries for sort and find longest filename */ for (i = 0; g.gl_pathv[i]; i++) m = MAXIMUM(m, strlen(g.gl_pathv[i])); columns = width / (m + 2); columns = MAXIMUM(columns, 1); colspace = width / columns; } /* * Sorting: rather than mess with the contents of glob_t, prepare * an array of indices into it and sort that. For the usual * unsorted case, the indices are just the identity 1=1, 2=2, etc. */ for (nentries = 0; g.gl_pathv[nentries] != NULL; nentries++) ; /* count entries */ indices = calloc(nentries, sizeof(*indices)); for (i = 0; i < nentries; i++) indices[i] = i; if (lflag & SORT_FLAGS) { sort_glob = &g; sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT); qsort(indices, nentries, sizeof(*indices), sglob_comp); sort_glob = NULL; } for (j = 0; j < nentries && !interrupted; j++) { i = indices[j]; fname = path_strip(g.gl_pathv[i], strip_path); if (lflag & LS_LONG_VIEW) { if (g.gl_statv[i] == NULL) { error("no stat information for %s", fname); continue; } lname = ls_file(fname, g.gl_statv[i], 1, (lflag & LS_SI_UNITS)); mprintf("%s\n", lname); free(lname); } else { mprintf("%-*s", colspace, fname); if (c >= columns) { printf("\n"); c = 1; } else c++; } free(fname); } if (!(lflag & LS_LONG_VIEW) && (c != 1)) printf("\n"); out: if (g.gl_pathc) globfree(&g); free(indices); return 0; } static int do_df(struct sftp_conn *conn, const char *path, int hflag, int iflag) { struct sftp_statvfs st; char s_used[FMT_SCALED_STRSIZE], s_avail[FMT_SCALED_STRSIZE]; char s_root[FMT_SCALED_STRSIZE], s_total[FMT_SCALED_STRSIZE]; char s_icapacity[16], s_dcapacity[16]; if (do_statvfs(conn, path, &st, 1) == -1) return -1; if (st.f_files == 0) strlcpy(s_icapacity, "ERR", sizeof(s_icapacity)); else { snprintf(s_icapacity, sizeof(s_icapacity), "%3llu%%", (unsigned long long)(100 * (st.f_files - st.f_ffree) / st.f_files)); } if (st.f_blocks == 0) strlcpy(s_dcapacity, "ERR", sizeof(s_dcapacity)); else { snprintf(s_dcapacity, sizeof(s_dcapacity), "%3llu%%", (unsigned long long)(100 * (st.f_blocks - st.f_bfree) / st.f_blocks)); } if (iflag) { printf(" Inodes Used Avail " "(root) %%Capacity\n"); printf("%11llu %11llu %11llu %11llu %s\n", (unsigned long long)st.f_files, (unsigned long long)(st.f_files - st.f_ffree), (unsigned long long)st.f_favail, (unsigned long long)st.f_ffree, s_icapacity); } else if (hflag) { strlcpy(s_used, "error", sizeof(s_used)); strlcpy(s_avail, "error", sizeof(s_avail)); strlcpy(s_root, "error", sizeof(s_root)); strlcpy(s_total, "error", sizeof(s_total)); fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used); fmt_scaled(st.f_bavail * st.f_frsize, s_avail); fmt_scaled(st.f_bfree * st.f_frsize, s_root); fmt_scaled(st.f_blocks * st.f_frsize, s_total); printf(" Size Used Avail (root) %%Capacity\n"); printf("%7sB %7sB %7sB %7sB %s\n", s_total, s_used, s_avail, s_root, s_dcapacity); } else { printf(" Size Used Avail " "(root) %%Capacity\n"); printf("%12llu %12llu %12llu %12llu %s\n", (unsigned long long)(st.f_frsize * st.f_blocks / 1024), (unsigned long long)(st.f_frsize * (st.f_blocks - st.f_bfree) / 1024), (unsigned long long)(st.f_frsize * st.f_bavail / 1024), (unsigned long long)(st.f_frsize * st.f_bfree / 1024), s_dcapacity); } return 0; } /* * Undo escaping of glob sequences in place. Used to undo extra escaping * applied in makeargv() when the string is destined for a function that * does not glob it. */ static void undo_glob_escape(char *s) { size_t i, j; for (i = j = 0;;) { if (s[i] == '\0') { s[j] = '\0'; return; } if (s[i] != '\\') { s[j++] = s[i++]; continue; } /* s[i] == '\\' */ ++i; switch (s[i]) { case '?': case '[': case '*': case '\\': s[j++] = s[i++]; break; case '\0': s[j++] = '\\'; s[j] = '\0'; return; default: s[j++] = '\\'; s[j++] = s[i++]; break; } } } /* * Split a string into an argument vector using sh(1)-style quoting, * comment and escaping rules, but with some tweaks to handle glob(3) * wildcards. * The "sloppy" flag allows for recovery from missing terminating quote, for * use in parsing incomplete commandlines during tab autocompletion. * * Returns NULL on error or a NULL-terminated array of arguments. * * If "lastquote" is not NULL, the quoting character used for the last * argument is placed in *lastquote ("\0", "'" or "\""). * * If "terminated" is not NULL, *terminated will be set to 1 when the * last argument's quote has been properly terminated or 0 otherwise. * This parameter is only of use if "sloppy" is set. */ #define MAXARGS 128 #define MAXARGLEN 8192 static char ** makeargv(const char *arg, int *argcp, int sloppy, char *lastquote, u_int *terminated) { int argc, quot; size_t i, j; static char argvs[MAXARGLEN]; static char *argv[MAXARGS + 1]; enum { MA_START, MA_SQUOTE, MA_DQUOTE, MA_UNQUOTED } state, q; *argcp = argc = 0; if (strlen(arg) > sizeof(argvs) - 1) { args_too_longs: error("string too long"); return NULL; } if (terminated != NULL) *terminated = 1; if (lastquote != NULL) *lastquote = '\0'; state = MA_START; i = j = 0; for (;;) { if ((size_t)argc >= sizeof(argv) / sizeof(*argv)){ error("Too many arguments."); return NULL; } if (isspace((unsigned char)arg[i])) { if (state == MA_UNQUOTED) { /* Terminate current argument */ argvs[j++] = '\0'; argc++; state = MA_START; } else if (state != MA_START) argvs[j++] = arg[i]; } else if (arg[i] == '"' || arg[i] == '\'') { q = arg[i] == '"' ? MA_DQUOTE : MA_SQUOTE; if (state == MA_START) { argv[argc] = argvs + j; state = q; if (lastquote != NULL) *lastquote = arg[i]; } else if (state == MA_UNQUOTED) state = q; else if (state == q) state = MA_UNQUOTED; else argvs[j++] = arg[i]; } else if (arg[i] == '\\') { if (state == MA_SQUOTE || state == MA_DQUOTE) { quot = state == MA_SQUOTE ? '\'' : '"'; /* Unescape quote we are in */ /* XXX support \n and friends? */ if (arg[i + 1] == quot) { i++; argvs[j++] = arg[i]; } else if (arg[i + 1] == '?' || arg[i + 1] == '[' || arg[i + 1] == '*') { /* * Special case for sftp: append * double-escaped glob sequence - * glob will undo one level of * escaping. NB. string can grow here. */ if (j >= sizeof(argvs) - 5) goto args_too_longs; argvs[j++] = '\\'; argvs[j++] = arg[i++]; argvs[j++] = '\\'; argvs[j++] = arg[i]; } else { argvs[j++] = arg[i++]; argvs[j++] = arg[i]; } } else { if (state == MA_START) { argv[argc] = argvs + j; state = MA_UNQUOTED; if (lastquote != NULL) *lastquote = '\0'; } if (arg[i + 1] == '?' || arg[i + 1] == '[' || arg[i + 1] == '*' || arg[i + 1] == '\\') { /* * Special case for sftp: append * escaped glob sequence - * glob will undo one level of * escaping. */ argvs[j++] = arg[i++]; argvs[j++] = arg[i]; } else { /* Unescape everything */ /* XXX support \n and friends? */ i++; argvs[j++] = arg[i]; } } } else if (arg[i] == '#') { if (state == MA_SQUOTE || state == MA_DQUOTE) argvs[j++] = arg[i]; else goto string_done; } else if (arg[i] == '\0') { if (state == MA_SQUOTE || state == MA_DQUOTE) { if (sloppy) { state = MA_UNQUOTED; if (terminated != NULL) *terminated = 0; goto string_done; } error("Unterminated quoted argument"); return NULL; } string_done: if (state == MA_UNQUOTED) { argvs[j++] = '\0'; argc++; } break; } else { if (state == MA_START) { argv[argc] = argvs + j; state = MA_UNQUOTED; if (lastquote != NULL) *lastquote = '\0'; } if ((state == MA_SQUOTE || state == MA_DQUOTE) && (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) { /* * Special case for sftp: escape quoted * glob(3) wildcards. NB. string can grow * here. */ if (j >= sizeof(argvs) - 3) goto args_too_longs; argvs[j++] = '\\'; argvs[j++] = arg[i]; } else argvs[j++] = arg[i]; } i++; } *argcp = argc; return argv; } static int parse_args(const char **cpp, int *ignore_errors, int *disable_echo, int *aflag, int *fflag, int *hflag, int *iflag, int *lflag, int *pflag, int *rflag, int *sflag, unsigned long *n_arg, char **path1, char **path2) { const char *cmd, *cp = *cpp; char *cp2, **argv; int base = 0; long long ll; int path1_mandatory = 0, i, cmdnum, optidx, argc; /* Skip leading whitespace */ cp = cp + strspn(cp, WHITESPACE); /* * Check for leading '-' (disable error processing) and '@' (suppress * command echo) */ *ignore_errors = 0; *disable_echo = 0; for (;*cp != '\0'; cp++) { if (*cp == '-') { *ignore_errors = 1; } else if (*cp == '@') { *disable_echo = 1; } else { /* all other characters terminate prefix processing */ break; } } cp = cp + strspn(cp, WHITESPACE); /* Ignore blank lines and lines which begin with comment '#' char */ if (*cp == '\0' || *cp == '#') return (0); if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL) return -1; /* Figure out which command we have */ for (i = 0; cmds[i].c != NULL; i++) { if (argv[0] != NULL && strcasecmp(cmds[i].c, argv[0]) == 0) break; } cmdnum = cmds[i].n; cmd = cmds[i].c; /* Special case */ if (*cp == '!') { cp++; cmdnum = I_SHELL; } else if (cmdnum == -1) { error("Invalid command."); return -1; } /* Get arguments and parse flags */ *aflag = *fflag = *hflag = *iflag = *lflag = *pflag = 0; *rflag = *sflag = 0; *path1 = *path2 = NULL; optidx = 1; switch (cmdnum) { case I_GET: case I_REGET: case I_REPUT: case I_PUT: if ((optidx = parse_getput_flags(cmd, argv, argc, aflag, fflag, pflag, rflag)) == -1) return -1; /* Get first pathname (mandatory) */ if (argc - optidx < 1) { error("You must specify at least one path after a " "%s command.", cmd); return -1; } *path1 = xstrdup(argv[optidx]); /* Get second pathname (optional) */ if (argc - optidx > 1) { *path2 = xstrdup(argv[optidx + 1]); /* Destination is not globbed */ undo_glob_escape(*path2); } break; case I_LINK: if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1) return -1; goto parse_two_paths; + case I_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); remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i] && !interrupted; i++) { if (!quiet) mprintf("Removing %s\n", g.gl_pathv[i]); err = do_rm(conn, g.gl_pathv[i]); if (err != 0 && err_abort) break; } break; case I_MKDIR: path1 = make_absolute(path1, *pwd); attrib_clear(&a); a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; a.perm = 0777; err = do_mkdir(conn, path1, &a, 1); break; case I_RMDIR: path1 = make_absolute(path1, *pwd); err = do_rmdir(conn, path1); break; case I_CHDIR: if (path1 == NULL || *path1 == '\0') path1 = xstrdup(startdir); path1 = make_absolute(path1, *pwd); if ((tmp = do_realpath(conn, path1)) == NULL) { err = 1; break; } if ((aa = do_stat(conn, tmp, 0)) == NULL) { free(tmp); err = 1; break; } if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { error("Can't change directory: Can't check target"); free(tmp); err = 1; break; } if (!S_ISDIR(aa->perm)) { error("Can't change directory: \"%s\" is not " "a directory", tmp); free(tmp); err = 1; break; } free(*pwd); *pwd = tmp; break; case I_LS: if (!path1) { do_ls_dir(conn, *pwd, *pwd, lflag); break; } /* Strip pwd off beginning of non-absolute paths */ tmp = NULL; if (!path_absolute(path1)) tmp = *pwd; path1 = make_absolute(path1, *pwd); err = do_globbed_ls(conn, path1, tmp, lflag); break; case I_DF: /* Default to current directory if no path specified */ if (path1 == NULL) path1 = xstrdup(*pwd); path1 = make_absolute(path1, *pwd); err = do_df(conn, path1, hflag, iflag); break; case I_LCHDIR: if (path1 == NULL || *path1 == '\0') path1 = xstrdup("~"); tmp = tilde_expand_filename(path1, getuid()); free(path1); path1 = tmp; if (chdir(path1) == -1) { error("Couldn't change local directory to " "\"%s\": %s", path1, strerror(errno)); err = 1; } break; case I_LMKDIR: if (mkdir(path1, 0777) == -1) { error("Couldn't create local directory " "\"%s\": %s", path1, strerror(errno)); err = 1; } break; case I_LLS: local_do_ls(cmd); break; case I_SHELL: local_do_shell(cmd); break; case I_LUMASK: umask(n_arg); printf("Local umask: %03lo\n", n_arg); break; case I_CHMOD: path1 = make_absolute(path1, *pwd); attrib_clear(&a); a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; a.perm = n_arg; remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i] && !interrupted; i++) { if (!quiet) mprintf("Changing mode on %s\n", g.gl_pathv[i]); err = (hflag ? do_lsetstat : do_setstat)(conn, g.gl_pathv[i], &a); if (err != 0 && err_abort) break; } break; case I_CHOWN: case I_CHGRP: path1 = make_absolute(path1, *pwd); remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i] && !interrupted; i++) { if (!(aa = (hflag ? do_lstat : do_stat)(conn, g.gl_pathv[i], 0))) { if (err_abort) { err = -1; break; } else continue; } if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { error("Can't get current ownership of " "remote file \"%s\"", g.gl_pathv[i]); if (err_abort) { err = -1; break; } else continue; } aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; if (cmdnum == I_CHOWN) { if (!quiet) mprintf("Changing owner on %s\n", g.gl_pathv[i]); aa->uid = n_arg; } else { if (!quiet) mprintf("Changing group on %s\n", g.gl_pathv[i]); aa->gid = n_arg; } err = (hflag ? do_lsetstat : do_setstat)(conn, g.gl_pathv[i], aa); if (err != 0 && err_abort) break; } break; case I_PWD: mprintf("Remote working directory: %s\n", *pwd); break; case I_LPWD: if (!getcwd(path_buf, sizeof(path_buf))) { error("Couldn't get local cwd: %s", strerror(errno)); err = -1; break; } mprintf("Local working directory: %s\n", path_buf); break; case I_QUIT: /* Processed below */ break; case I_HELP: help(); break; case I_VERSION: printf("SFTP protocol version %u\n", sftp_proto_version(conn)); break; case I_PROGRESS: showprogress = !showprogress; if (showprogress) printf("Progress meter enabled\n"); else printf("Progress meter disabled\n"); break; default: fatal("%d is not implemented", cmdnum); } if (g.gl_pathc) globfree(&g); free(path1); free(path2); /* If an unignored error occurs in batch mode we should abort. */ if (err_abort && err != 0) return (-1); else if (cmdnum == I_QUIT) return (1); return (0); } #ifdef USE_LIBEDIT static char * prompt(EditLine *el) { return ("sftp> "); } /* Display entries in 'list' after skipping the first 'len' chars */ static void complete_display(char **list, u_int len) { u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen; struct winsize ws; char *tmp; /* Count entries for sort and find longest */ for (y = 0; list[y]; y++) m = MAXIMUM(m, strlen(list[y])); if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) width = ws.ws_col; m = m > len ? m - len : 0; columns = width / (m + 2); columns = MAXIMUM(columns, 1); colspace = width / columns; colspace = MINIMUM(colspace, width); printf("\n"); m = 1; for (y = 0; list[y]; y++) { llen = strlen(list[y]); tmp = llen > len ? list[y] + len : ""; mprintf("%-*s", colspace, tmp); if (m >= columns) { printf("\n"); m = 1; } else m++; } printf("\n"); } /* * Given a "list" of words that begin with a common prefix of "word", * attempt to find an autocompletion to extends "word" by the next * characters common to all entries in "list". */ static char * complete_ambiguous(const char *word, char **list, size_t count) { if (word == NULL) return NULL; if (count > 0) { u_int y, matchlen = strlen(list[0]); /* Find length of common stem */ for (y = 1; list[y]; y++) { u_int x; for (x = 0; x < matchlen; x++) if (list[0][x] != list[y][x]) break; matchlen = x; } if (matchlen > strlen(word)) { char *tmp = xstrdup(list[0]); tmp[matchlen] = '\0'; return tmp; } } return xstrdup(word); } /* Autocomplete a sftp command */ static int complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, int terminated) { u_int y, count = 0, cmdlen, tmplen; char *tmp, **list, argterm[3]; const LineInfo *lf; list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *)); /* No command specified: display all available commands */ if (cmd == NULL) { for (y = 0; cmds[y].c; y++) list[count++] = xstrdup(cmds[y].c); list[count] = NULL; complete_display(list, 0); for (y = 0; list[y] != NULL; y++) free(list[y]); free(list); return count; } /* Prepare subset of commands that start with "cmd" */ cmdlen = strlen(cmd); for (y = 0; cmds[y].c; y++) { if (!strncasecmp(cmd, cmds[y].c, cmdlen)) list[count++] = xstrdup(cmds[y].c); } list[count] = NULL; if (count == 0) { free(list); return 0; } /* Complete ambiguous command */ tmp = complete_ambiguous(cmd, list, count); if (count > 1) complete_display(list, 0); for (y = 0; list[y]; y++) free(list[y]); free(list); if (tmp != NULL) { tmplen = strlen(tmp); cmdlen = strlen(cmd); /* If cmd may be extended then do so */ if (tmplen > cmdlen) if (el_insertstr(el, tmp + cmdlen) == -1) fatal("el_insertstr failed."); lf = el_line(el); /* Terminate argument cleanly */ if (count == 1) { y = 0; if (!terminated) argterm[y++] = quote; if (lastarg || *(lf->cursor) != ' ') argterm[y++] = ' '; argterm[y] = '\0'; if (y > 0 && el_insertstr(el, argterm) == -1) fatal("el_insertstr failed."); } free(tmp); } return count; } /* * Determine whether a particular sftp command's arguments (if any) * represent local or remote files. */ static int complete_is_remote(char *cmd) { int i; if (cmd == NULL) return -1; for (i = 0; cmds[i].c; i++) { if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c))) return cmds[i].t; } return -1; } /* Autocomplete a filename "file" */ static int complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, char *file, int remote, int lastarg, char quote, int terminated) { glob_t g; char *tmp, *tmp2, ins[8]; u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs; int clen; const LineInfo *lf; /* Glob from "file" location */ if (file == NULL) tmp = xstrdup("*"); else xasprintf(&tmp, "%s*", file); /* Check if the path is absolute. */ isabs = path_absolute(tmp); memset(&g, 0, sizeof(g)); if (remote != LOCAL) { tmp = make_absolute(tmp, remote_path); remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); } else glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); /* Determine length of pwd so we can trim completion display */ for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) { /* Terminate counting on first unescaped glob metacharacter */ if (tmp[tmplen] == '*' || tmp[tmplen] == '?') { if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0') hadglob = 1; break; } if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0') tmplen++; if (tmp[tmplen] == '/') pwdlen = tmplen + 1; /* track last seen '/' */ } free(tmp); tmp = NULL; if (g.gl_matchc == 0) goto out; if (g.gl_matchc > 1) complete_display(g.gl_pathv, pwdlen); /* Don't try to extend globs */ if (file == NULL || hadglob) goto out; tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc); tmp = path_strip(tmp2, isabs ? NULL : remote_path); free(tmp2); if (tmp == NULL) goto out; tmplen = strlen(tmp); filelen = strlen(file); /* Count the number of escaped characters in the input string. */ cesc = isesc = 0; for (i = 0; i < filelen; i++) { if (!isesc && file[i] == '\\' && i + 1 < filelen){ isesc = 1; cesc++; } else isesc = 0; } if (tmplen > (filelen - cesc)) { tmp2 = tmp + filelen - cesc; len = strlen(tmp2); /* quote argument on way out */ for (i = 0; i < len; i += clen) { if ((clen = mblen(tmp2 + i, len - i)) < 0 || (size_t)clen > sizeof(ins) - 2) fatal("invalid multibyte character"); ins[0] = '\\'; memcpy(ins + 1, tmp2 + i, clen); ins[clen + 1] = '\0'; switch (tmp2[i]) { case '\'': case '"': case '\\': case '\t': case '[': case ' ': case '#': case '*': if (quote == '\0' || tmp2[i] == quote) { if (el_insertstr(el, ins) == -1) fatal("el_insertstr " "failed."); break; } /* FALLTHROUGH */ default: if (el_insertstr(el, ins + 1) == -1) fatal("el_insertstr failed."); break; } } } lf = el_line(el); if (g.gl_matchc == 1) { i = 0; if (!terminated && quote != '\0') ins[i++] = quote; if (*(lf->cursor - 1) != '/' && (lastarg || *(lf->cursor) != ' ')) ins[i++] = ' '; ins[i] = '\0'; if (i > 0 && el_insertstr(el, ins) == -1) fatal("el_insertstr failed."); } free(tmp); out: globfree(&g); return g.gl_matchc; } /* tab-completion hook function, called via libedit */ static unsigned char complete(EditLine *el, int ch) { char **argv, *line, quote; int argc, carg; u_int cursor, len, terminated, ret = CC_ERROR; const LineInfo *lf; struct complete_ctx *complete_ctx; lf = el_line(el); if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0) fatal_f("el_get failed"); /* Figure out which argument the cursor points to */ cursor = lf->cursor - lf->buffer; line = xmalloc(cursor + 1); memcpy(line, lf->buffer, cursor); line[cursor] = '\0'; argv = makeargv(line, &carg, 1, "e, &terminated); free(line); /* Get all the arguments on the line */ len = lf->lastchar - lf->buffer; line = xmalloc(len + 1); memcpy(line, lf->buffer, len); line[len] = '\0'; argv = makeargv(line, &argc, 1, NULL, NULL); /* Ensure cursor is at EOL or a argument boundary */ if (line[cursor] != ' ' && line[cursor] != '\0' && line[cursor] != '\n') { free(line); return ret; } if (carg == 0) { /* Show all available commands */ complete_cmd_parse(el, NULL, argc == carg, '\0', 1); ret = CC_REDISPLAY; } else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ') { /* Handle the command parsing */ if (complete_cmd_parse(el, argv[0], argc == carg, quote, terminated) != 0) ret = CC_REDISPLAY; } else if (carg >= 1) { /* Handle file parsing */ int remote = complete_is_remote(argv[0]); char *filematch = NULL; if (carg > 1 && line[cursor-1] != ' ') filematch = argv[carg - 1]; if (remote != 0 && complete_match(el, complete_ctx->conn, *complete_ctx->remote_pathp, filematch, remote, carg == argc, quote, terminated) != 0) ret = CC_REDISPLAY; } free(line); return ret; } #endif /* USE_LIBEDIT */ static int interactive_loop(struct sftp_conn *conn, char *file1, char *file2) { char *remote_path; char *dir = NULL, *startdir = NULL; char cmd[2048]; int err, interactive; EditLine *el = NULL; #ifdef USE_LIBEDIT History *hl = NULL; HistEvent hev; extern char *__progname; struct complete_ctx complete_ctx; if (!batchmode && isatty(STDIN_FILENO)) { if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL) fatal("Couldn't initialise editline"); if ((hl = history_init()) == NULL) fatal("Couldn't initialise editline history"); history(hl, &hev, H_SETSIZE, 100); el_set(el, EL_HIST, history, hl); el_set(el, EL_PROMPT, prompt); el_set(el, EL_EDITOR, "emacs"); el_set(el, EL_TERMINAL, NULL); el_set(el, EL_SIGNAL, 1); el_source(el, NULL); /* Tab Completion */ el_set(el, EL_ADDFN, "ftp-complete", "Context sensitive argument completion", complete); complete_ctx.conn = conn; complete_ctx.remote_pathp = &remote_path; el_set(el, EL_CLIENTDATA, (void*)&complete_ctx); el_set(el, EL_BIND, "^I", "ftp-complete", NULL); /* enable ctrl-left-arrow and ctrl-right-arrow */ el_set(el, EL_BIND, "\\e[1;5C", "em-next-word", NULL); el_set(el, EL_BIND, "\\e\\e[C", "em-next-word", NULL); el_set(el, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL); el_set(el, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL); /* make ^w match ksh behaviour */ el_set(el, EL_BIND, "^w", "ed-delete-prev-word", NULL); } #endif /* USE_LIBEDIT */ remote_path = do_realpath(conn, "."); if (remote_path == NULL) fatal("Need cwd"); startdir = xstrdup(remote_path); if (file1 != NULL) { dir = xstrdup(file1); dir = make_absolute(dir, remote_path); if (remote_is_dir(conn, dir) && file2 == NULL) { if (!quiet) mprintf("Changing to: %s\n", dir); snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); if (parse_dispatch_command(conn, cmd, &remote_path, startdir, 1, 0) != 0) { free(dir); free(startdir); free(remote_path); free(conn); return (-1); } } else { /* XXX this is wrong wrt quoting */ snprintf(cmd, sizeof cmd, "get%s %s%s%s", global_aflag ? " -a" : "", dir, file2 == NULL ? "" : " ", file2 == NULL ? "" : file2); err = parse_dispatch_command(conn, cmd, &remote_path, startdir, 1, 0); free(dir); free(startdir); free(remote_path); free(conn); return (err); } free(dir); } setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(infile, NULL, _IOLBF, 0); interactive = !batchmode && isatty(STDIN_FILENO); err = 0; for (;;) { 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" " [-J destination] [-l limit] [-o ssh_option] [-P port]\n" " [-R num_requests] [-S program] [-s subsystem | sftp_server]\n" " destination\n", __progname); exit(1); } int main(int argc, char **argv) { int in, out, ch, err, tmp, port = -1, noisy = 0; char *host = NULL, *user, *cp, *file2 = NULL; int debug_level = 0; char *file1 = NULL, *sftp_server = NULL; char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; const char *errstr; LogLevel ll = SYSLOG_LEVEL_INFO; arglist args; extern int optind; extern char *optarg; struct sftp_conn *conn; size_t copy_buffer_len = 0; size_t num_requests = 0; long long limit_kbps = 0; /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); msetlocale(); seed_rng(); __progname = ssh_get_progname(argv[0]); memset(&args, '\0', sizeof(args)); args.list = NULL; addargs(&args, "%s", ssh_program); addargs(&args, "-oForwardX11 no"); addargs(&args, "-oPermitLocalCommand no"); addargs(&args, "-oClearAllForwardings yes"); ll = SYSLOG_LEVEL_INFO; infile = stdin; while ((ch = getopt(argc, argv, "1246AafhNpqrvCc:D:i:l:o:s:S:b:B:F:J:P:R:")) != -1) { switch (ch) { /* Passed through to ssh(1) */ case 'A': case '4': case '6': case 'C': addargs(&args, "-%c", ch); break; /* Passed through to ssh(1) with argument */ case 'F': case 'J': case 'c': case 'i': case 'o': addargs(&args, "-%c", ch); addargs(&args, "%s", optarg); break; case 'q': ll = SYSLOG_LEVEL_ERROR; quiet = 1; showprogress = 0; addargs(&args, "-%c", ch); break; case 'P': port = a2port(optarg); if (port <= 0) fatal("Bad port \"%s\"\n", optarg); break; case 'v': if (debug_level < 3) { addargs(&args, "-v"); ll = SYSLOG_LEVEL_DEBUG1 + debug_level; } debug_level++; break; case '1': fatal("SSH protocol v.1 is no longer supported"); break; case '2': /* accept silently */ break; case 'a': global_aflag = 1; break; case 'B': copy_buffer_len = strtol(optarg, &cp, 10); if (copy_buffer_len == 0 || *cp != '\0') fatal("Invalid buffer size \"%s\"", optarg); break; case 'b': if (batchmode) fatal("Batch file already specified."); /* Allow "-" as stdin */ if (strcmp(optarg, "-") != 0 && (infile = fopen(optarg, "r")) == NULL) fatal("%s (%s).", strerror(errno), optarg); showprogress = 0; quiet = batchmode = 1; addargs(&args, "-obatchmode yes"); break; case 'f': global_fflag = 1; break; case 'N': noisy = 1; /* Used to clear quiet mode after getopt */ break; case 'p': global_pflag = 1; break; case 'D': sftp_direct = optarg; break; case 'l': limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024, &errstr); if (errstr != NULL) usage(); limit_kbps *= 1024; /* kbps */ break; case 'r': global_rflag = 1; break; case 'R': num_requests = strtol(optarg, &cp, 10); if (num_requests == 0 || *cp != '\0') fatal("Invalid number of requests \"%s\"", optarg); break; case 's': sftp_server = optarg; break; case 'S': ssh_program = optarg; replacearg(&args, 0, "%s", ssh_program); break; case 'h': default: usage(); } } /* Do this last because we want the user to be able to override it */ addargs(&args, "-oForwardAgent no"); if (!isatty(STDERR_FILENO)) showprogress = 0; if (noisy) quiet = 0; log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); if (sftp_direct == NULL) { if (optind == argc || argc > (optind + 2)) usage(); argv += optind; switch (parse_uri("sftp", *argv, &user, &host, &tmp, &file1)) { case -1: usage(); break; case 0: if (tmp != -1) port = tmp; break; default: /* Try with user, host and path. */ if (parse_user_host_path(*argv, &user, &host, &file1) == 0) break; /* Try with user and host. */ if (parse_user_host_port(*argv, &user, &host, NULL) == 0) break; /* Treat as a plain hostname. */ host = xstrdup(*argv); host = cleanhostname(host); break; } file2 = *(argv + 1); if (!*host) { fprintf(stderr, "Missing hostname\n"); usage(); } if (port != -1) addargs(&args, "-oPort %d", port); if (user != NULL) { addargs(&args, "-l"); addargs(&args, "%s", user); } /* no subsystem if the server-spec contains a '/' */ if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) addargs(&args, "-s"); addargs(&args, "--"); addargs(&args, "%s", host); addargs(&args, "%s", (sftp_server != NULL ? sftp_server : "sftp")); connect_to_server(ssh_program, args.list, &in, &out); } else { args.list = NULL; addargs(&args, "sftp-server"); connect_to_server(sftp_direct, args.list, &in, &out); } freeargs(&args); conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps); if (conn == NULL) fatal("Couldn't initialise connection to server"); if (!quiet) { if (sftp_direct == NULL) fprintf(stderr, "Connected to %s.\n", host); else fprintf(stderr, "Attached to %s.\n", sftp_direct); } err = interactive_loop(conn, file1, file2); #if !defined(USE_PIPES) shutdown(in, SHUT_RDWR); shutdown(out, SHUT_RDWR); #endif close(in); close(out); if (batchmode) fclose(infile); while (waitpid(sshpid, NULL, 0) == -1 && sshpid > 1) if (errno != EINTR) fatal("Couldn't wait for ssh process: %s", strerror(errno)); exit(err == 0 ? 0 : 1); } diff --git a/crypto/openssh/ssh-agent.1 b/crypto/openssh/ssh-agent.1 index ed73e0084a4a..8844b2eb45e8 100644 --- a/crypto/openssh/ssh-agent.1 +++ b/crypto/openssh/ssh-agent.1 @@ -1,236 +1,236 @@ -.\" $OpenBSD: ssh-agent.1,v 1.72 2020/06/22 05:52:05 djm Exp $ +.\" $OpenBSD: ssh-agent.1,v 1.73 2022/03/31 17:27:27 naddy Exp $ .\" $FreeBSD$ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , 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: June 22 2020 $ +.Dd $Mdocdate: March 31 2022 $ .Dt SSH-AGENT 1 .Os .Sh NAME .Nm ssh-agent .Nd OpenSSH authentication agent .Sh SYNOPSIS .Nm ssh-agent .Op Fl c | s .Op Fl \&Ddx .Op Fl a Ar bind_address .Op Fl E Ar fingerprint_hash .Op Fl P Ar allowed_providers .Op Fl t Ar life .Nm ssh-agent .Op Fl a Ar bind_address .Op Fl E Ar fingerprint_hash .Op Fl P Ar allowed_providers .Op Fl t Ar life .Ar command Op Ar arg ... .Nm ssh-agent .Op Fl c | s .Fl k .Sh DESCRIPTION .Nm 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 .Xr ssh 1 . .Pp The options are as follows: .Bl -tag -width Ds .It Fl a Ar bind_address Bind the agent to the .Ux Ns -domain socket .Ar bind_address . The default is .Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt . .It Fl c Generate C-shell commands on .Dv stdout . This is the default if .Ev SHELL looks like it's a csh style of shell. .It Fl D Foreground mode. -When this option is specified +When this option is specified, .Nm will not fork. .It Fl d Debug mode. -When this option is specified +When this option is specified, .Nm will not fork and will write debug information to standard error. .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 k Kill the current agent (given by the .Ev SSH_AGENT_PID environment variable). .It Fl P Ar 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 .Fl S or .Fl s options to .Xr ssh-add 1 . Libraries that do not match the pattern list will be refused. See PATTERNS in .Xr ssh_config 5 for a description of pattern-list syntax. The default list is .Dq /usr/lib/*,/usr/local/lib/* . .It Fl s Generate Bourne shell commands on .Dv stdout . This is the default if .Ev SHELL does not look like it's a csh style of shell. .It Fl t Ar 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 .Xr sshd_config 5 . A lifetime specified for an identity with .Xr ssh-add 1 overrides this value. Without this option the default maximum lifetime is forever. .It Fl x Exit after the last client has disconnected. .It Ar command Op Ar 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. .El .Pp 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 .Nm program. The agent starts a command under which its environment variables are exported, for example .Cm ssh-agent xterm & . When the command terminates, so does the agent. .Pp The second method is used for a login session. When .Nm 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 .Cm eval `ssh-agent -s` . .Pp In both cases, .Xr ssh 1 looks at these environment variables and uses them to establish a connection to the agent. .Pp The agent initially does not have any private keys. Keys are added using .Xr ssh-add 1 or by .Xr ssh 1 when .Cm AddKeysToAgent is set in .Xr ssh_config 5 . Multiple identities may be stored in .Nm concurrently and .Xr ssh 1 will automatically use them if present. .Xr ssh-add 1 is also used to remove keys from .Nm and to query the keys that are held in one. .Pp Connections to .Nm may be forwarded from further remote hosts using the .Fl A option to .Xr 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. .Sh ENVIRONMENT .Bl -tag -width "SSH_AGENT_PID" .It Ev SSH_AGENT_PID When .Nm starts, it stores the name of the agent's process ID (PID) in this variable. .It Ev SSH_AUTH_SOCK When .Nm starts, it creates a .Ux Ns -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. .El .Sh FILES .Bl -tag -width Ds .It Pa $TMPDIR/ssh-XXXXXXXXXX/agent. .Ux Ns -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. .El .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-add 1 , .Xr ssh-keygen 1 , .Xr ssh_config 5 , .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 , 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/crypto/openssh/ssh-keygen.c b/crypto/openssh/ssh-keygen.c index d4b7f4dcf800..d62fab3e818a 100644 --- a/crypto/openssh/ssh-keygen.c +++ b/crypto/openssh/ssh-keygen.c @@ -1,3861 +1,3868 @@ -/* $OpenBSD: ssh-keygen.c,v 1.448 2022/02/01 23:32:51 djm Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.450 2022/03/18 02:32:22 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , 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 #include #include #ifdef WITH_OPENSSL #include #include #include "openbsd-compat/openssl-compat.h" #endif #ifdef HAVE_STDINT_H # include #endif #include #include #include #ifdef HAVE_PATHS_H # include #endif #include #include #include #include #include #include #include #include #include #include "xmalloc.h" #include "sshkey.h" #include "authfile.h" #include "sshbuf.h" #include "pathnames.h" #include "log.h" #include "misc.h" #include "match.h" #include "hostfile.h" #include "dns.h" #include "ssh.h" #include "ssh2.h" #include "ssherr.h" #include "ssh-pkcs11.h" #include "atomicio.h" #include "krl.h" #include "digest.h" #include "utf8.h" #include "authfd.h" #include "sshsig.h" #include "ssh-sk.h" #include "sk-api.h" /* XXX for SSH_SK_USER_PRESENCE_REQD; remove */ #include "cipher.h" #ifdef WITH_OPENSSL # define DEFAULT_KEY_TYPE_NAME "rsa" #else # define DEFAULT_KEY_TYPE_NAME "ed25519" #endif /* * Default number of bits in the RSA, DSA and ECDSA keys. These value can be * overridden on the command line. * * These values, with the exception of DSA, provide security equivalent to at * least 128 bits of security according to NIST Special Publication 800-57: * Recommendation for Key Management Part 1 rev 4 section 5.6.1. * For DSA it (and FIPS-186-4 section 4.2) specifies that the only size for * which a 160bit hash is acceptable is 1kbit, and since ssh-dss specifies only * SHA1 we limit the DSA key size 1k bits. */ #define DEFAULT_BITS 3072 #define DEFAULT_BITS_DSA 1024 #define DEFAULT_BITS_ECDSA 256 static int quiet = 0; /* Flag indicating that we just want to see the key fingerprint */ static int print_fingerprint = 0; static int print_bubblebabble = 0; /* Hash algorithm to use for fingerprints. */ static int fingerprint_hash = SSH_FP_HASH_DEFAULT; /* The identity file name, given on the command line or entered by the user. */ static char identity_file[PATH_MAX]; static int have_identity = 0; /* This is set to the passphrase if given on the command line. */ static char *identity_passphrase = NULL; /* This is set to the new passphrase if given on the command line. */ static char *identity_new_passphrase = NULL; /* Key type when certifying */ static u_int cert_key_type = SSH2_CERT_TYPE_USER; /* "key ID" of signed key */ static char *cert_key_id = NULL; /* Comma-separated list of principal names for certifying keys */ static char *cert_principals = NULL; /* Validity period for certificates */ static u_int64_t cert_valid_from = 0; static u_int64_t cert_valid_to = ~0ULL; /* Certificate options */ #define CERTOPT_X_FWD (1) #define CERTOPT_AGENT_FWD (1<<1) #define CERTOPT_PORT_FWD (1<<2) #define CERTOPT_PTY (1<<3) #define CERTOPT_USER_RC (1<<4) #define CERTOPT_NO_REQUIRE_USER_PRESENCE (1<<5) #define CERTOPT_DEFAULT (CERTOPT_X_FWD|CERTOPT_AGENT_FWD| \ CERTOPT_PORT_FWD|CERTOPT_PTY|CERTOPT_USER_RC) static u_int32_t certflags_flags = CERTOPT_DEFAULT; static char *certflags_command = NULL; static char *certflags_src_addr = NULL; /* Arbitrary extensions specified by user */ struct cert_ext { char *key; char *val; int crit; }; static struct cert_ext *cert_ext; static size_t ncert_ext; /* Conversion to/from various formats */ enum { FMT_RFC4716, FMT_PKCS8, FMT_PEM } convert_format = FMT_RFC4716; static char *key_type_name = NULL; /* Load key from this PKCS#11 provider */ static char *pkcs11provider = NULL; /* FIDO/U2F provider to use */ static char *sk_provider = NULL; /* Format for writing private keys */ static int private_key_format = SSHKEY_PRIVATE_OPENSSH; /* Cipher for new-format private keys */ static char *openssh_format_cipher = NULL; /* Number of KDF rounds to derive new format keys. */ static int rounds = 0; /* argv0 */ extern char *__progname; static char hostname[NI_MAXHOST]; #ifdef WITH_OPENSSL /* moduli.c */ int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *); int prime_test(FILE *, FILE *, u_int32_t, u_int32_t, char *, unsigned long, unsigned long); #endif static void type_bits_valid(int type, const char *name, u_int32_t *bitsp) { if (type == KEY_UNSPEC) fatal("unknown key type %s", key_type_name); if (*bitsp == 0) { #ifdef WITH_OPENSSL int nid; switch(type) { case KEY_DSA: *bitsp = DEFAULT_BITS_DSA; break; case KEY_ECDSA: if (name != NULL && (nid = sshkey_ecdsa_nid_from_name(name)) > 0) *bitsp = sshkey_curve_nid_to_bits(nid); if (*bitsp == 0) *bitsp = DEFAULT_BITS_ECDSA; break; case KEY_RSA: *bitsp = DEFAULT_BITS; break; } #endif } #ifdef WITH_OPENSSL switch (type) { case KEY_DSA: if (*bitsp != 1024) fatal("Invalid DSA key length: must be 1024 bits"); break; case KEY_RSA: if (*bitsp < SSH_RSA_MINIMUM_MODULUS_SIZE) fatal("Invalid RSA key length: minimum is %d bits", SSH_RSA_MINIMUM_MODULUS_SIZE); else if (*bitsp > OPENSSL_RSA_MAX_MODULUS_BITS) fatal("Invalid RSA key length: maximum is %d bits", OPENSSL_RSA_MAX_MODULUS_BITS); break; case KEY_ECDSA: if (sshkey_ecdsa_bits_to_nid(*bitsp) == -1) #ifdef OPENSSL_HAS_NISTP521 fatal("Invalid ECDSA key length: valid lengths are " "256, 384 or 521 bits"); #else fatal("Invalid ECDSA key length: valid lengths are " "256 or 384 bits"); #endif } #endif } /* * Checks whether a file exists and, if so, asks the user whether they wish * to overwrite it. * Returns nonzero if the file does not already exist or if the user agrees to * overwrite, or zero otherwise. */ static int confirm_overwrite(const char *filename) { char yesno[3]; struct stat st; if (stat(filename, &st) != 0) return 1; printf("%s already exists.\n", filename); printf("Overwrite (y/n)? "); fflush(stdout); if (fgets(yesno, sizeof(yesno), stdin) == NULL) return 0; if (yesno[0] != 'y' && yesno[0] != 'Y') return 0; return 1; } static void ask_filename(struct passwd *pw, const char *prompt) { char buf[1024]; char *name = NULL; if (key_type_name == NULL) name = _PATH_SSH_CLIENT_ID_RSA; else { switch (sshkey_type_from_name(key_type_name)) { case KEY_DSA_CERT: case KEY_DSA: name = _PATH_SSH_CLIENT_ID_DSA; break; #ifdef OPENSSL_HAS_ECC case KEY_ECDSA_CERT: case KEY_ECDSA: name = _PATH_SSH_CLIENT_ID_ECDSA; break; case KEY_ECDSA_SK_CERT: case KEY_ECDSA_SK: name = _PATH_SSH_CLIENT_ID_ECDSA_SK; break; #endif case KEY_RSA_CERT: case KEY_RSA: name = _PATH_SSH_CLIENT_ID_RSA; break; case KEY_ED25519: case KEY_ED25519_CERT: name = _PATH_SSH_CLIENT_ID_ED25519; break; case KEY_ED25519_SK: case KEY_ED25519_SK_CERT: name = _PATH_SSH_CLIENT_ID_ED25519_SK; break; case KEY_XMSS: case KEY_XMSS_CERT: name = _PATH_SSH_CLIENT_ID_XMSS; break; default: fatal("bad key type"); } } snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name); printf("%s (%s): ", prompt, identity_file); fflush(stdout); if (fgets(buf, sizeof(buf), stdin) == NULL) exit(1); buf[strcspn(buf, "\n")] = '\0'; if (strcmp(buf, "") != 0) strlcpy(identity_file, buf, sizeof(identity_file)); have_identity = 1; } static struct sshkey * load_identity(const char *filename, char **commentp) { char *pass; struct sshkey *prv; int r; if (commentp != NULL) *commentp = NULL; if ((r = sshkey_load_private(filename, "", &prv, commentp)) == 0) return prv; if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) fatal_r(r, "Load key \"%s\"", filename); if (identity_passphrase) pass = xstrdup(identity_passphrase); else pass = read_passphrase("Enter passphrase: ", RP_ALLOW_STDIN); r = sshkey_load_private(filename, pass, &prv, commentp); freezero(pass, strlen(pass)); if (r != 0) fatal_r(r, "Load key \"%s\"", filename); return prv; } #define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----" #define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----" #define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----" #define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb #ifdef WITH_OPENSSL static void do_convert_to_ssh2(struct passwd *pw, struct sshkey *k) { struct sshbuf *b; char comment[61], *b64; int r; if ((b = sshbuf_new()) == NULL) fatal_f("sshbuf_new failed"); if ((r = sshkey_putb(k, b)) != 0) fatal_fr(r, "put key"); if ((b64 = sshbuf_dtob64_string(b, 1)) == NULL) fatal_f("sshbuf_dtob64_string failed"); /* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */ snprintf(comment, sizeof(comment), "%u-bit %s, converted by %s@%s from OpenSSH", sshkey_size(k), sshkey_type(k), pw->pw_name, hostname); sshkey_free(k); sshbuf_free(b); fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); fprintf(stdout, "Comment: \"%s\"\n%s", comment, b64); fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); free(b64); exit(0); } static void do_convert_to_pkcs8(struct sshkey *k) { switch (sshkey_type_plain(k->type)) { case KEY_RSA: if (!PEM_write_RSA_PUBKEY(stdout, k->rsa)) fatal("PEM_write_RSA_PUBKEY failed"); break; case KEY_DSA: if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) fatal("PEM_write_DSA_PUBKEY failed"); break; #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa)) fatal("PEM_write_EC_PUBKEY failed"); break; #endif default: fatal_f("unsupported key type %s", sshkey_type(k)); } exit(0); } static void do_convert_to_pem(struct sshkey *k) { switch (sshkey_type_plain(k->type)) { case KEY_RSA: if (!PEM_write_RSAPublicKey(stdout, k->rsa)) fatal("PEM_write_RSAPublicKey failed"); break; case KEY_DSA: if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) fatal("PEM_write_DSA_PUBKEY failed"); break; #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa)) fatal("PEM_write_EC_PUBKEY failed"); break; #endif default: fatal_f("unsupported key type %s", sshkey_type(k)); } exit(0); } static void do_convert_to(struct passwd *pw) { struct sshkey *k; struct stat st; int r; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) == -1) fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); if ((r = sshkey_load_public(identity_file, &k, NULL)) != 0) k = load_identity(identity_file, NULL); switch (convert_format) { case FMT_RFC4716: do_convert_to_ssh2(pw, k); break; case FMT_PKCS8: do_convert_to_pkcs8(k); break; case FMT_PEM: do_convert_to_pem(k); break; default: fatal_f("unknown key format %d", convert_format); } exit(0); } /* * This is almost exactly the bignum1 encoding, but with 32 bit for length * instead of 16. */ static void buffer_get_bignum_bits(struct sshbuf *b, BIGNUM *value) { u_int bytes, bignum_bits; int r; if ((r = sshbuf_get_u32(b, &bignum_bits)) != 0) fatal_fr(r, "parse"); bytes = (bignum_bits + 7) / 8; if (sshbuf_len(b) < bytes) fatal_f("input buffer too small: need %d have %zu", bytes, sshbuf_len(b)); if (BN_bin2bn(sshbuf_ptr(b), bytes, value) == NULL) fatal_f("BN_bin2bn failed"); if ((r = sshbuf_consume(b, bytes)) != 0) fatal_fr(r, "consume"); } static struct sshkey * do_convert_private_ssh2(struct sshbuf *b) { struct sshkey *key = NULL; char *type, *cipher; u_char e1, e2, e3, *sig = NULL, data[] = "abcde12345"; int r, rlen, ktype; u_int magic, i1, i2, i3, i4; size_t slen; u_long e; BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL; BIGNUM *dsa_pub_key = NULL, *dsa_priv_key = NULL; BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL; BIGNUM *rsa_p = NULL, *rsa_q = NULL, *rsa_iqmp = NULL; if ((r = sshbuf_get_u32(b, &magic)) != 0) fatal_fr(r, "parse magic"); if (magic != SSH_COM_PRIVATE_KEY_MAGIC) { error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC); return NULL; } if ((r = sshbuf_get_u32(b, &i1)) != 0 || (r = sshbuf_get_cstring(b, &type, NULL)) != 0 || (r = sshbuf_get_cstring(b, &cipher, NULL)) != 0 || (r = sshbuf_get_u32(b, &i2)) != 0 || (r = sshbuf_get_u32(b, &i3)) != 0 || (r = sshbuf_get_u32(b, &i4)) != 0) fatal_fr(r, "parse"); debug("ignore (%d %d %d %d)", i1, i2, i3, i4); if (strcmp(cipher, "none") != 0) { error("unsupported cipher %s", cipher); free(cipher); free(type); return NULL; } free(cipher); if (strstr(type, "dsa")) { ktype = KEY_DSA; } else if (strstr(type, "rsa")) { ktype = KEY_RSA; } else { free(type); return NULL; } if ((key = sshkey_new(ktype)) == NULL) fatal("sshkey_new failed"); free(type); switch (key->type) { case KEY_DSA: if ((dsa_p = BN_new()) == NULL || (dsa_q = BN_new()) == NULL || (dsa_g = BN_new()) == NULL || (dsa_pub_key = BN_new()) == NULL || (dsa_priv_key = BN_new()) == NULL) fatal_f("BN_new"); buffer_get_bignum_bits(b, dsa_p); buffer_get_bignum_bits(b, dsa_g); buffer_get_bignum_bits(b, dsa_q); buffer_get_bignum_bits(b, dsa_pub_key); buffer_get_bignum_bits(b, dsa_priv_key); if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g)) fatal_f("DSA_set0_pqg failed"); dsa_p = dsa_q = dsa_g = NULL; /* transferred */ if (!DSA_set0_key(key->dsa, dsa_pub_key, dsa_priv_key)) fatal_f("DSA_set0_key failed"); dsa_pub_key = dsa_priv_key = NULL; /* transferred */ break; case KEY_RSA: if ((r = sshbuf_get_u8(b, &e1)) != 0 || (e1 < 30 && (r = sshbuf_get_u8(b, &e2)) != 0) || (e1 < 30 && (r = sshbuf_get_u8(b, &e3)) != 0)) fatal_fr(r, "parse RSA"); e = e1; debug("e %lx", e); if (e < 30) { e <<= 8; e += e2; debug("e %lx", e); e <<= 8; e += e3; debug("e %lx", e); } if ((rsa_e = BN_new()) == NULL) fatal_f("BN_new"); if (!BN_set_word(rsa_e, e)) { BN_clear_free(rsa_e); sshkey_free(key); return NULL; } if ((rsa_n = BN_new()) == NULL || (rsa_d = BN_new()) == NULL || (rsa_p = BN_new()) == NULL || (rsa_q = BN_new()) == NULL || (rsa_iqmp = BN_new()) == NULL) fatal_f("BN_new"); buffer_get_bignum_bits(b, rsa_d); buffer_get_bignum_bits(b, rsa_n); buffer_get_bignum_bits(b, rsa_iqmp); buffer_get_bignum_bits(b, rsa_q); buffer_get_bignum_bits(b, rsa_p); if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, rsa_d)) fatal_f("RSA_set0_key failed"); rsa_n = rsa_e = rsa_d = NULL; /* transferred */ if (!RSA_set0_factors(key->rsa, rsa_p, rsa_q)) fatal_f("RSA_set0_factors failed"); rsa_p = rsa_q = NULL; /* transferred */ if ((r = ssh_rsa_complete_crt_parameters(key, rsa_iqmp)) != 0) fatal_fr(r, "generate RSA parameters"); BN_clear_free(rsa_iqmp); break; } rlen = sshbuf_len(b); if (rlen != 0) error_f("remaining bytes in key blob %d", rlen); /* try the key */ if (sshkey_sign(key, &sig, &slen, data, sizeof(data), NULL, NULL, NULL, 0) != 0 || sshkey_verify(key, sig, slen, data, sizeof(data), NULL, 0, NULL) != 0) { sshkey_free(key); free(sig); return NULL; } free(sig); return key; } static int get_line(FILE *fp, char *line, size_t len) { int c; size_t pos = 0; line[0] = '\0'; while ((c = fgetc(fp)) != EOF) { if (pos >= len - 1) fatal("input line too long."); switch (c) { case '\r': c = fgetc(fp); if (c != EOF && c != '\n' && ungetc(c, fp) == EOF) fatal("unget: %s", strerror(errno)); return pos; case '\n': return pos; } line[pos++] = c; line[pos] = '\0'; } /* We reached EOF */ return -1; } static void do_convert_from_ssh2(struct passwd *pw, struct sshkey **k, int *private) { int r, blen, escaped = 0; u_int len; char line[1024]; struct sshbuf *buf; char encoded[8096]; FILE *fp; if ((buf = sshbuf_new()) == NULL) fatal("sshbuf_new failed"); if ((fp = fopen(identity_file, "r")) == NULL) fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); encoded[0] = '\0'; while ((blen = get_line(fp, line, sizeof(line))) != -1) { if (blen > 0 && line[blen - 1] == '\\') escaped++; if (strncmp(line, "----", 4) == 0 || strstr(line, ": ") != NULL) { if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL) *private = 1; if (strstr(line, " END ") != NULL) { break; } /* fprintf(stderr, "ignore: %s", line); */ continue; } if (escaped) { escaped--; /* fprintf(stderr, "escaped: %s", line); */ continue; } strlcat(encoded, line, sizeof(encoded)); } len = strlen(encoded); if (((len % 4) == 3) && (encoded[len-1] == '=') && (encoded[len-2] == '=') && (encoded[len-3] == '=')) encoded[len-3] = '\0'; if ((r = sshbuf_b64tod(buf, encoded)) != 0) fatal_fr(r, "base64 decode"); if (*private) { if ((*k = do_convert_private_ssh2(buf)) == NULL) fatal_f("private key conversion failed"); } else if ((r = sshkey_fromb(buf, k)) != 0) fatal_fr(r, "parse key"); sshbuf_free(buf); fclose(fp); } static void do_convert_from_pkcs8(struct sshkey **k, int *private) { EVP_PKEY *pubkey; FILE *fp; if ((fp = fopen(identity_file, "r")) == NULL) fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); if ((pubkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { fatal_f("%s is not a recognised public key format", identity_file); } fclose(fp); switch (EVP_PKEY_base_id(pubkey)) { case EVP_PKEY_RSA: if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new failed"); (*k)->type = KEY_RSA; (*k)->rsa = EVP_PKEY_get1_RSA(pubkey); break; case EVP_PKEY_DSA: if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new failed"); (*k)->type = KEY_DSA; (*k)->dsa = EVP_PKEY_get1_DSA(pubkey); break; #ifdef OPENSSL_HAS_ECC case EVP_PKEY_EC: if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new failed"); (*k)->type = KEY_ECDSA; (*k)->ecdsa = EVP_PKEY_get1_EC_KEY(pubkey); (*k)->ecdsa_nid = sshkey_ecdsa_key_to_nid((*k)->ecdsa); break; #endif default: fatal_f("unsupported pubkey type %d", EVP_PKEY_base_id(pubkey)); } EVP_PKEY_free(pubkey); return; } static void do_convert_from_pem(struct sshkey **k, int *private) { FILE *fp; RSA *rsa; if ((fp = fopen(identity_file, "r")) == NULL) fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); if ((rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL)) != NULL) { if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new failed"); (*k)->type = KEY_RSA; (*k)->rsa = rsa; fclose(fp); return; } fatal_f("unrecognised raw private key format"); } static void do_convert_from(struct passwd *pw) { struct sshkey *k = NULL; int r, private = 0, ok = 0; struct stat st; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) == -1) fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); switch (convert_format) { case FMT_RFC4716: do_convert_from_ssh2(pw, &k, &private); break; case FMT_PKCS8: do_convert_from_pkcs8(&k, &private); break; case FMT_PEM: do_convert_from_pem(&k, &private); break; default: fatal_f("unknown key format %d", convert_format); } if (!private) { if ((r = sshkey_write(k, stdout)) == 0) ok = 1; if (ok) fprintf(stdout, "\n"); } else { switch (k->type) { case KEY_DSA: ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL); break; #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: ok = PEM_write_ECPrivateKey(stdout, k->ecdsa, NULL, NULL, 0, NULL, NULL); break; #endif case KEY_RSA: ok = PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL); break; default: fatal_f("unsupported key type %s", sshkey_type(k)); } } if (!ok) fatal("key write failed"); sshkey_free(k); exit(0); } #endif static void do_print_public(struct passwd *pw) { struct sshkey *prv; struct stat st; int r; char *comment = NULL; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) == -1) fatal("%s: %s", identity_file, strerror(errno)); prv = load_identity(identity_file, &comment); if ((r = sshkey_write(prv, stdout)) != 0) fatal_fr(r, "write key"); if (comment != NULL && *comment != '\0') fprintf(stdout, " %s", comment); fprintf(stdout, "\n"); if (sshkey_is_sk(prv)) { debug("sk_application: \"%s\", sk_flags 0x%02x", prv->sk_application, prv->sk_flags); } sshkey_free(prv); free(comment); exit(0); } static void do_download(struct passwd *pw) { #ifdef ENABLE_PKCS11 struct sshkey **keys = NULL; int i, nkeys; enum sshkey_fp_rep rep; int fptype; char *fp, *ra, **comments = NULL; fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash; rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT; pkcs11_init(1); nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys, &comments); if (nkeys <= 0) fatal("cannot read public key from pkcs11"); for (i = 0; i < nkeys; i++) { if (print_fingerprint) { fp = sshkey_fingerprint(keys[i], fptype, rep); ra = sshkey_fingerprint(keys[i], fingerprint_hash, SSH_FP_RANDOMART); if (fp == NULL || ra == NULL) fatal_f("sshkey_fingerprint fail"); printf("%u %s %s (PKCS11 key)\n", sshkey_size(keys[i]), fp, sshkey_type(keys[i])); if (log_level_get() >= SYSLOG_LEVEL_VERBOSE) printf("%s\n", ra); free(ra); free(fp); } else { (void) sshkey_write(keys[i], stdout); /* XXX check */ fprintf(stdout, "%s%s\n", *(comments[i]) == '\0' ? "" : " ", comments[i]); } free(comments[i]); sshkey_free(keys[i]); } free(comments); free(keys); pkcs11_terminate(); exit(0); #else fatal("no pkcs11 support"); #endif /* ENABLE_PKCS11 */ } static struct sshkey * try_read_key(char **cpp) { struct sshkey *ret; int r; if ((ret = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new failed"); if ((r = sshkey_read(ret, cpp)) == 0) return ret; /* Not a key */ sshkey_free(ret); return NULL; } static void fingerprint_one_key(const struct sshkey *public, const char *comment) { char *fp = NULL, *ra = NULL; enum sshkey_fp_rep rep; int fptype; fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash; rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT; fp = sshkey_fingerprint(public, fptype, rep); ra = sshkey_fingerprint(public, fingerprint_hash, SSH_FP_RANDOMART); if (fp == NULL || ra == NULL) fatal_f("sshkey_fingerprint failed"); mprintf("%u %s %s (%s)\n", sshkey_size(public), fp, comment ? comment : "no comment", sshkey_type(public)); if (log_level_get() >= SYSLOG_LEVEL_VERBOSE) printf("%s\n", ra); free(ra); free(fp); } static void fingerprint_private(const char *path) { struct stat st; char *comment = NULL; struct sshkey *privkey = NULL, *pubkey = NULL; int r; if (stat(identity_file, &st) == -1) fatal("%s: %s", path, strerror(errno)); if ((r = sshkey_load_public(path, &pubkey, &comment)) != 0) debug_r(r, "load public \"%s\"", path); if (pubkey == NULL || comment == NULL || *comment == '\0') { free(comment); if ((r = sshkey_load_private(path, NULL, &privkey, &comment)) != 0) debug_r(r, "load private \"%s\"", path); } if (pubkey == NULL && privkey == NULL) fatal("%s is not a key file.", path); fingerprint_one_key(pubkey == NULL ? privkey : pubkey, comment); sshkey_free(pubkey); sshkey_free(privkey); free(comment); } static void do_fingerprint(struct passwd *pw) { FILE *f; struct sshkey *public = NULL; char *comment = NULL, *cp, *ep, *line = NULL; size_t linesize = 0; int i, invalid = 1; const char *path; u_long lnum = 0; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); path = identity_file; if (strcmp(identity_file, "-") == 0) { f = stdin; path = "(stdin)"; } else if ((f = fopen(path, "r")) == NULL) fatal("%s: %s: %s", __progname, path, strerror(errno)); while (getline(&line, &linesize, f) != -1) { lnum++; cp = line; cp[strcspn(cp, "\n")] = '\0'; /* Trim leading space and comments */ cp = line + strspn(line, " \t"); if (*cp == '#' || *cp == '\0') continue; /* * Input may be plain keys, private keys, authorized_keys * or known_hosts. */ /* * Try private keys first. Assume a key is private if * "SSH PRIVATE KEY" appears on the first line and we're * not reading from stdin (XXX support private keys on stdin). */ if (lnum == 1 && strcmp(identity_file, "-") != 0 && strstr(cp, "PRIVATE KEY") != NULL) { free(line); fclose(f); fingerprint_private(path); exit(0); } /* * If it's not a private key, then this must be prepared to * accept a public key prefixed with a hostname or options. * Try a bare key first, otherwise skip the leading stuff. */ if ((public = try_read_key(&cp)) == NULL) { i = strtol(cp, &ep, 10); if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { int quoted = 0; comment = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } if (!*cp) continue; *cp++ = '\0'; } } /* Retry after parsing leading hostname/key options */ if (public == NULL && (public = try_read_key(&cp)) == NULL) { debug("%s:%lu: not a public key", path, lnum); continue; } /* Find trailing comment, if any */ for (; *cp == ' ' || *cp == '\t'; cp++) ; if (*cp != '\0' && *cp != '#') comment = cp; fingerprint_one_key(public, comment); sshkey_free(public); invalid = 0; /* One good key in the file is sufficient */ } fclose(f); free(line); if (invalid) fatal("%s is not a public key file.", path); exit(0); } static void do_gen_all_hostkeys(struct passwd *pw) { struct { char *key_type; char *key_type_display; char *path; } key_types[] = { #ifdef WITH_OPENSSL { "rsa", "RSA" ,_PATH_HOST_RSA_KEY_FILE }, { "dsa", "DSA", _PATH_HOST_DSA_KEY_FILE }, #ifdef OPENSSL_HAS_ECC { "ecdsa", "ECDSA",_PATH_HOST_ECDSA_KEY_FILE }, #endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ { "ed25519", "ED25519",_PATH_HOST_ED25519_KEY_FILE }, #ifdef WITH_XMSS { "xmss", "XMSS",_PATH_HOST_XMSS_KEY_FILE }, #endif /* WITH_XMSS */ { NULL, NULL, NULL } }; u_int32_t bits = 0; int first = 0; struct stat st; struct sshkey *private, *public; char comment[1024], *prv_tmp, *pub_tmp, *prv_file, *pub_file; int i, type, fd, r; for (i = 0; key_types[i].key_type; i++) { public = private = NULL; prv_tmp = pub_tmp = prv_file = pub_file = NULL; xasprintf(&prv_file, "%s%s", identity_file, key_types[i].path); /* Check whether private key exists and is not zero-length */ if (stat(prv_file, &st) == 0) { if (st.st_size != 0) goto next; } else if (errno != ENOENT) { error("Could not stat %s: %s", key_types[i].path, strerror(errno)); goto failnext; } /* * Private key doesn't exist or is invalid; proceed with * key generation. */ xasprintf(&prv_tmp, "%s%s.XXXXXXXXXX", identity_file, key_types[i].path); xasprintf(&pub_tmp, "%s%s.pub.XXXXXXXXXX", identity_file, key_types[i].path); xasprintf(&pub_file, "%s%s.pub", identity_file, key_types[i].path); if (first == 0) { first = 1; printf("%s: generating new host keys: ", __progname); } printf("%s ", key_types[i].key_type_display); fflush(stdout); type = sshkey_type_from_name(key_types[i].key_type); if ((fd = mkstemp(prv_tmp)) == -1) { error("Could not save your private key in %s: %s", prv_tmp, strerror(errno)); goto failnext; } (void)close(fd); /* just using mkstemp() to reserve a name */ bits = 0; type_bits_valid(type, NULL, &bits); if ((r = sshkey_generate(type, bits, &private)) != 0) { error_r(r, "sshkey_generate failed"); goto failnext; } if ((r = sshkey_from_private(private, &public)) != 0) fatal_fr(r, "sshkey_from_private"); snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); if ((r = sshkey_save_private(private, prv_tmp, "", comment, private_key_format, openssh_format_cipher, rounds)) != 0) { error_r(r, "Saving key \"%s\" failed", prv_tmp); goto failnext; } if ((fd = mkstemp(pub_tmp)) == -1) { error("Could not save your public key in %s: %s", pub_tmp, strerror(errno)); goto failnext; } (void)fchmod(fd, 0644); (void)close(fd); if ((r = sshkey_save_public(public, pub_tmp, comment)) != 0) { error_r(r, "Unable to save public key to %s", identity_file); goto failnext; } /* Rename temporary files to their permanent locations. */ if (rename(pub_tmp, pub_file) != 0) { error("Unable to move %s into position: %s", pub_file, strerror(errno)); goto failnext; } if (rename(prv_tmp, prv_file) != 0) { error("Unable to move %s into position: %s", key_types[i].path, strerror(errno)); failnext: first = 0; goto next; } next: sshkey_free(private); sshkey_free(public); free(prv_tmp); free(pub_tmp); free(prv_file); free(pub_file); } if (first != 0) printf("\n"); } struct known_hosts_ctx { const char *host; /* Hostname searched for in find/delete case */ FILE *out; /* Output file, stdout for find_hosts case */ int has_unhashed; /* When hashing, original had unhashed hosts */ int found_key; /* For find/delete, host was found */ int invalid; /* File contained invalid items; don't delete */ int hash_hosts; /* Hash hostnames as we go */ int find_host; /* Search for specific hostname */ int delete_host; /* Delete host from known_hosts */ }; static int known_hosts_hash(struct hostkey_foreach_line *l, void *_ctx) { struct known_hosts_ctx *ctx = (struct known_hosts_ctx *)_ctx; char *hashed, *cp, *hosts, *ohosts; int has_wild = l->hosts && strcspn(l->hosts, "*?!") != strlen(l->hosts); int was_hashed = l->hosts && l->hosts[0] == HASH_DELIM; switch (l->status) { case HKF_STATUS_OK: case HKF_STATUS_MATCHED: /* * Don't hash hosts already already hashed, with wildcard * characters or a CA/revocation marker. */ if (was_hashed || has_wild || l->marker != MRK_NONE) { fprintf(ctx->out, "%s\n", l->line); if (has_wild && !ctx->find_host) { logit("%s:%lu: ignoring host name " "with wildcard: %.64s", l->path, l->linenum, l->hosts); } return 0; } /* * Split any comma-separated hostnames from the host list, * hash and store separately. */ ohosts = hosts = xstrdup(l->hosts); while ((cp = strsep(&hosts, ",")) != NULL && *cp != '\0') { lowercase(cp); if ((hashed = host_hash(cp, NULL, 0)) == NULL) fatal("hash_host failed"); fprintf(ctx->out, "%s %s\n", hashed, l->rawkey); 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); /* extensions */ if ((certflags_flags & CERTOPT_X_FWD) != 0) cert_ext_add("permit-X11-forwarding", NULL, 0); if ((certflags_flags & CERTOPT_AGENT_FWD) != 0) cert_ext_add("permit-agent-forwarding", NULL, 0); if ((certflags_flags & CERTOPT_PORT_FWD) != 0) cert_ext_add("permit-port-forwarding", NULL, 0); if ((certflags_flags & CERTOPT_PTY) != 0) cert_ext_add("permit-pty", NULL, 0); if ((certflags_flags & CERTOPT_USER_RC) != 0) cert_ext_add("permit-user-rc", NULL, 0); if ((certflags_flags & CERTOPT_NO_REQUIRE_USER_PRESENCE) != 0) cert_ext_add("no-touch-required", NULL, 0); /* order lexically by key */ if (ncert_ext > 0) qsort(cert_ext, ncert_ext, sizeof(*cert_ext), cert_ext_cmp); } static struct sshkey * load_pkcs11_key(char *path) { #ifdef ENABLE_PKCS11 struct sshkey **keys = NULL, *public, *private = NULL; int r, i, nkeys; if ((r = sshkey_load_public(path, &public, NULL)) != 0) fatal_r(r, "Couldn't load CA public key \"%s\"", path); nkeys = pkcs11_add_provider(pkcs11provider, identity_passphrase, &keys, NULL); debug3_f("%d keys", nkeys); if (nkeys <= 0) fatal("cannot read public key from pkcs11"); for (i = 0; i < nkeys; i++) { if (sshkey_equal_public(public, keys[i])) { private = keys[i]; continue; } sshkey_free(keys[i]); } free(keys); sshkey_free(public); return private; #else fatal("no pkcs11 support"); #endif /* ENABLE_PKCS11 */ } /* Signer for sshkey_certify_custom that uses the agent */ static int agent_signer(struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, const char *alg, const char *provider, const char *pin, u_int compat, void *ctx) { int *agent_fdp = (int *)ctx; return ssh_agent_sign(*agent_fdp, key, sigp, lenp, data, datalen, alg, compat); } static void do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent, unsigned long long cert_serial, int cert_serial_autoinc, int argc, char **argv) { int r, i, found, agent_fd = -1; u_int n; struct sshkey *ca, *public; char valid[64], *otmp, *tmp, *cp, *out, *comment; char *ca_fp = NULL, **plist = NULL, *pin = NULL; struct ssh_identitylist *agent_ids; size_t j; struct notifier_ctx *notifier = NULL; #ifdef ENABLE_PKCS11 pkcs11_init(1); #endif tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); if (pkcs11provider != NULL) { /* If a PKCS#11 token was specified then try to use it */ if ((ca = load_pkcs11_key(tmp)) == NULL) fatal("No PKCS#11 key matching %s found", ca_key_path); } else if (prefer_agent) { /* * Agent signature requested. Try to use agent after making * sure the public key specified is actually present in the * agent. */ if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0) fatal_r(r, "Cannot load CA public key %s", tmp); if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) fatal_r(r, "Cannot use public key for CA signature"); if ((r = ssh_fetch_identitylist(agent_fd, &agent_ids)) != 0) fatal_r(r, "Retrieve agent key list"); found = 0; for (j = 0; j < agent_ids->nkeys; j++) { if (sshkey_equal(ca, agent_ids->keys[j])) { found = 1; break; } } if (!found) fatal("CA key %s not found in agent", tmp); ssh_free_identitylist(agent_ids); ca->flags |= SSHKEY_FLAG_EXT; } else { /* CA key is assumed to be a private key on the filesystem */ ca = load_identity(tmp, NULL); if (sshkey_is_sk(ca) && (ca->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) { if ((pin = read_passphrase("Enter PIN for CA key: ", RP_ALLOW_STDIN)) == NULL) fatal_f("couldn't read PIN"); } } free(tmp); if (key_type_name != NULL) { if (sshkey_type_from_name(key_type_name) != ca->type) { fatal("CA key type %s doesn't match specified %s", sshkey_ssh_name(ca), key_type_name); } } else if (ca->type == KEY_RSA) { /* Default to a good signature algorithm */ key_type_name = "rsa-sha2-512"; } ca_fp = sshkey_fingerprint(ca, fingerprint_hash, SSH_FP_DEFAULT); finalise_cert_exts(); for (i = 0; i < argc; i++) { /* Split list of principals */ n = 0; if (cert_principals != NULL) { otmp = tmp = xstrdup(cert_principals); plist = NULL; for (; (cp = strsep(&tmp, ",")) != NULL; n++) { plist = xreallocarray(plist, n + 1, sizeof(*plist)); if (*(plist[n] = xstrdup(cp)) == '\0') fatal("Empty principal name"); } free(otmp); } if (n > SSHKEY_CERT_MAX_PRINCIPALS) fatal("Too many certificate principals specified"); tmp = tilde_expand_filename(argv[i], pw->pw_uid); if ((r = sshkey_load_public(tmp, &public, &comment)) != 0) fatal_r(r, "load pubkey \"%s\"", tmp); if (sshkey_is_cert(public)) fatal_f("key \"%s\" type %s cannot be certified", tmp, sshkey_type(public)); /* Prepare certificate to sign */ if ((r = sshkey_to_certified(public)) != 0) fatal_r(r, "Could not upgrade key %s to certificate", tmp); public->cert->type = cert_key_type; public->cert->serial = (u_int64_t)cert_serial; public->cert->key_id = xstrdup(cert_key_id); public->cert->nprincipals = n; public->cert->principals = plist; public->cert->valid_after = cert_valid_from; public->cert->valid_before = cert_valid_to; prepare_options_buf(public->cert->critical, OPTIONS_CRITICAL); prepare_options_buf(public->cert->extensions, OPTIONS_EXTENSIONS); if ((r = sshkey_from_private(ca, &public->cert->signature_key)) != 0) fatal_r(r, "sshkey_from_private (ca key)"); if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) { if ((r = sshkey_certify_custom(public, ca, key_type_name, sk_provider, NULL, agent_signer, &agent_fd)) != 0) fatal_r(r, "Couldn't certify %s via agent", tmp); } else { if (sshkey_is_sk(ca) && (ca->sk_flags & SSH_SK_USER_PRESENCE_REQD)) { notifier = notify_start(0, "Confirm user presence for key %s %s", sshkey_type(ca), ca_fp); } r = sshkey_certify(public, ca, key_type_name, sk_provider, pin); notify_complete(notifier, "User presence confirmed"); if (r != 0) fatal_r(r, "Couldn't certify key %s", tmp); } if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) *cp = '\0'; xasprintf(&out, "%s-cert.pub", tmp); free(tmp); if ((r = sshkey_save_public(public, out, comment)) != 0) { fatal_r(r, "Unable to save public key to %s", identity_file); } if (!quiet) { sshkey_format_cert_validity(public->cert, valid, sizeof(valid)); logit("Signed %s key %s: id \"%s\" serial %llu%s%s " "valid %s", sshkey_cert_type(public), out, public->cert->key_id, (unsigned long long)public->cert->serial, cert_principals != NULL ? " for " : "", cert_principals != NULL ? cert_principals : "", valid); } sshkey_free(public); free(out); if (cert_serial_autoinc) cert_serial++; } if (pin != NULL) freezero(pin, strlen(pin)); free(ca_fp); #ifdef ENABLE_PKCS11 pkcs11_terminate(); #endif exit(0); } static u_int64_t parse_relative_time(const char *s, time_t now) { int64_t mul, secs; mul = *s == '-' ? -1 : 1; if ((secs = convtime(s + 1)) == -1) fatal("Invalid relative certificate time %s", s); if (mul == -1 && secs > now) fatal("Certificate time %s cannot be represented", s); return now + (u_int64_t)(secs * mul); } static void parse_cert_times(char *timespec) { char *from, *to; time_t now = time(NULL); int64_t secs; /* +timespec relative to now */ if (*timespec == '+' && strchr(timespec, ':') == NULL) { if ((secs = convtime(timespec + 1)) == -1) fatal("Invalid relative certificate life %s", timespec); cert_valid_to = now + secs; /* * Backdate certificate one minute to avoid problems on hosts * with poorly-synchronised clocks. */ cert_valid_from = ((now - 59)/ 60) * 60; return; } /* * from:to, where * from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | "always" * to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | "forever" */ from = xstrdup(timespec); to = strchr(from, ':'); if (to == NULL || from == to || *(to + 1) == '\0') fatal("Invalid certificate life specification %s", timespec); *to++ = '\0'; if (*from == '-' || *from == '+') cert_valid_from = parse_relative_time(from, now); else if (strcmp(from, "always") == 0) cert_valid_from = 0; else if (parse_absolute_time(from, &cert_valid_from) != 0) fatal("Invalid from time \"%s\"", from); if (*to == '-' || *to == '+') cert_valid_to = parse_relative_time(to, now); else if (strcmp(to, "forever") == 0) cert_valid_to = ~(u_int64_t)0; else if (parse_absolute_time(to, &cert_valid_to) != 0) fatal("Invalid to time \"%s\"", to); if (cert_valid_to <= cert_valid_from) fatal("Empty certificate validity interval"); free(from); } static void add_cert_option(char *opt) { char *val, *cp; int iscrit = 0; if (strcasecmp(opt, "clear") == 0) certflags_flags = 0; else if (strcasecmp(opt, "no-x11-forwarding") == 0) certflags_flags &= ~CERTOPT_X_FWD; else if (strcasecmp(opt, "permit-x11-forwarding") == 0) certflags_flags |= CERTOPT_X_FWD; else if (strcasecmp(opt, "no-agent-forwarding") == 0) certflags_flags &= ~CERTOPT_AGENT_FWD; else if (strcasecmp(opt, "permit-agent-forwarding") == 0) certflags_flags |= CERTOPT_AGENT_FWD; else if (strcasecmp(opt, "no-port-forwarding") == 0) certflags_flags &= ~CERTOPT_PORT_FWD; else if (strcasecmp(opt, "permit-port-forwarding") == 0) certflags_flags |= CERTOPT_PORT_FWD; else if (strcasecmp(opt, "no-pty") == 0) certflags_flags &= ~CERTOPT_PTY; else if (strcasecmp(opt, "permit-pty") == 0) certflags_flags |= CERTOPT_PTY; else if (strcasecmp(opt, "no-user-rc") == 0) certflags_flags &= ~CERTOPT_USER_RC; else if (strcasecmp(opt, "permit-user-rc") == 0) certflags_flags |= CERTOPT_USER_RC; else if (strcasecmp(opt, "touch-required") == 0) certflags_flags &= ~CERTOPT_NO_REQUIRE_USER_PRESENCE; else if (strcasecmp(opt, "no-touch-required") == 0) certflags_flags |= CERTOPT_NO_REQUIRE_USER_PRESENCE; else if (strncasecmp(opt, "force-command=", 14) == 0) { val = opt + 14; if (*val == '\0') fatal("Empty force-command option"); if (certflags_command != NULL) fatal("force-command already specified"); certflags_command = xstrdup(val); } else if (strncasecmp(opt, "source-address=", 15) == 0) { val = opt + 15; if (*val == '\0') fatal("Empty source-address option"); if (certflags_src_addr != NULL) fatal("source-address already specified"); if (addr_match_cidr_list(NULL, val) != 0) fatal("Invalid source-address list"); certflags_src_addr = xstrdup(val); } else if (strncasecmp(opt, "extension:", 10) == 0 || (iscrit = (strncasecmp(opt, "critical:", 9) == 0))) { val = xstrdup(strchr(opt, ':') + 1); if ((cp = strchr(val, '=')) != NULL) *cp++ = '\0'; cert_ext_add(val, cp, iscrit); free(val); } else fatal("Unsupported certificate option \"%s\"", opt); } static void show_options(struct sshbuf *optbuf, int in_critical) { char *name, *arg, *hex; struct sshbuf *options, *option = NULL; int r; if ((options = sshbuf_fromb(optbuf)) == NULL) fatal_f("sshbuf_fromb failed"); while (sshbuf_len(options) != 0) { sshbuf_free(option); option = NULL; if ((r = sshbuf_get_cstring(options, &name, NULL)) != 0 || (r = sshbuf_froms(options, &option)) != 0) fatal_fr(r, "parse option"); printf(" %s", name); if (!in_critical && (strcmp(name, "permit-X11-forwarding") == 0 || strcmp(name, "permit-agent-forwarding") == 0 || strcmp(name, "permit-port-forwarding") == 0 || strcmp(name, "permit-pty") == 0 || strcmp(name, "permit-user-rc") == 0 || strcmp(name, "no-touch-required") == 0)) { printf("\n"); } else if (in_critical && (strcmp(name, "force-command") == 0 || strcmp(name, "source-address") == 0)) { if ((r = sshbuf_get_cstring(option, &arg, NULL)) != 0) fatal_fr(r, "parse critical"); printf(" %s\n", arg); free(arg); } else if (sshbuf_len(option) > 0) { hex = sshbuf_dtob16(option); printf(" UNKNOWN OPTION: %s (len %zu)\n", hex, sshbuf_len(option)); sshbuf_reset(option); free(hex); } else printf(" UNKNOWN FLAG OPTION\n"); free(name); if (sshbuf_len(option) != 0) fatal("Option corrupt: extra data at end"); } sshbuf_free(option); sshbuf_free(options); } static void print_cert(struct sshkey *key) { char valid[64], *key_fp, *ca_fp; u_int i; key_fp = sshkey_fingerprint(key, fingerprint_hash, SSH_FP_DEFAULT); ca_fp = sshkey_fingerprint(key->cert->signature_key, fingerprint_hash, SSH_FP_DEFAULT); if (key_fp == NULL || ca_fp == NULL) fatal_f("sshkey_fingerprint fail"); sshkey_format_cert_validity(key->cert, valid, sizeof(valid)); printf(" Type: %s %s certificate\n", sshkey_ssh_name(key), sshkey_cert_type(key)); printf(" Public key: %s %s\n", sshkey_type(key), key_fp); printf(" Signing CA: %s %s (using %s)\n", sshkey_type(key->cert->signature_key), ca_fp, key->cert->signature_type); printf(" Key ID: \"%s\"\n", key->cert->key_id); printf(" Serial: %llu\n", (unsigned long long)key->cert->serial); printf(" Valid: %s\n", valid); printf(" Principals: "); if (key->cert->nprincipals == 0) printf("(none)\n"); else { for (i = 0; i < key->cert->nprincipals; i++) printf("\n %s", key->cert->principals[i]); printf("\n"); } printf(" Critical Options: "); if (sshbuf_len(key->cert->critical) == 0) printf("(none)\n"); else { printf("\n"); show_options(key->cert->critical, 1); } printf(" Extensions: "); if (sshbuf_len(key->cert->extensions) == 0) printf("(none)\n"); else { printf("\n"); show_options(key->cert->extensions, 0); } } static void do_show_cert(struct passwd *pw) { struct sshkey *key = NULL; struct stat st; int r, is_stdin = 0, ok = 0; FILE *f; char *cp, *line = NULL; const char *path; size_t linesize = 0; u_long lnum = 0; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (strcmp(identity_file, "-") != 0 && stat(identity_file, &st) == -1) fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); path = identity_file; if (strcmp(path, "-") == 0) { f = stdin; path = "(stdin)"; is_stdin = 1; } else if ((f = fopen(identity_file, "r")) == NULL) fatal("fopen %s: %s", identity_file, strerror(errno)); while (getline(&line, &linesize, f) != -1) { lnum++; sshkey_free(key); key = NULL; /* Trim leading space and comments */ cp = line + strspn(line, " \t"); if (*cp == '#' || *cp == '\0') continue; if ((key = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new"); if ((r = sshkey_read(key, &cp)) != 0) { error_r(r, "%s:%lu: invalid key", path, lnum); continue; } if (!sshkey_is_cert(key)) { error("%s:%lu is not a certificate", path, lnum); continue; } ok = 1; if (!is_stdin && lnum == 1) printf("%s:\n", path); else printf("%s:%lu:\n", path, lnum); print_cert(key); } free(line); sshkey_free(key); fclose(f); exit(ok ? 0 : 1); } static void load_krl(const char *path, struct ssh_krl **krlp) { struct sshbuf *krlbuf; int r; if ((r = sshbuf_load_file(path, &krlbuf)) != 0) fatal_r(r, "Unable to load KRL %s", path); /* XXX check sigs */ if ((r = ssh_krl_from_blob(krlbuf, krlp, NULL, 0)) != 0 || *krlp == NULL) fatal_r(r, "Invalid KRL file %s", path); sshbuf_free(krlbuf); } static void hash_to_blob(const char *cp, u_char **blobp, size_t *lenp, const char *file, u_long lnum) { char *tmp; size_t tlen; struct sshbuf *b; int r; if (strncmp(cp, "SHA256:", 7) != 0) fatal("%s:%lu: unsupported hash algorithm", file, lnum); cp += 7; /* * OpenSSH base64 hashes omit trailing '=' * characters; put them back for decode. */ tlen = strlen(cp); tmp = xmalloc(tlen + 4 + 1); strlcpy(tmp, cp, tlen + 1); while ((tlen % 4) != 0) { tmp[tlen++] = '='; tmp[tlen] = '\0'; } if ((b = sshbuf_new()) == NULL) fatal_f("sshbuf_new failed"); if ((r = sshbuf_b64tod(b, tmp)) != 0) fatal_r(r, "%s:%lu: decode hash failed", file, lnum); free(tmp); *lenp = sshbuf_len(b); *blobp = xmalloc(*lenp); memcpy(*blobp, sshbuf_ptr(b), *lenp); sshbuf_free(b); } static void update_krl_from_file(struct passwd *pw, const char *file, int wild_ca, const struct sshkey *ca, struct ssh_krl *krl) { struct sshkey *key = NULL; u_long lnum = 0; char *path, *cp, *ep, *line = NULL; u_char *blob = NULL; size_t blen = 0, linesize = 0; unsigned long long serial, serial2; int i, was_explicit_key, was_sha1, was_sha256, was_hash, r; FILE *krl_spec; path = tilde_expand_filename(file, pw->pw_uid); if (strcmp(path, "-") == 0) { krl_spec = stdin; free(path); path = xstrdup("(standard input)"); } else if ((krl_spec = fopen(path, "r")) == NULL) fatal("fopen %s: %s", path, strerror(errno)); if (!quiet) printf("Revoking from %s\n", path); while (getline(&line, &linesize, krl_spec) != -1) { lnum++; was_explicit_key = was_sha1 = was_sha256 = was_hash = 0; cp = line + strspn(line, " \t"); /* Trim trailing space, comments and strip \n */ for (i = 0, r = -1; cp[i] != '\0'; i++) { if (cp[i] == '#' || cp[i] == '\n') { cp[i] = '\0'; break; } if (cp[i] == ' ' || cp[i] == '\t') { /* Remember the start of a span of whitespace */ if (r == -1) r = i; } else r = -1; } if (r != -1) cp[r] = '\0'; if (*cp == '\0') continue; if (strncasecmp(cp, "serial:", 7) == 0) { if (ca == NULL && !wild_ca) { fatal("revoking certificates by serial number " "requires specification of a CA key"); } cp += 7; cp = cp + strspn(cp, " \t"); errno = 0; serial = strtoull(cp, &ep, 0); if (*cp == '\0' || (*ep != '\0' && *ep != '-')) fatal("%s:%lu: invalid serial \"%s\"", path, lnum, cp); if (errno == ERANGE && serial == ULLONG_MAX) fatal("%s:%lu: serial out of range", path, lnum); serial2 = serial; if (*ep == '-') { cp = ep + 1; errno = 0; serial2 = strtoull(cp, &ep, 0); if (*cp == '\0' || *ep != '\0') fatal("%s:%lu: invalid serial \"%s\"", path, lnum, cp); if (errno == ERANGE && serial2 == ULLONG_MAX) fatal("%s:%lu: serial out of range", path, lnum); if (serial2 <= serial) fatal("%s:%lu: invalid serial range " "%llu:%llu", path, lnum, (unsigned long long)serial, (unsigned long long)serial2); } if (ssh_krl_revoke_cert_by_serial_range(krl, ca, serial, serial2) != 0) { fatal_f("revoke serial failed"); } } else if (strncasecmp(cp, "id:", 3) == 0) { if (ca == NULL && !wild_ca) { fatal("revoking certificates by key ID " "requires specification of a CA key"); } cp += 3; cp = cp + strspn(cp, " \t"); if (ssh_krl_revoke_cert_by_key_id(krl, ca, cp) != 0) fatal_f("revoke key ID failed"); } else if (strncasecmp(cp, "hash:", 5) == 0) { cp += 5; cp = cp + strspn(cp, " \t"); hash_to_blob(cp, &blob, &blen, file, lnum); r = ssh_krl_revoke_key_sha256(krl, blob, blen); if (r != 0) fatal_fr(r, "revoke key failed"); } else { if (strncasecmp(cp, "key:", 4) == 0) { cp += 4; cp = cp + strspn(cp, " \t"); was_explicit_key = 1; } else if (strncasecmp(cp, "sha1:", 5) == 0) { cp += 5; cp = cp + strspn(cp, " \t"); was_sha1 = 1; } else if (strncasecmp(cp, "sha256:", 7) == 0) { cp += 7; cp = cp + strspn(cp, " \t"); was_sha256 = 1; /* * Just try to process the line as a key. * Parsing will fail if it isn't. */ } if ((key = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new"); if ((r = sshkey_read(key, &cp)) != 0) fatal_r(r, "%s:%lu: invalid key", path, lnum); if (was_explicit_key) r = ssh_krl_revoke_key_explicit(krl, key); else if (was_sha1) { if (sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1, &blob, &blen) != 0) { fatal("%s:%lu: fingerprint failed", file, lnum); } r = ssh_krl_revoke_key_sha1(krl, blob, blen); } else if (was_sha256) { if (sshkey_fingerprint_raw(key, SSH_DIGEST_SHA256, &blob, &blen) != 0) { fatal("%s:%lu: fingerprint failed", file, lnum); } r = ssh_krl_revoke_key_sha256(krl, blob, blen); } else r = ssh_krl_revoke_key(krl, key); if (r != 0) fatal_fr(r, "revoke key failed"); freezero(blob, blen); blob = NULL; blen = 0; sshkey_free(key); } } if (strcmp(path, "-") != 0) fclose(krl_spec); free(line); free(path); } static void do_gen_krl(struct passwd *pw, int updating, const char *ca_key_path, unsigned long long krl_version, const char *krl_comment, int argc, char **argv) { struct ssh_krl *krl; struct stat sb; struct sshkey *ca = NULL; int i, r, wild_ca = 0; char *tmp; struct sshbuf *kbuf; if (*identity_file == '\0') fatal("KRL generation requires an output file"); if (stat(identity_file, &sb) == -1) { if (errno != ENOENT) fatal("Cannot access KRL \"%s\": %s", identity_file, strerror(errno)); if (updating) fatal("KRL \"%s\" does not exist", identity_file); } if (ca_key_path != NULL) { if (strcasecmp(ca_key_path, "none") == 0) wild_ca = 1; else { tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0) fatal_r(r, "Cannot load CA public key %s", tmp); free(tmp); } } if (updating) load_krl(identity_file, &krl); else if ((krl = ssh_krl_init()) == NULL) fatal("couldn't create KRL"); if (krl_version != 0) ssh_krl_set_version(krl, krl_version); if (krl_comment != NULL) ssh_krl_set_comment(krl, krl_comment); for (i = 0; i < argc; i++) update_krl_from_file(pw, argv[i], wild_ca, ca, krl); if ((kbuf = sshbuf_new()) == NULL) fatal("sshbuf_new failed"); if (ssh_krl_to_blob(krl, kbuf, NULL, 0) != 0) fatal("Couldn't generate KRL"); if ((r = sshbuf_write_file(identity_file, kbuf)) != 0) fatal("write %s: %s", identity_file, strerror(errno)); sshbuf_free(kbuf); ssh_krl_free(krl); sshkey_free(ca); } static void do_check_krl(struct passwd *pw, int print_krl, int argc, char **argv) { int i, r, ret = 0; char *comment; struct ssh_krl *krl; struct sshkey *k; if (*identity_file == '\0') fatal("KRL checking requires an input file"); load_krl(identity_file, &krl); if (print_krl) krl_dump(krl, stdout); for (i = 0; i < argc; i++) { if ((r = sshkey_load_public(argv[i], &k, &comment)) != 0) fatal_r(r, "Cannot load public key %s", argv[i]); r = ssh_krl_check_key(krl, k); printf("%s%s%s%s: %s\n", argv[i], *comment ? " (" : "", comment, *comment ? ")" : "", r == 0 ? "ok" : "REVOKED"); if (r != 0) ret = 1; sshkey_free(k); free(comment); } ssh_krl_free(krl); exit(ret); } static struct sshkey * load_sign_key(const char *keypath, const struct sshkey *pubkey) { size_t i, slen, plen = strlen(keypath); char *privpath = xstrdup(keypath); static const char * const suffixes[] = { "-cert.pub", ".pub", NULL }; struct sshkey *ret = NULL, *privkey = NULL; int r; /* * If passed a public key filename, then try to locate the corresponding * private key. This lets us specify certificates on the command-line * and have ssh-keygen find the appropriate private key. */ for (i = 0; suffixes[i]; i++) { slen = strlen(suffixes[i]); if (plen <= slen || strcmp(privpath + plen - slen, suffixes[i]) != 0) continue; privpath[plen - slen] = '\0'; debug_f("%s looks like a public key, using private key " "path %s instead", keypath, privpath); } if ((privkey = load_identity(privpath, NULL)) == NULL) { error("Couldn't load identity %s", keypath); goto done; } if (!sshkey_equal_public(pubkey, privkey)) { error("Public key %s doesn't match private %s", keypath, privpath); goto done; } if (sshkey_is_cert(pubkey) && !sshkey_is_cert(privkey)) { /* * Graft the certificate onto the private key to make * it capable of signing. */ if ((r = sshkey_to_certified(privkey)) != 0) { error_fr(r, "sshkey_to_certified"); goto done; } if ((r = sshkey_cert_copy(pubkey, privkey)) != 0) { error_fr(r, "sshkey_cert_copy"); goto done; } } /* success */ ret = privkey; privkey = NULL; done: sshkey_free(privkey); free(privpath); return ret; } static int sign_one(struct sshkey *signkey, const char *filename, int fd, const char *sig_namespace, 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) { 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) debug_r(r, "Couldn't get agent socket"); else { if ((r = ssh_agent_has_key(agent_fd, pubkey)) == 0) signer = agent_signer; else debug_r(r, "Couldn't find key in agent"); } if (signer == NULL) { /* Not using agent - try to load private key */ if ((privkey = load_sign_key(keypath, pubkey)) == NULL) goto done; signkey = privkey; } else { /* Will use key in agent */ signkey = pubkey; } if (argc == 0) { if ((r = sign_one(signkey, "(stdin)", STDIN_FILENO, sig_namespace, 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 */ } static char * private_key_passphrase(void) { char *passphrase1, *passphrase2; /* Ask for a passphrase (twice). */ if (identity_passphrase) passphrase1 = xstrdup(identity_passphrase); else if (identity_new_passphrase) passphrase1 = xstrdup(identity_new_passphrase); else { passphrase_again: passphrase1 = read_passphrase("Enter passphrase (empty for no " "passphrase): ", RP_ALLOW_STDIN); passphrase2 = read_passphrase("Enter same passphrase again: ", RP_ALLOW_STDIN); if (strcmp(passphrase1, passphrase2) != 0) { /* * The passphrases do not match. Clear them and * retry. */ freezero(passphrase1, strlen(passphrase1)); freezero(passphrase2, strlen(passphrase2)); printf("Passphrases do not match. Try again.\n"); goto passphrase_again; } /* Clear the other copy of the passphrase. */ freezero(passphrase2, strlen(passphrase2)); } return passphrase1; } static 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 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 *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); } 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++) { fflush(stdout); r = sshsk_enroll(type, sk_provider, sk_device, sk_application == NULL ? "ssh:" : sk_application, sk_user, sk_flags, passphrase, challenge, &private, attest); if (r == 0) break; if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) fatal_r(r, "Key enrollment failed"); else if (passphrase != NULL) { error("PIN incorrect"); freezero(passphrase, strlen(passphrase)); passphrase = NULL; } if (i >= 3) fatal("Too many incorrect PINs"); passphrase = read_passphrase("Enter PIN for " "authenticator: ", RP_ALLOW_STDIN); if (!quiet) { printf("You may need to touch your " "authenticator (again) to authorize " "key generation.\n"); } } if (passphrase != NULL) { freezero(passphrase, strlen(passphrase)); passphrase = NULL; } break; default: if ((r = sshkey_generate(type, bits, &private)) != 0) fatal("sshkey_generate failed"); break; } if ((r = sshkey_from_private(private, &public)) != 0) fatal_r(r, "sshkey_from_private"); if (!have_identity) ask_filename(pw, "Enter file in which to save the key"); /* Create ~/.ssh directory if it doesn't already exist. */ hostfile_create_user_ssh_dir(identity_file, !quiet); /* If the file already exists, ask the user to confirm. */ if (!confirm_overwrite(identity_file)) exit(1); /* Determine the passphrase for the private key */ passphrase = private_key_passphrase(); if (identity_comment) { strlcpy(comment, identity_comment, sizeof(comment)); } else { /* Create default comment field for the passphrase. */ snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); } /* Save the key with the given passphrase and comment. */ if ((r = sshkey_save_private(private, identity_file, passphrase, comment, private_key_format, openssh_format_cipher, rounds)) != 0) { error_r(r, "Saving key \"%s\" failed", identity_file); freezero(passphrase, strlen(passphrase)); exit(1); } freezero(passphrase, strlen(passphrase)); sshkey_free(private); if (!quiet) { printf("Your identification has been saved in %s\n", identity_file); } strlcat(identity_file, ".pub", sizeof(identity_file)); if ((r = sshkey_save_public(public, identity_file, comment)) != 0) fatal_r(r, "Unable to save public key to %s", identity_file); if (!quiet) { fp = sshkey_fingerprint(public, fingerprint_hash, SSH_FP_DEFAULT); ra = sshkey_fingerprint(public, fingerprint_hash, SSH_FP_RANDOMART); if (fp == NULL || ra == NULL) fatal("sshkey_fingerprint failed"); printf("Your public key has been saved in %s\n", identity_file); printf("The key fingerprint is:\n"); printf("%s %s\n", fp, comment); printf("The key's randomart image is:\n"); printf("%s\n", ra); free(ra); free(fp); } if (sk_attestation_path != NULL) save_attestation(attest, sk_attestation_path); sshbuf_free(attest); sshkey_free(public); exit(0); } diff --git a/crypto/openssh/ssh-keysign.8 b/crypto/openssh/ssh-keysign.8 index 73b62397c10b..6b4b9b270ba9 100644 --- a/crypto/openssh/ssh-keysign.8 +++ b/crypto/openssh/ssh-keysign.8 @@ -1,93 +1,93 @@ -.\" $OpenBSD: ssh-keysign.8,v 1.16 2019/11/30 07:07:59 jmc Exp $ +.\" $OpenBSD: ssh-keysign.8,v 1.17 2022/03/31 17:27:27 naddy 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. .\" -.Dd $Mdocdate: November 30 2019 $ +.Dd $Mdocdate: March 31 2022 $ .Dt SSH-KEYSIGN 8 .Os .Sh NAME .Nm ssh-keysign .Nd OpenSSH helper for host-based authentication .Sh SYNOPSIS .Nm .Sh DESCRIPTION .Nm is used by .Xr ssh 1 to access the local host keys and generate the digital signature required during host-based authentication. .Pp .Nm is disabled by default and can only be enabled in the global client configuration file .Pa /etc/ssh/ssh_config by setting .Cm EnableSSHKeysign to .Dq yes . .Pp .Nm is not intended to be invoked by the user, but from .Xr ssh 1 . See .Xr ssh 1 and .Xr sshd 8 for more information about host-based authentication. .Sh FILES .Bl -tag -width Ds -compact .It Pa /etc/ssh/ssh_config Controls whether .Nm is enabled. .Pp .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 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, .Nm must be set-uid root if host-based authentication is used. .Pp .It Pa /etc/ssh/ssh_host_dsa_key-cert.pub .It Pa /etc/ssh/ssh_host_ecdsa_key-cert.pub .It Pa /etc/ssh/ssh_host_ed25519_key-cert.pub .It Pa /etc/ssh/ssh_host_rsa_key-cert.pub -If these files exist they are assumed to contain public certificate +If these files exist, they are assumed to contain public certificate information corresponding with the private keys above. .El .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-keygen 1 , .Xr ssh_config 5 , .Xr sshd 8 .Sh HISTORY .Nm first appeared in .Ox 3.2 . .Sh AUTHORS .An Markus Friedl Aq Mt markus@openbsd.org diff --git a/crypto/openssh/ssh.1 b/crypto/openssh/ssh.1 index a6384460872d..9c6f5b798778 100644 --- a/crypto/openssh/ssh.1 +++ b/crypto/openssh/ssh.1 @@ -1,1780 +1,1780 @@ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , 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.429 2022/02/06 00:29:03 jsg Exp $ +.\" $OpenBSD: ssh.1,v 1.430 2022/03/31 17:27:27 naddy Exp $ .\" $FreeBSD$ -.Dd $Mdocdate: February 6 2022 $ +.Dd $Mdocdate: March 31 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. .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. .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 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 VersionAddendum .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 +.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 +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 +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/crypto/openssh/ssh.c b/crypto/openssh/ssh.c index a12dd11edec0..e1c8011bba8c 100644 --- a/crypto/openssh/ssh.c +++ b/crypto/openssh/ssh.c @@ -1,2391 +1,2391 @@ -/* $OpenBSD: ssh.c,v 1.573 2022/02/08 08:59:12 dtucker Exp $ */ +/* $OpenBSD: ssh.c,v 1.574 2022/03/30 04:33:09 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , 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 * 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" __RCSID("$FreeBSD$"); #include #ifdef HAVE_SYS_STAT_H # include #endif #include #include #include #include #include #include #include #include #ifdef HAVE_PATHS_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef WITH_OPENSSL #include #include #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. */ static void check_load(int r, const char *path, const char *message) { switch (r) { case 0: break; case SSH_ERR_INTERNAL_ERROR: case SSH_ERR_ALLOC_FAIL: fatal_r(r, "load %s \"%s\"", message, path); case SSH_ERR_SYSTEM_ERROR: /* Ignore missing files */ if (errno == ENOENT) break; /* FALLTHROUGH */ default: error_r(r, "load %s \"%s\"", message, path); break; } } /* * Read per-user configuration file. Ignore the system wide config * file if the user specifies a config file on the command line. */ static void process_config_files(const char *host_name, struct passwd *pw, int final_pass, int *want_final_pass) { char buf[PATH_MAX]; int r; if (config != NULL) { if (strcasecmp(config, "none") != 0 && !read_config_file(config, pw, host, host_name, &options, SSHCONF_USERCONF | (final_pass ? SSHCONF_FINAL : 0), want_final_pass)) fatal("Can't open user config file %.100s: " "%.100s", config, strerror(errno)); } else { r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_USER_CONFFILE); if (r > 0 && (size_t)r < sizeof(buf)) (void)read_config_file(buf, pw, host, host_name, &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | (final_pass ? SSHCONF_FINAL : 0), want_final_pass); /* Read systemwide configuration file after user config. */ (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, host, host_name, &options, final_pass ? SSHCONF_FINAL : 0, want_final_pass); } } /* Rewrite the port number in an addrinfo list of addresses */ static void set_addrinfo_port(struct addrinfo *addrs, int port) { struct addrinfo *addr; for (addr = addrs; addr != NULL; addr = addr->ai_next) { switch (addr->ai_family) { case AF_INET: ((struct sockaddr_in *)addr->ai_addr)-> sin_port = htons(port); break; case AF_INET6: ((struct sockaddr_in6 *)addr->ai_addr)-> sin6_port = htons(port); break; } } } static void ssh_conn_info_free(struct ssh_conn_info *cinfo) { if (cinfo == NULL) return; free(cinfo->conn_hash_hex); free(cinfo->shorthost); free(cinfo->uidstr); free(cinfo->keyalias); free(cinfo->thishost); free(cinfo->host_arg); free(cinfo->portstr); free(cinfo->remhost); free(cinfo->remuser); free(cinfo->homedir); free(cinfo->locuser); free(cinfo); } /* * Main program for the ssh client. */ int main(int ac, char **av) { struct ssh *ssh = NULL; int i, r, opt, exit_status, use_syslog, direct, timeout_ms; int was_addr, config_test = 0, opt_terminated = 0, want_final_pass = 0; char *p, *cp, *line, *argv0, *logfile, *host_arg; char cname[NI_MAXHOST], thishost[NI_MAXHOST]; struct stat st; struct passwd *pw; extern int optind, optreset; extern char *optarg; struct Forward fwd; struct addrinfo *addrs = NULL; size_t n, len; u_int j; struct ssh_conn_info *cinfo = NULL; /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); /* * 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) { + "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': if (options.version_addendum != NULL && *options.version_addendum != '\0') fprintf(stderr, "%s %s, %s\n", SSH_RELEASE, options.version_addendum, SSH_OPENSSL_VERSION); else 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"); } } /* * 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) /* version_addendum is always NULL at this point */ 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); /* Find canonic host name. */ if (strchr(host, '.') == 0) { struct addrinfo hints; struct addrinfo *ai = NULL; int errgai; memset(&hints, 0, sizeof(hints)); hints.ai_family = options.address_family; hints.ai_flags = AI_CANONNAME; hints.ai_socktype = SOCK_STREAM; errgai = getaddrinfo(host, NULL, &hints, &ai); if (errgai == 0) { if (ai->ai_canonname != NULL) host = xstrdup(ai->ai_canonname); freeaddrinfo(ai); } } /* * 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"); \ 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"); \ 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"); debug("identity file %s type %d", filename, public ? public->type : -1); free(options.identity_files[i]); identity_files[n_ids] = filename; identity_keys[n_ids] = public; identity_file_userprovided[n_ids] = options.identity_file_userprovided[i]; if (++n_ids >= SSH_MAX_IDENTITY_FILES) continue; /* * If no certificates have been explicitly listed then try * to add the default certificate variant too. */ if (options.num_certificate_files != 0) continue; xasprintf(&cp, "%s-cert", filename); check_load(sshkey_load_public(cp, &public, NULL), filename, "pubkey"); debug("identity file %s type %d", cp, public ? public->type : -1); if (public == NULL) { free(cp); continue; } if (!sshkey_is_cert(public)) { debug_f("key %s type %s is not a certificate", cp, sshkey_type(public)); sshkey_free(public); free(cp); continue; } /* NB. leave filename pointing to private key */ identity_files[n_ids] = xstrdup(filename); identity_keys[n_ids] = public; identity_file_userprovided[n_ids] = options.identity_file_userprovided[i]; n_ids++; } if (options.num_certificate_files > SSH_MAX_CERTIFICATE_FILES) fatal_f("too many certificates"); for (i = 0; i < options.num_certificate_files; i++) { cp = tilde_expand_filename(options.certificate_files[i], getuid()); filename = default_client_percent_dollar_expand(cp, cinfo); free(cp); check_load(sshkey_load_public(filename, &public, NULL), filename, "certificate"); debug("certificate file %s type %d", filename, public ? public->type : -1); free(options.certificate_files[i]); options.certificate_files[i] = NULL; if (public == NULL) { free(filename); continue; } if (!sshkey_is_cert(public)) { debug_f("key %s type %s is not a certificate", filename, sshkey_type(public)); sshkey_free(public); free(filename); continue; } certificate_files[n_certs] = filename; certificates[n_certs] = public; certificate_file_userprovided[n_certs] = options.certificate_file_userprovided[i]; ++n_certs; } options.num_identity_files = n_ids; memcpy(options.identity_files, identity_files, sizeof(identity_files)); memcpy(options.identity_keys, identity_keys, sizeof(identity_keys)); memcpy(options.identity_file_userprovided, identity_file_userprovided, sizeof(identity_file_userprovided)); options.num_certificate_files = n_certs; memcpy(options.certificate_files, certificate_files, sizeof(certificate_files)); memcpy(options.certificates, certificates, sizeof(certificates)); memcpy(options.certificate_file_userprovided, certificate_file_userprovided, sizeof(certificate_file_userprovided)); } static void main_sigchld_handler(int sig) { int save_errno = errno; pid_t pid; int status; while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || (pid == -1 && errno == EINTR)) ; errno = save_errno; } diff --git a/crypto/openssh/ssh_config b/crypto/openssh/ssh_config index 02d72f367089..792a47f333ee 100644 --- a/crypto/openssh/ssh_config +++ b/crypto/openssh/ssh_config @@ -1,49 +1,49 @@ # $OpenBSD: ssh_config,v 1.35 2020/07/17 03:43:42 dtucker Exp $ # $FreeBSD$ # This is the ssh client system-wide configuration file. See # ssh_config(5) for more information. This file provides defaults for # users, and the values can be changed in per-user configuration files # or on the command line. # 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. # Site-wide defaults for some commonly used options. For a comprehensive # list of available options, their meanings and defaults, please see the # ssh_config(5) man page. # Host * # ForwardAgent no # ForwardX11 no # PasswordAuthentication yes # HostbasedAuthentication no # GSSAPIAuthentication no # GSSAPIDelegateCredentials no # BatchMode no # CheckHostIP no # AddressFamily any # ConnectTimeout 0 # StrictHostKeyChecking ask # IdentityFile ~/.ssh/id_rsa # IdentityFile ~/.ssh/id_dsa # IdentityFile ~/.ssh/id_ecdsa # IdentityFile ~/.ssh/id_ed25519 # Port 22 # Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc # MACs hmac-md5,hmac-sha1,umac-64@openssh.com # EscapeChar ~ # Tunnel no # TunnelDevice any:any # PermitLocalCommand no # VisualHostKey no # ProxyCommand ssh -q -W %h:%p gateway.example.com # RekeyLimit 1G 1h # UserKnownHostsFile ~/.ssh/known_hosts.d/%k # VerifyHostKeyDNS yes -# VersionAddendum FreeBSD-20220413 +# VersionAddendum FreeBSD-20220415 diff --git a/crypto/openssh/ssh_config.5 b/crypto/openssh/ssh_config.5 index 4af0833a1ba8..2762e25004b4 100644 --- a/crypto/openssh/ssh_config.5 +++ b/crypto/openssh/ssh_config.5 @@ -1,2197 +1,2197 @@ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , 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.369 2022/02/15 05:13:36 djm Exp $ +.\" $OpenBSD: ssh_config.5,v 1.371 2022/03/31 17:58:44 naddy Exp $ .\" $FreeBSD$ -.Dd $Mdocdate: February 15 2022 $ +.Dd $Mdocdate: March 31 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. The default is .Cm no . .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-rsa-cert-v01@openssh.com, ssh-ed25519, ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, sk-ssh-ed25519@openssh.com, sk-ecdsa-sha2-nistp256@openssh.com, rsa-sha2-512,rsa-sha2-256,ssh-rsa .Ed .Pp The .Fl Q option of .Xr ssh 1 may be used to list supported signature algorithms. This was formerly named HostbasedKeyTypes. .It Cm HostbasedAuthentication Specifies whether to try rhosts based authentication with public key authentication. The argument must be .Cm yes or .Cm no (the default). .It Cm HostKeyAlgorithms Specifies the host key signature algorithms that the client wants to use in order of preference. Alternately if the specified list begins with a .Sq + character, then the specified signature algorithms will be appended to the default set instead of replacing them. If the specified list begins with a .Sq - character, then the specified signature algorithms (including wildcards) will be removed from the default set instead of replacing them. If the specified list begins with a .Sq ^ character, then the specified signature algorithms will be placed at the head of the default set. The default for this option is: .Bd -literal -offset 3n ssh-ed25519-cert-v01@openssh.com, ecdsa-sha2-nistp256-cert-v01@openssh.com, ecdsa-sha2-nistp384-cert-v01@openssh.com, ecdsa-sha2-nistp521-cert-v01@openssh.com, sk-ssh-ed25519-cert-v01@openssh.com, sk-ecdsa-sha2-nistp256-cert-v01@openssh.com, rsa-sha2-512-cert-v01@openssh.com, rsa-sha2-256-cert-v01@openssh.com, ssh-rsa-cert-v01@openssh.com, ssh-ed25519, ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, sk-ecdsa-sha2-nistp256@openssh.com, sk-ssh-ed25519@openssh.com, rsa-sha2-512,rsa-sha2-256,ssh-rsa .Ed .Pp If hostkeys are known for the destination host then this default is modified to prefer their algorithms. .Pp The list of available signature algorithms may also be obtained using .Qq ssh -Q HostKeyAlgorithms . .It Cm HostKeyAlias Specifies an alias that should be used instead of the real host name when looking up or saving the host key in the host key database files and when validating host certificates. This option is useful for tunneling SSH connections or for multiple servers running on a single host. .It Cm Hostname Specifies the real host name to log into. This can be used to specify nicknames or abbreviations for hosts. Arguments to .Cm Hostname accept the tokens described in the .Sx TOKENS section. Numeric IP addresses are also permitted (both on the command line and in .Cm Hostname specifications). The default is the name given on the command line. .It Cm IdentitiesOnly Specifies that .Xr ssh 1 should only use the configured authentication identity and certificate files (either the default files, or those explicitly configured in the .Nm files or passed on the .Xr ssh 1 command-line), even if .Xr ssh-agent 1 or a .Cm PKCS11Provider or .Cm SecurityKeyProvider offers more identities. The argument to this keyword must be .Cm yes or .Cm no (the default). This option is intended for situations where ssh-agent offers many different identities. .It Cm IdentityAgent Specifies the .Ux Ns -domain socket used to communicate with the authentication agent. .Pp This option overrides the .Ev SSH_AUTH_SOCK environment variable and can be used to select a specific agent. Setting the socket name to .Cm none disables the use of an authentication agent. If the string .Qq SSH_AUTH_SOCK is specified, the location of the socket will be read from the .Ev SSH_AUTH_SOCK environment variable. Otherwise if the specified value begins with a .Sq $ character, then it will be treated as an environment variable containing the location of the socket. .Pp Arguments to .Cm IdentityAgent may use the tilde syntax to refer to a user's home directory, the tokens described in the .Sx TOKENS section and environment variables as described in the .Sx ENVIRONMENT VARIABLES section. .It Cm IdentityFile Specifies a file from which the user's DSA, ECDSA, authenticator-hosted ECDSA, Ed25519, authenticator-hosted Ed25519 or RSA authentication identity is read. The default is .Pa ~/.ssh/id_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, -sntrup761x25519-sha512@openssh.com, diffie-hellman-group-exchange-sha256, diffie-hellman-group16-sha512, diffie-hellman-group18-sha512, diffie-hellman-group14-sha256 .Ed .Pp The list of available key exchange algorithms may also be obtained using .Qq ssh -Q kex . .It Cm KnownHostsCommand Specifies a command to use to obtain a list of host keys, in addition to those listed in .Cm UserKnownHostsFile and .Cm GlobalKnownHostsFile . This command is executed after the files have been read. It may write host key lines to standard output in identical format to the usual files (described in the .Sx VERIFYING HOST KEYS section in .Xr ssh 1 ) . Arguments to .Cm KnownHostsCommand accept the tokens described in the .Sx TOKENS section. The command may be invoked multiple times per connection: once when preparing the preference list of host key algorithms to use, again to obtain the host key for the requested host name and, if .Cm CheckHostIP is enabled, one more time to obtain the host key matching the server's address. If the command exits abnormally or returns a non-zero exit status then the connection is terminated. .It Cm LocalCommand Specifies a command to execute on the local machine after successfully connecting to the server. The command string extends to the end of the line, and is executed with the user's shell. Arguments to .Cm LocalCommand accept the tokens described in the .Sx TOKENS section. .Pp The command is run synchronously and does not have access to the session of the .Xr ssh 1 that spawned it. It should not be used for interactive commands. .Pp This directive is ignored unless .Cm PermitLocalCommand has been enabled. .It Cm LocalForward Specifies that a TCP port on the local machine be forwarded over the secure channel to the specified host and port from the remote machine. The first argument specifies the listener and may be .Sm off .Oo Ar bind_address : Oc Ar port .Sm on or a Unix domain socket path. The second argument is the destination and may be .Ar host : Ns Ar hostport or a Unix domain socket path if the remote host supports it. .Pp IPv6 addresses can be specified by enclosing addresses in square brackets. Multiple forwardings may be specified, and additional forwardings can be given on the command line. Only the superuser can forward privileged ports. By default, the local port is bound in accordance with the .Cm GatewayPorts setting. However, an explicit .Ar bind_address may be used to bind the connection to a specific address. The .Ar bind_address of .Cm localhost indicates that the listening port be bound for local use only, while an empty address or .Sq * indicates that the port should be available from all interfaces. Unix domain socket paths may use the tokens described in the .Sx TOKENS section and environment variables as described in the .Sx ENVIRONMENT VARIABLES section. .It Cm LogLevel Gives the verbosity level that is used when logging messages from .Xr ssh 1 . The possible values are: QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3. The default is INFO. DEBUG and DEBUG1 are equivalent. DEBUG2 and DEBUG3 each specify higher levels of verbose output. .It Cm LogVerbose Specify one or more overrides to LogLevel. An override consists of a pattern lists that matches the source file, function and line number to force detailed logging for. For example, an override pattern of: .Bd -literal -offset indent kex.c:*:1000,*:kex_exchange_identification():*,packet.c:* .Ed .Pp would enable detailed logging for line 1000 of .Pa kex.c , everything in the .Fn kex_exchange_identification function, and all code in the .Pa packet.c file. This option is intended for debugging and no overrides are enabled by default. .It Cm MACs Specifies the MAC (message authentication code) algorithms in order of preference. The MAC algorithm is used for data integrity protection. Multiple algorithms must be comma-separated. If the specified list begins with a .Sq + character, then the specified algorithms will be appended to the default set instead of replacing them. If the specified list begins with a .Sq - character, then the specified algorithms (including wildcards) will be removed from the default set instead of replacing them. If the specified list begins with a .Sq ^ character, then the specified algorithms will be placed at the head of the default set. .Pp The algorithms that contain .Qq -etm calculate the MAC after encryption (encrypt-then-mac). These are considered safer and their use recommended. .Pp The default is: .Bd -literal -offset indent umac-64-etm@openssh.com,umac-128-etm@openssh.com, hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com, hmac-sha1-etm@openssh.com, umac-64@openssh.com,umac-128@openssh.com, hmac-sha2-256,hmac-sha2-512,hmac-sha1 .Ed .Pp The list of available MAC algorithms may also be obtained using .Qq ssh -Q mac . .It Cm NoHostAuthenticationForLocalhost Disable host authentication for localhost (loopback addresses). The argument to this keyword must be .Cm yes or .Cm no (the default). .It Cm NumberOfPasswordPrompts Specifies the number of password prompts before giving up. The argument to this keyword must be an integer. The default is 3. .It Cm PasswordAuthentication Specifies whether to use password authentication. The argument to this keyword must be .Cm yes (the default) or .Cm no . .It Cm PermitLocalCommand Allow local command execution via the .Ic LocalCommand option or using the .Ic !\& Ns Ar command escape sequence in .Xr ssh 1 . The argument must be .Cm yes or .Cm no (the default). .It Cm PermitRemoteOpen Specifies the destinations to which remote TCP port forwarding is permitted when .Cm RemoteForward is used as a SOCKS proxy. The forwarding specification must be one of the following forms: .Pp .Bl -item -offset indent -compact .It .Cm PermitRemoteOpen .Sm off .Ar host : port .Sm on .It .Cm PermitRemoteOpen .Sm off .Ar IPv4_addr : port .Sm on .It .Cm PermitRemoteOpen .Sm off .Ar \&[ IPv6_addr \&] : port .Sm on .El .Pp Multiple forwards may be specified by separating them with whitespace. An argument of .Cm any can be used to remove all restrictions and permit any forwarding requests. An argument of .Cm none can be used to prohibit all forwarding requests. The wildcard .Sq * can be used for host or port to allow all hosts or ports respectively. Otherwise, no pattern matching or address lookups are performed on supplied names. .It Cm PKCS11Provider Specifies which PKCS#11 provider to use or .Cm none to indicate that no provider should be used (the default). The argument to this keyword is a path to the PKCS#11 shared library .Xr ssh 1 should use to communicate with a PKCS#11 token providing keys for user authentication. .It Cm Port Specifies the port number to connect on the remote host. The default is 22. .It Cm PreferredAuthentications Specifies the order in which the client should try authentication methods. This allows a client to prefer one method (e.g.\& .Cm keyboard-interactive ) over another method (e.g.\& .Cm password ) . The default is: .Bd -literal -offset indent gssapi-with-mic,hostbased,publickey, keyboard-interactive,password .Ed .It Cm ProxyCommand Specifies the command to use to connect to the server. The command string extends to the end of the line, and is executed using the user's shell .Ql exec directive to avoid a lingering shell process. .Pp Arguments to .Cm ProxyCommand accept the tokens described in the .Sx TOKENS section. The command can be basically anything, and should read from its standard input and write to its standard output. It should eventually connect an .Xr sshd 8 server running on some machine, or execute .Ic sshd -i somewhere. Host key management will be done using the .Cm Hostname of the host being connected (defaulting to the name typed by the user). Setting the command to .Cm none disables this option entirely. Note that .Cm CheckHostIP is not available for connects with a proxy command. .Pp This directive is useful in conjunction with .Xr nc 1 and its proxy support. For example, the following directive would connect via an HTTP proxy at 192.0.2.0: .Bd -literal -offset 3n ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p .Ed .It Cm ProxyJump Specifies one or more jump proxies as either .Xo .Sm off .Op Ar user No @ .Ar host .Op : Ns Ar port .Sm on or an ssh URI .Xc . Multiple proxies may be separated by comma characters and will be visited sequentially. Setting this option will cause .Xr ssh 1 to connect to the target host by first making a .Xr ssh 1 connection to the specified .Cm ProxyJump host and then establishing a TCP forwarding to the ultimate target from there. Setting the host to .Cm none disables this option entirely. .Pp Note that this option will compete with the .Cm ProxyCommand option - whichever is specified first will prevent later instances of the other from taking effect. .Pp Note also that the configuration for the destination host (either supplied via the command-line or the configuration file) is not generally applied to jump hosts. .Pa ~/.ssh/config should be used if specific configuration is required for jump hosts. .It Cm ProxyUseFdpass Specifies that .Cm ProxyCommand will pass a connected file descriptor back to .Xr ssh 1 instead of continuing to execute and pass data. The default is .Cm no . .It Cm PubkeyAcceptedAlgorithms Specifies the signature algorithms that will be used for public key authentication as a comma-separated list of patterns. If the specified list begins with a .Sq + character, then the algorithms after it will be appended to the default instead of replacing it. If the specified list begins with a .Sq - character, then the specified algorithms (including wildcards) will be removed from the default set instead of replacing them. If the specified list begins with a .Sq ^ character, then the specified algorithms will be placed at the head of the default set. The default for this option is: .Bd -literal -offset 3n ssh-ed25519-cert-v01@openssh.com, ecdsa-sha2-nistp256-cert-v01@openssh.com, ecdsa-sha2-nistp384-cert-v01@openssh.com, ecdsa-sha2-nistp521-cert-v01@openssh.com, sk-ssh-ed25519-cert-v01@openssh.com, sk-ecdsa-sha2-nistp256-cert-v01@openssh.com, rsa-sha2-512-cert-v01@openssh.com, rsa-sha2-256-cert-v01@openssh.com, -ssh-rsa-cert-v01@openssh.com, ssh-ed25519, ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, sk-ssh-ed25519@openssh.com, sk-ecdsa-sha2-nistp256@openssh.com, rsa-sha2-512,rsa-sha2-256,ssh-rsa .Ed .Pp The list of available signature algorithms may also be obtained using .Qq ssh -Q PubkeyAcceptedAlgorithms . .It Cm PubkeyAuthentication Specifies whether to try public key authentication. The argument to this keyword must be .Cm yes (the default), .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. 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 +When acting as a SOCKS proxy, the destination of the connection can be restricted by .Cm PermitRemoteOpen . .Pp IPv6 addresses can be specified by enclosing addresses in square brackets. Multiple forwardings may be specified, and additional forwardings can be given on the command line. Privileged ports can be forwarded only when logging in as root on the remote machine. Unix domain socket paths may use the tokens described in the .Sx TOKENS section and environment variables as described in the .Sx ENVIRONMENT VARIABLES section. .Pp If the .Ar port argument is 0, the listen port will be dynamically allocated on the server and reported to the client at run time. .Pp If the .Ar bind_address is not specified, the default is to only bind to loopback addresses. If the .Ar bind_address is .Ql * or an empty string, then the forwarding is requested to listen on all interfaces. Specifying a remote .Ar bind_address will only succeed if the server's .Cm GatewayPorts option is enabled (see .Xr sshd_config 5 ) . .It Cm RequestTTY Specifies whether to request a pseudo-tty for the session. The argument may be one of: .Cm no (never request a TTY), .Cm yes (always request a TTY when standard input is a TTY), .Cm force (always request a TTY) or .Cm auto (request a TTY when opening a login session). This option mirrors the .Fl t and .Fl T flags for .Xr ssh 1 . .It Cm RevokedHostKeys Specifies revoked host public keys. Keys listed in this file will be refused for host authentication. Note that if this file does not exist or is not readable, then host authentication will be refused for all hosts. Keys may be specified as a text file, listing one public key per line, or as an OpenSSH Key Revocation List (KRL) as generated by .Xr ssh-keygen 1 . For more information on KRLs, see the KEY REVOCATION LISTS section in .Xr ssh-keygen 1 . .It Cm SecurityKeyProvider Specifies a path to a library that will be used when loading any FIDO authenticator-hosted keys, overriding the default of using the built-in USB HID support. .Pp If the specified value begins with a .Sq $ character, then it will be treated as an environment variable containing the path to the library. .It Cm SendEnv Specifies what variables from the local .Xr environ 7 should be sent to the server. The server must also support it, and the server must be configured to accept these environment variables. Note that the .Ev TERM environment variable is always sent whenever a pseudo-terminal is requested as it is required by the protocol. Refer to .Cm AcceptEnv in .Xr sshd_config 5 for how to configure the server. Variables are specified by name, which may contain wildcard characters. Multiple environment variables may be separated by whitespace or spread across multiple .Cm SendEnv directives. .Pp See .Sx PATTERNS for more information on patterns. .Pp It is possible to clear previously set .Cm SendEnv variable names by prefixing patterns with .Pa - . The default is not to send any environment variables. .It Cm ServerAliveCountMax Sets the number of server alive messages (see below) which may be sent without .Xr ssh 1 receiving any messages back from the server. If this threshold is reached while server alive messages are being sent, ssh will disconnect from the server, terminating the session. It is important to note that the use of server alive messages is very different from .Cm TCPKeepAlive (below). The server alive messages are sent through the encrypted channel and therefore will not be spoofable. The TCP keepalive option enabled by .Cm TCPKeepAlive is spoofable. The server alive mechanism is valuable when the client or server depend on knowing when a connection has become unresponsive. .Pp The default value is 3. If, for example, .Cm ServerAliveInterval (see below) is set to 15 and .Cm ServerAliveCountMax is left at the default, if the server becomes unresponsive, ssh will disconnect after approximately 45 seconds. .It Cm ServerAliveInterval Sets a timeout interval in seconds after which if no data has been received from the server, .Xr ssh 1 will send a message through the encrypted channel to request a response from the server. The default is 0, indicating that these messages will not be sent to the server. .It Cm 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 yes if compiled with LDNS and .Cm no otherwise. .Pp See also .Sx VERIFYING HOST KEYS in .Xr ssh 1 . .It Cm VersionAddendum Specifies a string to append to the regular version string to identify OS- or site-specific modifications. The default is -.Dq FreeBSD-20220413 . +.Dq FreeBSD-20220415 . The value .Cm none may be used to disable this. .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/local/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. .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/crypto/openssh/sshd.8 b/crypto/openssh/sshd.8 index 877621b011a4..db4c35da847c 100644 --- a/crypto/openssh/sshd.8 +++ b/crypto/openssh/sshd.8 @@ -1,1037 +1,1037 @@ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , 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.317 2021/09/10 11:38:38 dtucker Exp $ +.\" $OpenBSD: sshd.8,v 1.318 2022/03/31 17:27:27 naddy Exp $ .\" $FreeBSD$ -.Dd $Mdocdate: September 10 2021 $ +.Dd $Mdocdate: March 31 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.d/sshd . 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 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 and .Pa /var/run/nologin ; if one exists, it prints the 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. .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 +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.allow .It Pa /etc/hosts.deny Access controls that should be enforced by tcp-wrappers are defined here. Further details are described in .Xr hosts_access 5 . .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 hosts_access 5 , .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/crypto/openssh/sshd.c b/crypto/openssh/sshd.c index 78bfdf0d8a99..99fae00aa7ce 100644 --- a/crypto/openssh/sshd.c +++ b/crypto/openssh/sshd.c @@ -1,2528 +1,2528 @@ -/* $OpenBSD: sshd.c,v 1.584 2022/03/01 01:59:19 djm Exp $ */ +/* $OpenBSD: sshd.c,v 1.585 2022/03/18 04:04:11 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , 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" __RCSID("$FreeBSD$"); #include #include #include #include #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_SYS_TIME_H # include #endif #include "openbsd-compat/sys-tree.h" #include "openbsd-compat/sys-queue.h" #include #include #include #include #ifdef HAVE_PATHS_H #include #endif #include #ifdef HAVE_POLL_H #include #endif #include #include #include #include #include #include #include #include #ifdef WITH_OPENSSL #include #include #include #include "openbsd-compat/openssl-compat.h" #endif #ifdef HAVE_SECUREWARE #include #include #endif #ifdef __FreeBSD__ #include #if defined(GSSAPI) && defined(HAVE_GSSAPI_GSSAPI_H) #include #elif defined(GSSAPI) && defined(HAVE_GSSAPI_H) #include #endif #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" #include "blacklist_client.h" #ifdef LIBWRAP #include #include int allow_severity; int deny_severity; #endif /* LIBWRAP */ /* 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); } BLACKLIST_NOTIFY(the_active_state, BLACKLIST_AUTH_FAIL, "ssh"); /* 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) { if (options.version_addendum != NULL && *options.version_addendum != '\0') fprintf(stderr, "%s %s, %s\n", SSH_RELEASE, options.version_addendum, SSH_OPENSSL_VERSION); else 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) { 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); + 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]); } 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); /* Avoid killing the process in high-pressure swapping environments. */ if (!inetd_flag && madvise(NULL, 0, MADV_PROTECT) != 0) debug("madvise(): %.200s", strerror(errno)); /* * 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); #ifdef __FreeBSD__ /* * Initialize the resolver. This may not happen automatically * before privsep chroot(). */ if ((_res.options & RES_INIT) == 0) { debug("res_init()"); res_init(); } #ifdef GSSAPI /* * Force GSS-API to parse its configuration and load any * mechanism plugins. */ { gss_OID_set mechs; OM_uint32 minor_status; gss_indicate_mechs(&minor_status, &mechs); gss_release_oid_set(&minor_status, &mechs); } #endif #endif /* * 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 HAVE_LOGIN_CAP /* Also caches remote hostname for sandboxed child. */ auth_get_canonical_hostname(ssh, options.use_dns); #endif #ifdef SSH_AUDIT_EVENTS audit_connection_from(remote_ip, remote_port); #endif #ifdef LIBWRAP allow_severity = options.log_facility|LOG_INFO; deny_severity = options.log_facility|LOG_WARNING; /* Check whether logins are denied from this host. */ if (ssh_packet_connection_is_on_socket(ssh)) { struct request_info req; request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0); fromhost(&req); if (!hosts_access(&req)) { debug("Connection refused by tcp wrapper"); refuse(&req); /* NOTREACHED */ fatal("libwrap refuse returns"); } } #endif /* LIBWRAP */ 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(); BLACKLIST_INIT(); if (use_privsep) { if (privsep_preauth(ssh) == 1) goto authenticated; } else if (have_agent) { if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) { error_r(r, "Unable to get agent socket"); have_agent = 0; } } /* perform the key exchange */ /* authenticate user and start session */ do_ssh2_kex(ssh); do_authentication2(ssh); /* * If we use privilege separation, the unprivileged child transfers * the current keystate and exits */ if (use_privsep) { mm_send_keystate(ssh, pmonitor); ssh_packet_clear_keys(ssh); exit(0); } authenticated: /* * Cancel the alarm we set to limit the time taken for * authentication. */ alarm(0); ssh_signal(SIGALRM, SIG_DFL); authctxt->authenticated = 1; if (startup_pipe != -1) { close(startup_pipe); startup_pipe = -1; } #ifdef SSH_AUDIT_EVENTS audit_event(ssh, SSH_AUTH_SUCCESS); #endif #ifdef GSSAPI if (options.gss_authentication) { temporarily_use_uid(authctxt->pw); ssh_gssapi_storecreds(); restore_uid(); } #endif #ifdef USE_PAM if (options.use_pam) { do_pam_setcred(1); do_pam_session(ssh); } #endif /* * In privilege separation, we fork another child and prepare * file descriptor passing. */ if (use_privsep) { privsep_postauth(ssh, authctxt); /* the monitor process [priv] will not return */ } ssh_packet_set_timeout(ssh, options.client_alive_interval, options.client_alive_count_max); /* Try to send all our hostkeys to the client */ notify_hostkeys(ssh); /* Start session. */ do_authenticated(ssh, authctxt); /* The connection has been terminated. */ ssh_packet_get_bytes(ssh, &ibytes, &obytes); verbose("Transferred: sent %llu, received %llu bytes", (unsigned long long)obytes, (unsigned long long)ibytes); verbose("Closing connection to %.500s port %d", remote_ip, remote_port); #ifdef USE_PAM if (options.use_pam) finish_pam(); #endif /* USE_PAM */ #ifdef SSH_AUDIT_EVENTS PRIVSEP(audit_event(ssh, SSH_CONNECTION_CLOSE)); #endif ssh_packet_close(ssh); if (use_privsep) mm_terminate(); exit(0); } int sshd_hostkey_sign(struct ssh *ssh, struct sshkey *privkey, struct sshkey *pubkey, u_char **signature, size_t *slenp, const u_char *data, size_t dlen, const char *alg) { int r; if (use_privsep) { if (privkey) { if (mm_sshkey_sign(ssh, privkey, signature, slenp, data, dlen, alg, options.sk_provider, NULL, ssh->compat) < 0) fatal_f("privkey sign failed"); } else { if (mm_sshkey_sign(ssh, pubkey, signature, slenp, data, dlen, alg, options.sk_provider, NULL, ssh->compat) < 0) fatal_f("pubkey sign failed"); } } else { if (privkey) { if (sshkey_sign(privkey, signature, slenp, data, dlen, alg, options.sk_provider, NULL, ssh->compat) < 0) fatal_f("privkey sign failed"); } else { if ((r = ssh_agent_sign(auth_sock, pubkey, signature, slenp, data, dlen, alg, ssh->compat)) != 0) { fatal_fr(r, "agent sign failed"); } } } return 0; } /* SSH2 key exchange */ static void do_ssh2_kex(struct ssh *ssh) { char *myproposal[PROPOSAL_MAX] = { KEX_SERVER }; struct kex *kex; int r; myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(ssh, options.kex_algorithms); myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(ssh, options.ciphers); myproposal[PROPOSAL_ENC_ALGS_STOC] = compat_cipher_proposal(ssh, options.ciphers); myproposal[PROPOSAL_MAC_ALGS_CTOS] = myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; if (options.compression == COMP_NONE) { myproposal[PROPOSAL_COMP_ALGS_CTOS] = myproposal[PROPOSAL_COMP_ALGS_STOC] = "none"; } if (options.rekey_limit || options.rekey_interval) ssh_packet_set_rekey_limits(ssh, options.rekey_limit, options.rekey_interval); myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( ssh, list_hostkey_types()); /* start key exchange */ if ((r = kex_setup(ssh, myproposal)) != 0) fatal_r(r, "kex_setup"); kex = ssh->kex; #ifdef WITH_OPENSSL kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server; kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server; kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_server; kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_server; kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_server; kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; # ifdef OPENSSL_HAS_ECC kex->kex[KEX_ECDH_SHA2] = kex_gen_server; # endif #endif kex->kex[KEX_C25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; kex->load_host_public_key=&get_hostkey_public_by_type; kex->load_host_private_key=&get_hostkey_private_by_type; kex->host_key_index=&get_hostkey_index; kex->sign = sshd_hostkey_sign; ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &kex->done); #ifdef DEBUG_KEXDH /* send 1st encrypted/maced/compressed message */ if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 || (r = sshpkt_put_cstring(ssh, "markus")) != 0 || (r = sshpkt_send(ssh)) != 0 || (r = ssh_packet_write_wait(ssh)) != 0) fatal_fr(r, "send test"); #endif debug("KEX done"); } /* server specific fatal cleanup */ void cleanup_exit(int i) { if (the_active_state != NULL && the_authctxt != NULL) { do_cleanup(the_active_state, the_authctxt); if (use_privsep && privsep_is_preauth && pmonitor != NULL && pmonitor->m_pid > 1) { debug("Killing privsep child %d", pmonitor->m_pid); if (kill(pmonitor->m_pid, SIGKILL) != 0 && errno != ESRCH) { error_f("kill(%d): %s", pmonitor->m_pid, strerror(errno)); } } } #ifdef SSH_AUDIT_EVENTS /* done after do_cleanup so it can cancel the PAM auth 'thread' */ if (the_active_state != NULL && (!use_privsep || mm_is_monitor())) audit_event(the_active_state, SSH_CONNECTION_ABANDON); #endif _exit(i); } diff --git a/crypto/openssh/sshd_config b/crypto/openssh/sshd_config index 284ef2a34f64..1be5dcad866c 100644 --- a/crypto/openssh/sshd_config +++ b/crypto/openssh/sshd_config @@ -1,122 +1,122 @@ # $OpenBSD: sshd_config,v 1.104 2021/07/02 05:11:21 dtucker Exp $ # $FreeBSD$ # This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. # This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin # The strategy used for options in the default sshd_config shipped with # OpenSSH is to specify options with their default value where # possible, but leave them commented. Uncommented options override the # default value. # Note that some of FreeBSD's defaults differ from OpenBSD's, and # FreeBSD has a few additional options. #Port 22 #AddressFamily any #ListenAddress 0.0.0.0 #ListenAddress :: #HostKey /etc/ssh/ssh_host_rsa_key #HostKey /etc/ssh/ssh_host_ecdsa_key #HostKey /etc/ssh/ssh_host_ed25519_key # Ciphers and keying #RekeyLimit default none # Logging #SyslogFacility AUTH #LogLevel INFO # Authentication: #LoginGraceTime 2m #PermitRootLogin no #StrictModes yes #MaxAuthTries 6 #MaxSessions 10 #PubkeyAuthentication yes # The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 # but this is overridden so installations will only check .ssh/authorized_keys AuthorizedKeysFile .ssh/authorized_keys #AuthorizedPrincipalsFile none #AuthorizedKeysCommand none #AuthorizedKeysCommandUser nobody # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts #HostbasedAuthentication no # Change to yes if you don't trust ~/.ssh/known_hosts for # HostbasedAuthentication #IgnoreUserKnownHosts no # Don't read the user's ~/.rhosts and ~/.shosts files #IgnoreRhosts yes # Change to yes to enable built-in password authentication. # Note that passwords may also be accepted via KbdInteractiveAuthentication. #PasswordAuthentication no #PermitEmptyPasswords no # Change to no to disable PAM authentication #KbdInteractiveAuthentication yes # Kerberos options #KerberosAuthentication no #KerberosOrLocalPasswd yes #KerberosTicketCleanup yes #KerberosGetAFSToken no # GSSAPI options #GSSAPIAuthentication no #GSSAPICleanupCredentials yes # Set this to 'no' to disable PAM authentication, account processing, # and session processing. If this is enabled, PAM authentication will # be allowed through the KbdInteractiveAuthentication and # PasswordAuthentication. Depending on your PAM configuration, # PAM authentication via KbdInteractiveAuthentication may bypass # the setting of "PermitRootLogin prohibit-password". # If you just want the PAM account and session checks to run without # PAM authentication, then enable this but set PasswordAuthentication # and KbdInteractiveAuthentication to 'no'. #UsePAM yes #AllowAgentForwarding yes #AllowTcpForwarding yes #GatewayPorts no #X11Forwarding yes #X11DisplayOffset 10 #X11UseLocalhost yes #PermitTTY yes #PrintMotd yes #PrintLastLog yes #TCPKeepAlive yes #PermitUserEnvironment no #Compression delayed #ClientAliveInterval 0 #ClientAliveCountMax 3 #UseDNS yes #PidFile /var/run/sshd.pid #MaxStartups 10:30:100 #PermitTunnel no #ChrootDirectory none #UseBlacklist no -#VersionAddendum FreeBSD-20220413 +#VersionAddendum FreeBSD-20220415 # no default banner path #Banner none # override default of no subsystems Subsystem sftp /usr/libexec/sftp-server # Example of overriding settings on a per-user basis #Match User anoncvs # X11Forwarding no # AllowTcpForwarding no # PermitTTY no # ForceCommand cvs server diff --git a/crypto/openssh/sshd_config.5 b/crypto/openssh/sshd_config.5 index 287ebb870192..ef5da8a1655a 100644 --- a/crypto/openssh/sshd_config.5 +++ b/crypto/openssh/sshd_config.5 @@ -1,2008 +1,2008 @@ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , 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.339 2021/12/04 00:05:39 naddy Exp $ +.\" $OpenBSD: sshd_config.5,v 1.340 2022/03/31 17:58:44 naddy Exp $ .\" $FreeBSD$ -.Dd $Mdocdate: September 3 2021 $ +.Dd $Mdocdate: March 31 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-rsa-cert-v01@openssh.com, ssh-ed25519, ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, sk-ssh-ed25519@openssh.com, sk-ecdsa-sha2-nistp256@openssh.com, rsa-sha2-512,rsa-sha2-256,ssh-rsa .Ed .Pp The list of available signature algorithms may also be obtained using .Qq ssh -Q HostbasedAcceptedAlgorithms . This was formerly named HostbasedAcceptedKeyTypes. .It Cm HostbasedAuthentication Specifies whether rhosts or /etc/hosts.equiv authentication together with successful public key client host authentication is allowed (host-based authentication). The default is .Cm no . .It Cm HostbasedUsesNameFromPacketOnly Specifies whether or not the server will attempt to perform a reverse name lookup when matching the name in the .Pa ~/.shosts , .Pa ~/.rhosts , and .Pa /etc/hosts.equiv files during .Cm HostbasedAuthentication . A setting of .Cm yes means that .Xr sshd 8 uses the name supplied by the client rather than attempting to resolve the name from the TCP connection itself. The default is .Cm no . .It Cm HostCertificate Specifies a file containing a public host certificate. The certificate's public key must match a private host key already specified by .Cm HostKey . The default behaviour of .Xr sshd 8 is not to load any certificates. .It Cm HostKey Specifies a file containing a private host key used by SSH. The defaults are .Pa /etc/ssh/ssh_host_ecdsa_key , .Pa /etc/ssh/ssh_host_ed25519_key and .Pa /etc/ssh/ssh_host_rsa_key . .Pp Note that .Xr sshd 8 will refuse to use a file if it is group/world-accessible and that the .Cm HostKeyAlgorithms option restricts which of the keys are actually used by .Xr sshd 8 . .Pp It is possible to have multiple host key files. It is also possible to specify public host key files instead. In this case operations on the private key will be delegated to an .Xr ssh-agent 1 . .It Cm HostKeyAgent Identifies the UNIX-domain socket used to communicate with an agent that has access to the private host keys. If the string .Qq SSH_AUTH_SOCK is specified, the location of the socket will be read from the .Ev SSH_AUTH_SOCK environment variable. .It Cm HostKeyAlgorithms Specifies the host key signature algorithms that the server offers. The default for this option is: .Bd -literal -offset 3n ssh-ed25519-cert-v01@openssh.com, ecdsa-sha2-nistp256-cert-v01@openssh.com, ecdsa-sha2-nistp384-cert-v01@openssh.com, ecdsa-sha2-nistp521-cert-v01@openssh.com, sk-ssh-ed25519-cert-v01@openssh.com, sk-ecdsa-sha2-nistp256-cert-v01@openssh.com, rsa-sha2-512-cert-v01@openssh.com, rsa-sha2-256-cert-v01@openssh.com, ssh-rsa-cert-v01@openssh.com, ssh-ed25519, ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, sk-ssh-ed25519@openssh.com, sk-ecdsa-sha2-nistp256@openssh.com, rsa-sha2-512,rsa-sha2-256,ssh-rsa .Ed .Pp The list of available signature algorithms may also be obtained using .Qq ssh -Q HostKeyAlgorithms . .It Cm IgnoreRhosts Specifies whether to ignore per-user .Pa .rhosts and .Pa .shosts files during .Cm HostbasedAuthentication . The system-wide .Pa /etc/hosts.equiv and .Pa /etc/ssh/shosts.equiv are still used regardless of this setting. .Pp Accepted values are .Cm yes (the default) to ignore all per-user files, .Cm shosts-only to allow the use of .Pa .shosts but to ignore .Pa .rhosts or .Cm no to allow both .Pa .shosts and .Pa rhosts . .It Cm IgnoreUserKnownHosts Specifies whether .Xr sshd 8 should ignore the user's .Pa ~/.ssh/known_hosts during .Cm HostbasedAuthentication and use only the system-wide known hosts file .Pa /etc/ssh/known_hosts . The default is .Dq no . .It Cm Include Include the specified configuration file(s). Multiple pathnames may be specified and each pathname may contain .Xr glob 7 wildcards that will be expanded and processed in lexical order. Files without absolute paths are assumed to be in .Pa /etc/ssh . An .Cm Include directive may appear inside a .Cm Match block to perform conditional inclusion. .It Cm IPQoS Specifies the IPv4 type-of-service or DSCP class for the connection. Accepted values are .Cm af11 , .Cm af12 , .Cm af13 , .Cm af21 , .Cm af22 , .Cm af23 , .Cm af31 , .Cm af32 , .Cm af33 , .Cm af41 , .Cm af42 , .Cm af43 , .Cm cs0 , .Cm cs1 , .Cm cs2 , .Cm cs3 , .Cm cs4 , .Cm cs5 , .Cm cs6 , .Cm cs7 , .Cm ef , .Cm le , .Cm lowdelay , .Cm throughput , .Cm reliability , a numeric value, or .Cm none to use the operating system default. This option may take one or two arguments, separated by whitespace. If one argument is specified, it is used as the packet class unconditionally. If two values are specified, the first is automatically selected for interactive sessions and the second for non-interactive sessions. The default is .Cm af21 (Low-Latency Data) for interactive sessions and .Cm cs1 (Lower Effort) for non-interactive sessions. .It Cm KbdInteractiveAuthentication Specifies whether to allow keyboard-interactive authentication. 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, -sntrup761x25519-sha512@openssh.com, 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. Note that passwords may also be accepted via .Cm KbdInteractiveAuthentication . See also .Cm UsePAM . The default is .Cm no . .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 no . Note that if .Cm ChallengeResponseAuthentication and .Cm UsePAM are both .Cm yes , this setting may be overridden by the PAM policy. .Pp If this option is set to .Cm prohibit-password (or its deprecated alias, .Cm without-password ) , password and keyboard-interactive authentication are disabled for root. .Pp If this option is set to .Cm forced-commands-only , root login with public key authentication will be allowed, but only if the .Ar command option has been specified (which may be useful for taking remote backups even if root login is normally not allowed). All other authentication methods are disabled for root. .Pp If this option is set to .Cm no , root is not allowed to log in. .It Cm PermitTTY Specifies whether .Xr pty 4 allocation is permitted. The default is .Cm yes . .It Cm PermitTunnel Specifies whether .Xr tun 4 device forwarding is allowed. The argument must be .Cm yes , .Cm point-to-point (layer 3), .Cm ethernet (layer 2), or .Cm no . Specifying .Cm yes permits both .Cm point-to-point and .Cm ethernet . The default is .Cm no . .Pp Independent of this setting, the permissions of the selected .Xr tun 4 device must allow access to the user. .It Cm PermitUserEnvironment Specifies whether .Pa ~/.ssh/environment and .Cm environment= options in .Pa ~/.ssh/authorized_keys are processed by .Xr sshd 8 . Valid options are .Cm yes , .Cm no or a pattern-list specifying which environment variable names to accept (for example .Qq LANG,LC_* ) . The default is .Cm no . Enabling environment processing may enable users to bypass access restrictions in some configurations using mechanisms such as .Ev LD_PRELOAD . .It Cm PermitUserRC Specifies whether any .Pa ~/.ssh/rc file is executed. The default is .Cm yes . .It Cm PerSourceMaxStartups Specifies the number of unauthenticated connections allowed from a given source address, or .Dq none if there is no limit. This limit is applied in addition to .Cm MaxStartups , whichever is lower. The default is .Cm none . .It Cm PerSourceNetBlockSize Specifies the number of bits of source address that are grouped together for the purposes of applying PerSourceMaxStartups limits. Values for IPv4 and optionally IPv6 may be specified, separated by a colon. The default is .Cm 32:128 , which means each address is considered individually. .It Cm PidFile Specifies the file that contains the process ID of the SSH daemon, or .Cm none to not write one. The default is .Pa /var/run/sshd.pid . .It Cm Port Specifies the port number that .Xr sshd 8 listens on. The default is 22. Multiple options of this type are permitted. See also .Cm ListenAddress . .It Cm PrintLastLog Specifies whether .Xr sshd 8 should print the date and time of the last user login when a user logs in interactively. The default is .Cm yes . .It Cm PrintMotd Specifies whether .Xr sshd 8 should print .Pa /etc/motd when a user logs in interactively. (On some systems it is also printed by the shell, .Pa /etc/profile , or equivalent.) The default is .Cm yes . .It Cm PubkeyAcceptedAlgorithms Specifies the signature algorithms that will be accepted for public key authentication as a list of comma-separated patterns. Alternately if the specified list begins with a .Sq + character, then the specified algorithms will be appended to the default set instead of replacing them. If the specified list begins with a .Sq - character, then the specified algorithms (including wildcards) will be removed from the default set instead of replacing them. If the specified list begins with a .Sq ^ character, then the specified algorithms will be placed at the head of the default set. The default for this option is: .Bd -literal -offset 3n ssh-ed25519-cert-v01@openssh.com, ecdsa-sha2-nistp256-cert-v01@openssh.com, ecdsa-sha2-nistp384-cert-v01@openssh.com, ecdsa-sha2-nistp521-cert-v01@openssh.com, sk-ssh-ed25519-cert-v01@openssh.com, sk-ecdsa-sha2-nistp256-cert-v01@openssh.com, rsa-sha2-512-cert-v01@openssh.com, rsa-sha2-256-cert-v01@openssh.com, ssh-rsa-cert-v01@openssh.com, ssh-ed25519, ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, sk-ssh-ed25519@openssh.com, sk-ecdsa-sha2-nistp256@openssh.com, rsa-sha2-512,rsa-sha2-256,ssh-rsa .Ed .Pp The list of available signature algorithms may also be obtained using .Qq ssh -Q PubkeyAcceptedAlgorithms . .It Cm PubkeyAuthOptions Sets one or more public key authentication options. The supported keywords are: .Cm none (the default; indicating no additional options are enabled), .Cm touch-required and .Cm verify-required . .Pp The .Cm touch-required option causes public key authentication using a FIDO authenticator algorithm (i.e.\& .Cm ecdsa-sk or .Cm ed25519-sk ) to always require the signature to attest that a physically present user explicitly confirmed the authentication (usually by touching the authenticator). By default, .Xr sshd 8 requires user presence unless overridden with an authorized_keys option. The .Cm touch-required flag disables this override. .Pp The .Cm verify-required option requires a FIDO key signature attest that the user was verified, e.g. via a PIN. .Pp Neither the .Cm touch-required or .Cm verify-required options have any effect for other, non-FIDO, public key types. .It Cm PubkeyAuthentication Specifies whether public key authentication is allowed. The default is .Cm yes . .It Cm RekeyLimit Specifies the maximum amount of data that may be transmitted before the session key is renegotiated, optionally followed by a maximum amount of time that may pass before the session key is renegotiated. The first argument is specified in bytes and may have a suffix of .Sq K , .Sq M , or .Sq G to indicate Kilobytes, Megabytes, or Gigabytes, respectively. The default is between .Sq 1G and .Sq 4G , depending on the cipher. The optional second value is specified in seconds and may use any of the units documented in the .Sx TIME FORMATS section. The default value for .Cm RekeyLimit is .Cm default none , which means that rekeying is performed after the cipher's default amount of data has been sent or received and no time based rekeying is done. .It Cm RevokedKeys Specifies revoked public keys file, or .Cm none to not use one. Keys listed in this file will be refused for public key authentication. Note that if this file is not readable, then public key authentication will be refused for all users. Keys may be specified as a text file, listing one public key per line, or as an OpenSSH Key Revocation List (KRL) as generated by .Xr ssh-keygen 1 . For more information on KRLs, see the KEY REVOCATION LISTS section in .Xr ssh-keygen 1 . .It Cm RDomain Specifies an explicit routing domain that is applied after authentication has completed. The user session, as well 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 UseBlacklist Specifies whether .Xr sshd 8 attempts to send authentication success and failure messages to the .Xr blacklistd 8 daemon. The default is .Cm no . For forward compatibility with an upcoming .Xr blacklistd rename, the .Cm UseBlocklist alias can be used instead. .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 , then only addresses and not host names may be used in .Pa ~/.ssh/authorized_keys .Cm from and .Nm .Cm Match .Cm Host directives. The default is .Dq yes . .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 yes . .It Cm VersionAddendum Optionally specifies additional text to append to the SSH protocol banner sent by the server upon connection. The default is -.Qq FreeBSD-20220413 . +.Qq FreeBSD-20220415 . The value .Cm none may be used to disable this. .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 yes . .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/local/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/crypto/openssh/sshsig.c b/crypto/openssh/sshsig.c index 773613462758..1e3b63982ba8 100644 --- a/crypto/openssh/sshsig.c +++ b/crypto/openssh/sshsig.c @@ -1,1142 +1,1147 @@ -/* $OpenBSD: sshsig.c,v 1.28 2022/02/01 23:34:47 djm Exp $ */ +/* $OpenBSD: sshsig.c,v 1.29 2022/03/30 04:27:51 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 #include #include #include #include #include #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; 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: sshbuf_free(b); ssh_digest_free(ctx); explicit_bzero(hash, sizeof(hash)); 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) { + 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/crypto/openssh/version.h b/crypto/openssh/version.h index 2584f0b0328c..52b1897c57b0 100644 --- a/crypto/openssh/version.h +++ b/crypto/openssh/version.h @@ -1,9 +1,9 @@ /* $OpenBSD: version.h,v 1.93 2022/02/23 11:07:09 djm Exp $ */ /* $FreeBSD$ */ -#define SSH_VERSION "OpenSSH_8.9" +#define SSH_VERSION "OpenSSH_9.0" #define SSH_PORTABLE "p1" #define SSH_RELEASE SSH_VERSION SSH_PORTABLE -#define SSH_VERSION_FREEBSD "FreeBSD-20220413" +#define SSH_VERSION_FREEBSD "FreeBSD-20220415" diff --git a/crypto/openssh/xmalloc.c b/crypto/openssh/xmalloc.c index b48d33bbf68c..67191e3f214d 100644 --- a/crypto/openssh/xmalloc.c +++ b/crypto/openssh/xmalloc.c @@ -1,119 +1,118 @@ -/* $OpenBSD: xmalloc.c,v 1.36 2019/11/12 22:32:48 djm Exp $ */ +/* $OpenBSD: xmalloc.c,v 1.37 2022/03/13 23:27:54 cheloha Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved * Versions of malloc and friends that check their results, and never return * failure (they call fatal if they encounter an error). * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". */ #include "includes.h" #include #ifdef HAVE_STDINT_H # include #endif #include #include #include #include "xmalloc.h" #include "log.h" #if defined(__OpenBSD__) char *malloc_options = "S"; #endif /* __OpenBSD__ */ void * xmalloc(size_t size) { void *ptr; if (size == 0) fatal("xmalloc: zero size"); ptr = malloc(size); if (ptr == NULL) fatal("xmalloc: out of memory (allocating %zu bytes)", size); return ptr; } void * xcalloc(size_t nmemb, size_t size) { void *ptr; if (size == 0 || nmemb == 0) fatal("xcalloc: zero size"); if (SIZE_MAX / nmemb < size) fatal("xcalloc: nmemb * size > SIZE_MAX"); ptr = calloc(nmemb, size); if (ptr == NULL) fatal("xcalloc: out of memory (allocating %zu bytes)", size * nmemb); return ptr; } void * xreallocarray(void *ptr, size_t nmemb, size_t size) { void *new_ptr; new_ptr = reallocarray(ptr, nmemb, size); if (new_ptr == NULL) fatal("xreallocarray: out of memory (%zu elements of %zu bytes)", nmemb, size); return new_ptr; } void * xrecallocarray(void *ptr, size_t onmemb, size_t nmemb, size_t size) { void *new_ptr; new_ptr = recallocarray(ptr, onmemb, nmemb, size); if (new_ptr == NULL) fatal("xrecallocarray: out of memory (%zu elements of %zu bytes)", nmemb, size); return new_ptr; } char * xstrdup(const char *str) { size_t len; char *cp; len = strlen(str) + 1; cp = xmalloc(len); - strlcpy(cp, str, len); - return cp; + return memcpy(cp, str, len); } int xvasprintf(char **ret, const char *fmt, va_list ap) { int i; i = vasprintf(ret, fmt, ap); if (i < 0 || *ret == NULL) fatal("xvasprintf: could not allocate memory"); return i; } int xasprintf(char **ret, const char *fmt, ...) { va_list ap; int i; va_start(ap, fmt); i = xvasprintf(ret, fmt, ap); va_end(ap); return i; }