+/* $OpenBSD: auth2.c,v 1.113 2006/08/03 03:34:41 deraadt Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
*/
#include "includes.h"
-RCSID("$OpenBSD: auth2.c,v 1.102 2003/08/26 09:58:43 markus Exp $");
-#include "ssh2.h"
+#include <sys/types.h>
+
+#include <pwd.h>
+#include <stdarg.h>
+#include <string.h>
+
#include "xmalloc.h"
+#include "ssh2.h"
#include "packet.h"
#include "log.h"
+#include "buffer.h"
#include "servconf.h"
+#include "compat.h"
+#include "key.h"
+#include "hostfile.h"
#include "auth.h"
#include "dispatch.h"
#include "pathnames.h"
-#include "monitor_wrap.h"
+#include "buffer.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
+#include "monitor_wrap.h"
/* import */
extern ServerOptions options;
extern u_char *session_id2;
extern u_int session_id2_len;
-
-Authctxt *x_authctxt = NULL;
+extern Buffer loginmsg;
/* methods */
extern Authmethod method_hostbased;
#ifdef GSSAPI
extern Authmethod method_external;
+extern Authmethod method_gsskeyex;
extern Authmethod method_gssapi;
+extern Authmethod method_gssapi_compat;
#endif
Authmethod *authmethods[] = {
&method_none,
-#ifdef GSSAPI
- &method_external,
- &method_gssapi,
-#endif
&method_pubkey,
#ifdef GSSAPI
+ &method_gsskeyex,
+ &method_external,
&method_gssapi,
+ &method_gssapi_compat,
#endif
&method_passwd,
&method_kbdint,
static Authmethod *authmethod_lookup(const char *);
static char *authmethods_get(void);
int user_key_allowed(struct passwd *, Key *);
-int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
/*
* loop until authctxt->success == TRUE
*/
-Authctxt *
-do_authentication2(void)
+void
+do_authentication2(Authctxt *authctxt)
{
- Authctxt *authctxt = authctxt_new();
-
- x_authctxt = authctxt; /*XXX*/
-
/* challenge-response is implemented via keyboard interactive */
if (options.challenge_response_authentication)
options.kbd_interactive_authentication = 1;
dispatch_init(&dispatch_protocol_error);
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
-
- return (authctxt);
}
+/*ARGSUSED*/
static void
input_service_request(int type, u_int32_t seq, void *ctxt)
{
xfree(service);
}
+/*ARGSUSED*/
static void
input_userauth_request(int type, u_int32_t seq, void *ctxt)
{
method = packet_get_string(NULL);
#ifdef GSSAPI
- if (strcmp(user, "") == 0) {
+ if (user[0] == '\0') {
debug("received empty username for %s", method);
- if (strcmp(method, "external-keyx") == 0) {
+ if (strcmp(method, "external-keyx") == 0 ||
+ strcmp(method, "gssapi-keyex") == 0) {
char *lname = NULL;
PRIVSEP(ssh_gssapi_localname(&lname));
if (lname && lname[0] != '\0') {
xfree(user);
user = lname;
debug("set username to %s from gssapi context", user);
- } else if (authctxt->valid) {
+ } else {
debug("failed to set username from gssapi context");
+ packet_send_debug("failed to set username from gssapi context");
}
}
}
#endif
debug("userauth-request for user %s service %s method %s",
- (user && user[0]) ? user : "<implicit>", service, method);
+ user[0] ? user : "<implicit>", service, method);
debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
if ((style = strchr(user, ':')) != NULL)
*style++ = 0;
- authctxt->attempt++;
- if (!authctxt->user ||
- strcmp(user, authctxt->user) != 0) {
- /* setup auth context */
+ /* If first time or username changed or implicit username,
+ setup/reset authentication context. */
+ if ((authctxt->attempt++ == 0) ||
+ (strcmp(user, authctxt->user) != 0) ||
+ (strcmp(user, "") == 0)) {
if (authctxt->user) {
xfree(authctxt->user);
authctxt->user = NULL;
}
- if (authctxt->service) {
- xfree(authctxt->service);
- authctxt->service = NULL;
- }
- if (authctxt->style) {
- xfree(authctxt->style);
- authctxt->style = NULL;
- }
+ authctxt->valid = 0;
#ifdef GSSAPI
- /* We'll verify the username after we set it from the
- GSSAPI context. */
+ /* If we're going to set the username based on the
+ GSSAPI context later, then wait until then to
+ verify it. Just put in placeholders for now. */
if ((strcmp(user, "") == 0) &&
((strcmp(method, "gssapi") == 0) ||
- (strcmp(method, "external-keyx") == 0))) {
- authctxt->pw = NULL;
- authctxt->valid = 1;
+ (strcmp(method, "gssapi-with-mic") == 0))) {
+ authctxt->pw = fakepw();
+ authctxt->user = xstrdup(user);
} else {
#endif
authctxt->pw = PRIVSEP(getpwnamallow(user));
+ authctxt->user = xstrdup(user);
if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
authctxt->valid = 1;
debug2("input_userauth_request: setting up authctxt for %s", user);
-#ifdef USE_PAM
- if (options.use_pam)
- PRIVSEP(start_pam(authctxt->pw->pw_name));
-#endif
} else {
- logit("input_userauth_request: illegal user %s", user);
+ logit("input_userauth_request: invalid user %s", user);
authctxt->pw = fakepw();
-#ifdef USE_PAM
- if (options.use_pam)
- PRIVSEP(start_pam(user));
+#ifdef SSH_AUDIT_EVENTS
+ PRIVSEP(audit_event(SSH_INVALID_USER));
#endif
}
#ifdef GSSAPI
- }
+ } /* endif for setting username based on GSSAPI context */
#endif
- setproctitle("%s%s", authctxt->pw ? user : "unknown",
+#ifdef USE_PAM
+ if (options.use_pam)
+ PRIVSEP(start_pam(authctxt));
+#endif
+ setproctitle("%s%s", authctxt->valid ? user : "unknown",
use_privsep ? " [net]" : "");
- authctxt->user = xstrdup(user);
+#ifdef GSSAPI
+ if (authctxt->attempt == 1) {
+#endif
authctxt->service = xstrdup(service);
authctxt->style = style ? xstrdup(style) : NULL;
- if (use_privsep && (authctxt->attempt == 1))
+ if (use_privsep)
mm_inform_authserv(service, style);
- } else if (strcmp(service, authctxt->service) != 0) {
+#ifdef GSSAPI
+ } /* if (authctxt->attempt == 1) */
+#endif
+ }
+ if (strcmp(service, authctxt->service) != 0) {
packet_disconnect("Change of service not allowed: "
"(%s,%s) -> (%s,%s)",
authctxt->user, authctxt->service, user, service);
#endif
authctxt->postponed = 0;
+ authctxt->server_caused_failure = 0;
/* try to authenticate user */
m = authmethod_lookup(method);
/* Special handling for root */
if (authenticated && authctxt->pw->pw_uid == 0 &&
- !auth_root_allowed(method))
+ !auth_root_allowed(method)) {
authenticated = 0;
+#ifdef SSH_AUDIT_EVENTS
+ PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED));
+#endif
+ }
#ifdef USE_PAM
- if (options.use_pam && authenticated && !PRIVSEP(do_pam_account()))
- authenticated = 0;
+ if (options.use_pam && authenticated) {
+ if (!PRIVSEP(do_pam_account())) {
+ /* if PAM returned a message, send it to the user */
+ if (buffer_len(&loginmsg) > 0) {
+ buffer_append(&loginmsg, "\0", 1);
+ userauth_send_banner(buffer_ptr(&loginmsg));
+ packet_write_wait();
+ }
+ fatal("Access denied for user %s by PAM account "
+ "configuration", authctxt->user);
+ }
+ }
#endif
#ifdef _UNICOS
/* now we can break out */
authctxt->success = 1;
} else {
- if (authctxt->failures++ > AUTH_FAIL_MAX)
+ /* Dont count server configuration issues against the client */
+ if (!authctxt->server_caused_failure &&
+ authctxt->failures++ > options.max_authtries) {
+#ifdef SSH_AUDIT_EVENTS
+ PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
+#endif
packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
+ }
methods = authmethods_get();
packet_start(SSH2_MSG_USERAUTH_FAILURE);
packet_put_cstring(methods);
}
}
-/* get current user */
-
-struct passwd*
-auth_get_user(void)
-{
- return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
-}
-
#define DELIM ","
static char *