Ejemplo n.º 1
0
void
auth_log(Authctxt *authctxt, int authenticated, int partial,
    const char *method, const char *submethod)
{
	void (*authlog) (const char *fmt,...) = verbose;
	char *authmsg;

	if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
		return;

	/* Raise logging level */
	if (authenticated == 1 ||
	    !authctxt->valid ||
	    authctxt->failures >= options.max_authtries / 2 ||
	    strcmp(method, "password") == 0)
		authlog = logit;

	if (authctxt->postponed)
		authmsg = "Postponed";
	else if (partial)
		authmsg = "Partial";
	else {
		authmsg = authenticated ? "Accepted" : "Failed";
		BLACKLIST_NOTIFY(authenticated ?
		    BLACKLIST_AUTH_OK : BLACKLIST_AUTH_FAIL);
	}

	authlog("%s %s%s%s for %s%.100s from %.200s port %d %s%s%s",
	    authmsg,
	    method,
	    submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
	    authctxt->valid ? "" : "invalid user ",
	    authctxt->user,
	    get_remote_ipaddr(),
	    get_remote_port(),
	    compat20 ? "ssh2" : "ssh1",
	    authctxt->info != NULL ? ": " : "",
	    authctxt->info != NULL ? authctxt->info : "");
	free(authctxt->info);
	authctxt->info = NULL;

#ifdef CUSTOM_FAILED_LOGIN
	if (authenticated == 0 && !authctxt->postponed &&
	    (strcmp(method, "password") == 0 ||
	    strncmp(method, "keyboard-interactive", 20) == 0 ||
	    strcmp(method, "challenge-response") == 0))
		record_failed_login(authctxt->user,
		    get_canonical_hostname(options.use_dns), "ssh");
# ifdef WITH_AIXAUTHENTICATE
	if (authenticated)
		sys_auth_record_login(authctxt->user,
		    get_canonical_hostname(options.use_dns), "ssh", &loginmsg);
# endif
#endif
#ifdef SSH_AUDIT_EVENTS
	if (authenticated == 0 && !authctxt->postponed)
		audit_event(audit_classify_auth(method));
#endif
}
Ejemplo n.º 2
0
static int
sshpam_query(void *ctx, char **name, char **info,
    u_int *num, char ***prompts, u_int **echo_on)
{
	Buffer buffer;
	struct pam_ctxt *ctxt = ctx;
	size_t plen;
	u_char type;
	char *msg;
	size_t len, mlen;

	debug3("PAM: %s entering", __func__);
	buffer_init(&buffer);
	*name = xstrdup("");
	*info = xstrdup("");
	*prompts = xmalloc(sizeof(char *));
	**prompts = NULL;
	plen = 0;
	*echo_on = xmalloc(sizeof(u_int));
	while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {
		type = buffer_get_char(&buffer);
		msg = buffer_get_string(&buffer, NULL);
		mlen = strlen(msg);
		switch (type) {
		case PAM_PROMPT_ECHO_ON:
		case PAM_PROMPT_ECHO_OFF:
			*num = 1;
			len = plen + mlen + 1;
			**prompts = xreallocarray(**prompts, 1, len);
			strlcpy(**prompts + plen, msg, len - plen);
			plen += mlen;
			**echo_on = (type == PAM_PROMPT_ECHO_ON);
			free(msg);
			return (0);
		case PAM_ERROR_MSG:
		case PAM_TEXT_INFO:
			/* accumulate messages */
			len = plen + mlen + 2;
			**prompts = xreallocarray(**prompts, 1, len);
			strlcpy(**prompts + plen, msg, len - plen);
			plen += mlen;
			strlcat(**prompts + plen, "\n", len - plen);
			plen++;
			free(msg);
			break;
		case PAM_ACCT_EXPIRED:
			sshpam_account_status = 0;
			/* FALLTHROUGH */
		case PAM_AUTH_ERR:
			debug3("PAM: %s", pam_strerror(sshpam_handle, type));
			if (**prompts != NULL && strlen(**prompts) != 0) {
				*info = **prompts;
				**prompts = NULL;
				*num = 0;
				**echo_on = 0;
				ctxt->pam_done = -1;
				free(msg);
				return 0;
			}
			/* FALLTHROUGH */
		case PAM_SUCCESS:
			if (**prompts != NULL) {
				/* drain any accumulated messages */
				debug("PAM: %s", **prompts);
				buffer_append(&loginmsg, **prompts,
				    strlen(**prompts));
				free(**prompts);
				**prompts = NULL;
			}
			if (type == PAM_SUCCESS) {
				if (!sshpam_authctxt->valid ||
				    (sshpam_authctxt->pw->pw_uid == 0 &&
				    options.permit_root_login != PERMIT_YES))
					fatal("Internal error: PAM auth "
					    "succeeded when it should have "
					    "failed");
				import_environments(&buffer);
				*num = 0;
				**echo_on = 0;
				ctxt->pam_done = 1;
				free(msg);
				return (0);
			}
			BLACKLIST_NOTIFY(BLACKLIST_AUTH_FAIL);
			error("PAM: %s for %s%.100s from %.100s", msg,
			    sshpam_authctxt->valid ? "" : "illegal user ",
			    sshpam_authctxt->user,
			    get_remote_name_or_ip(utmp_len, options.use_dns));
			/* FALLTHROUGH */
		default:
			*num = 0;
			**echo_on = 0;
			free(msg);
			ctxt->pam_done = -1;
			return (-1);
		}
	}
	return (-1);
}
Ejemplo n.º 3
0
/*
 * Performs authentication of an incoming connection.  Session key has already
 * been exchanged and encryption is enabled.
 */
void
do_authentication(Authctxt *authctxt)
{
	u_int ulen;
	char *user, *style = NULL;

	/* Get the name of the user that we wish to log in as. */
	packet_read_expect(SSH_CMSG_USER);

	/* Get the user name. */
	user = packet_get_cstring(&ulen);
	packet_check_eom();

	if ((style = strchr(user, ':')) != NULL)
		*style++ = '\0';

	authctxt->user = user;
	authctxt->style = style;

	/* Verify that the user is a valid user. */
	if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
		authctxt->valid = 1;
	else {
		debug("do_authentication: invalid user %s", user);
		authctxt->pw = fakepw();
		BLACKLIST_NOTIFY(BLACKLIST_AUTH_FAIL);
	}

	/* Configuration may have changed as a result of Match */
	if (options.num_auth_methods != 0)
		fatal("AuthenticationMethods is not supported with SSH "
		    "protocol 1");

	setproctitle("%s%s", authctxt->valid ? user : "******",
	    use_privsep ? " [net]" : "");

#ifdef USE_PAM
	if (options.use_pam)
		PRIVSEP(start_pam(authctxt));
#endif

	/*
	 * If we are not running as root, the user must have the same uid as
	 * the server.
	 */
#ifndef HAVE_CYGWIN
	if (!use_privsep && getuid() != 0 && authctxt->pw &&
	    authctxt->pw->pw_uid != getuid())
		packet_disconnect("Cannot change user when server not running as root.");
#endif

	/*
	 * Loop until the user has been authenticated or the connection is
	 * closed, do_authloop() returns only if authentication is successful
	 */
	do_authloop(authctxt);

	/* The user has been authenticated and accepted. */
	packet_start(SSH_SMSG_SUCCESS);
	packet_send();
	packet_write_wait();
}
Ejemplo n.º 4
0
/*
 * read packets, try to authenticate the user and
 * return only if authentication is successful
 */
static void
do_authloop(Authctxt *authctxt)
{
	int authenticated = 0;
	int prev = 0, type = 0;
	const struct AuthMethod1 *meth;

	debug("Attempting authentication for %s%.100s.",
	    authctxt->valid ? "" : "invalid user ", authctxt->user);

	/* If the user has no password, accept authentication immediately. */
	if (options.permit_empty_passwd && options.password_authentication &&
#ifdef KRB5
	    (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
#endif
	    PRIVSEP(auth_password(authctxt, ""))) {
#ifdef USE_PAM
		if (options.use_pam && (PRIVSEP(do_pam_account())))
#endif
		{
			auth_log(authctxt, 1, 0, "without authentication",
			    NULL);
			return;
		}
	}

	/* Indicate that authentication is needed. */
	packet_start(SSH_SMSG_FAILURE);
	packet_send();
	packet_write_wait();

	for (;;) {
		/* default to fail */
		authenticated = 0;


		/* Get a packet from the client. */
		prev = type;
		type = packet_read();

		/*
		 * If we started challenge-response authentication but the
		 * next packet is not a response to our challenge, release
		 * the resources allocated by get_challenge() (which would
		 * normally have been released by verify_response() had we
		 * received such a response)
		 */
		if (prev == SSH_CMSG_AUTH_TIS &&
		    type != SSH_CMSG_AUTH_TIS_RESPONSE)
			abandon_challenge_response(authctxt);

		if (authctxt->failures >= options.max_authtries)
			goto skip;
		if ((meth = lookup_authmethod1(type)) == NULL) {
			logit("Unknown message during authentication: "
			    "type %d", type);
			goto skip;
		}

		if (!*(meth->enabled)) {
			verbose("%s authentication disabled.", meth->name);
			goto skip;
		}

		authenticated = meth->method(authctxt);
		if (authenticated == -1)
			continue; /* "postponed" */

#ifdef BSD_AUTH
		if (authctxt->as) {
			auth_close(authctxt->as);
			authctxt->as = NULL;
		}
#endif
		if (!authctxt->valid && authenticated)
			fatal("INTERNAL ERROR: authenticated invalid user %s",
			    authctxt->user);

#ifdef _UNICOS
		if (authenticated && cray_access_denied(authctxt->user)) {
			authenticated = 0;
			fatal("Access denied for user %s.",authctxt->user);
		}
#endif /* _UNICOS */

#ifndef HAVE_CYGWIN
		/* Special handling for root */
		if (authenticated && authctxt->pw->pw_uid == 0 &&
		    !auth_root_allowed(meth->name)) {
 			authenticated = 0;
# ifdef SSH_AUDIT_EVENTS
			PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED));
# endif
		}
#endif

#ifdef USE_PAM
		if (options.use_pam && authenticated &&
		    !PRIVSEP(do_pam_account())) {
			char *msg;
			size_t len;

			BLACKLIST_NOTIFY(BLACKLIST_AUTH_FAIL);
			error("Access denied for user %s by PAM account "
			    "configuration", authctxt->user);
			len = buffer_len(&loginmsg);
			buffer_append(&loginmsg, "\0", 1);
			msg = buffer_ptr(&loginmsg);
			/* strip trailing newlines */
			if (len > 0)
				while (len > 0 && msg[--len] == '\n')
					msg[len] = '\0';
			else
				msg = "Access denied.";
			packet_disconnect("%s", msg);
		}
#endif

 skip:
		/* Log before sending the reply */
		auth_log(authctxt, authenticated, 0, get_authname(type), NULL);

		free(client_user);
		client_user = NULL;

		if (authenticated)
			return;

		if (++authctxt->failures >= options.max_authtries) {
#ifdef SSH_AUDIT_EVENTS
			PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
#endif
			auth_maxtries_exceeded(authctxt);
		}

		packet_start(SSH_SMSG_FAILURE);
		packet_send();
		packet_write_wait();
	}
}
Ejemplo n.º 5
0
struct passwd *
getpwnamallow(const char *user)
{
#ifdef HAVE_LOGIN_CAP
	extern login_cap_t *lc;
#ifdef BSD_AUTH
	auth_session_t *as;
#endif
#endif
	struct passwd *pw;
	struct connection_info *ci = get_connection_info(1, options.use_dns);

	ci->user = user;
	parse_server_match_config(&options, ci);

#if defined(_AIX) && defined(HAVE_SETAUTHDB)
	aix_setauthdb(user);
#endif

	pw = getpwnam(user);

#if defined(_AIX) && defined(HAVE_SETAUTHDB)
	aix_restoreauthdb();
#endif
#ifdef HAVE_CYGWIN
	/*
	 * Windows usernames are case-insensitive.  To avoid later problems
	 * when trying to match the username, the user is only allowed to
	 * login if the username is given in the same case as stored in the
	 * user database.
	 */
	if (pw != NULL && strcmp(user, pw->pw_name) != 0) {
		logit("Login name %.100s does not match stored username %.100s",
		    user, pw->pw_name);
		pw = NULL;
	}
#endif
	if (pw == NULL) {
		BLACKLIST_NOTIFY(BLACKLIST_AUTH_FAIL);
		logit("Invalid user %.100s from %.100s",
		    user, get_remote_ipaddr());
#ifdef CUSTOM_FAILED_LOGIN
		record_failed_login(user,
		    get_canonical_hostname(options.use_dns), "ssh");
#endif
#ifdef SSH_AUDIT_EVENTS
		audit_event(SSH_INVALID_USER);
#endif /* SSH_AUDIT_EVENTS */
		return (NULL);
	}
	if (!allowed_user(pw))
		return (NULL);
#ifdef HAVE_LOGIN_CAP
	if ((lc = login_getpwclass(pw)) == NULL) {
		debug("unable to get login class: %s", user);
		return (NULL);
	}
#ifdef BSD_AUTH
	if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
	    auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
		debug("Approval failure for %s", user);
		pw = NULL;
	}
	if (as != NULL)
		auth_close(as);
#endif
#endif
	if (pw != NULL)
		return (pwcopy(pw));
	return (NULL);
}
Ejemplo n.º 6
0
static int
sshpam_query(void *ctx, char **name, char **info,
    u_int *num, char ***prompts, u_int **echo_on)
{
	struct ssh *ssh = active_state; /* XXX */
	struct sshbuf *buffer;
	struct pam_ctxt *ctxt = ctx;
	size_t plen;
	u_char type;
	char *msg;
	size_t len, mlen;
	int r;

	debug3("PAM: %s entering", __func__);
	if ((buffer = sshbuf_new()) == NULL)
		fatal("%s: sshbuf_new failed", __func__);
	*name = xstrdup("");
	*info = xstrdup("");
	*prompts = xmalloc(sizeof(char *));
	**prompts = NULL;
	plen = 0;
	*echo_on = xmalloc(sizeof(u_int));
	while (ssh_msg_recv(ctxt->pam_psock, buffer) == 0) {
		if ((r = sshbuf_get_u8(buffer, &type)) != 0 ||
		    (r = sshbuf_get_cstring(buffer, &msg, &mlen)) != 0)
			fatal("%s: buffer error: %s", __func__, ssh_err(r));
		switch (type) {
		case PAM_PROMPT_ECHO_ON:
		case PAM_PROMPT_ECHO_OFF:
			*num = 1;
			len = plen + mlen + 1;
			**prompts = xreallocarray(**prompts, 1, len);
			strlcpy(**prompts + plen, msg, len - plen);
			plen += mlen;
			**echo_on = (type == PAM_PROMPT_ECHO_ON);
			free(msg);
			return (0);
		case PAM_ERROR_MSG:
		case PAM_TEXT_INFO:
			/* accumulate messages */
			len = plen + mlen + 2;
			**prompts = xreallocarray(**prompts, 1, len);
			strlcpy(**prompts + plen, msg, len - plen);
			plen += mlen;
			strlcat(**prompts + plen, "\n", len - plen);
			plen++;
			free(msg);
			break;
		case PAM_ACCT_EXPIRED:
		case PAM_MAXTRIES:
			if (type == PAM_ACCT_EXPIRED)
				sshpam_account_status = 0;
			if (type == PAM_MAXTRIES)
				sshpam_set_maxtries_reached(1);
			/* FALLTHROUGH */
		case PAM_AUTH_ERR:
			debug3("PAM: %s", pam_strerror(sshpam_handle, type));
			if (**prompts != NULL && strlen(**prompts) != 0) {
				*info = **prompts;
				**prompts = NULL;
				*num = 0;
				**echo_on = 0;
				ctxt->pam_done = -1;
				free(msg);
				return 0;
			}
			/* FALLTHROUGH */
		case PAM_SUCCESS:
			if (**prompts != NULL) {
				/* drain any accumulated messages */
				debug("PAM: %s", **prompts);
				if ((r = sshbuf_put(loginmsg, **prompts,
				    strlen(**prompts))) != 0)
					fatal("%s: buffer error: %s",
					    __func__, ssh_err(r));
				free(**prompts);
				**prompts = NULL;
			}
			if (type == PAM_SUCCESS) {
				if (!sshpam_authctxt->valid ||
				    (sshpam_authctxt->pw->pw_uid == 0 &&
				    options.permit_root_login != PERMIT_YES))
					fatal("Internal error: PAM auth "
					    "succeeded when it should have "
					    "failed");
				import_environments(buffer);
				*num = 0;
				**echo_on = 0;
				ctxt->pam_done = 1;
				free(msg);
				return (0);
			}
			BLACKLIST_NOTIFY(BLACKLIST_BAD_USER,
			    sshpam_authctxt->user);
			error("PAM: %s for %s%.100s from %.100s", msg,
			    sshpam_authctxt->valid ? "" : "illegal user ",
			    sshpam_authctxt->user,
			    auth_get_canonical_hostname(ssh, options.use_dns));
			/* FALLTHROUGH */
		default:
			*num = 0;
			**echo_on = 0;
			free(msg);
			ctxt->pam_done = -1;
			return (-1);
		}
	}
	return (-1);
}
Ejemplo n.º 7
0
void
auth_log(Authctxt *authctxt, int authenticated, int partial,
    const char *method, const char *submethod)
{
	struct ssh *ssh = active_state; /* XXX */
	void (*authlog) (const char *fmt,...) = verbose;
	const char *authmsg;
	char *extra = NULL;

	if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
		return;

	/* Raise logging level */
	if (authenticated == 1 ||
	    !authctxt->valid ||
	    authctxt->failures >= options.max_authtries / 2 ||
	    strcmp(method, "password") == 0)
		authlog = logit;

	if (authctxt->postponed)
		authmsg = "Postponed";
	else if (partial)
		authmsg = "Partial";
	else {
		authmsg = authenticated ? "Accepted" : "Failed";
		if (authenticated)
			BLACKLIST_NOTIFY(BLACKLIST_AUTH_OK, "ssh");
	}

	if ((extra = format_method_key(authctxt)) == NULL) {
		if (authctxt->auth_method_info != NULL)
			extra = xstrdup(authctxt->auth_method_info);
	}

	authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
	    authmsg,
	    method,
	    submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
	    authctxt->valid ? "" : "invalid user ",
	    authctxt->user,
	    ssh_remote_ipaddr(ssh),
	    ssh_remote_port(ssh),
	    extra != NULL ? ": " : "",
	    extra != NULL ? extra : "");

	free(extra);

#ifdef CUSTOM_FAILED_LOGIN
	if (authenticated == 0 && !authctxt->postponed &&
	    (strcmp(method, "password") == 0 ||
	    strncmp(method, "keyboard-interactive", 20) == 0 ||
	    strcmp(method, "challenge-response") == 0))
		record_failed_login(authctxt->user,
		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
# ifdef WITH_AIXAUTHENTICATE
	if (authenticated)
		sys_auth_record_login(authctxt->user,
		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh",
		    &loginmsg);
# endif
#endif
#ifdef SSH_AUDIT_EVENTS
	if (authenticated == 0 && !authctxt->postponed)
		audit_event(audit_classify_auth(method));
#endif
}