summaryrefslogtreecommitdiff
path: root/auth.c
diff options
context:
space:
mode:
Diffstat (limited to 'auth.c')
-rw-r--r--auth.c351
1 files changed, 346 insertions, 5 deletions
diff --git a/auth.c b/auth.c
index 68a1e4a76..68b9fe795 100644
--- a/auth.c
+++ b/auth.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth.c,v 1.124 2017/09/12 06:32:07 djm Exp $ */ 1/* $OpenBSD: auth.c,v 1.127 2018/03/12 00:52:01 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -28,6 +28,7 @@
28#include <sys/types.h> 28#include <sys/types.h>
29#include <sys/stat.h> 29#include <sys/stat.h>
30#include <sys/socket.h> 30#include <sys/socket.h>
31#include <sys/wait.h>
31 32
32#include <netinet/in.h> 33#include <netinet/in.h>
33 34
@@ -73,12 +74,14 @@
73#include "authfile.h" 74#include "authfile.h"
74#include "ssherr.h" 75#include "ssherr.h"
75#include "compat.h" 76#include "compat.h"
77#include "channels.h"
76 78
77/* import */ 79/* import */
78extern ServerOptions options; 80extern ServerOptions options;
79extern int use_privsep; 81extern int use_privsep;
80extern Buffer loginmsg; 82extern Buffer loginmsg;
81extern struct passwd *privsep_pw; 83extern struct passwd *privsep_pw;
84extern struct sshauthopt *auth_opts;
82 85
83/* Debugging messages */ 86/* Debugging messages */
84Buffer auth_debug; 87Buffer auth_debug;
@@ -385,10 +388,8 @@ auth_maxtries_exceeded(Authctxt *authctxt)
385 * Check whether root logins are disallowed. 388 * Check whether root logins are disallowed.
386 */ 389 */
387int 390int
388auth_root_allowed(const char *method) 391auth_root_allowed(struct ssh *ssh, const char *method)
389{ 392{
390 struct ssh *ssh = active_state; /* XXX */
391
392 switch (options.permit_root_login) { 393 switch (options.permit_root_login) {
393 case PERMIT_YES: 394 case PERMIT_YES:
394 return 1; 395 return 1;
@@ -400,7 +401,7 @@ auth_root_allowed(const char *method)
400 return 1; 401 return 1;
401 break; 402 break;
402 case PERMIT_FORCED_ONLY: 403 case PERMIT_FORCED_ONLY:
403 if (forced_command) { 404 if (auth_opts->force_command != NULL) {
404 logit("Root login accepted for forced command."); 405 logit("Root login accepted for forced command.");
405 return 1; 406 return 1;
406 } 407 }
@@ -747,3 +748,343 @@ auth_get_canonical_hostname(struct ssh *ssh, int use_dns)
747 return dnsname; 748 return dnsname;
748 } 749 }
749} 750}
751
752/*
753 * Runs command in a subprocess wuth a minimal environment.
754 * Returns pid on success, 0 on failure.
755 * The child stdout and stderr maybe captured, left attached or sent to
756 * /dev/null depending on the contents of flags.
757 * "tag" is prepended to log messages.
758 * NB. "command" is only used for logging; the actual command executed is
759 * av[0].
760 */
761pid_t
762subprocess(const char *tag, struct passwd *pw, const char *command,
763 int ac, char **av, FILE **child, u_int flags)
764{
765 FILE *f = NULL;
766 struct stat st;
767 int fd, devnull, p[2], i;
768 pid_t pid;
769 char *cp, errmsg[512];
770 u_int envsize;
771 char **child_env;
772
773 if (child != NULL)
774 *child = NULL;
775
776 debug3("%s: %s command \"%s\" running as %s (flags 0x%x)", __func__,
777 tag, command, pw->pw_name, flags);
778
779 /* Check consistency */
780 if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 &&
781 (flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) {
782 error("%s: inconsistent flags", __func__);
783 return 0;
784 }
785 if (((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) != (child == NULL)) {
786 error("%s: inconsistent flags/output", __func__);
787 return 0;
788 }
789
790 /*
791 * If executing an explicit binary, then verify the it exists
792 * and appears safe-ish to execute
793 */
794 if (*av[0] != '/') {
795 error("%s path is not absolute", tag);
796 return 0;
797 }
798 temporarily_use_uid(pw);
799 if (stat(av[0], &st) < 0) {
800 error("Could not stat %s \"%s\": %s", tag,
801 av[0], strerror(errno));
802 restore_uid();
803 return 0;
804 }
805 if (safe_path(av[0], &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) {
806 error("Unsafe %s \"%s\": %s", tag, av[0], errmsg);
807 restore_uid();
808 return 0;
809 }
810 /* Prepare to keep the child's stdout if requested */
811 if (pipe(p) != 0) {
812 error("%s: pipe: %s", tag, strerror(errno));
813 restore_uid();
814 return 0;
815 }
816 restore_uid();
817
818 switch ((pid = fork())) {
819 case -1: /* error */
820 error("%s: fork: %s", tag, strerror(errno));
821 close(p[0]);
822 close(p[1]);
823 return 0;
824 case 0: /* child */
825 /* Prepare a minimal environment for the child. */
826 envsize = 5;
827 child_env = xcalloc(sizeof(*child_env), envsize);
828 child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH);
829 child_set_env(&child_env, &envsize, "USER", pw->pw_name);
830 child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name);
831 child_set_env(&child_env, &envsize, "HOME", pw->pw_dir);
832 if ((cp = getenv("LANG")) != NULL)
833 child_set_env(&child_env, &envsize, "LANG", cp);
834
835 for (i = 0; i < NSIG; i++)
836 signal(i, SIG_DFL);
837
838 if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
839 error("%s: open %s: %s", tag, _PATH_DEVNULL,
840 strerror(errno));
841 _exit(1);
842 }
843 if (dup2(devnull, STDIN_FILENO) == -1) {
844 error("%s: dup2: %s", tag, strerror(errno));
845 _exit(1);
846 }
847
848 /* Set up stdout as requested; leave stderr in place for now. */
849 fd = -1;
850 if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0)
851 fd = p[1];
852 else if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0)
853 fd = devnull;
854 if (fd != -1 && dup2(fd, STDOUT_FILENO) == -1) {
855 error("%s: dup2: %s", tag, strerror(errno));
856 _exit(1);
857 }
858 closefrom(STDERR_FILENO + 1);
859
860 /* Don't use permanently_set_uid() here to avoid fatal() */
861 if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
862 error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid,
863 strerror(errno));
864 _exit(1);
865 }
866 if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
867 error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid,
868 strerror(errno));
869 _exit(1);
870 }
871 /* stdin is pointed to /dev/null at this point */
872 if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 &&
873 dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
874 error("%s: dup2: %s", tag, strerror(errno));
875 _exit(1);
876 }
877
878 execve(av[0], av, child_env);
879 error("%s exec \"%s\": %s", tag, command, strerror(errno));
880 _exit(127);
881 default: /* parent */
882 break;
883 }
884
885 close(p[1]);
886 if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0)
887 close(p[0]);
888 else if ((f = fdopen(p[0], "r")) == NULL) {
889 error("%s: fdopen: %s", tag, strerror(errno));
890 close(p[0]);
891 /* Don't leave zombie child */
892 kill(pid, SIGTERM);
893 while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
894 ;
895 return 0;
896 }
897 /* Success */
898 debug3("%s: %s pid %ld", __func__, tag, (long)pid);
899 if (child != NULL)
900 *child = f;
901 return pid;
902}
903
904/* These functions link key/cert options to the auth framework */
905
906/* Log sshauthopt options locally and (optionally) for remote transmission */
907void
908auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote)
909{
910 int do_env = options.permit_user_env && opts->nenv > 0;
911 int do_permitopen = opts->npermitopen > 0 &&
912 (options.allow_tcp_forwarding & FORWARD_LOCAL) != 0;
913 size_t i;
914 char msg[1024], buf[64];
915
916 snprintf(buf, sizeof(buf), "%d", opts->force_tun_device);
917 /* Try to keep this alphabetically sorted */
918 snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s%s",
919 opts->permit_agent_forwarding_flag ? " agent-forwarding" : "",
920 opts->force_command == NULL ? "" : " command",
921 do_env ? " environment" : "",
922 opts->valid_before == 0 ? "" : "expires",
923 do_permitopen ? " permitopen" : "",
924 opts->permit_port_forwarding_flag ? " port-forwarding" : "",
925 opts->cert_principals == NULL ? "" : " principals",
926 opts->permit_pty_flag ? " pty" : "",
927 opts->force_tun_device == -1 ? "" : " tun=",
928 opts->force_tun_device == -1 ? "" : buf,
929 opts->permit_user_rc ? " user-rc" : "",
930 opts->permit_x11_forwarding_flag ? " x11-forwarding" : "");
931
932 debug("%s: %s", loc, msg);
933 if (do_remote)
934 auth_debug_add("%s: %s", loc, msg);
935
936 if (options.permit_user_env) {
937 for (i = 0; i < opts->nenv; i++) {
938 debug("%s: environment: %s", loc, opts->env[i]);
939 if (do_remote) {
940 auth_debug_add("%s: environment: %s",
941 loc, opts->env[i]);
942 }
943 }
944 }
945
946 /* Go into a little more details for the local logs. */
947 if (opts->valid_before != 0) {
948 format_absolute_time(opts->valid_before, buf, sizeof(buf));
949 debug("%s: expires at %s", loc, buf);
950 }
951 if (opts->cert_principals != NULL) {
952 debug("%s: authorized principals: \"%s\"",
953 loc, opts->cert_principals);
954 }
955 if (opts->force_command != NULL)
956 debug("%s: forced command: \"%s\"", loc, opts->force_command);
957 if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) {
958 for (i = 0; i < opts->npermitopen; i++) {
959 debug("%s: permitted open: %s",
960 loc, opts->permitopen[i]);
961 }
962 }
963}
964
965/* Activate a new set of key/cert options; merging with what is there. */
966int
967auth_activate_options(struct ssh *ssh, struct sshauthopt *opts)
968{
969 struct sshauthopt *old = auth_opts;
970 const char *emsg = NULL;
971
972 debug("%s: setting new authentication options", __func__);
973 if ((auth_opts = sshauthopt_merge(old, opts, &emsg)) == NULL) {
974 error("Inconsistent authentication options: %s", emsg);
975 return -1;
976 }
977 return 0;
978}
979
980/* Disable forwarding, etc for the session */
981void
982auth_restrict_session(struct ssh *ssh)
983{
984 struct sshauthopt *restricted;
985
986 debug("%s: restricting session", __func__);
987
988 /* A blank sshauthopt defaults to permitting nothing */
989 restricted = sshauthopt_new();
990 restricted->restricted = 1;
991
992 if (auth_activate_options(ssh, restricted) != 0)
993 fatal("%s: failed to restrict session", __func__);
994 sshauthopt_free(restricted);
995}
996
997int
998auth_authorise_keyopts(struct ssh *ssh, struct passwd *pw,
999 struct sshauthopt *opts, int allow_cert_authority, const char *loc)
1000{
1001 const char *remote_ip = ssh_remote_ipaddr(ssh);
1002 const char *remote_host = auth_get_canonical_hostname(ssh,
1003 options.use_dns);
1004 time_t now = time(NULL);
1005 char buf[64];
1006
1007 /*
1008 * Check keys/principals file expiry time.
1009 * NB. validity interval in certificate is handled elsewhere.
1010 */
1011 if (opts->valid_before && now > 0 &&
1012 opts->valid_before < (uint64_t)now) {
1013 format_absolute_time(opts->valid_before, buf, sizeof(buf));
1014 debug("%s: entry expired at %s", loc, buf);
1015 auth_debug_add("%s: entry expired at %s", loc, buf);
1016 return -1;
1017 }
1018 /* Consistency checks */
1019 if (opts->cert_principals != NULL && !opts->cert_authority) {
1020 debug("%s: principals on non-CA key", loc);
1021 auth_debug_add("%s: principals on non-CA key", loc);
1022 /* deny access */
1023 return -1;
1024 }
1025 /* cert-authority flag isn't valid in authorized_principals files */
1026 if (!allow_cert_authority && opts->cert_authority) {
1027 debug("%s: cert-authority flag invalid here", loc);
1028 auth_debug_add("%s: cert-authority flag invalid here", loc);
1029 /* deny access */
1030 return -1;
1031 }
1032
1033 /* Perform from= checks */
1034 if (opts->required_from_host_keys != NULL) {
1035 switch (match_host_and_ip(remote_host, remote_ip,
1036 opts->required_from_host_keys )) {
1037 case 1:
1038 /* Host name matches. */
1039 break;
1040 case -1:
1041 default:
1042 debug("%s: invalid from criteria", loc);
1043 auth_debug_add("%s: invalid from criteria", loc);
1044 /* FALLTHROUGH */
1045 case 0:
1046 logit("%s: Authentication tried for %.100s with "
1047 "correct key but not from a permitted "
1048 "host (host=%.200s, ip=%.200s, required=%.200s).",
1049 loc, pw->pw_name, remote_host, remote_ip,
1050 opts->required_from_host_keys);
1051 auth_debug_add("%s: Your host '%.200s' is not "
1052 "permitted to use this key for login.",
1053 loc, remote_host);
1054 /* deny access */
1055 return -1;
1056 }
1057 }
1058 /* Check source-address restriction from certificate */
1059 if (opts->required_from_host_cert != NULL) {
1060 switch (addr_match_cidr_list(remote_ip,
1061 opts->required_from_host_cert)) {
1062 case 1:
1063 /* accepted */
1064 break;
1065 case -1:
1066 default:
1067 /* invalid */
1068 error("%s: Certificate source-address invalid",
1069 loc);
1070 /* FALLTHROUGH */
1071 case 0:
1072 logit("%s: Authentication tried for %.100s with valid "
1073 "certificate but not from a permitted source "
1074 "address (%.200s).", loc, pw->pw_name, remote_ip);
1075 auth_debug_add("%s: Your address '%.200s' is not "
1076 "permitted to use this certificate for login.",
1077 loc, remote_ip);
1078 return -1;
1079 }
1080 }
1081 /*
1082 *
1083 * XXX this is spammy. We should report remotely only for keys
1084 * that are successful in actual auth attempts, and not PK_OK
1085 * tests.
1086 */
1087 auth_log_authopts(loc, opts, 1);
1088
1089 return 0;
1090}