зеркало из https://github.com/Azure/sonic-openssh.git
upstream: switch over to the new authorized_keys options API and
remove the legacy one. Includes a fairly big refactor of auth2-pubkey.c to retain less state between key file lines. feedback and ok markus@ OpenBSD-Commit-ID: dece6cae0f47751b9892080eb13d6625599573df
This commit is contained in:
Родитель
90c4bec8b5
Коммит
7c85685760
7
.depend
7
.depend
|
@ -7,8 +7,7 @@ audit-linux.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-c
|
|||
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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h xmalloc.h ssh.h packet.h openbsd-compat/sys-queue.h dispatch.h opacket.h log.h misc.h servconf.h uidswap.h key.h sshkey.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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h openbsd-compat/sys-queue.h key.h sshkey.h xmalloc.h match.h ssherr.h log.h canohost.h packet.h dispatch.h opacket.h misc.h channels.h servconf.h auth-options.h hostfile.h auth.h auth-pam.h
|
||||
auth-options.o: 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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h openbsd-compat/sys-queue.h xmalloc.h ssherr.h log.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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h packet.h openbsd-compat/sys-queue.h dispatch.h opacket.h log.h misc.h servconf.h key.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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h packet.h openbsd-compat/sys-queue.h dispatch.h opacket.h uidswap.h pathnames.h log.h misc.h key.h sshkey.h servconf.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h
|
||||
|
@ -16,7 +15,7 @@ auth-shadow.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-c
|
|||
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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h
|
||||
auth-skey.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h xmalloc.h match.h groupaccess.h log.h misc.h servconf.h key.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth-options.h canohost.h uidswap.h packet.h openbsd-compat/sys-queue.h
|
||||
auth.o: dispatch.h opacket.h authfile.h monitor_wrap.h ssherr.h compat.h
|
||||
auth.o: dispatch.h opacket.h authfile.h monitor_wrap.h ssherr.h compat.h channels.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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h xmalloc.h ssh2.h key.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h packet.h openbsd-compat/sys-queue.h dispatch.h opacket.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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h opacket.h log.h misc.h servconf.h compat.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h canohost.h
|
||||
|
@ -161,7 +160,7 @@ sshconnect.o: ssh2.h version.h authfile.h ssherr.h authfd.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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h packet.h dispatch.h opacket.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h key.h sshkey.h kex.h mac.h
|
||||
sshconnect2.o: myproposal.h sshconnect.h authfile.h dh.h authfd.h log.h misc.h readconf.h match.h canohost.h msg.h pathnames.h uidswap.h hostfile.h ssherr.h utf8.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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshpty.h packet.h dispatch.h opacket.h log.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h
|
||||
sshd.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h key.h sshkey.h kex.h mac.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 version.h ssherr.h
|
||||
sshd.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h key.h sshkey.h kex.h mac.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 ssherr.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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.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/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h buffer.h sshbuf.h crypto_api.h ssh2.h ssherr.h misc.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h sshkey-xmss.h match.h xmss_fast.h
|
||||
|
|
650
auth-options.c
650
auth-options.c
|
@ -1,14 +1,4 @@
|
|||
/* $OpenBSD: auth-options.c,v 1.75 2018/03/03 03:06:02 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
/* $OpenBSD: auth-options.c,v 1.76 2018/03/03 03:15:51 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2018 Damien Miller <djm@mindrot.org>
|
||||
*
|
||||
|
@ -39,649 +29,15 @@
|
|||
|
||||
#include "openbsd-compat/sys-queue.h"
|
||||
|
||||
#include "key.h" /* XXX for typedef */
|
||||
#include "buffer.h" /* XXX for typedef */
|
||||
#include "xmalloc.h"
|
||||
#include "match.h"
|
||||
#include "ssherr.h"
|
||||
#include "ssh2.h"
|
||||
#include "log.h"
|
||||
#include "canohost.h"
|
||||
#include "packet.h"
|
||||
#include "sshbuf.h"
|
||||
#include "misc.h"
|
||||
#include "channels.h"
|
||||
#include "servconf.h"
|
||||
#include "sshkey.h"
|
||||
#include "match.h"
|
||||
#include "ssh2.h"
|
||||
#include "auth-options.h"
|
||||
#include "hostfile.h"
|
||||
#include "auth.h"
|
||||
|
||||
/* Flags set authorized_keys flags */
|
||||
int no_port_forwarding_flag = 0;
|
||||
int no_agent_forwarding_flag = 0;
|
||||
int no_x11_forwarding_flag = 0;
|
||||
int no_pty_flag = 0;
|
||||
int no_user_rc = 0;
|
||||
int key_is_cert_authority = 0;
|
||||
|
||||
/* "command=" option. */
|
||||
char *forced_command = NULL;
|
||||
|
||||
/* "environment=" options. */
|
||||
struct envstring *custom_environment = NULL;
|
||||
|
||||
/* "tunnel=" option. */
|
||||
int forced_tun_device = -1;
|
||||
|
||||
/* "principals=" option. */
|
||||
char *authorized_principals = NULL;
|
||||
|
||||
extern ServerOptions options;
|
||||
|
||||
/* XXX refactor to be stateless */
|
||||
|
||||
void
|
||||
auth_clear_options(void)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
|
||||
no_agent_forwarding_flag = 0;
|
||||
no_port_forwarding_flag = 0;
|
||||
no_pty_flag = 0;
|
||||
no_x11_forwarding_flag = 0;
|
||||
no_user_rc = 0;
|
||||
key_is_cert_authority = 0;
|
||||
while (custom_environment) {
|
||||
struct envstring *ce = custom_environment;
|
||||
custom_environment = ce->next;
|
||||
free(ce->s);
|
||||
free(ce);
|
||||
}
|
||||
free(forced_command);
|
||||
forced_command = NULL;
|
||||
free(authorized_principals);
|
||||
authorized_principals = NULL;
|
||||
forced_tun_device = -1;
|
||||
channel_clear_permitted_opens(ssh);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 and, if 'msg' is not NULL
|
||||
* then a message based on it added via auth_debug_add().
|
||||
*/
|
||||
static int
|
||||
match_flag(const char *opt, int allow_negate, char **optsp, const char *msg)
|
||||
{
|
||||
size_t opt_len = strlen(opt);
|
||||
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;
|
||||
if (msg != NULL) {
|
||||
auth_debug_add("%s %s.", msg,
|
||||
negate ? "disabled" : "enabled");
|
||||
}
|
||||
return negate ? 0 : 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* return 1 if access is granted, 0 if not.
|
||||
* side effect: sets key option flags
|
||||
* XXX remove side effects; fill structure instead.
|
||||
*/
|
||||
int
|
||||
auth_parse_options(struct passwd *pw, char *opts, const char *file,
|
||||
u_long linenum)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
const char *cp;
|
||||
int i, r;
|
||||
|
||||
/* reset options */
|
||||
auth_clear_options();
|
||||
|
||||
if (!opts)
|
||||
return 1;
|
||||
|
||||
while (*opts && *opts != ' ' && *opts != '\t') {
|
||||
if ((r = match_flag("cert-authority", 0, &opts, NULL)) != -1) {
|
||||
key_is_cert_authority = r;
|
||||
goto next_option;
|
||||
}
|
||||
if ((r = match_flag("restrict", 0, &opts, NULL)) != -1) {
|
||||
auth_debug_add("Key is restricted.");
|
||||
no_port_forwarding_flag = 1;
|
||||
no_agent_forwarding_flag = 1;
|
||||
no_x11_forwarding_flag = 1;
|
||||
no_pty_flag = 1;
|
||||
no_user_rc = 1;
|
||||
goto next_option;
|
||||
}
|
||||
if ((r = match_flag("port-forwarding", 1, &opts,
|
||||
"Port forwarding")) != -1) {
|
||||
no_port_forwarding_flag = r != 1;
|
||||
goto next_option;
|
||||
}
|
||||
if ((r = match_flag("agent-forwarding", 1, &opts,
|
||||
"Agent forwarding")) != -1) {
|
||||
no_agent_forwarding_flag = r != 1;
|
||||
goto next_option;
|
||||
}
|
||||
if ((r = match_flag("x11-forwarding", 1, &opts,
|
||||
"X11 forwarding")) != -1) {
|
||||
no_x11_forwarding_flag = r != 1;
|
||||
goto next_option;
|
||||
}
|
||||
if ((r = match_flag("pty", 1, &opts,
|
||||
"PTY allocation")) != -1) {
|
||||
no_pty_flag = r != 1;
|
||||
goto next_option;
|
||||
}
|
||||
if ((r = match_flag("user-rc", 1, &opts,
|
||||
"User rc execution")) != -1) {
|
||||
no_user_rc = r != 1;
|
||||
goto next_option;
|
||||
}
|
||||
cp = "command=\"";
|
||||
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
|
||||
opts += strlen(cp);
|
||||
free(forced_command);
|
||||
forced_command = xmalloc(strlen(opts) + 1);
|
||||
i = 0;
|
||||
while (*opts) {
|
||||
if (*opts == '"')
|
||||
break;
|
||||
if (*opts == '\\' && opts[1] == '"') {
|
||||
opts += 2;
|
||||
forced_command[i++] = '"';
|
||||
continue;
|
||||
}
|
||||
forced_command[i++] = *opts++;
|
||||
}
|
||||
if (!*opts) {
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
file, linenum);
|
||||
auth_debug_add("%.100s, line %lu: missing end quote",
|
||||
file, linenum);
|
||||
free(forced_command);
|
||||
forced_command = NULL;
|
||||
goto bad_option;
|
||||
}
|
||||
forced_command[i] = '\0';
|
||||
auth_debug_add("Forced command.");
|
||||
opts++;
|
||||
goto next_option;
|
||||
}
|
||||
cp = "principals=\"";
|
||||
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
|
||||
opts += strlen(cp);
|
||||
free(authorized_principals);
|
||||
authorized_principals = xmalloc(strlen(opts) + 1);
|
||||
i = 0;
|
||||
while (*opts) {
|
||||
if (*opts == '"')
|
||||
break;
|
||||
if (*opts == '\\' && opts[1] == '"') {
|
||||
opts += 2;
|
||||
authorized_principals[i++] = '"';
|
||||
continue;
|
||||
}
|
||||
authorized_principals[i++] = *opts++;
|
||||
}
|
||||
if (!*opts) {
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
file, linenum);
|
||||
auth_debug_add("%.100s, line %lu: missing end quote",
|
||||
file, linenum);
|
||||
free(authorized_principals);
|
||||
authorized_principals = NULL;
|
||||
goto bad_option;
|
||||
}
|
||||
authorized_principals[i] = '\0';
|
||||
auth_debug_add("principals: %.900s",
|
||||
authorized_principals);
|
||||
opts++;
|
||||
goto next_option;
|
||||
}
|
||||
cp = "environment=\"";
|
||||
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
|
||||
char *s;
|
||||
struct envstring *new_envstring;
|
||||
|
||||
opts += strlen(cp);
|
||||
s = xmalloc(strlen(opts) + 1);
|
||||
i = 0;
|
||||
while (*opts) {
|
||||
if (*opts == '"')
|
||||
break;
|
||||
if (*opts == '\\' && opts[1] == '"') {
|
||||
opts += 2;
|
||||
s[i++] = '"';
|
||||
continue;
|
||||
}
|
||||
s[i++] = *opts++;
|
||||
}
|
||||
if (!*opts) {
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
file, linenum);
|
||||
auth_debug_add("%.100s, line %lu: missing end quote",
|
||||
file, linenum);
|
||||
free(s);
|
||||
goto bad_option;
|
||||
}
|
||||
s[i] = '\0';
|
||||
opts++;
|
||||
if (options.permit_user_env) {
|
||||
auth_debug_add("Adding to environment: "
|
||||
"%.900s", s);
|
||||
debug("Adding to environment: %.900s", s);
|
||||
new_envstring = xcalloc(1,
|
||||
sizeof(*new_envstring));
|
||||
new_envstring->s = s;
|
||||
new_envstring->next = custom_environment;
|
||||
custom_environment = new_envstring;
|
||||
s = NULL;
|
||||
}
|
||||
free(s);
|
||||
goto next_option;
|
||||
}
|
||||
cp = "from=\"";
|
||||
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
|
||||
const char *remote_ip = ssh_remote_ipaddr(ssh);
|
||||
const char *remote_host = auth_get_canonical_hostname(
|
||||
ssh, options.use_dns);
|
||||
char *patterns = xmalloc(strlen(opts) + 1);
|
||||
|
||||
opts += strlen(cp);
|
||||
i = 0;
|
||||
while (*opts) {
|
||||
if (*opts == '"')
|
||||
break;
|
||||
if (*opts == '\\' && opts[1] == '"') {
|
||||
opts += 2;
|
||||
patterns[i++] = '"';
|
||||
continue;
|
||||
}
|
||||
patterns[i++] = *opts++;
|
||||
}
|
||||
if (!*opts) {
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
file, linenum);
|
||||
auth_debug_add("%.100s, line %lu: missing end quote",
|
||||
file, linenum);
|
||||
free(patterns);
|
||||
goto bad_option;
|
||||
}
|
||||
patterns[i] = '\0';
|
||||
opts++;
|
||||
switch (match_host_and_ip(remote_host, remote_ip,
|
||||
patterns)) {
|
||||
case 1:
|
||||
free(patterns);
|
||||
/* Host name matches. */
|
||||
goto next_option;
|
||||
case -1:
|
||||
debug("%.100s, line %lu: invalid criteria",
|
||||
file, linenum);
|
||||
auth_debug_add("%.100s, line %lu: "
|
||||
"invalid criteria", file, linenum);
|
||||
/* FALLTHROUGH */
|
||||
case 0:
|
||||
free(patterns);
|
||||
logit("Authentication tried for %.100s with "
|
||||
"correct key but not from a permitted "
|
||||
"host (host=%.200s, ip=%.200s).",
|
||||
pw->pw_name, remote_host, remote_ip);
|
||||
auth_debug_add("Your host '%.200s' is not "
|
||||
"permitted to use this key for login.",
|
||||
remote_host);
|
||||
break;
|
||||
}
|
||||
/* deny access */
|
||||
return 0;
|
||||
}
|
||||
cp = "permitopen=\"";
|
||||
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
|
||||
char *host, *p;
|
||||
int port;
|
||||
char *patterns = xmalloc(strlen(opts) + 1);
|
||||
|
||||
opts += strlen(cp);
|
||||
i = 0;
|
||||
while (*opts) {
|
||||
if (*opts == '"')
|
||||
break;
|
||||
if (*opts == '\\' && opts[1] == '"') {
|
||||
opts += 2;
|
||||
patterns[i++] = '"';
|
||||
continue;
|
||||
}
|
||||
patterns[i++] = *opts++;
|
||||
}
|
||||
if (!*opts) {
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
file, linenum);
|
||||
auth_debug_add("%.100s, line %lu: missing "
|
||||
"end quote", file, linenum);
|
||||
free(patterns);
|
||||
goto bad_option;
|
||||
}
|
||||
patterns[i] = '\0';
|
||||
opts++;
|
||||
p = patterns;
|
||||
/* XXX - add streamlocal support */
|
||||
host = hpdelim(&p);
|
||||
if (host == NULL || strlen(host) >= NI_MAXHOST) {
|
||||
debug("%.100s, line %lu: Bad permitopen "
|
||||
"specification <%.100s>", file, linenum,
|
||||
patterns);
|
||||
auth_debug_add("%.100s, line %lu: "
|
||||
"Bad permitopen specification", file,
|
||||
linenum);
|
||||
free(patterns);
|
||||
goto bad_option;
|
||||
}
|
||||
host = cleanhostname(host);
|
||||
if (p == NULL || (port = permitopen_port(p)) < 0) {
|
||||
debug("%.100s, line %lu: Bad permitopen port "
|
||||
"<%.100s>", file, linenum, p ? p : "");
|
||||
auth_debug_add("%.100s, line %lu: "
|
||||
"Bad permitopen port", file, linenum);
|
||||
free(patterns);
|
||||
goto bad_option;
|
||||
}
|
||||
if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0)
|
||||
channel_add_permitted_opens(ssh, host, port);
|
||||
free(patterns);
|
||||
goto next_option;
|
||||
}
|
||||
cp = "tunnel=\"";
|
||||
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
|
||||
char *tun = NULL;
|
||||
opts += strlen(cp);
|
||||
tun = xmalloc(strlen(opts) + 1);
|
||||
i = 0;
|
||||
while (*opts) {
|
||||
if (*opts == '"')
|
||||
break;
|
||||
tun[i++] = *opts++;
|
||||
}
|
||||
if (!*opts) {
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
file, linenum);
|
||||
auth_debug_add("%.100s, line %lu: missing end quote",
|
||||
file, linenum);
|
||||
free(tun);
|
||||
forced_tun_device = -1;
|
||||
goto bad_option;
|
||||
}
|
||||
tun[i] = '\0';
|
||||
forced_tun_device = a2tun(tun, NULL);
|
||||
free(tun);
|
||||
if (forced_tun_device == SSH_TUNID_ERR) {
|
||||
debug("%.100s, line %lu: invalid tun device",
|
||||
file, linenum);
|
||||
auth_debug_add("%.100s, line %lu: invalid tun device",
|
||||
file, linenum);
|
||||
forced_tun_device = -1;
|
||||
goto bad_option;
|
||||
}
|
||||
auth_debug_add("Forced tun device: %d", forced_tun_device);
|
||||
opts++;
|
||||
goto next_option;
|
||||
}
|
||||
next_option:
|
||||
/*
|
||||
* Skip the comma, and move to the next option
|
||||
* (or break out if there are no more).
|
||||
*/
|
||||
if (!*opts)
|
||||
fatal("Bugs in auth-options.c option processing.");
|
||||
if (*opts == ' ' || *opts == '\t')
|
||||
break; /* End of options. */
|
||||
if (*opts != ',')
|
||||
goto bad_option;
|
||||
opts++;
|
||||
/* Process the next option. */
|
||||
}
|
||||
|
||||
/* grant access */
|
||||
return 1;
|
||||
|
||||
bad_option:
|
||||
logit("Bad options in %.100s file, line %lu: %.50s",
|
||||
file, linenum, opts);
|
||||
auth_debug_add("Bad options in %.100s file, line %lu: %.50s",
|
||||
file, linenum, opts);
|
||||
|
||||
/* deny access */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define OPTIONS_CRITICAL 1
|
||||
#define OPTIONS_EXTENSIONS 2
|
||||
static int
|
||||
parse_option_list(struct sshbuf *oblob, struct passwd *pw,
|
||||
u_int which, int crit,
|
||||
int *cert_no_port_forwarding_flag,
|
||||
int *cert_no_agent_forwarding_flag,
|
||||
int *cert_no_x11_forwarding_flag,
|
||||
int *cert_no_pty_flag,
|
||||
int *cert_no_user_rc,
|
||||
char **cert_forced_command,
|
||||
int *cert_source_address_done)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
char *command, *allowed;
|
||||
const char *remote_ip;
|
||||
char *name = NULL;
|
||||
struct sshbuf *c = NULL, *data = NULL;
|
||||
int r, ret = -1, result, found;
|
||||
|
||||
if ((c = sshbuf_fromb(oblob)) == NULL) {
|
||||
error("%s: sshbuf_fromb failed", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (sshbuf_len(c) > 0) {
|
||||
sshbuf_free(data);
|
||||
data = NULL;
|
||||
if ((r = sshbuf_get_cstring(c, &name, NULL)) != 0 ||
|
||||
(r = sshbuf_froms(c, &data)) != 0) {
|
||||
error("Unable to parse certificate options: %s",
|
||||
ssh_err(r));
|
||||
goto out;
|
||||
}
|
||||
debug3("found certificate option \"%.100s\" len %zu",
|
||||
name, sshbuf_len(data));
|
||||
found = 0;
|
||||
if ((which & OPTIONS_EXTENSIONS) != 0) {
|
||||
if (strcmp(name, "permit-X11-forwarding") == 0) {
|
||||
*cert_no_x11_forwarding_flag = 0;
|
||||
found = 1;
|
||||
} else if (strcmp(name,
|
||||
"permit-agent-forwarding") == 0) {
|
||||
*cert_no_agent_forwarding_flag = 0;
|
||||
found = 1;
|
||||
} else if (strcmp(name,
|
||||
"permit-port-forwarding") == 0) {
|
||||
*cert_no_port_forwarding_flag = 0;
|
||||
found = 1;
|
||||
} else if (strcmp(name, "permit-pty") == 0) {
|
||||
*cert_no_pty_flag = 0;
|
||||
found = 1;
|
||||
} else if (strcmp(name, "permit-user-rc") == 0) {
|
||||
*cert_no_user_rc = 0;
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
if (!found && (which & OPTIONS_CRITICAL) != 0) {
|
||||
if (strcmp(name, "force-command") == 0) {
|
||||
if ((r = sshbuf_get_cstring(data, &command,
|
||||
NULL)) != 0) {
|
||||
error("Unable to parse \"%s\" "
|
||||
"section: %s", name, ssh_err(r));
|
||||
goto out;
|
||||
}
|
||||
if (*cert_forced_command != NULL) {
|
||||
error("Certificate has multiple "
|
||||
"force-command options");
|
||||
free(command);
|
||||
goto out;
|
||||
}
|
||||
*cert_forced_command = command;
|
||||
found = 1;
|
||||
}
|
||||
if (strcmp(name, "source-address") == 0) {
|
||||
if ((r = sshbuf_get_cstring(data, &allowed,
|
||||
NULL)) != 0) {
|
||||
error("Unable to parse \"%s\" "
|
||||
"section: %s", name, ssh_err(r));
|
||||
goto out;
|
||||
}
|
||||
if ((*cert_source_address_done)++) {
|
||||
error("Certificate has multiple "
|
||||
"source-address options");
|
||||
free(allowed);
|
||||
goto out;
|
||||
}
|
||||
remote_ip = ssh_remote_ipaddr(ssh);
|
||||
result = addr_match_cidr_list(remote_ip,
|
||||
allowed);
|
||||
free(allowed);
|
||||
switch (result) {
|
||||
case 1:
|
||||
/* accepted */
|
||||
break;
|
||||
case 0:
|
||||
/* no match */
|
||||
logit("Authentication tried for %.100s "
|
||||
"with valid certificate but not "
|
||||
"from a permitted host "
|
||||
"(ip=%.200s).", pw->pw_name,
|
||||
remote_ip);
|
||||
auth_debug_add("Your address '%.200s' "
|
||||
"is not permitted to use this "
|
||||
"certificate for login.",
|
||||
remote_ip);
|
||||
goto out;
|
||||
case -1:
|
||||
default:
|
||||
error("Certificate source-address "
|
||||
"contents invalid");
|
||||
goto out;
|
||||
}
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (crit) {
|
||||
error("Certificate critical option \"%s\" "
|
||||
"is not supported", name);
|
||||
goto out;
|
||||
} else {
|
||||
logit("Certificate extension \"%s\" "
|
||||
"is not supported", name);
|
||||
}
|
||||
} else if (sshbuf_len(data) != 0) {
|
||||
error("Certificate option \"%s\" corrupt "
|
||||
"(extra data)", name);
|
||||
goto out;
|
||||
}
|
||||
free(name);
|
||||
name = NULL;
|
||||
}
|
||||
/* successfully parsed all options */
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
if (ret != 0 &&
|
||||
cert_forced_command != NULL &&
|
||||
*cert_forced_command != NULL) {
|
||||
free(*cert_forced_command);
|
||||
*cert_forced_command = NULL;
|
||||
}
|
||||
free(name);
|
||||
sshbuf_free(data);
|
||||
sshbuf_free(c);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set options from critical certificate options. These supersede user key
|
||||
* options so this must be called after auth_parse_options().
|
||||
*/
|
||||
int
|
||||
auth_cert_options(struct sshkey *k, struct passwd *pw, const char **reason)
|
||||
{
|
||||
int cert_no_port_forwarding_flag = 1;
|
||||
int cert_no_agent_forwarding_flag = 1;
|
||||
int cert_no_x11_forwarding_flag = 1;
|
||||
int cert_no_pty_flag = 1;
|
||||
int cert_no_user_rc = 1;
|
||||
char *cert_forced_command = NULL;
|
||||
int cert_source_address_done = 0;
|
||||
|
||||
*reason = "invalid certificate options";
|
||||
|
||||
/* Separate options and extensions for v01 certs */
|
||||
if (parse_option_list(k->cert->critical, pw,
|
||||
OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL,
|
||||
&cert_forced_command,
|
||||
&cert_source_address_done) == -1)
|
||||
return -1;
|
||||
if (parse_option_list(k->cert->extensions, pw,
|
||||
OPTIONS_EXTENSIONS, 0,
|
||||
&cert_no_port_forwarding_flag,
|
||||
&cert_no_agent_forwarding_flag,
|
||||
&cert_no_x11_forwarding_flag,
|
||||
&cert_no_pty_flag,
|
||||
&cert_no_user_rc,
|
||||
NULL, NULL) == -1)
|
||||
return -1;
|
||||
|
||||
no_port_forwarding_flag |= cert_no_port_forwarding_flag;
|
||||
no_agent_forwarding_flag |= cert_no_agent_forwarding_flag;
|
||||
no_x11_forwarding_flag |= cert_no_x11_forwarding_flag;
|
||||
no_pty_flag |= cert_no_pty_flag;
|
||||
no_user_rc |= cert_no_user_rc;
|
||||
/*
|
||||
* Only permit both CA and key option forced-command if they match.
|
||||
* Otherwise refuse the certificate.
|
||||
*/
|
||||
if (cert_forced_command != NULL && forced_command != NULL) {
|
||||
if (strcmp(forced_command, cert_forced_command) == 0) {
|
||||
free(forced_command);
|
||||
forced_command = cert_forced_command;
|
||||
} else {
|
||||
*reason = "certificate and key options forced command "
|
||||
"do not match";
|
||||
free(cert_forced_command);
|
||||
return -1;
|
||||
}
|
||||
} else if (cert_forced_command != NULL)
|
||||
forced_command = cert_forced_command;
|
||||
/* success */
|
||||
*reason = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* authorized_keys options processing.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Match flag 'opt' in *optsp, and if allow_negate is set then also match
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
/* $OpenBSD: auth-options.h,v 1.24 2018/03/03 03:06:02 djm Exp $ */
|
||||
/* $OpenBSD: auth-options.h,v 1.25 2018/03/03 03:15:51 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Copyright (c) 2018 Damien Miller <djm@mindrot.org>
|
||||
*
|
||||
* 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".
|
||||
* 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 AUTH_OPTIONS_H
|
||||
|
@ -18,30 +22,6 @@
|
|||
struct passwd;
|
||||
struct sshkey;
|
||||
|
||||
/* Linked list of custom environment strings */
|
||||
struct envstring {
|
||||
struct envstring *next;
|
||||
char *s;
|
||||
};
|
||||
|
||||
/* Flags that may be set in authorized_keys options. */
|
||||
extern int no_port_forwarding_flag;
|
||||
extern int no_agent_forwarding_flag;
|
||||
extern int no_x11_forwarding_flag;
|
||||
extern int no_pty_flag;
|
||||
extern int no_user_rc;
|
||||
extern char *forced_command;
|
||||
extern struct envstring *custom_environment;
|
||||
extern int forced_tun_device;
|
||||
extern int key_is_cert_authority;
|
||||
extern char *authorized_principals;
|
||||
|
||||
int auth_parse_options(struct passwd *, char *, const char *, u_long);
|
||||
void auth_clear_options(void);
|
||||
int auth_cert_options(struct sshkey *, struct passwd *, const char **);
|
||||
|
||||
/* authorized_keys options handling */
|
||||
|
||||
/*
|
||||
* sshauthopt represents key options parsed from authorized_keys or
|
||||
* from certificate extensions/options.
|
||||
|
|
|
@ -1077,7 +1077,7 @@ do_pam_chauthtok(void)
|
|||
}
|
||||
|
||||
void
|
||||
do_pam_session(void)
|
||||
do_pam_session(struct ssh *ssh)
|
||||
{
|
||||
debug3("PAM: opening session");
|
||||
|
||||
|
@ -1093,7 +1093,7 @@ do_pam_session(void)
|
|||
sshpam_session_open = 1;
|
||||
else {
|
||||
sshpam_session_open = 0;
|
||||
disable_forwarding();
|
||||
auth_restrict_session(ssh);
|
||||
error("PAM: pam_open_session(): %s",
|
||||
pam_strerror(sshpam_handle, sshpam_err));
|
||||
}
|
||||
|
|
|
@ -25,10 +25,12 @@
|
|||
#include "includes.h"
|
||||
#ifdef USE_PAM
|
||||
|
||||
struct ssh;
|
||||
|
||||
void start_pam(Authctxt *);
|
||||
void finish_pam(void);
|
||||
u_int do_pam_account(void);
|
||||
void do_pam_session(void);
|
||||
void do_pam_session(struct ssh *);
|
||||
void do_pam_setcred(int );
|
||||
void do_pam_chauthtok(void);
|
||||
int do_pam_putenv(char *, char *);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: auth-passwd.c,v 1.45 2016/07/21 01:39:35 dtucker Exp $ */
|
||||
/* $OpenBSD: auth-passwd.c,v 1.46 2018/03/03 03:15:51 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -68,22 +68,15 @@ extern login_cap_t *lc;
|
|||
|
||||
#define MAX_PASSWORD_LEN 1024
|
||||
|
||||
void
|
||||
disable_forwarding(void)
|
||||
{
|
||||
no_port_forwarding_flag = 1;
|
||||
no_agent_forwarding_flag = 1;
|
||||
no_x11_forwarding_flag = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to authenticate the user using password. Returns true if
|
||||
* authentication succeeds.
|
||||
*/
|
||||
int
|
||||
auth_password(Authctxt *authctxt, const char *password)
|
||||
auth_password(struct ssh *ssh, const char *password)
|
||||
{
|
||||
struct passwd * pw = authctxt->pw;
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
struct passwd *pw = authctxt->pw;
|
||||
int result, ok = authctxt->valid;
|
||||
#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
|
||||
static int expire_checked = 0;
|
||||
|
@ -128,9 +121,9 @@ auth_password(Authctxt *authctxt, const char *password)
|
|||
authctxt->force_pwchange = 1;
|
||||
}
|
||||
#endif
|
||||
result = sys_auth_passwd(authctxt, password);
|
||||
result = sys_auth_passwd(ssh, password);
|
||||
if (authctxt->force_pwchange)
|
||||
disable_forwarding();
|
||||
auth_restrict_session(ssh);
|
||||
return (result && ok);
|
||||
}
|
||||
|
||||
|
@ -170,19 +163,19 @@ warn_expiry(Authctxt *authctxt, auth_session_t *as)
|
|||
}
|
||||
|
||||
int
|
||||
sys_auth_passwd(Authctxt *authctxt, const char *password)
|
||||
sys_auth_passwd(struct ssh *ssh, const char *password)
|
||||
{
|
||||
struct passwd *pw = authctxt->pw;
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
auth_session_t *as;
|
||||
static int expire_checked = 0;
|
||||
|
||||
as = auth_usercheck(pw->pw_name, authctxt->style, "auth-ssh",
|
||||
as = auth_usercheck(authctxt->pw->pw_name, authctxt->style, "auth-ssh",
|
||||
(char *)password);
|
||||
if (as == NULL)
|
||||
return (0);
|
||||
if (auth_getstate(as) & AUTH_PWEXPIRED) {
|
||||
auth_close(as);
|
||||
disable_forwarding();
|
||||
auth_restrict_session(ssh);
|
||||
authctxt->force_pwchange = 1;
|
||||
return (1);
|
||||
} else {
|
||||
|
@ -195,8 +188,9 @@ sys_auth_passwd(Authctxt *authctxt, const char *password)
|
|||
}
|
||||
#elif !defined(CUSTOM_SYS_AUTH_PASSWD)
|
||||
int
|
||||
sys_auth_passwd(Authctxt *authctxt, const char *password)
|
||||
sys_auth_passwd(struct ssh *ssh, const char *password)
|
||||
{
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
struct passwd *pw = authctxt->pw;
|
||||
char *encrypted_password, *salt = NULL;
|
||||
|
||||
|
|
180
auth.c
180
auth.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: auth.c,v 1.125 2018/01/08 15:21:49 markus Exp $ */
|
||||
/* $OpenBSD: auth.c,v 1.126 2018/03/03 03:15:51 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
|
@ -74,12 +74,14 @@
|
|||
#include "authfile.h"
|
||||
#include "ssherr.h"
|
||||
#include "compat.h"
|
||||
#include "channels.h"
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
extern int use_privsep;
|
||||
extern Buffer loginmsg;
|
||||
extern struct passwd *privsep_pw;
|
||||
extern struct sshauthopt *auth_opts;
|
||||
|
||||
/* Debugging messages */
|
||||
Buffer auth_debug;
|
||||
|
@ -386,10 +388,8 @@ auth_maxtries_exceeded(Authctxt *authctxt)
|
|||
* Check whether root logins are disallowed.
|
||||
*/
|
||||
int
|
||||
auth_root_allowed(const char *method)
|
||||
auth_root_allowed(struct ssh *ssh, const char *method)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
|
||||
switch (options.permit_root_login) {
|
||||
case PERMIT_YES:
|
||||
return 1;
|
||||
|
@ -400,7 +400,7 @@ auth_root_allowed(const char *method)
|
|||
return 1;
|
||||
break;
|
||||
case PERMIT_FORCED_ONLY:
|
||||
if (forced_command) {
|
||||
if (auth_opts->force_command != NULL) {
|
||||
logit("Root login accepted for forced command.");
|
||||
return 1;
|
||||
}
|
||||
|
@ -993,3 +993,173 @@ subprocess(const char *tag, struct passwd *pw, const char *command,
|
|||
*child = f;
|
||||
return pid;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
size_t i;
|
||||
char msg[1024], tbuf[32];
|
||||
|
||||
snprintf(tbuf, sizeof(tbuf), "%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",
|
||||
opts->permit_agent_forwarding_flag ? " agent-forwarding" : "",
|
||||
opts->force_command == NULL ? "" : " command",
|
||||
do_env ? " environment" : "",
|
||||
do_permitopen ? " permitopen" : "",
|
||||
opts->permit_port_forwarding_flag ? " port-forwarding" : "",
|
||||
opts->cert_principals == NULL ? "" : " principals",
|
||||
opts->permit_pty_flag ? " pty" : "",
|
||||
opts->force_tun_device == -1 ? "" : " tun=",
|
||||
opts->force_tun_device == -1 ? "" : tbuf,
|
||||
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->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 ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) {
|
||||
for (i = 0; i < opts->npermitopen; i++) {
|
||||
debug("%s: permitted open: %s",
|
||||
loc, opts->permitopen[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("%s: setting new authentication options", __func__);
|
||||
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("%s: restricting session", __func__);
|
||||
|
||||
/* A blank sshauthopt defaults to permitting nothing */
|
||||
restricted = sshauthopt_new();
|
||||
restricted->restricted = 1;
|
||||
|
||||
if (auth_activate_options(ssh, restricted) != 0)
|
||||
fatal("%s: failed to restrict session", __func__);
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
|
28
auth.h
28
auth.h
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: auth.h,v 1.94 2018/01/08 15:21:49 markus Exp $ */
|
||||
/* $OpenBSD: auth.h,v 1.95 2018/03/03 03:15:51 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
|
@ -42,9 +42,11 @@
|
|||
#include <krb5.h>
|
||||
#endif
|
||||
|
||||
struct passwd;
|
||||
struct ssh;
|
||||
struct sshkey;
|
||||
struct sshbuf;
|
||||
struct sshkey;
|
||||
struct sshauthopt;
|
||||
|
||||
typedef struct Authctxt Authctxt;
|
||||
typedef struct Authmethod Authmethod;
|
||||
|
@ -128,11 +130,12 @@ struct KbdintDevice
|
|||
int
|
||||
auth_rhosts2(struct passwd *, const char *, const char *, const char *);
|
||||
|
||||
int auth_password(Authctxt *, const char *);
|
||||
int auth_password(struct ssh *, const char *);
|
||||
|
||||
int hostbased_key_allowed(struct passwd *, const char *, char *,
|
||||
struct sshkey *);
|
||||
int user_key_allowed(struct passwd *, struct sshkey *, int);
|
||||
int user_key_allowed(struct ssh *, struct passwd *, struct sshkey *, int,
|
||||
struct sshauthopt **);
|
||||
int auth2_key_already_used(Authctxt *, const struct sshkey *);
|
||||
|
||||
/*
|
||||
|
@ -163,14 +166,12 @@ int auth_shadow_pwexpired(Authctxt *);
|
|||
#include "audit.h"
|
||||
void remove_kbdint_device(const char *);
|
||||
|
||||
void disable_forwarding(void);
|
||||
|
||||
void do_authentication2(Authctxt *);
|
||||
|
||||
void auth_log(Authctxt *, int, int, const char *, const char *);
|
||||
void auth_maxtries_exceeded(Authctxt *) __attribute__((noreturn));
|
||||
void userauth_finish(struct ssh *, int, const char *, const char *);
|
||||
int auth_root_allowed(const char *);
|
||||
int auth_root_allowed(struct ssh *, const char *);
|
||||
|
||||
void userauth_send_banner(const char *);
|
||||
|
||||
|
@ -214,8 +215,17 @@ int get_hostkey_index(struct sshkey *, int, struct ssh *);
|
|||
int sshd_hostkey_sign(struct sshkey *, struct sshkey *, u_char **,
|
||||
size_t *, const u_char *, size_t, const char *, u_int);
|
||||
|
||||
/* Key / cert options linkage to auth layer */
|
||||
const struct sshauthopt *auth_options(struct ssh *);
|
||||
int auth_activate_options(struct ssh *, struct sshauthopt *);
|
||||
void auth_restrict_session(struct ssh *);
|
||||
int auth_authorise_keyopts(struct ssh *, struct passwd *pw,
|
||||
struct sshauthopt *, int, const char *);
|
||||
void auth_log_authopts(const char *, const struct sshauthopt *, int);
|
||||
|
||||
/* debug messages during authentication */
|
||||
void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2)));
|
||||
void auth_debug_add(const char *fmt,...)
|
||||
__attribute__((format(printf, 1, 2)));
|
||||
void auth_debug_send(void);
|
||||
void auth_debug_reset(void);
|
||||
|
||||
|
@ -227,7 +237,7 @@ struct passwd *fakepw(void);
|
|||
pid_t subprocess(const char *, struct passwd *,
|
||||
const char *, int, char **, FILE **, u_int flags);
|
||||
|
||||
int sys_auth_passwd(Authctxt *, const char *);
|
||||
int sys_auth_passwd(struct ssh *, const char *);
|
||||
|
||||
#define SKEY_PROMPT "\nS/Key Password: "
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: auth2-none.c,v 1.20 2017/05/30 14:29:59 markus Exp $ */
|
||||
/* $OpenBSD: auth2-none.c,v 1.21 2018/03/03 03:15:51 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
|
@ -68,7 +68,7 @@ userauth_none(struct ssh *ssh)
|
|||
if ((r = sshpkt_get_end(ssh)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
if (options.permit_empty_passwd && options.password_authentication)
|
||||
return (PRIVSEP(auth_password(ssh->authctxt, "")));
|
||||
return (PRIVSEP(auth_password(ssh, "")));
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: auth2-passwd.c,v 1.14 2017/05/30 14:29:59 markus Exp $ */
|
||||
/* $OpenBSD: auth2-passwd.c,v 1.15 2018/03/03 03:15:51 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
|
@ -63,7 +63,7 @@ userauth_passwd(struct ssh *ssh)
|
|||
|
||||
if (change)
|
||||
logit("password change not supported");
|
||||
else if (PRIVSEP(auth_password(ssh->authctxt, password)) == 1)
|
||||
else if (PRIVSEP(auth_password(ssh, password)) == 1)
|
||||
authenticated = 1;
|
||||
explicit_bzero(password, len);
|
||||
free(password);
|
||||
|
|
534
auth2-pubkey.c
534
auth2-pubkey.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: auth2-pubkey.c,v 1.76 2018/02/07 22:52:45 dtucker Exp $ */
|
||||
/* $OpenBSD: auth2-pubkey.c,v 1.77 2018/03/03 03:15:51 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
|
@ -88,6 +88,7 @@ static int
|
|||
userauth_pubkey(struct ssh *ssh)
|
||||
{
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
struct passwd *pw = authctxt->pw;
|
||||
struct sshbuf *b;
|
||||
struct sshkey *key = NULL;
|
||||
char *pkalg, *userstyle = NULL, *key_s = NULL, *ca_s = NULL;
|
||||
|
@ -95,6 +96,7 @@ userauth_pubkey(struct ssh *ssh)
|
|||
size_t blen, slen;
|
||||
int r, pktype;
|
||||
int authenticated = 0;
|
||||
struct sshauthopt *authopts = NULL;
|
||||
|
||||
if (!authctxt->valid) {
|
||||
debug2("%s: disabled because of invalid user", __func__);
|
||||
|
@ -185,7 +187,7 @@ userauth_pubkey(struct ssh *ssh)
|
|||
|
||||
/* test for correct signature */
|
||||
authenticated = 0;
|
||||
if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) &&
|
||||
if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) &&
|
||||
PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
|
||||
sshbuf_len(b), NULL, ssh->compat)) == 0) {
|
||||
authenticated = 1;
|
||||
|
@ -210,7 +212,7 @@ userauth_pubkey(struct ssh *ssh)
|
|||
* if a user is not allowed to login. is this an
|
||||
* issue? -markus
|
||||
*/
|
||||
if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) {
|
||||
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 ||
|
||||
|
@ -221,10 +223,14 @@ userauth_pubkey(struct ssh *ssh)
|
|||
authctxt->postponed = 1;
|
||||
}
|
||||
}
|
||||
if (authenticated != 1)
|
||||
auth_clear_options();
|
||||
done:
|
||||
if (authenticated == 1 && auth_activate_options(ssh, authopts) != 0) {
|
||||
debug("%s: key options inconsistent with existing", __func__);
|
||||
authenticated = 0;
|
||||
}
|
||||
debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg);
|
||||
|
||||
sshauthopt_free(authopts);
|
||||
sshkey_free(key);
|
||||
free(userstyle);
|
||||
free(pkalg);
|
||||
|
@ -254,18 +260,77 @@ match_principals_option(const char *principal_list, struct sshkey_cert *cert)
|
|||
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
|
||||
process_principals(FILE *f, const char *file, struct passwd *pw,
|
||||
const struct sshkey_cert *cert)
|
||||
check_principals_line(struct ssh *ssh, char *cp, const struct sshkey_cert *cert,
|
||||
const char *loc, struct sshauthopt **authoptsp)
|
||||
{
|
||||
char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts;
|
||||
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[SSH_MAX_PUBKEY_BYTES], *cp, *ep;
|
||||
u_long linenum = 0;
|
||||
u_int i, found_principal = 0;
|
||||
u_int found_principal = 0;
|
||||
|
||||
if (authoptsp != NULL)
|
||||
*authoptsp = NULL;
|
||||
|
||||
while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
|
||||
/* Always consume entire input */
|
||||
if (found_principal)
|
||||
continue;
|
||||
|
||||
/* Skip leading whitespace. */
|
||||
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
|
@ -274,50 +339,33 @@ process_principals(FILE *f, const char *file, struct passwd *pw,
|
|||
*ep = '\0';
|
||||
if (!*cp || *cp == '\n')
|
||||
continue;
|
||||
/* 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;
|
||||
}
|
||||
for (i = 0; i < cert->nprincipals; i++) {
|
||||
if (strcmp(cp, cert->principals[i]) == 0) {
|
||||
debug3("%s:%lu: matched principal \"%.100s\"",
|
||||
file, linenum, cert->principals[i]);
|
||||
if (auth_parse_options(pw, line_opts,
|
||||
file, linenum) != 1)
|
||||
continue;
|
||||
found_principal = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum);
|
||||
if (check_principals_line(ssh, cp, cert, loc, authoptsp) == 0)
|
||||
found_principal = 1;
|
||||
}
|
||||
return found_principal;
|
||||
}
|
||||
|
||||
/* XXX remove pw args here and elsewhere once ssh->authctxt is guaranteed */
|
||||
|
||||
static int
|
||||
match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert)
|
||||
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(f, file, pw, cert);
|
||||
success = process_principals(ssh, f, file, cert, authoptsp);
|
||||
fclose(f);
|
||||
restore_uid();
|
||||
return success;
|
||||
|
@ -328,12 +376,13 @@ match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert)
|
|||
* returns 1 if the principal is allowed or 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
match_principals_command(struct passwd *user_pw, const struct sshkey *key)
|
||||
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;
|
||||
struct passwd *pw;
|
||||
int i, ac = 0, uid_swapped = 0;
|
||||
pid_t pid;
|
||||
char *tmp, *username = NULL, *command = NULL, **av = NULL;
|
||||
|
@ -341,6 +390,8 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
|
|||
char serial_s[16];
|
||||
void (*osigchld)(int);
|
||||
|
||||
if (authoptsp != NULL)
|
||||
*authoptsp = NULL;
|
||||
if (options.authorized_principals_command == NULL)
|
||||
return 0;
|
||||
if (options.authorized_principals_command_user == NULL) {
|
||||
|
@ -358,8 +409,8 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
|
|||
/* Prepare and verify the user for the command */
|
||||
username = percent_expand(options.authorized_principals_command_user,
|
||||
"u", user_pw->pw_name, (char *)NULL);
|
||||
pw = getpwnam(username);
|
||||
if (pw == NULL) {
|
||||
runas_pw = getpwnam(username);
|
||||
if (runas_pw == NULL) {
|
||||
error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s",
|
||||
username, strerror(errno));
|
||||
goto out;
|
||||
|
@ -417,15 +468,15 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
|
|||
/* Prepare a printable command for logs, etc. */
|
||||
command = argv_assemble(ac, av);
|
||||
|
||||
if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command,
|
||||
if ((pid = subprocess("AuthorizedPrincipalsCommand", runas_pw, command,
|
||||
ac, av, &f,
|
||||
SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
|
||||
goto out;
|
||||
|
||||
uid_swapped = 1;
|
||||
temporarily_use_uid(pw);
|
||||
temporarily_use_uid(runas_pw);
|
||||
|
||||
ok = process_principals(f, "(command)", pw, cert);
|
||||
ok = process_principals(ssh, f, "(command)", cert, authoptsp);
|
||||
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
|
@ -452,130 +503,225 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
|
|||
free(keytext);
|
||||
return found_principal;
|
||||
}
|
||||
|
||||
static void
|
||||
skip_space(char **cpp)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
*cpp = cp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Advanced *cpp past the end of key options, defined as the first unquoted
|
||||
* whitespace character. Returns 0 on success or -1 on failure (e.g.
|
||||
* unterminated quotes).
|
||||
*/
|
||||
static int
|
||||
advance_past_options(char **cpp)
|
||||
{
|
||||
char *cp = *cpp;
|
||||
int quoted = 0;
|
||||
|
||||
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
|
||||
if (*cp == '\\' && cp[1] == '"')
|
||||
cp++; /* Skip both */
|
||||
else if (*cp == '"')
|
||||
quoted = !quoted;
|
||||
}
|
||||
*cpp = cp;
|
||||
/* return failure for unterminated quotes */
|
||||
return (*cp == '\0' && quoted) ? -1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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("%s: keytype %d failed", __func__, 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 (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("%s: fingerprint failed", __func__);
|
||||
|
||||
debug("%s: matching %s found: %s %s", loc,
|
||||
sshkey_is_cert(key) ? "CA" : "key", sshkey_type(found), fp);
|
||||
|
||||
if (auth_authorise_keyopts(ssh, pw, keyopts,
|
||||
sshkey_is_cert(key), loc) != 0) {
|
||||
reason = "Refused by key options";
|
||||
goto fail_reason;
|
||||
}
|
||||
/* That's all we need for plain keys. */
|
||||
if (!sshkey_is_cert(key)) {
|
||||
verbose("Accepted key %s %s found at %s",
|
||||
sshkey_type(found), fp, loc);
|
||||
finalopts = keyopts;
|
||||
keyopts = NULL;
|
||||
goto success;
|
||||
}
|
||||
|
||||
/*
|
||||
* Additional authorisation for certificates.
|
||||
*/
|
||||
|
||||
/* Parse and check options present in certificate */
|
||||
if ((certopts = sshauthopt_from_cert(key)) == NULL) {
|
||||
reason = "Invalid certificate options";
|
||||
goto fail_reason;
|
||||
}
|
||||
if (auth_authorise_keyopts(ssh, pw, certopts, 0, loc) != 0) {
|
||||
reason = "Refused by certificate options";
|
||||
goto fail_reason;
|
||||
}
|
||||
if ((finalopts = sshauthopt_merge(keyopts, certopts, &reason)) == NULL)
|
||||
goto fail_reason;
|
||||
|
||||
/*
|
||||
* If the user has specified a list of principals as
|
||||
* a key option, then prefer that list to matching
|
||||
* their username in the certificate principals list.
|
||||
*/
|
||||
if (keyopts->cert_principals != NULL &&
|
||||
!match_principals_option(keyopts->cert_principals, key->cert)) {
|
||||
reason = "Certificate does not contain an authorized principal";
|
||||
goto fail_reason;
|
||||
}
|
||||
if (sshkey_cert_check_authority(key, 0, 0,
|
||||
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("%s: internal error: missing options", __func__);
|
||||
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(FILE *f, char *file, struct sshkey *key, struct passwd *pw)
|
||||
check_authkeys_file(struct ssh *ssh, struct passwd *pw, FILE *f,
|
||||
char *file, struct sshkey *key, struct sshauthopt **authoptsp)
|
||||
{
|
||||
char line[SSH_MAX_PUBKEY_BYTES];
|
||||
char *cp, line[SSH_MAX_PUBKEY_BYTES], loc[256];
|
||||
int found_key = 0;
|
||||
u_long linenum = 0;
|
||||
struct sshkey *found = NULL;
|
||||
|
||||
if (authoptsp != NULL)
|
||||
*authoptsp = NULL;
|
||||
|
||||
while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
|
||||
char *cp, *key_options = NULL, *fp = NULL;
|
||||
const char *reason = NULL;
|
||||
|
||||
/* Always consume entire file */
|
||||
if (found_key)
|
||||
continue;
|
||||
sshkey_free(found);
|
||||
found = sshkey_new(sshkey_is_cert(key) ? KEY_UNSPEC : key->type);
|
||||
if (found == NULL)
|
||||
goto done;
|
||||
auth_clear_options();
|
||||
|
||||
/* Skip leading whitespace, empty and comment lines. */
|
||||
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
cp = line;
|
||||
skip_space(&cp);
|
||||
if (!*cp || *cp == '\n' || *cp == '#')
|
||||
continue;
|
||||
|
||||
if (sshkey_read(found, &cp) != 0) {
|
||||
/* no key? check if there are options for this key */
|
||||
int quoted = 0;
|
||||
debug2("user_key_allowed: check options: '%s'", cp);
|
||||
key_options = cp;
|
||||
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
|
||||
if (*cp == '\\' && cp[1] == '"')
|
||||
cp++; /* Skip both */
|
||||
else if (*cp == '"')
|
||||
quoted = !quoted;
|
||||
}
|
||||
/* Skip remaining whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
if (sshkey_read(found, &cp) != 0) {
|
||||
debug2("user_key_allowed: advance: '%s'", cp);
|
||||
/* still no key? advance to next line*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (sshkey_is_cert(key)) {
|
||||
if (!sshkey_equal(found, key->cert->signature_key))
|
||||
continue;
|
||||
if (auth_parse_options(pw, key_options, file,
|
||||
linenum) != 1)
|
||||
continue;
|
||||
if (!key_is_cert_authority)
|
||||
continue;
|
||||
if ((fp = sshkey_fingerprint(found,
|
||||
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
|
||||
continue;
|
||||
debug("matching CA found: file %s, line %lu, %s %s",
|
||||
file, linenum, sshkey_type(found), fp);
|
||||
/*
|
||||
* 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 (authorized_principals != NULL &&
|
||||
!match_principals_option(authorized_principals,
|
||||
key->cert)) {
|
||||
reason = "Certificate does not contain an "
|
||||
"authorized principal";
|
||||
fail_reason:
|
||||
free(fp);
|
||||
error("%s", reason);
|
||||
auth_debug_add("%s", reason);
|
||||
continue;
|
||||
}
|
||||
if (sshkey_cert_check_authority(key, 0, 0,
|
||||
authorized_principals == NULL ? pw->pw_name : NULL,
|
||||
&reason) != 0)
|
||||
goto fail_reason;
|
||||
if (auth_cert_options(key, pw, &reason) != 0)
|
||||
goto fail_reason;
|
||||
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(found), fp, file);
|
||||
free(fp);
|
||||
snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum);
|
||||
if (check_authkey_line(ssh, pw, key, cp, loc, authoptsp) == 0)
|
||||
found_key = 1;
|
||||
break;
|
||||
} else if (sshkey_equal(found, key)) {
|
||||
if (auth_parse_options(pw, key_options, file,
|
||||
linenum) != 1)
|
||||
continue;
|
||||
if (key_is_cert_authority)
|
||||
continue;
|
||||
if ((fp = sshkey_fingerprint(found,
|
||||
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
|
||||
continue;
|
||||
debug("matching key found: file %s, line %lu %s %s",
|
||||
file, linenum, sshkey_type(found), fp);
|
||||
free(fp);
|
||||
found_key = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
done:
|
||||
sshkey_free(found);
|
||||
if (!found_key)
|
||||
debug2("key not found");
|
||||
return found_key;
|
||||
}
|
||||
|
||||
/* Authenticate a certificate key against TrustedUserCAKeys */
|
||||
static int
|
||||
user_cert_trusted_ca(struct passwd *pw, struct sshkey *key)
|
||||
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;
|
||||
|
||||
|
@ -596,36 +742,69 @@ user_cert_trusted_ca(struct passwd *pw, struct sshkey *key)
|
|||
* against the username.
|
||||
*/
|
||||
if ((principals_file = authorized_principals_file(pw)) != NULL) {
|
||||
if (match_principals_file(principals_file, pw, key->cert))
|
||||
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(pw, key))
|
||||
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";
|
||||
fail_reason:
|
||||
error("%s", reason);
|
||||
auth_debug_add("%s", reason);
|
||||
goto out;
|
||||
goto fail_reason;
|
||||
}
|
||||
if (use_authorized_principals && principals_opts == NULL)
|
||||
fatal("%s: internal error: missing principals_opts", __func__);
|
||||
if (sshkey_cert_check_authority(key, 0, 1,
|
||||
use_authorized_principals ? NULL : pw->pw_name, &reason) != 0)
|
||||
goto fail_reason;
|
||||
if (auth_cert_options(key, pw, &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;
|
||||
|
@ -636,17 +815,22 @@ user_cert_trusted_ca(struct passwd *pw, struct sshkey *key)
|
|||
* returns 1 if the key is allowed or 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
user_key_allowed2(struct passwd *pw, struct sshkey *key, char *file)
|
||||
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(f, file, key, pw);
|
||||
found_key = check_authkeys_file(ssh, pw, f, file,
|
||||
key, authoptsp);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
@ -659,17 +843,20 @@ user_key_allowed2(struct passwd *pw, struct sshkey *key, char *file)
|
|||
* returns 1 if the key is allowed or 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
|
||||
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;
|
||||
struct passwd *pw;
|
||||
int i, uid_swapped = 0, ac = 0;
|
||||
pid_t pid;
|
||||
char *username = NULL, *key_fp = NULL, *keytext = NULL;
|
||||
char *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) {
|
||||
|
@ -686,8 +873,8 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
|
|||
/* Prepare and verify the user for the command */
|
||||
username = percent_expand(options.authorized_keys_command_user,
|
||||
"u", user_pw->pw_name, (char *)NULL);
|
||||
pw = getpwnam(username);
|
||||
if (pw == NULL) {
|
||||
runas_pw = getpwnam(username);
|
||||
if (runas_pw == NULL) {
|
||||
error("AuthorizedKeysCommandUser \"%s\" not found: %s",
|
||||
username, strerror(errno));
|
||||
goto out;
|
||||
|
@ -745,15 +932,16 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
|
|||
xasprintf(&command, "%s %s", av[0], av[1]);
|
||||
}
|
||||
|
||||
if ((pid = subprocess("AuthorizedKeysCommand", pw, command,
|
||||
if ((pid = subprocess("AuthorizedKeysCommand", runas_pw, command,
|
||||
ac, av, &f,
|
||||
SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
|
||||
goto out;
|
||||
|
||||
uid_swapped = 1;
|
||||
temporarily_use_uid(pw);
|
||||
temporarily_use_uid(runas_pw);
|
||||
|
||||
ok = check_authkeys_file(f, options.authorized_keys_command, key, pw);
|
||||
ok = check_authkeys_file(ssh, user_pw, f,
|
||||
options.authorized_keys_command, key, authoptsp);
|
||||
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
|
@ -783,10 +971,14 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
|
|||
* Check whether key authenticates and authorises the user.
|
||||
*/
|
||||
int
|
||||
user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt)
|
||||
user_key_allowed(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
|
||||
int auth_attempt, struct sshauthopt **authoptsp)
|
||||
{
|
||||
u_int success, i;
|
||||
char *file;
|
||||
struct sshauthopt *opts = NULL;
|
||||
if (authoptsp != NULL)
|
||||
*authoptsp = NULL;
|
||||
|
||||
if (auth_key_is_revoked(key))
|
||||
return 0;
|
||||
|
@ -794,25 +986,31 @@ user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt)
|
|||
auth_key_is_revoked(key->cert->signature_key))
|
||||
return 0;
|
||||
|
||||
success = user_cert_trusted_ca(pw, key);
|
||||
if (success)
|
||||
return success;
|
||||
if ((success = user_cert_trusted_ca(ssh, pw, key, &opts)) != 0)
|
||||
goto out;
|
||||
sshauthopt_free(opts);
|
||||
opts = NULL;
|
||||
|
||||
success = user_key_command_allowed2(pw, key);
|
||||
if (success > 0)
|
||||
return success;
|
||||
if ((success = user_key_command_allowed2(ssh, pw, key, &opts)) != 0)
|
||||
goto out;
|
||||
sshauthopt_free(opts);
|
||||
opts = NULL;
|
||||
|
||||
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(pw, key, file);
|
||||
success = user_key_allowed2(ssh, pw, key, file, &opts);
|
||||
free(file);
|
||||
}
|
||||
|
||||
out:
|
||||
if (success && authoptsp != NULL) {
|
||||
*authoptsp = opts;
|
||||
opts = NULL;
|
||||
}
|
||||
sshauthopt_free(opts);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
|
4
auth2.c
4
auth2.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: auth2.c,v 1.144 2018/01/23 05:27:21 djm Exp $ */
|
||||
/* $OpenBSD: auth2.c,v 1.145 2018/03/03 03:15:51 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
|
@ -310,7 +310,7 @@ userauth_finish(struct ssh *ssh, int authenticated, const char *method,
|
|||
|
||||
/* Special handling for root */
|
||||
if (authenticated && authctxt->pw->pw_uid == 0 &&
|
||||
!auth_root_allowed(method)) {
|
||||
!auth_root_allowed(ssh, method)) {
|
||||
authenticated = 0;
|
||||
#ifdef SSH_AUDIT_EVENTS
|
||||
PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED));
|
||||
|
|
3
misc.c
3
misc.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: misc.c,v 1.124 2018/03/02 03:02:11 djm Exp $ */
|
||||
/* $OpenBSD: misc.c,v 1.125 2018/03/03 03:15:51 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2005,2006 Damien Miller. All rights reserved.
|
||||
|
@ -1921,6 +1921,7 @@ child_set_env(char ***envp, u_int *envsizep, const char *name,
|
|||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
|
70
monitor.c
70
monitor.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: monitor.c,v 1.179 2018/02/05 05:37:46 tb Exp $ */
|
||||
/* $OpenBSD: monitor.c,v 1.180 2018/03/03 03:15:51 djm Exp $ */
|
||||
/*
|
||||
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
||||
* Copyright 2002 Markus Friedl <markus@openbsd.org>
|
||||
|
@ -116,6 +116,7 @@ extern u_char session_id[];
|
|||
extern Buffer auth_debug;
|
||||
extern int auth_debug_init;
|
||||
extern Buffer loginmsg;
|
||||
extern struct sshauthopt *auth_opts; /* XXX move to permanent ssh->authctxt? */
|
||||
|
||||
/* State exported from the child */
|
||||
static struct sshbuf *child_state;
|
||||
|
@ -172,6 +173,7 @@ static Authctxt *authctxt;
|
|||
static u_char *key_blob = NULL;
|
||||
static u_int key_bloblen = 0;
|
||||
static 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";
|
||||
|
@ -252,7 +254,6 @@ struct mon_table mon_dispatch_postauth20[] = {
|
|||
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)
|
||||
{
|
||||
|
@ -297,6 +298,7 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
|
|||
|
||||
authctxt = _authctxt;
|
||||
memset(authctxt, 0, sizeof(*authctxt));
|
||||
ssh->authctxt = authctxt;
|
||||
|
||||
authctxt->loginmsg = &loginmsg;
|
||||
|
||||
|
@ -331,7 +333,7 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
|
|||
fatal("%s: unexpected authentication from %d",
|
||||
__func__, ent->type);
|
||||
if (authctxt->pw->pw_uid == 0 &&
|
||||
!auth_root_allowed(auth_method))
|
||||
!auth_root_allowed(ssh, auth_method))
|
||||
authenticated = 0;
|
||||
#ifdef USE_PAM
|
||||
/* PAM needs to perform account checks after auth */
|
||||
|
@ -365,6 +367,7 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
|
|||
|
||||
debug("%s: %s has been authenticated by privileged process",
|
||||
__func__, authctxt->user);
|
||||
ssh->authctxt = NULL;
|
||||
ssh_packet_set_log_preamble(ssh, "user %s", authctxt->user);
|
||||
|
||||
mm_get_keystate(pmonitor);
|
||||
|
@ -413,7 +416,7 @@ monitor_child_postauth(struct monitor *pmonitor)
|
|||
monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
|
||||
monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
|
||||
|
||||
if (!no_pty_flag) {
|
||||
if (auth_opts->permit_pty_flag) {
|
||||
monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
|
||||
monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1);
|
||||
}
|
||||
|
@ -558,9 +561,11 @@ monitor_reset_key_state(void)
|
|||
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;
|
||||
}
|
||||
|
@ -828,6 +833,7 @@ mm_answer_authserv(int sock, Buffer *m)
|
|||
int
|
||||
mm_answer_authpassword(int sock, Buffer *m)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
static int call_count;
|
||||
char *passwd;
|
||||
int authenticated;
|
||||
|
@ -838,7 +844,7 @@ mm_answer_authpassword(int sock, Buffer *m)
|
|||
passwd = buffer_get_string(m, &plen);
|
||||
/* Only authenticate if the context is valid */
|
||||
authenticated = options.password_authentication &&
|
||||
auth_password(authctxt, passwd);
|
||||
auth_password(ssh, passwd);
|
||||
explicit_bzero(passwd, strlen(passwd));
|
||||
free(passwd);
|
||||
|
||||
|
@ -1129,15 +1135,16 @@ mm_answer_pam_free_ctx(int sock, Buffer *m)
|
|||
int
|
||||
mm_answer_keyallowed(int sock, Buffer *m)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
struct sshkey *key;
|
||||
char *cuser, *chost;
|
||||
u_char *blob;
|
||||
u_int bloblen, pubkey_auth_attempt;
|
||||
enum mm_keytype type = 0;
|
||||
int allowed = 0;
|
||||
int r, allowed = 0;
|
||||
struct sshauthopt *opts = NULL;
|
||||
|
||||
debug3("%s entering", __func__);
|
||||
|
||||
type = buffer_get_int(m);
|
||||
cuser = buffer_get_string(m, NULL);
|
||||
chost = buffer_get_string(m, NULL);
|
||||
|
@ -1156,28 +1163,31 @@ mm_answer_keyallowed(int sock, Buffer *m)
|
|||
|
||||
switch (type) {
|
||||
case MM_USERKEY:
|
||||
allowed = options.pubkey_authentication &&
|
||||
!auth2_key_already_used(authctxt, key) &&
|
||||
match_pattern_list(sshkey_ssh_name(key),
|
||||
options.pubkey_key_types, 0) == 1 &&
|
||||
user_key_allowed(authctxt->pw, key,
|
||||
pubkey_auth_attempt);
|
||||
auth_method = "publickey";
|
||||
if (options.pubkey_authentication &&
|
||||
(!pubkey_auth_attempt || allowed != 1))
|
||||
auth_clear_options();
|
||||
if (!options.pubkey_authentication)
|
||||
break;
|
||||
if (auth2_key_already_used(authctxt, key))
|
||||
break;
|
||||
if (match_pattern_list(sshkey_ssh_name(key),
|
||||
options.pubkey_key_types, 0) != 1)
|
||||
break;
|
||||
allowed = user_key_allowed(ssh, authctxt->pw, key,
|
||||
pubkey_auth_attempt, &opts);
|
||||
break;
|
||||
case MM_HOSTKEY:
|
||||
allowed = options.hostbased_authentication &&
|
||||
!auth2_key_already_used(authctxt, key) &&
|
||||
match_pattern_list(sshkey_ssh_name(key),
|
||||
options.hostbased_key_types, 0) == 1 &&
|
||||
hostbased_key_allowed(authctxt->pw,
|
||||
auth_method = "hostbased";
|
||||
if (!options.hostbased_authentication)
|
||||
break;
|
||||
if (auth2_key_already_used(authctxt, key))
|
||||
break;
|
||||
if (match_pattern_list(sshkey_ssh_name(key),
|
||||
options.hostbased_key_types, 0) != 1)
|
||||
break;
|
||||
allowed = hostbased_key_allowed(authctxt->pw,
|
||||
cuser, chost, key);
|
||||
auth2_record_info(authctxt,
|
||||
"client user \"%.100s\", client host \"%.100s\"",
|
||||
cuser, chost);
|
||||
auth_method = "hostbased";
|
||||
break;
|
||||
default:
|
||||
fatal("%s: unknown key type %d", __func__, type);
|
||||
|
@ -1185,7 +1195,10 @@ mm_answer_keyallowed(int sock, Buffer *m)
|
|||
}
|
||||
}
|
||||
|
||||
debug3("%s: key is %s", __func__, allowed ? "allowed" : "not allowed");
|
||||
debug3("%s: %s authentication%s: %s key is %s", __func__,
|
||||
auth_method, pubkey_auth_attempt ? "" : " test",
|
||||
(key == NULL || !authctxt->valid) ? "invalid" : sshkey_type(key),
|
||||
allowed ? "allowed" : "not allowed");
|
||||
|
||||
auth2_record_key(authctxt, 0, key);
|
||||
sshkey_free(key);
|
||||
|
@ -1198,6 +1211,7 @@ mm_answer_keyallowed(int sock, Buffer *m)
|
|||
key_blob = blob;
|
||||
key_bloblen = bloblen;
|
||||
key_blobtype = type;
|
||||
key_opts = opts;
|
||||
hostbased_cuser = cuser;
|
||||
hostbased_chost = chost;
|
||||
} else {
|
||||
|
@ -1210,10 +1224,13 @@ mm_answer_keyallowed(int sock, Buffer *m)
|
|||
|
||||
buffer_clear(m);
|
||||
buffer_put_int(m, allowed);
|
||||
buffer_put_int(m, forced_command != NULL);
|
||||
|
||||
if (opts != NULL && (r = sshauthopt_serialise(opts, m, 1)) != 0)
|
||||
fatal("%s: sshauthopt_serialise: %s", __func__, ssh_err(r));
|
||||
mm_request_send(sock, MONITOR_ANS_KEYALLOWED, m);
|
||||
|
||||
if (!allowed)
|
||||
sshauthopt_free(opts);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -1336,6 +1353,7 @@ monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser,
|
|||
int
|
||||
mm_answer_keyverify(int sock, struct sshbuf *m)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
struct sshkey *key;
|
||||
u_char *signature, *data, *blob;
|
||||
char *sigalg;
|
||||
|
@ -1390,6 +1408,8 @@ mm_answer_keyverify(int sock, struct sshbuf *m)
|
|||
free(data);
|
||||
free(sigalg);
|
||||
|
||||
if (key_blobtype == MM_USERKEY)
|
||||
auth_activate_options(ssh, key_opts);
|
||||
monitor_reset_key_state();
|
||||
|
||||
sshkey_free(key);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: monitor_wrap.c,v 1.98 2018/01/08 15:14:44 markus Exp $ */
|
||||
/* $OpenBSD: monitor_wrap.c,v 1.99 2018/03/03 03:15:51 djm Exp $ */
|
||||
/*
|
||||
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
||||
* Copyright 2002 Markus Friedl <markus@openbsd.org>
|
||||
|
@ -351,7 +351,7 @@ mm_inform_authserv(char *service, char *style)
|
|||
|
||||
/* Do the password authentication */
|
||||
int
|
||||
mm_auth_password(Authctxt *authctxt, char *password)
|
||||
mm_auth_password(struct ssh *ssh, char *password)
|
||||
{
|
||||
Buffer m;
|
||||
int authenticated = 0;
|
||||
|
@ -378,34 +378,38 @@ mm_auth_password(Authctxt *authctxt, char *password)
|
|||
}
|
||||
|
||||
int
|
||||
mm_user_key_allowed(struct passwd *pw, struct sshkey *key,
|
||||
int pubkey_auth_attempt)
|
||||
mm_user_key_allowed(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
|
||||
int pubkey_auth_attempt, struct sshauthopt **authoptp)
|
||||
{
|
||||
return (mm_key_allowed(MM_USERKEY, NULL, NULL, key,
|
||||
pubkey_auth_attempt));
|
||||
pubkey_auth_attempt, authoptp));
|
||||
}
|
||||
|
||||
int
|
||||
mm_hostbased_key_allowed(struct passwd *pw, const char *user, const char *host,
|
||||
struct sshkey *key)
|
||||
{
|
||||
return (mm_key_allowed(MM_HOSTKEY, user, host, key, 0));
|
||||
return (mm_key_allowed(MM_HOSTKEY, user, host, key, 0, NULL));
|
||||
}
|
||||
|
||||
int
|
||||
mm_key_allowed(enum mm_keytype type, const char *user, const char *host,
|
||||
struct sshkey *key, int pubkey_auth_attempt)
|
||||
struct sshkey *key, int pubkey_auth_attempt, struct sshauthopt **authoptp)
|
||||
{
|
||||
Buffer m;
|
||||
u_char *blob;
|
||||
u_int len;
|
||||
int allowed = 0, have_forced = 0;
|
||||
int r, allowed = 0;
|
||||
struct sshauthopt *opts = NULL;
|
||||
|
||||
debug3("%s entering", __func__);
|
||||
|
||||
if (authoptp != NULL)
|
||||
*authoptp = NULL;
|
||||
|
||||
/* Convert the key to a blob and the pass it over */
|
||||
if (!key_to_blob(key, &blob, &len))
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
buffer_init(&m);
|
||||
buffer_put_int(&m, type);
|
||||
|
@ -418,18 +422,24 @@ mm_key_allowed(enum mm_keytype type, const char *user, const char *host,
|
|||
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYALLOWED, &m);
|
||||
|
||||
debug3("%s: waiting for MONITOR_ANS_KEYALLOWED", __func__);
|
||||
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KEYALLOWED, &m);
|
||||
mm_request_receive_expect(pmonitor->m_recvfd,
|
||||
MONITOR_ANS_KEYALLOWED, &m);
|
||||
|
||||
allowed = buffer_get_int(&m);
|
||||
|
||||
/* fake forced command */
|
||||
auth_clear_options();
|
||||
have_forced = buffer_get_int(&m);
|
||||
forced_command = have_forced ? xstrdup("true") : NULL;
|
||||
|
||||
if (allowed && type == MM_USERKEY) {
|
||||
if ((r = sshauthopt_deserialise(&m, &opts)) != 0)
|
||||
fatal("%s: sshauthopt_deserialise: %s",
|
||||
__func__, ssh_err(r));
|
||||
}
|
||||
buffer_free(&m);
|
||||
|
||||
return (allowed);
|
||||
if (authoptp != NULL) {
|
||||
*authoptp = opts;
|
||||
opts = NULL;
|
||||
}
|
||||
sshauthopt_free(opts);
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: monitor_wrap.h,v 1.36 2017/12/18 02:25:15 djm Exp $ */
|
||||
/* $OpenBSD: monitor_wrap.h,v 1.37 2018/03/03 03:15:51 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
||||
|
@ -35,6 +35,8 @@ enum mm_keytype { MM_NOKEY, MM_HOSTKEY, MM_USERKEY };
|
|||
|
||||
struct monitor;
|
||||
struct Authctxt;
|
||||
struct sshkey;
|
||||
struct sshauthopt;
|
||||
|
||||
void mm_log_handler(LogLevel, const char *, void *);
|
||||
int mm_is_monitor(void);
|
||||
|
@ -44,10 +46,11 @@ int mm_key_sign(struct sshkey *, u_char **, u_int *, const u_char *, u_int,
|
|||
void mm_inform_authserv(char *, char *);
|
||||
struct passwd *mm_getpwnamallow(const char *);
|
||||
char *mm_auth2_read_banner(void);
|
||||
int mm_auth_password(struct Authctxt *, char *);
|
||||
int mm_auth_password(struct ssh *, char *);
|
||||
int mm_key_allowed(enum mm_keytype, const char *, const char *, struct sshkey *,
|
||||
int);
|
||||
int mm_user_key_allowed(struct passwd *, struct sshkey *, int);
|
||||
int, struct sshauthopt **);
|
||||
int mm_user_key_allowed(struct ssh *, struct passwd *, struct sshkey *, int,
|
||||
struct sshauthopt **);
|
||||
int mm_hostbased_key_allowed(struct passwd *, const char *,
|
||||
const char *, struct sshkey *);
|
||||
int mm_sshkey_verify(const struct sshkey *, const u_char *, size_t,
|
||||
|
|
33
serverloop.c
33
serverloop.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: serverloop.c,v 1.204 2018/02/11 21:16:56 dtucker Exp $ */
|
||||
/* $OpenBSD: serverloop.c,v 1.205 2018/03/03 03:15:51 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -82,6 +82,7 @@ extern ServerOptions options;
|
|||
|
||||
/* XXX */
|
||||
extern Authctxt *the_authctxt;
|
||||
extern struct sshauthopt *auth_opts;
|
||||
extern int use_privsep;
|
||||
|
||||
static int no_more_sessions = 0; /* Disallow further sessions. */
|
||||
|
@ -456,12 +457,13 @@ server_request_direct_tcpip(struct ssh *ssh, int *reason, const char **errmsg)
|
|||
originator_port = packet_get_int();
|
||||
packet_check_eom();
|
||||
|
||||
debug("server_request_direct_tcpip: originator %s port %d, target %s "
|
||||
"port %d", originator, originator_port, target, target_port);
|
||||
debug("%s: originator %s port %d, target %s port %d", __func__,
|
||||
originator, originator_port, target, target_port);
|
||||
|
||||
/* XXX fine grained permissions */
|
||||
if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 &&
|
||||
!no_port_forwarding_flag && !options.disable_forwarding) {
|
||||
auth_opts->permit_port_forwarding_flag &&
|
||||
!options.disable_forwarding) {
|
||||
c = channel_connect_to_port(ssh, target, target_port,
|
||||
"direct-tcpip", "direct-tcpip", reason, errmsg);
|
||||
} else {
|
||||
|
@ -487,20 +489,20 @@ server_request_direct_streamlocal(struct ssh *ssh)
|
|||
struct passwd *pw = the_authctxt->pw;
|
||||
|
||||
if (pw == NULL || !the_authctxt->valid)
|
||||
fatal("server_input_global_request: no/invalid user");
|
||||
fatal("%s: no/invalid user", __func__);
|
||||
|
||||
target = packet_get_string(NULL);
|
||||
originator = packet_get_string(NULL);
|
||||
originator_port = packet_get_int();
|
||||
packet_check_eom();
|
||||
|
||||
debug("server_request_direct_streamlocal: originator %s port %d, target %s",
|
||||
debug("%s: originator %s port %d, target %s", __func__,
|
||||
originator, originator_port, target);
|
||||
|
||||
/* XXX fine grained permissions */
|
||||
if ((options.allow_streamlocal_forwarding & FORWARD_LOCAL) != 0 &&
|
||||
!no_port_forwarding_flag && !options.disable_forwarding &&
|
||||
(pw->pw_uid == 0 || use_privsep)) {
|
||||
auth_opts->permit_port_forwarding_flag &&
|
||||
!options.disable_forwarding && (pw->pw_uid == 0 || use_privsep)) {
|
||||
c = channel_connect_to_path(ssh, target,
|
||||
"direct-streamlocal@openssh.com", "direct-streamlocal");
|
||||
} else {
|
||||
|
@ -519,8 +521,7 @@ static Channel *
|
|||
server_request_tun(struct ssh *ssh)
|
||||
{
|
||||
Channel *c = NULL;
|
||||
int mode, tun;
|
||||
int sock;
|
||||
int mode, tun, sock;
|
||||
char *tmp, *ifname = NULL;
|
||||
|
||||
mode = packet_get_int();
|
||||
|
@ -539,10 +540,10 @@ server_request_tun(struct ssh *ssh)
|
|||
}
|
||||
|
||||
tun = packet_get_int();
|
||||
if (forced_tun_device != -1) {
|
||||
if (tun != SSH_TUNID_ANY && forced_tun_device != tun)
|
||||
if (auth_opts->force_tun_device != -1) {
|
||||
if (tun != SSH_TUNID_ANY && auth_opts->force_tun_device != tun)
|
||||
goto done;
|
||||
tun = forced_tun_device;
|
||||
tun = auth_opts->force_tun_device;
|
||||
}
|
||||
sock = tun_open(tun, mode, &ifname);
|
||||
if (sock < 0)
|
||||
|
@ -767,7 +768,8 @@ server_input_global_request(int type, u_int32_t seq, struct ssh *ssh)
|
|||
|
||||
/* check permissions */
|
||||
if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 ||
|
||||
no_port_forwarding_flag || options.disable_forwarding ||
|
||||
!auth_opts->permit_port_forwarding_flag ||
|
||||
options.disable_forwarding ||
|
||||
(!want_reply && fwd.listen_port == 0) ||
|
||||
(fwd.listen_port != 0 &&
|
||||
!bind_permitted(fwd.listen_port, pw->pw_uid))) {
|
||||
|
@ -805,7 +807,8 @@ server_input_global_request(int type, u_int32_t seq, struct ssh *ssh)
|
|||
|
||||
/* check permissions */
|
||||
if ((options.allow_streamlocal_forwarding & FORWARD_REMOTE) == 0
|
||||
|| no_port_forwarding_flag || options.disable_forwarding ||
|
||||
|| !auth_opts->permit_port_forwarding_flag ||
|
||||
options.disable_forwarding ||
|
||||
(pw->pw_uid != 0 && !use_privsep)) {
|
||||
success = 0;
|
||||
packet_send_debug("Server has disabled "
|
||||
|
|
85
session.c
85
session.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: session.c,v 1.293 2017/10/23 05:08:00 djm Exp $ */
|
||||
/* $OpenBSD: session.c,v 1.294 2018/03/03 03:15:51 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
|
@ -140,6 +140,7 @@ extern u_int utmp_len;
|
|||
extern int startup_pipe;
|
||||
extern void destroy_sensitive_data(void);
|
||||
extern Buffer loginmsg;
|
||||
extern struct sshauthopt *auth_opts;
|
||||
char *tun_fwd_ifnames; /* serverloop.c */
|
||||
|
||||
/* original command from peer. */
|
||||
|
@ -288,14 +289,42 @@ prepare_auth_info_file(struct passwd *pw, struct sshbuf *info)
|
|||
restore_uid();
|
||||
}
|
||||
|
||||
static void
|
||||
set_permitopen_from_authopts(struct ssh *ssh, const struct sshauthopt *opts)
|
||||
{
|
||||
char *tmp, *cp, *host;
|
||||
int port;
|
||||
size_t i;
|
||||
|
||||
if ((options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
|
||||
return;
|
||||
channel_clear_permitted_opens(ssh);
|
||||
for (i = 0; i < auth_opts->npermitopen; i++) {
|
||||
tmp = cp = xstrdup(auth_opts->permitopen[i]);
|
||||
/* This shouldn't fail as it has already been checked */
|
||||
if ((host = hpdelim(&cp)) == NULL)
|
||||
fatal("%s: internal error: hpdelim", __func__);
|
||||
host = cleanhostname(host);
|
||||
if (cp == NULL || (port = permitopen_port(cp)) < 0)
|
||||
fatal("%s: internal error: permitopen port",
|
||||
__func__);
|
||||
channel_add_permitted_opens(ssh, host, port);
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
do_authenticated(struct ssh *ssh, Authctxt *authctxt)
|
||||
{
|
||||
setproctitle("%s", authctxt->pw->pw_name);
|
||||
|
||||
auth_log_authopts("active", auth_opts, 0);
|
||||
|
||||
/* setup the channel layer */
|
||||
/* XXX - streamlocal? */
|
||||
if (no_port_forwarding_flag || options.disable_forwarding ||
|
||||
set_permitopen_from_authopts(ssh, auth_opts);
|
||||
if (!auth_opts->permit_port_forwarding_flag ||
|
||||
options.disable_forwarding ||
|
||||
(options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
|
||||
channel_disable_adm_local_opens(ssh);
|
||||
else
|
||||
|
@ -642,9 +671,9 @@ do_exec(struct ssh *ssh, Session *s, const char *command)
|
|||
original_command = command;
|
||||
command = options.adm_forced_command;
|
||||
forced = "(config)";
|
||||
} else if (forced_command) {
|
||||
} else if (auth_opts->force_command != NULL) {
|
||||
original_command = command;
|
||||
command = forced_command;
|
||||
command = auth_opts->force_command;
|
||||
forced = "(key-option)";
|
||||
}
|
||||
if (forced != NULL) {
|
||||
|
@ -947,8 +976,9 @@ static char **
|
|||
do_setup_env(struct ssh *ssh, Session *s, const char *shell)
|
||||
{
|
||||
char buf[256];
|
||||
size_t n;
|
||||
u_int i, envsize;
|
||||
char **env, *laddr;
|
||||
char *ocp, *cp, **env, *laddr;
|
||||
struct passwd *pw = s->pw;
|
||||
#if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN)
|
||||
char *path = NULL;
|
||||
|
@ -1023,20 +1053,17 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell)
|
|||
if (getenv("TZ"))
|
||||
child_set_env(&env, &envsize, "TZ", getenv("TZ"));
|
||||
|
||||
/* Set custom environment options from RSA authentication. */
|
||||
while (custom_environment) {
|
||||
struct envstring *ce = custom_environment;
|
||||
char *str = ce->s;
|
||||
|
||||
for (i = 0; str[i] != '=' && str[i]; i++)
|
||||
;
|
||||
if (str[i] == '=') {
|
||||
str[i] = 0;
|
||||
child_set_env(&env, &envsize, str, str + i + 1);
|
||||
/* Set custom environment options from pubkey authentication. */
|
||||
if (options.permit_user_env) {
|
||||
for (n = 0 ; n < auth_opts->nenv; n++) {
|
||||
ocp = xstrdup(auth_opts->env[n]);
|
||||
cp = strchr(ocp, '=');
|
||||
if (*cp == '=') {
|
||||
*cp = '\0';
|
||||
child_set_env(&env, &envsize, ocp, cp + 1);
|
||||
}
|
||||
free(ocp);
|
||||
}
|
||||
custom_environment = ce->next;
|
||||
free(ce->s);
|
||||
free(ce);
|
||||
}
|
||||
|
||||
/* SSH_CLIENT deprecated */
|
||||
|
@ -1138,7 +1165,7 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell)
|
|||
* first in this order).
|
||||
*/
|
||||
static void
|
||||
do_rc_files(Session *s, const char *shell)
|
||||
do_rc_files(struct ssh *ssh, Session *s, const char *shell)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
char cmd[1024];
|
||||
|
@ -1150,7 +1177,7 @@ do_rc_files(Session *s, const char *shell)
|
|||
|
||||
/* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */
|
||||
if (!s->is_subsystem && options.adm_forced_command == NULL &&
|
||||
!no_user_rc && options.permit_user_rc &&
|
||||
auth_opts->permit_user_rc && options.permit_user_rc &&
|
||||
stat(_PATH_SSH_USER_RC, &st) >= 0) {
|
||||
snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
|
||||
shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
|
||||
|
@ -1570,7 +1597,7 @@ do_child(struct ssh *ssh, Session *s, const char *command)
|
|||
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
|
||||
do_rc_files(s, shell);
|
||||
do_rc_files(ssh, s, shell);
|
||||
|
||||
/* restore SIGPIPE for child */
|
||||
signal(SIGPIPE, SIG_DFL);
|
||||
|
@ -1833,8 +1860,8 @@ session_pty_req(struct ssh *ssh, Session *s)
|
|||
u_int len;
|
||||
int n_bytes;
|
||||
|
||||
if (no_pty_flag || !options.permit_tty) {
|
||||
debug("Allocating a pty not permitted for this authentication.");
|
||||
if (!auth_opts->permit_pty_flag || !options.permit_tty) {
|
||||
debug("Allocating a pty not permitted for this connection.");
|
||||
return 0;
|
||||
}
|
||||
if (s->ttyfd != -1) {
|
||||
|
@ -2022,9 +2049,11 @@ static int
|
|||
session_auth_agent_req(struct ssh *ssh, Session *s)
|
||||
{
|
||||
static int called = 0;
|
||||
|
||||
packet_check_eom();
|
||||
if (no_agent_forwarding_flag || !options.allow_agent_forwarding) {
|
||||
debug("session_auth_agent_req: no_agent_forwarding_flag");
|
||||
if (!auth_opts->permit_agent_forwarding_flag ||
|
||||
!options.allow_agent_forwarding) {
|
||||
debug("%s: agent forwarding disabled", __func__);
|
||||
return 0;
|
||||
}
|
||||
if (called) {
|
||||
|
@ -2402,8 +2431,8 @@ session_setup_x11fwd(struct ssh *ssh, Session *s)
|
|||
char hostname[NI_MAXHOST];
|
||||
u_int i;
|
||||
|
||||
if (no_x11_forwarding_flag) {
|
||||
packet_send_debug("X11 forwarding disabled in user configuration file.");
|
||||
if (!auth_opts->permit_x11_forwarding_flag) {
|
||||
packet_send_debug("X11 forwarding disabled by key options.");
|
||||
return 0;
|
||||
}
|
||||
if (!options.x11_forwarding) {
|
||||
|
@ -2412,7 +2441,7 @@ session_setup_x11fwd(struct ssh *ssh, Session *s)
|
|||
}
|
||||
if (options.xauth_location == NULL ||
|
||||
(stat(options.xauth_location, &st) == -1)) {
|
||||
packet_send_debug("No xauth program; cannot forward with spoofing.");
|
||||
packet_send_debug("No xauth program; cannot forward X11.");
|
||||
return 0;
|
||||
}
|
||||
if (s->display != NULL) {
|
||||
|
|
12
sshd.c
12
sshd.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sshd.c,v 1.505 2018/02/23 15:58:38 markus Exp $ */
|
||||
/* $OpenBSD: sshd.c,v 1.506 2018/03/03 03:15:51 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -119,6 +119,7 @@
|
|||
#endif
|
||||
#include "monitor_wrap.h"
|
||||
#include "ssh-sandbox.h"
|
||||
#include "auth-options.h"
|
||||
#include "version.h"
|
||||
#include "ssherr.h"
|
||||
|
||||
|
@ -232,6 +233,9 @@ static int privsep_chroot = 1;
|
|||
/* global authentication context */
|
||||
Authctxt *the_authctxt = NULL;
|
||||
|
||||
/* global key/cert auth options. XXX move to permanent ssh->authctxt? */
|
||||
struct sshauthopt *auth_opts = NULL;
|
||||
|
||||
/* sshd_config buffer */
|
||||
Buffer cfg;
|
||||
|
||||
|
@ -2066,6 +2070,10 @@ main(int ac, char **av)
|
|||
/* 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 */
|
||||
buffer_init(&loginmsg);
|
||||
auth_debug_reset();
|
||||
|
@ -2122,7 +2130,7 @@ main(int ac, char **av)
|
|||
#ifdef USE_PAM
|
||||
if (options.use_pam) {
|
||||
do_pam_setcred(1);
|
||||
do_pam_session();
|
||||
do_pam_session(ssh);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче