diff --git a/ChangeLog b/ChangeLog index def04ff41..58d21ac55 100644 --- a/ChangeLog +++ b/ChangeLog @@ -54,6 +54,11 @@ prototype pedant. not very creative... - () -> (void) - no variable names + - dugsong@cvs.openbsd.org 2001/06/26 16:15:25 + [auth1.c auth.h auth-krb4.c auth-passwd.c readconf.c readconf.h + servconf.c servconf.h session.c sshconnect1.c sshd.c] + Kerberos v5 support for SSH1, mostly from Assar Westerlund + and Bjorn Gronvall . markus@ ok 20010629 - (bal) Removed net_aton() since we don't use it any more @@ -5881,4 +5886,4 @@ - Wrote replacements for strlcpy and mkdtemp - Released 1.0pre1 -$Id: ChangeLog,v 1.1357 2001/07/04 04:07:12 mouring Exp $ +$Id: ChangeLog,v 1.1358 2001/07/04 04:21:14 mouring Exp $ diff --git a/auth-krb4.c b/auth-krb4.c index 8bb6e3d6f..031dcd301 100644 --- a/auth-krb4.c +++ b/auth-krb4.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-krb4.c,v 1.23 2001/01/22 08:15:00 markus Exp $"); +RCSID("$OpenBSD: auth-krb4.c,v 1.24 2001/06/26 16:15:22 dugsong Exp $"); #include "ssh.h" #include "ssh1.h" @@ -31,6 +31,7 @@ RCSID("$OpenBSD: auth-krb4.c,v 1.23 2001/01/22 08:15:00 markus Exp $"); #include "xmalloc.h" #include "log.h" #include "servconf.h" +#include "uidswap.h" #include "auth.h" #ifdef AFS @@ -38,70 +39,114 @@ RCSID("$OpenBSD: auth-krb4.c,v 1.23 2001/01/22 08:15:00 markus Exp $"); #endif #ifdef KRB4 -char *ticket = NULL; - extern ServerOptions options; +static int +krb4_init(void *context) +{ + static int cleanup_registered = 0; + Authctxt *authctxt = (Authctxt *)context; + const char *tkt_root = TKT_ROOT; + struct stat st; + int fd; + + if (!authctxt->krb4_ticket_file) { + /* Set unique ticket string manually since we're still root. */ + authctxt->krb4_ticket_file = xmalloc(MAXPATHLEN); +#ifdef AFS + if (lstat("/ticket", &st) != -1) + tkt_root = "/ticket/"; +#endif /* AFS */ + snprintf(authctxt->krb4_ticket_file, MAXPATHLEN, "%s%u_%d", + tkt_root, authctxt->pw->pw_uid, getpid()); + krb_set_tkt_string(authctxt->krb4_ticket_file); + } + /* Register ticket cleanup in case of fatal error. */ + if (!cleanup_registered) { + fatal_add_cleanup(krb4_cleanup_proc, authctxt); + cleanup_registered = 1; + } + /* Try to create our ticket file. */ + if ((fd = mkstemp(authctxt->krb4_ticket_file)) != -1) { + close(fd); + return (1); + } + /* Ticket file exists - make sure user owns it (just passed ticket). */ + if (lstat(authctxt->krb4_ticket_file, &st) != -1) { + if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) && + st.st_uid == authctxt->pw->pw_uid) + return (1); + } + /* Failure - cancel cleanup function, leaving ticket for inspection. */ + log("WARNING: bad ticket file %s", authctxt->krb4_ticket_file); + + fatal_remove_cleanup(krb4_cleanup_proc, authctxt); + cleanup_registered = 0; + + xfree(authctxt->krb4_ticket_file); + authctxt->krb4_ticket_file = NULL; + + return (0); +} + /* * try krb4 authentication, * return 1 on success, 0 on failure, -1 if krb4 is not available */ - int -auth_krb4_password(struct passwd * pw, const char *password) +auth_krb4_password(Authctxt *authctxt, const char *password) { AUTH_DAT adata; KTEXT_ST tkt; struct hostent *hp; - u_long faddr; - char localhost[MAXHOSTNAMELEN]; - char phost[INST_SZ]; - char realm[REALM_SZ]; + struct passwd *pw; + char localhost[MAXHOSTNAMELEN], phost[INST_SZ], realm[REALM_SZ]; + u_int32_t faddr; int r; - + + if ((pw = authctxt->pw) == NULL) + return (0); + /* * Try Kerberos password authentication only for non-root * users and only if Kerberos is installed. */ if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) { - /* Set up our ticket file. */ - if (!krb4_init(pw->pw_uid)) { + if (!krb4_init(authctxt)) { log("Couldn't initialize Kerberos ticket file for %s!", pw->pw_name); - goto kerberos_auth_failure; + goto failure; } /* Try to get TGT using our password. */ - r = krb_get_pw_in_tkt((char *) pw->pw_name, "", - realm, "krbtgt", realm, - DEFAULT_TKT_LIFE, (char *) password); + r = krb_get_pw_in_tkt((char *) pw->pw_name, "", realm, + "krbtgt", realm, DEFAULT_TKT_LIFE, (char *)password); if (r != INTK_OK) { - packet_send_debug("Kerberos V4 password " - "authentication for %s failed: %s", - pw->pw_name, krb_err_txt[r]); - goto kerberos_auth_failure; + debug("Kerberos v4 password authentication for %s " + "failed: %s", pw->pw_name, krb_err_txt[r]); + goto failure; } /* Successful authentication. */ chown(tkt_string(), pw->pw_uid, pw->pw_gid); - + /* * Now that we have a TGT, try to get a local * "rcmd" ticket to ensure that we are not talking * to a bogus Kerberos server. */ - (void) gethostname(localhost, sizeof(localhost)); - (void) strlcpy(phost, (char *) krb_get_phost(localhost), - INST_SZ); + gethostname(localhost, sizeof(localhost)); + strlcpy(phost, (char *)krb_get_phost(localhost), + sizeof(phost)); r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33); - + if (r == KSUCCESS) { - if (!(hp = gethostbyname(localhost))) { + if ((hp = gethostbyname(localhost)) == NULL) { log("Couldn't get local host address!"); - goto kerberos_auth_failure; + goto failure; } - memmove((void *) &faddr, (void *) hp->h_addr, + memmove((void *)&faddr, (void *)hp->h_addr, sizeof(faddr)); - + /* Verify our "rcmd" ticket. */ r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost, faddr, &adata, ""); @@ -110,119 +155,74 @@ auth_krb4_password(struct passwd * pw, const char *password) * Probably didn't have a srvtab on * localhost. Disallow login. */ - log("Kerberos V4 TGT for %s unverifiable, " + log("Kerberos v4 TGT for %s unverifiable, " "no srvtab installed? krb_rd_req: %s", pw->pw_name, krb_err_txt[r]); - goto kerberos_auth_failure; + goto failure; } else if (r != KSUCCESS) { - log("Kerberos V4 %s ticket unverifiable: %s", + log("Kerberos v4 %s ticket unverifiable: %s", KRB4_SERVICE_NAME, krb_err_txt[r]); - goto kerberos_auth_failure; + goto failure; } } else if (r == KDC_PR_UNKNOWN) { /* * Disallow login if no rcmd service exists, and * log the error. */ - log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s " + log("Kerberos v4 TGT for %s unverifiable: %s; %s.%s " "not registered, or srvtab is wrong?", pw->pw_name, - krb_err_txt[r], KRB4_SERVICE_NAME, phost); - goto kerberos_auth_failure; + krb_err_txt[r], KRB4_SERVICE_NAME, phost); + goto failure; } else { /* * TGT is bad, forget it. Possibly spoofed! */ - packet_send_debug("WARNING: Kerberos V4 TGT " - "possibly spoofed for %s: %s", - pw->pw_name, krb_err_txt[r]); - goto kerberos_auth_failure; + debug("WARNING: Kerberos v4 TGT possibly spoofed " + "for %s: %s", pw->pw_name, krb_err_txt[r]); + goto failure; } - /* Authentication succeeded. */ - return 1; - -kerberos_auth_failure: - krb4_cleanup_proc(NULL); - - if (!options.kerberos_or_local_passwd) - return 0; - } else { + return (1); + } else /* Logging in as root or no local Kerberos realm. */ - packet_send_debug("Unable to authenticate to Kerberos."); - } + debug("Unable to authenticate to Kerberos."); + + failure: + krb4_cleanup_proc(authctxt); + + if (!options.kerberos_or_local_passwd) + return (0); + /* Fall back to ordinary passwd authentication. */ - return -1; + return (-1); } void -krb4_cleanup_proc(void *ignore) +krb4_cleanup_proc(void *context) { + Authctxt *authctxt = (Authctxt *)context; debug("krb4_cleanup_proc called"); - if (ticket) { + if (authctxt->krb4_ticket_file) { (void) dest_tkt(); - xfree(ticket); - ticket = NULL; + xfree(authctxt->krb4_ticket_file); + authctxt->krb4_ticket_file = NULL; } } int -krb4_init(uid_t uid) -{ - static int cleanup_registered = 0; - const char *tkt_root = TKT_ROOT; - struct stat st; - int fd; - - if (!ticket) { - /* Set unique ticket string manually since we're still root. */ - ticket = xmalloc(MAXPATHLEN); -#ifdef AFS - if (lstat("/ticket", &st) != -1) - tkt_root = "/ticket/"; -#endif /* AFS */ - snprintf(ticket, MAXPATHLEN, "%s%u_%d", tkt_root, uid, getpid()); - (void) krb_set_tkt_string(ticket); - } - /* Register ticket cleanup in case of fatal error. */ - if (!cleanup_registered) { - fatal_add_cleanup(krb4_cleanup_proc, NULL); - cleanup_registered = 1; - } - /* Try to create our ticket file. */ - if ((fd = mkstemp(ticket)) != -1) { - close(fd); - return 1; - } - /* Ticket file exists - make sure user owns it (just passed ticket). */ - if (lstat(ticket, &st) != -1) { - if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) && - st.st_uid == uid) - return 1; - } - /* Failure - cancel cleanup function, leaving bad ticket for inspection. */ - log("WARNING: bad ticket file %s", ticket); - fatal_remove_cleanup(krb4_cleanup_proc, NULL); - cleanup_registered = 0; - xfree(ticket); - ticket = NULL; - - return 0; -} - -int -auth_krb4(const char *server_user, KTEXT auth, char **client) +auth_krb4(Authctxt *authctxt, KTEXT auth, char **client) { AUTH_DAT adat = {0}; KTEXT_ST reply; - char instance[INST_SZ]; - int r, s; - socklen_t slen; - u_int cksum; Key_schedule schedule; struct sockaddr_in local, foreign; - + char instance[INST_SZ]; + socklen_t slen; + u_int cksum; + int r, s; + s = packet_get_connection_in(); - + slen = sizeof(local); memset(&local, 0, sizeof(local)); if (getsockname(s, (struct sockaddr *) & local, &slen) < 0) @@ -235,157 +235,139 @@ auth_krb4(const char *server_user, KTEXT auth, char **client) } instance[0] = '*'; instance[1] = 0; - + /* Get the encrypted request, challenge, and session key. */ - if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance, 0, &adat, ""))) { - packet_send_debug("Kerberos V4 krb_rd_req: %.100s", krb_err_txt[r]); - return 0; + if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance, + 0, &adat, ""))) { + debug("Kerberos v4 krb_rd_req: %.100s", krb_err_txt[r]); + return (0); } des_key_sched((des_cblock *) adat.session, schedule); - + *client = xmalloc(MAX_K_NAME_SZ); (void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname, *adat.pinst ? "." : "", adat.pinst, adat.prealm); - + /* Check ~/.klogin authorization now. */ - if (kuserok(&adat, (char *) server_user) != KSUCCESS) { - packet_send_debug("Kerberos V4 .klogin authorization failed!"); - log("Kerberos V4 .klogin authorization failed for %s to account %s", - *client, server_user); + if (kuserok(&adat, authctxt->user) != KSUCCESS) { + log("Kerberos v4 .klogin authorization failed for %s to " + "account %s", *client, authctxt->user); xfree(*client); - return 0; + return (0); } /* Increment the checksum, and return it encrypted with the session key. */ cksum = adat.checksum + 1; cksum = htonl(cksum); - + /* If we can't successfully encrypt the checksum, we send back an empty message, admitting our failure. */ if ((r = krb_mk_priv((u_char *) & cksum, reply.dat, sizeof(cksum) + 1, schedule, &adat.session, &local, &foreign)) < 0) { - packet_send_debug("Kerberos V4 mk_priv: (%d) %s", r, krb_err_txt[r]); + debug("Kerberos v4 mk_priv: (%d) %s", r, krb_err_txt[r]); reply.dat[0] = 0; reply.length = 0; } else reply.length = r; - + /* Clear session key. */ memset(&adat.session, 0, sizeof(&adat.session)); - + packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE); packet_put_string((char *) reply.dat, reply.length); packet_send(); packet_write_wait(); - return 1; + return (1); } #endif /* KRB4 */ #ifdef AFS int -auth_kerberos_tgt(struct passwd *pw, const char *string) +auth_krb4_tgt(Authctxt *authctxt, const char *string) { CREDENTIALS creds; - - if (pw == NULL) - goto auth_kerberos_tgt_failure; + struct passwd *pw; + + if ((pw = authctxt->pw) == NULL) + goto failure; + + temporarily_use_uid(pw); + if (!radix_to_creds(string, &creds)) { - log("Protocol error decoding Kerberos V4 tgt"); - packet_send_debug("Protocol error decoding Kerberos V4 tgt"); - goto auth_kerberos_tgt_failure; + log("Protocol error decoding Kerberos v4 TGT"); + goto failure; } if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */ strlcpy(creds.service, "krbtgt", sizeof creds.service); - + if (strcmp(creds.service, "krbtgt")) { - log("Kerberos V4 tgt (%s%s%s@%s) rejected for %s", creds.pname, - creds.pinst[0] ? "." : "", creds.pinst, creds.realm, - pw->pw_name); - packet_send_debug("Kerberos V4 tgt (%s%s%s@%s) rejected for %s", + log("Kerberos v4 TGT (%s%s%s@%s) rejected for %s", creds.pname, creds.pinst[0] ? "." : "", creds.pinst, creds.realm, pw->pw_name); - goto auth_kerberos_tgt_failure; + goto failure; } - if (!krb4_init(pw->pw_uid)) - goto auth_kerberos_tgt_failure; - + if (!krb4_init(authctxt)) + goto failure; + if (in_tkt(creds.pname, creds.pinst) != KSUCCESS) - goto auth_kerberos_tgt_failure; - + goto failure; + if (save_credentials(creds.service, creds.instance, creds.realm, - creds.session, creds.lifetime, creds.kvno, - &creds.ticket_st, creds.issue_date) != KSUCCESS) { - packet_send_debug("Kerberos V4 tgt refused: couldn't save credentials"); - goto auth_kerberos_tgt_failure; + creds.session, creds.lifetime, creds.kvno, &creds.ticket_st, + creds.issue_date) != KSUCCESS) { + debug("Kerberos v4 TGT refused: couldn't save credentials"); + goto failure; } /* Successful authentication, passed all checks. */ chown(tkt_string(), pw->pw_uid, pw->pw_gid); - - packet_send_debug("Kerberos V4 tgt accepted (%s.%s@%s, %s%s%s@%s)", - creds.service, creds.instance, creds.realm, creds.pname, - creds.pinst[0] ? "." : "", creds.pinst, creds.realm); + + debug("Kerberos v4 TGT accepted (%s%s%s@%s)", + creds.pname, creds.pinst[0] ? "." : "", creds.pinst, creds.realm); memset(&creds, 0, sizeof(creds)); - packet_start(SSH_SMSG_SUCCESS); - packet_send(); - packet_write_wait(); - return 1; - -auth_kerberos_tgt_failure: - krb4_cleanup_proc(NULL); + + restore_uid(); + + return (1); + + failure: + krb4_cleanup_proc(authctxt); memset(&creds, 0, sizeof(creds)); - packet_start(SSH_SMSG_FAILURE); - packet_send(); - packet_write_wait(); - return 0; + restore_uid(); + + return (0); } int -auth_afs_token(struct passwd *pw, const char *token_string) +auth_afs_token(Authctxt *authctxt, const char *token_string) { CREDENTIALS creds; + struct passwd *pw; uid_t uid; - - if (pw == NULL) { - /* XXX fake protocol error */ - packet_send_debug("Protocol error decoding AFS token"); - packet_start(SSH_SMSG_FAILURE); - packet_send(); - packet_write_wait(); - return 0; - } + + if ((pw = authctxt->pw) == NULL) + return (0); + if (!radix_to_creds(token_string, &creds)) { log("Protocol error decoding AFS token"); - packet_send_debug("Protocol error decoding AFS token"); - packet_start(SSH_SMSG_FAILURE); - packet_send(); - packet_write_wait(); - return 0; + return (0); } if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */ strlcpy(creds.service, "afs", sizeof creds.service); - + if (strncmp(creds.pname, "AFS ID ", 7) == 0) uid = atoi(creds.pname + 7); else uid = pw->pw_uid; - + if (kafs_settoken(creds.realm, uid, &creds)) { - log("AFS token (%s@%s) rejected for %s", creds.pname, creds.realm, - pw->pw_name); - packet_send_debug("AFS token (%s@%s) rejected for %s", creds.pname, - creds.realm, pw->pw_name); + log("AFS token (%s@%s) rejected for %s", + creds.pname, creds.realm, pw->pw_name); memset(&creds, 0, sizeof(creds)); - packet_start(SSH_SMSG_FAILURE); - packet_send(); - packet_write_wait(); - return 0; + return (0); } - packet_send_debug("AFS token accepted (%s@%s, %s@%s)", creds.service, - creds.realm, creds.pname, creds.realm); + debug("AFS token accepted (%s@%s)", creds.pname, creds.realm); memset(&creds, 0, sizeof(creds)); - packet_start(SSH_SMSG_SUCCESS); - packet_send(); - packet_write_wait(); - return 1; + + return (1); } #endif /* AFS */ diff --git a/auth-passwd.c b/auth-passwd.c index d53a9ea2d..988297cb4 100644 --- a/auth-passwd.c +++ b/auth-passwd.c @@ -36,7 +36,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-passwd.c,v 1.22 2001/03/20 18:57:04 markus Exp $"); +RCSID("$OpenBSD: auth-passwd.c,v 1.23 2001/06/26 16:15:23 dugsong Exp $"); #if !defined(USE_PAM) && !defined(HAVE_OSF_SIA) @@ -128,14 +128,14 @@ auth_password(Authctxt *authctxt, const char *password) #endif if (*password == '\0' && options.permit_empty_passwd == 0) return 0; -#ifdef BSD_AUTH - if (auth_userokay(pw->pw_name, authctxt->style, "auth-ssh", - (char *)password) == 0) - return 0; - else - return 1; +#ifdef KRB5 + if (options.kerberos_authentication == 1) { + int ret = auth_krb5_password(authctxt, password); + if (ret == 1 || ret == 0) + return ret; + /* Fall back to ordinary passwd authentication. */ + } #endif - #ifdef HAVE_CYGWIN if (is_winnt) { HANDLE hToken = cygwin_logon_user(pw, password); @@ -146,21 +146,24 @@ auth_password(Authctxt *authctxt, const char *password) return 1; } #endif - #ifdef WITH_AIXAUTHENTICATE return (authenticate(pw->pw_name,password,&reenter,&authmsg) == 0); #endif - #ifdef KRB4 if (options.kerberos_authentication == 1) { - int ret = auth_krb4_password(pw, password); + int ret = auth_krb4_password(authctxt, password); if (ret == 1 || ret == 0) return ret; /* Fall back to ordinary passwd authentication. */ } #endif - - +#ifdef BSD_AUTH + if (auth_userokay(pw->pw_name, authctxt->style, "auth-ssh", + (char *)password) == 0) + return 0; + else + return 1; +#endif pw_password = pw->pw_passwd; /* diff --git a/auth.h b/auth.h index a29944113..1c72dffa3 100644 --- a/auth.h +++ b/auth.h @@ -21,7 +21,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $OpenBSD: auth.h,v 1.20 2001/06/26 06:32:47 itojun Exp $ + * $OpenBSD: auth.h,v 1.21 2001/06/26 16:15:23 dugsong Exp $ */ #ifndef AUTH_H #define AUTH_H @@ -36,23 +36,36 @@ #ifdef BSD_AUTH #include #endif +#ifdef KRB5 +#include +#endif typedef struct Authctxt Authctxt; typedef struct KbdintDevice KbdintDevice; struct Authctxt { - int success; - int postponed; - int valid; - int attempt; - int failures; - char *user; - char *service; - struct passwd *pw; - char *style; - void *kbdintctxt; + int success; + int postponed; + int valid; + int attempt; + int failures; + char *user; + char *service; + struct passwd *pw; + char *style; + void *kbdintctxt; #ifdef BSD_AUTH - auth_session_t *as; + auth_session_t *as; +#endif +#ifdef KRB4 + char *krb4_ticket_file; +#endif +#ifdef KRB5 + krb5_context krb5_ctx; + krb5_auth_context krb5_auth_ctx; + krb5_ccache krb5_fwd_ccache; + krb5_principal krb5_user; + char *krb5_ticket_file; #endif }; @@ -125,21 +138,27 @@ int auth_rsa_challenge_dialog(RSA *); * if the client could not be authenticated, and 1 if authentication was * successful. This may exit if there is a serious protocol violation. */ -int auth_krb4(const char *, KTEXT, char **); -int krb4_init(uid_t); +int auth_krb4(Authctxt *, KTEXT, char **); +int auth_krb4_password(Authctxt *, const char *); void krb4_cleanup_proc(void *); -int auth_krb4_password(struct passwd *, const char *); #ifdef AFS #include /* Accept passed Kerberos v4 ticket-granting ticket and AFS tokens. */ -int auth_kerberos_tgt(struct passwd *, const char *); -int auth_afs_token(struct passwd *, const char *); +int auth_krb4_tgt(Authctxt *, const char *); +int auth_afs_token(Authctxt *, const char *); #endif /* AFS */ #endif /* KRB4 */ +#ifdef KRB5 +int auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client); +int auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt); +int auth_krb5_password(Authctxt *authctxt, const char *password); +void krb5_cleanup_proc(void *authctxt); +#endif /* KRB5 */ + #include "auth-pam.h" #include "auth2-pam.h" diff --git a/auth1.c b/auth1.c index d5b7fa7c8..da2c23e52 100644 --- a/auth1.c +++ b/auth1.c @@ -10,7 +10,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth1.c,v 1.24 2001/06/23 15:12:17 itojun Exp $"); +RCSID("$OpenBSD: auth1.c,v 1.25 2001/06/26 16:15:23 dugsong Exp $"); #include "xmalloc.h" #include "rsa.h" @@ -24,6 +24,7 @@ RCSID("$OpenBSD: auth1.c,v 1.24 2001/06/23 15:12:17 itojun Exp $"); #include "auth.h" #include "session.h" #include "misc.h" +#include "uidswap.h" /* import */ extern ServerOptions options; @@ -51,7 +52,7 @@ get_authname(int type) case SSH_CMSG_AUTH_TIS: case SSH_CMSG_AUTH_TIS_RESPONSE: return "challenge-response"; -#ifdef KRB4 +#if defined(KRB4) || defined(KRB5) case SSH_CMSG_AUTH_KERBEROS: return "kerberos"; #endif @@ -84,7 +85,7 @@ do_authloop(Authctxt *authctxt) /* If the user has no password, accept authentication immediately. */ if (options.password_authentication && -#ifdef KRB4 +#if defined(KRB4) || defined(KRB5) (!options.kerberos_authentication || options.kerberos_or_local_passwd) && #endif #ifdef USE_PAM @@ -116,62 +117,64 @@ do_authloop(Authctxt *authctxt) /* Process the packet. */ switch (type) { -#ifdef AFS - case SSH_CMSG_HAVE_KERBEROS_TGT: - if (!options.kerberos_tgt_passing) { - verbose("Kerberos tgt passing disabled."); - break; - } else { - /* Accept Kerberos tgt. */ - char *tgt = packet_get_string(&dlen); - packet_integrity_check(plen, 4 + dlen, type); - if (!auth_kerberos_tgt(pw, tgt)) - verbose("Kerberos tgt REFUSED for %.100s", authctxt->user); - xfree(tgt); - } - continue; - case SSH_CMSG_HAVE_AFS_TOKEN: - if (!options.afs_token_passing || !k_hasafs()) { - verbose("AFS token passing disabled."); - break; - } else { - /* Accept AFS token. */ - char *token_string = packet_get_string(&dlen); - packet_integrity_check(plen, 4 + dlen, type); - if (!auth_afs_token(pw, token_string)) - verbose("AFS token REFUSED for %.100s", authctxt->user); - xfree(token_string); - } - continue; -#endif /* AFS */ -#ifdef KRB4 +#if defined(KRB4) || defined(KRB5) case SSH_CMSG_AUTH_KERBEROS: if (!options.kerberos_authentication) { verbose("Kerberos authentication disabled."); - break; } else { - /* Try Kerberos v4 authentication. */ - KTEXT_ST auth; - char *tkt_user = NULL; - char *kdata = packet_get_string((u_int *) &auth.length); - packet_integrity_check(plen, 4 + auth.length, type); - - if (authctxt->valid) { - if (auth.length < MAX_KTXT_LEN) - memcpy(auth.dat, kdata, auth.length); - authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user); - if (authenticated) { - snprintf(info, sizeof info, - " tktuser %.100s", tkt_user); - xfree(tkt_user); + char *kdata = packet_get_string(&dlen); + + packet_integrity_check(plen, 4 + dlen, type); + + if (kdata[0] == 4) { /* KRB_PROT_VERSION */ +#ifdef KRB4 + KTEXT_ST tkt; + + tkt.length = dlen; + if (tkt.length < MAX_KTXT_LEN) + memcpy(tkt.dat, kdata, tkt.length); + + if (auth_krb4(authctxt, &tkt, &client_user)) { + authenticated = 1; + snprintf(info, sizeof(info), + " tktuser %.100s", + client_user); + xfree(client_user); } +#endif /* KRB4 */ + } else { +#ifdef KRB5 + krb5_data tkt; + tkt.length = dlen; + tkt.data = kdata; + + if (auth_krb5(authctxt, &tkt, &client_user)) { + authenticated = 1; + snprintf(info, sizeof(info), + " tktuser %.100s", + client_user); + xfree(client_user); + } +#endif /* KRB5 */ } xfree(kdata); } break; -#endif /* KRB4 */ - +#endif /* KRB4 || KRB5 */ + +#if defined(AFS) || defined(KRB5) + /* XXX - punt on backward compatibility here. */ + case SSH_CMSG_HAVE_KERBEROS_TGT: + packet_send_debug("Kerberos TGT passing disabled before authentication."); + break; +#ifdef AFS + case SSH_CMSG_HAVE_AFS_TOKEN: + packet_send_debug("AFS token passing disabled before authentication."); + break; +#endif /* AFS */ +#endif /* AFS || KRB5 */ + case SSH_CMSG_AUTH_RHOSTS: if (!options.rhosts_authentication) { verbose("Rhosts authentication disabled."); @@ -369,7 +372,7 @@ do_authentication() struct passwd *pw; int plen; u_int ulen; - char *user, *style = NULL; + char *p, *user, *style = NULL; /* Get the name of the user that we wish to log in as. */ packet_read_expect(&plen, SSH_CMSG_USER); @@ -379,8 +382,12 @@ do_authentication() packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER); if ((style = strchr(user, ':')) != NULL) - *style++ = 0; + *style++ = '\0'; + /* XXX - SSH.com Kerberos v5 braindeath. */ + if ((p = strchr(user, '@')) != NULL) + *p = '\0'; + authctxt = authctxt_new(); authctxt->user = user; authctxt->style = style; diff --git a/readconf.c b/readconf.c index 3c4d12662..4a1094685 100644 --- a/readconf.c +++ b/readconf.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: readconf.c,v 1.81 2001/06/23 02:34:30 markus Exp $"); +RCSID("$OpenBSD: readconf.c,v 1.82 2001/06/26 16:15:23 dugsong Exp $"); #include "ssh.h" #include "xmalloc.h" @@ -96,11 +96,14 @@ typedef enum { oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication, oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh, oChallengeResponseAuthentication, oXAuthLocation, -#ifdef KRB4 +#if defined(KRB4) || defined(KRB5) oKerberosAuthentication, -#endif /* KRB4 */ +#endif +#if defined(AFS) || defined(KRB5) + oKerberosTgtPassing, +#endif #ifdef AFS - oKerberosTgtPassing, oAFSTokenPassing, + oAFSTokenPassing, #endif oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, @@ -137,11 +140,13 @@ static struct { { "challengeresponseauthentication", oChallengeResponseAuthentication }, { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */ { "tisauthentication", oChallengeResponseAuthentication }, /* alias */ -#ifdef KRB4 +#if defined(KRB4) || defined(KRB5) { "kerberosauthentication", oKerberosAuthentication }, -#endif /* KRB4 */ -#ifdef AFS +#endif +#if defined(AFS) || defined(KRB5) { "kerberostgtpassing", oKerberosTgtPassing }, +#endif +#ifdef AFS { "afstokenpassing", oAFSTokenPassing }, #endif { "fallbacktorsh", oFallBackToRsh }, @@ -335,23 +340,21 @@ parse_flag: case oChallengeResponseAuthentication: intptr = &options->challenge_response_authentication; goto parse_flag; - -#ifdef KRB4 +#if defined(KRB4) || defined(KRB5) case oKerberosAuthentication: intptr = &options->kerberos_authentication; goto parse_flag; -#endif /* KRB4 */ - -#ifdef AFS +#endif +#if defined(AFS) || defined(KRB5) case oKerberosTgtPassing: intptr = &options->kerberos_tgt_passing; goto parse_flag; - +#endif +#ifdef AFS case oAFSTokenPassing: intptr = &options->afs_token_passing; goto parse_flag; #endif - case oFallBackToRsh: intptr = &options->fallback_to_rsh; goto parse_flag; @@ -724,11 +727,13 @@ initialize_options(Options * options) options->rsa_authentication = -1; options->pubkey_authentication = -1; options->challenge_response_authentication = -1; -#ifdef KRB4 +#if defined(KRB4) || defined(KRB5) options->kerberos_authentication = -1; #endif -#ifdef AFS +#if defined(AFS) || defined(KRB5) options->kerberos_tgt_passing = -1; +#endif +#ifdef AFS options->afs_token_passing = -1; #endif options->password_authentication = -1; @@ -799,16 +804,18 @@ fill_default_options(Options * options) options->pubkey_authentication = 1; if (options->challenge_response_authentication == -1) options->challenge_response_authentication = 0; -#ifdef KRB4 +#if defined(KRB4) || defined(KRB5) if (options->kerberos_authentication == -1) options->kerberos_authentication = 1; -#endif /* KRB4 */ -#ifdef AFS +#endif +#if defined(AFS) || defined(KRB5) if (options->kerberos_tgt_passing == -1) options->kerberos_tgt_passing = 1; +#endif +#ifdef AFS if (options->afs_token_passing == -1) options->afs_token_passing = 1; -#endif /* AFS */ +#endif if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) diff --git a/readconf.h b/readconf.h index 4b3be7615..2f784e6e2 100644 --- a/readconf.h +++ b/readconf.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: readconf.h,v 1.33 2001/06/26 06:32:58 itojun Exp $"); */ +/* RCSID("$OpenBSD: readconf.h,v 1.34 2001/06/26 16:15:24 dugsong Exp $"); */ #ifndef READCONF_H #define READCONF_H @@ -41,12 +41,13 @@ typedef struct { int hostbased_authentication; /* ssh2's rhosts_rsa */ int challenge_response_authentication; /* Try S/Key or TIS, authentication. */ -#ifdef KRB4 - int kerberos_authentication; /* Try Kerberos - * authentication. */ +#if defined(KRB4) || defined(KRB5) + int kerberos_authentication; /* Try Kerberos authentication. */ +#endif +#if defined(AFS) || defined(KRB5) + int kerberos_tgt_passing; /* Try Kerberos TGT passing. */ #endif #ifdef AFS - int kerberos_tgt_passing; /* Try Kerberos tgt passing. */ int afs_token_passing; /* Try AFS token passing. */ #endif int password_authentication; /* Try password diff --git a/servconf.c b/servconf.c index 55b0b0039..7dbf31834 100644 --- a/servconf.c +++ b/servconf.c @@ -10,14 +10,11 @@ */ #include "includes.h" -RCSID("$OpenBSD: servconf.c,v 1.84 2001/06/23 15:12:19 itojun Exp $"); +RCSID("$OpenBSD: servconf.c,v 1.85 2001/06/26 16:15:24 dugsong Exp $"); #ifdef KRB4 #include #endif -#ifdef AFS -#include -#endif #include "ssh.h" #include "log.h" @@ -70,13 +67,15 @@ initialize_server_options(ServerOptions *options) options->hostbased_uses_name_from_packet_only = -1; options->rsa_authentication = -1; options->pubkey_authentication = -1; -#ifdef KRB4 +#if defined(KRB4) || defined(KRB5) options->kerberos_authentication = -1; options->kerberos_or_local_passwd = -1; options->kerberos_ticket_cleanup = -1; #endif -#ifdef AFS +#if defined(AFS) || defined(KRB5) options->kerberos_tgt_passing = -1; +#endif +#ifdef AFS options->afs_token_passing = -1; #endif options->password_authentication = -1; @@ -170,20 +169,22 @@ fill_default_server_options(ServerOptions *options) options->rsa_authentication = 1; if (options->pubkey_authentication == -1) options->pubkey_authentication = 1; -#ifdef KRB4 +#if defined(KRB4) || defined(KRB5) if (options->kerberos_authentication == -1) options->kerberos_authentication = (access(KEYFILE, R_OK) == 0); if (options->kerberos_or_local_passwd == -1) options->kerberos_or_local_passwd = 1; if (options->kerberos_ticket_cleanup == -1) options->kerberos_ticket_cleanup = 1; -#endif /* KRB4 */ -#ifdef AFS +#endif +#if defined(AFS) || defined(KRB5) if (options->kerberos_tgt_passing == -1) options->kerberos_tgt_passing = 0; +#endif +#ifdef AFS if (options->afs_token_passing == -1) options->afs_token_passing = k_hasafs(); -#endif /* AFS */ +#endif if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) @@ -224,11 +225,14 @@ typedef enum { sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime, sPermitRootLogin, sLogFacility, sLogLevel, sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication, -#ifdef KRB4 +#if defined(KRB4) || defined(KRB5) sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, #endif +#if defined(AFS) || defined(KRB5) + sKerberosTgtPassing, +#endif #ifdef AFS - sKerberosTgtPassing, sAFSTokenPassing, + sAFSTokenPassing, #endif sChallengeResponseAuthentication, sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress, @@ -267,13 +271,15 @@ static struct { { "rsaauthentication", sRSAAuthentication }, { "pubkeyauthentication", sPubkeyAuthentication }, { "dsaauthentication", sPubkeyAuthentication }, /* alias */ -#ifdef KRB4 +#if defined(KRB4) || defined(KRB5) { "kerberosauthentication", sKerberosAuthentication }, { "kerberosorlocalpasswd", sKerberosOrLocalPasswd }, { "kerberosticketcleanup", sKerberosTicketCleanup }, #endif -#ifdef AFS +#if defined(AFS) || defined(KRB5) { "kerberostgtpassing", sKerberosTgtPassing }, +#endif +#ifdef AFS { "afstokenpassing", sAFSTokenPassing }, #endif { "passwordauthentication", sPasswordAuthentication }, @@ -584,8 +590,7 @@ parse_flag: case sPubkeyAuthentication: intptr = &options->pubkey_authentication; goto parse_flag; - -#ifdef KRB4 +#if defined(KRB4) || defined(KRB5) case sKerberosAuthentication: intptr = &options->kerberos_authentication; goto parse_flag; @@ -598,12 +603,12 @@ parse_flag: intptr = &options->kerberos_ticket_cleanup; goto parse_flag; #endif - -#ifdef AFS +#if defined(AFS) || defined(KRB5) case sKerberosTgtPassing: intptr = &options->kerberos_tgt_passing; goto parse_flag; - +#endif +#ifdef AFS case sAFSTokenPassing: intptr = &options->afs_token_passing; goto parse_flag; diff --git a/servconf.h b/servconf.h index a71b7c135..1b0220283 100644 --- a/servconf.h +++ b/servconf.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: servconf.h,v 1.45 2001/06/26 06:33:00 itojun Exp $"); */ +/* RCSID("$OpenBSD: servconf.h,v 1.46 2001/06/26 16:15:24 dugsong Exp $"); */ #ifndef SERVCONF_H #define SERVCONF_H @@ -73,7 +73,7 @@ typedef struct { int hostbased_uses_name_from_packet_only; /* experimental */ int rsa_authentication; /* If true, permit RSA authentication. */ int pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */ -#ifdef KRB4 +#if defined(KRB4) || defined(KRB5) int kerberos_authentication; /* If true, permit Kerberos * authentication. */ int kerberos_or_local_passwd; /* If true, permit kerberos @@ -84,9 +84,11 @@ typedef struct { int kerberos_ticket_cleanup; /* If true, destroy ticket * file on logout. */ #endif -#ifdef AFS - int kerberos_tgt_passing; /* If true, permit Kerberos tgt +#if defined(AFS) || defined(KRB5) + int kerberos_tgt_passing; /* If true, permit Kerberos TGT * passing. */ +#endif +#ifdef AFS int afs_token_passing; /* If true, permit AFS token passing. */ #endif int password_authentication; /* If true, permit password diff --git a/session.c b/session.c index 7d0e0723c..5a6afa7ec 100644 --- a/session.c +++ b/session.c @@ -33,7 +33,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.95 2001/06/25 08:25:39 markus Exp $"); +RCSID("$OpenBSD: session.c,v 1.96 2001/06/26 16:15:24 dugsong Exp $"); #include "ssh.h" #include "ssh1.h" @@ -99,7 +99,8 @@ typedef struct Session Session; struct Session { int used; int self; - struct passwd *pw; + struct passwd *pw; + Authctxt *authctxt; pid_t pid; /* tty */ char *term; @@ -198,6 +199,14 @@ do_authenticated(Authctxt *authctxt) /* remove agent socket */ if (auth_get_socket_name()) auth_sock_cleanup_proc(authctxt->pw); +#ifdef KRB4 + if (options.kerberos_ticket_cleanup) + krb4_cleanup_proc(authctxt); +#endif +#ifdef KRB5 + if (options.kerberos_ticket_cleanup) + krb5_cleanup_proc(authctxt); +#endif } /* @@ -216,6 +225,7 @@ do_authenticated1(Authctxt *authctxt) u_int proto_len, data_len, dlen; s = session_new(); + s->authctxt = authctxt; s->pw = authctxt->pw; /* @@ -300,6 +310,58 @@ do_authenticated1(Authctxt *authctxt) if (packet_set_maxsize(packet_get_int()) > 0) success = 1; break; + +#if defined(AFS) || defined(KRB5) + case SSH_CMSG_HAVE_KERBEROS_TGT: + if (!options.kerberos_tgt_passing) { + verbose("Kerberos TGT passing disabled."); + } else { + char *kdata = packet_get_string(&dlen); + packet_integrity_check(plen, 4 + dlen, type); + + /* XXX - 0x41, see creds_to_radix version */ + if (kdata[0] != 0x41) { +#ifdef KRB5 + krb5_data tgt; + tgt.data = kdata; + tgt.length = dlen; + + if (auth_krb5_tgt(s->authctxt, &tgt)) + success = 1; + else + verbose("Kerberos v5 TGT refused for %.100s", s->authctxt->user); +#endif /* KRB5 */ + } else { +#ifdef AFS + if (auth_krb4_tgt(s->authctxt, kdata)) + success = 1; + else + verbose("Kerberos v4 TGT refused for %.100s", s->authctxt->user); +#endif /* AFS */ + } + xfree(kdata); + } + break; +#endif /* AFS || KRB5 */ + +#ifdef AFS + case SSH_CMSG_HAVE_AFS_TOKEN: + if (!options.afs_token_passing || !k_hasafs()) { + verbose("AFS token passing disabled."); + } else { + /* Accept AFS token. */ + char *token = packet_get_string(&dlen); + packet_integrity_check(plen, 4 + dlen, type); + + if (auth_afs_token(s->authctxt, token)) + success = 1; + else + verbose("AFS token refused for %.100s", + s->authctxt->user); + xfree(token); + } + break; +#endif /* AFS */ case SSH_CMSG_EXEC_SHELL: case SSH_CMSG_EXEC_CMD: @@ -615,7 +677,7 @@ static int check_quietlogin(Session *s, const char *command) { char buf[256]; - struct passwd * pw = s->pw; + struct passwd *pw = s->pw; struct stat st; /* Return 1 if .hushlogin exists or a command given. */ @@ -955,7 +1017,7 @@ void do_child(Session *s, const char *command) { const char *shell, *hostname = NULL, *cp = NULL; - struct passwd * pw = s->pw; + struct passwd *pw = s->pw; char buf[256]; char cmd[1024]; FILE *f = NULL; @@ -1134,10 +1196,10 @@ do_child(Session *s, const char *command) /* Try to get AFS tokens for the local cell. */ if (k_hasafs()) { char cell[64]; - + if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) krb_afslog(cell, 0); - + krb_afslog(0, 0); } #endif /* AFS */ @@ -1221,16 +1283,16 @@ do_child(Session *s, const char *command) child_set_env(&env, &envsize, "KRB5CCNAME", cp); read_environment_file(&env, &envsize, "/etc/environment"); #endif - #ifdef KRB4 - { - extern char *ticket; - - if (ticket) - child_set_env(&env, &envsize, "KRBTKFILE", ticket); - } -#endif /* KRB4 */ - + if (s->authctxt->krb4_ticket_file) + child_set_env(&env, &envsize, "KRBTKFILE", + s->authctxt->krb4_ticket_file); +#endif +#ifdef KRB5 + if (s->authctxt->krb5_ticket_file) + child_set_env(&env, &envsize, "KRB5CCNAME", + s->authctxt->krb5_ticket_file); +#endif #ifdef USE_PAM /* Pull in any environment variables that may have been set by PAM. */ do_pam_environment(&env, &envsize); diff --git a/sshconnect1.c b/sshconnect1.c index ec0a5c96c..09203d714 100644 --- a/sshconnect1.c +++ b/sshconnect1.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect1.c,v 1.36 2001/06/23 22:37:46 markus Exp $"); +RCSID("$OpenBSD: sshconnect1.c,v 1.37 2001/06/26 16:15:24 dugsong Exp $"); #include #include @@ -21,6 +21,9 @@ RCSID("$OpenBSD: sshconnect1.c,v 1.36 2001/06/23 22:37:46 markus Exp $"); #ifdef KRB4 #include #endif +#ifdef KRB5 +#include +#endif #ifdef AFS #include #include "radix.h" @@ -43,6 +46,7 @@ RCSID("$OpenBSD: sshconnect1.c,v 1.36 2001/06/23 22:37:46 markus Exp $"); #include "readpass.h" #include "cipher.h" #include "canohost.h" +#include "auth.h" /* Session id for the current session. */ u_char session_id[16]; @@ -379,7 +383,7 @@ try_rhosts_rsa_authentication(const char *local_user, Key * host_key) #ifdef KRB4 static int -try_kerberos_authentication(void) +try_krb4_authentication(void) { KTEXT_ST auth; /* Kerberos data */ char *reply; @@ -397,20 +401,21 @@ try_kerberos_authentication(void) /* Don't do anything if we don't have any tickets. */ if (stat(tkt_string(), &st) < 0) return 0; - - strncpy(inst, (char *) krb_get_phost(get_canonical_hostname(1)), INST_SZ); - - realm = (char *) krb_realmofhost(get_canonical_hostname(1)); + + strlcpy(inst, (char *)krb_get_phost(get_canonical_hostname(1)), + INST_SZ); + + realm = (char *)krb_realmofhost(get_canonical_hostname(1)); if (!realm) { - debug("Kerberos V4: no realm for %s", get_canonical_hostname(1)); + debug("Kerberos v4: no realm for %s", get_canonical_hostname(1)); return 0; } /* This can really be anything. */ - checksum = (u_long) getpid(); - + checksum = (u_long)getpid(); + r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum); if (r != KSUCCESS) { - debug("Kerberos V4 krb_mk_req failed: %s", krb_err_txt[r]); + debug("Kerberos v4 krb_mk_req failed: %s", krb_err_txt[r]); return 0; } /* Get session key to decrypt the server's reply with. */ @@ -420,26 +425,26 @@ try_kerberos_authentication(void) return 0; } des_key_sched((des_cblock *) cred.session, schedule); - + /* Send authentication info to server. */ packet_start(SSH_CMSG_AUTH_KERBEROS); packet_put_string((char *) auth.dat, auth.length); packet_send(); packet_write_wait(); - + /* Zero the buffer. */ (void) memset(auth.dat, 0, MAX_KTXT_LEN); - + slen = sizeof(local); memset(&local, 0, sizeof(local)); if (getsockname(packet_get_connection_in(), - (struct sockaddr *) & local, &slen) < 0) + (struct sockaddr *)&local, &slen) < 0) debug("getsockname failed: %s", strerror(errno)); - + slen = sizeof(foreign); memset(&foreign, 0, sizeof(foreign)); if (getpeername(packet_get_connection_in(), - (struct sockaddr *) & foreign, &slen) < 0) { + (struct sockaddr *)&foreign, &slen) < 0) { debug("getpeername failed: %s", strerror(errno)); fatal_cleanup(); } @@ -448,96 +453,288 @@ try_kerberos_authentication(void) switch (type) { case SSH_SMSG_FAILURE: /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */ - debug("Kerberos V4 authentication failed."); + debug("Kerberos v4 authentication failed."); return 0; break; - + case SSH_SMSG_AUTH_KERBEROS_RESPONSE: /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */ - debug("Kerberos V4 authentication accepted."); - + debug("Kerberos v4 authentication accepted."); + /* Get server's response. */ reply = packet_get_string((u_int *) &auth.length); memcpy(auth.dat, reply, auth.length); xfree(reply); - + packet_integrity_check(plen, 4 + auth.length, type); - + /* * If his response isn't properly encrypted with the session * key, and the decrypted checksum fails to match, he's * bogus. Bail out. */ r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session, - &foreign, &local, &msg_data); + &foreign, &local, &msg_data); if (r != KSUCCESS) { - debug("Kerberos V4 krb_rd_priv failed: %s", krb_err_txt[r]); - packet_disconnect("Kerberos V4 challenge failed!"); + debug("Kerberos v4 krb_rd_priv failed: %s", + krb_err_txt[r]); + packet_disconnect("Kerberos v4 challenge failed!"); } /* Fetch the (incremented) checksum that we supplied in the request. */ - (void) memcpy((char *) &cksum, (char *) msg_data.app_data, sizeof(cksum)); + memcpy((char *)&cksum, (char *)msg_data.app_data, + sizeof(cksum)); cksum = ntohl(cksum); - + /* If it matches, we're golden. */ if (cksum == checksum + 1) { - debug("Kerberos V4 challenge successful."); + debug("Kerberos v4 challenge successful."); return 1; } else - packet_disconnect("Kerberos V4 challenge failed!"); + packet_disconnect("Kerberos v4 challenge failed!"); break; - + default: - packet_disconnect("Protocol error on Kerberos V4 response: %d", type); + packet_disconnect("Protocol error on Kerberos v4 response: %d", type); } return 0; } #endif /* KRB4 */ -#ifdef AFS +#ifdef KRB5 static int -send_kerberos_tgt(void) +try_krb5_authentication(krb5_context *context, krb5_auth_context *auth_context) +{ + krb5_error_code problem; + const char *tkfile; + struct stat buf; + krb5_ccache ccache = NULL; + const char *remotehost; + krb5_data ap; + int type, payload_len; + krb5_ap_rep_enc_part *reply = NULL; + int ret; + + memset(&ap, 0, sizeof(ap)); + + problem = krb5_init_context(context); + if (problem) { + debug("Kerberos v5: krb5_init_context failed"); + ret = 0; + goto out; + } + + tkfile = krb5_cc_default_name(*context); + if (strncmp(tkfile, "FILE:", 5) == 0) + tkfile += 5; + + if (stat(tkfile, &buf) == 0 && getuid() != buf.st_uid) { + debug("Kerberos v5: could not get default ccache (permission denied)."); + ret = 0; + goto out; + } + + problem = krb5_cc_default(*context, &ccache); + if (problem) { + debug("Kerberos v5: krb5_cc_default failed: %s", + krb5_get_err_text(*context, problem)); + ret = 0; + goto out; + } + + remotehost = get_canonical_hostname(1); + + problem = krb5_mk_req(*context, auth_context, AP_OPTS_MUTUAL_REQUIRED, + "host", remotehost, NULL, ccache, &ap); + if (problem) { + debug("Kerberos v5: krb5_mk_req failed: %s", + krb5_get_err_text(*context, problem)); + ret = 0; + goto out; + } + + packet_start(SSH_CMSG_AUTH_KERBEROS); + packet_put_string((char *) ap.data, ap.length); + packet_send(); + packet_write_wait(); + + xfree(ap.data); + ap.length = 0; + + type = packet_read(&payload_len); + switch (type) { + case SSH_SMSG_FAILURE: + /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */ + debug("Kerberos v5 authentication failed."); + ret = 0; + break; + + case SSH_SMSG_AUTH_KERBEROS_RESPONSE: + /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */ + debug("Kerberos v5 authentication accepted."); + + /* Get server's response. */ + ap.data = packet_get_string((unsigned int *) &ap.length); + + packet_integrity_check(payload_len, 4 + ap.length, type); + /* XXX je to dobre? */ + + problem = krb5_rd_rep(*context, *auth_context, &ap, &reply); + if (problem) { + ret = 0; + } + ret = 1; + break; + + default: + packet_disconnect("Protocol error on Kerberos v5 response: %d", + type); + ret = 0; + break; + + } + + out: + if (ccache != NULL) + krb5_cc_close(*context, ccache); + if (reply != NULL) + krb5_free_ap_rep_enc_part(*context, reply); + if (ap.length > 0) + krb5_data_free(&ap); + + return (ret); +} + +static void +send_krb5_tgt(krb5_context context, krb5_auth_context auth_context) +{ + int fd, type, payload_len; + krb5_error_code problem; + krb5_data outbuf; + krb5_ccache ccache = NULL; + krb5_creds creds; + krb5_kdc_flags flags; + const char *remotehost; + + memset(&creds, 0, sizeof(creds)); + memset(&outbuf, 0, sizeof(outbuf)); + + fd = packet_get_connection_in(); + + problem = krb5_auth_con_setaddrs_from_fd(context, auth_context, &fd); + if (problem) + goto out; + + problem = krb5_cc_default(context, &ccache); + if (problem) + goto out; + + problem = krb5_cc_get_principal(context, ccache, &creds.client); + if (problem) + goto out; + + problem = krb5_build_principal(context, &creds.server, + strlen(creds.client->realm), creds.client->realm, + "krbtgt", creds.client->realm, NULL); + if (problem) + goto out; + + creds.times.endtime = 0; + + flags.i = 0; + flags.b.forwarded = 1; + flags.b.forwardable = krb5_config_get_bool(context, NULL, + "libdefaults", "forwardable", NULL); + + remotehost = get_canonical_hostname(1); + + problem = krb5_get_forwarded_creds(context, auth_context, + ccache, flags.i, remotehost, &creds, &outbuf); + if (problem) + goto out; + + packet_start(SSH_CMSG_HAVE_KERBEROS_TGT); + packet_put_string((char *)outbuf.data, outbuf.length); + packet_send(); + packet_write_wait(); + + type = packet_read(&payload_len); + + if (type == SSH_SMSG_SUCCESS) { + char *pname; + + krb5_unparse_name(context, creds.client, &pname); + debug("Kerberos v5 TGT forwarded (%s).", pname); + xfree(pname); + } else + debug("Kerberos v5 TGT forwarding failed."); + + return; + + out: + if (problem) + debug("Kerberos v5 TGT forwarding failed: %s", + krb5_get_err_text(context, problem)); + if (creds.client) + krb5_free_principal(context, creds.client); + if (creds.server) + krb5_free_principal(context, creds.server); + if (ccache) + krb5_cc_close(context, ccache); + if (outbuf.data) + xfree(outbuf.data); +} +#endif /* KRB5 */ + +#ifdef AFS +static void +send_krb4_tgt(void) { CREDENTIALS *creds; - char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ]; - int r, type, plen; - char buffer[8192]; struct stat st; - + char buffer[4096], pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ]; + int problem, type, len; + /* Don't do anything if we don't have any tickets. */ if (stat(tkt_string(), &st) < 0) - return 0; - + return; + creds = xmalloc(sizeof(*creds)); - - if ((r = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm)) != KSUCCESS) { - debug("Kerberos V4 tf_fullname failed: %s", krb_err_txt[r]); - return 0; - } - if ((r = krb_get_cred("krbtgt", prealm, prealm, creds)) != GC_OK) { - debug("Kerberos V4 get_cred failed: %s", krb_err_txt[r]); - return 0; - } + + problem = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm); + if (problem) + goto out; + + problem = krb_get_cred("krbtgt", prealm, prealm, creds); + if (problem) + goto out; + if (time(0) > krb_life_to_time(creds->issue_date, creds->lifetime)) { - debug("Kerberos V4 ticket expired: %s", TKT_FILE); - return 0; + problem = RD_AP_EXP; + goto out; } - creds_to_radix(creds, (u_char *)buffer, sizeof buffer); - xfree(creds); - + creds_to_radix(creds, (u_char *)buffer, sizeof(buffer)); + packet_start(SSH_CMSG_HAVE_KERBEROS_TGT); packet_put_cstring(buffer); packet_send(); packet_write_wait(); - - type = packet_read(&plen); - - if (type == SSH_SMSG_FAILURE) - debug("Kerberos TGT for realm %s rejected.", prealm); - else if (type != SSH_SMSG_SUCCESS) - packet_disconnect("Protocol error on Kerberos TGT response: %d", type); - - return 1; + + type = packet_read(&len); + + if (type == SSH_SMSG_SUCCESS) + debug("Kerberos v4 TGT forwarded (%s%s%s@%s).", + creds->pname, creds->pinst[0] ? "." : "", + creds->pinst, creds->realm); + else + debug("Kerberos v4 TGT rejected."); + + xfree(creds); + return; + + out: + debug("Kerberos v4 TGT passing failed: %s", krb_err_txt[problem]); + xfree(creds); } static void @@ -546,10 +743,10 @@ send_afs_tokens(void) CREDENTIALS creds; struct ViceIoctl parms; struct ClearToken ct; - int i, type, len, plen; + int i, type, len; char buf[2048], *p, *server_cell; char buffer[8192]; - + /* Move over ktc_GetToken, here's something leaner. */ for (i = 0; i < 100; i++) { /* just in case */ parms.in = (char *) &i; @@ -559,7 +756,7 @@ send_afs_tokens(void) if (k_pioctl(0, VIOCGETTOK, &parms, 0) != 0) break; p = buf; - + /* Get secret token. */ memcpy(&creds.ticket_st.length, p, sizeof(u_int)); if (creds.ticket_st.length > MAX_KTXT_LEN) @@ -567,7 +764,7 @@ send_afs_tokens(void) p += sizeof(u_int); memcpy(creds.ticket_st.dat, p, creds.ticket_st.length); p += creds.ticket_st.length; - + /* Get clear token. */ memcpy(&len, p, sizeof(len)); if (len != sizeof(struct ClearToken)) @@ -577,20 +774,22 @@ send_afs_tokens(void) p += len; p += sizeof(len); /* primary flag */ server_cell = p; - + /* Flesh out our credentials. */ - strlcpy(creds.service, "afs", sizeof creds.service); + strlcpy(creds.service, "afs", sizeof(creds.service)); creds.instance[0] = '\0'; strlcpy(creds.realm, server_cell, REALM_SZ); memcpy(creds.session, ct.HandShakeKey, DES_KEY_SZ); creds.issue_date = ct.BeginTimestamp; - creds.lifetime = krb_time_to_life(creds.issue_date, ct.EndTimestamp); + creds.lifetime = krb_time_to_life(creds.issue_date, + ct.EndTimestamp); creds.kvno = ct.AuthHandle; snprintf(creds.pname, sizeof(creds.pname), "AFS ID %d", ct.ViceId); creds.pinst[0] = '\0'; - + /* Encode token, ship it off. */ - if (creds_to_radix(&creds, (u_char *) buffer, sizeof buffer) <= 0) + if (creds_to_radix(&creds, (u_char *)buffer, + sizeof(buffer)) <= 0) break; packet_start(SSH_CMSG_HAVE_AFS_TOKEN); packet_put_cstring(buffer); @@ -599,8 +798,8 @@ send_afs_tokens(void) /* Roger, Roger. Clearance, Clarence. What's your vector, Victor? */ - type = packet_read(&plen); - + type = packet_read(&len); + if (type == SSH_SMSG_FAILURE) debug("AFS token for cell %s rejected.", server_cell); else if (type != SSH_SMSG_SUCCESS) @@ -622,9 +821,9 @@ try_challenge_response_authentication(void) u_int clen; char prompt[1024]; char *challenge, *response; - + debug("Doing challenge reponse authentication."); - + for (i = 0; i < options.number_of_password_prompts; i++) { /* request a challenge */ packet_start(SSH_CMSG_AUTH_TIS); @@ -913,9 +1112,13 @@ void ssh_userauth1(const char *local_user, const char *server_user, char *host, Key **keys, int nkeys) { +#ifdef KRB5 + krb5_context context = NULL; + krb5_auth_context auth_context = NULL; +#endif int i, type; int payload_len; - + if (supported_authentications == 0) fatal("ssh_userauth1: server supports no auth methods"); @@ -934,43 +1137,40 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host, /* check whether the connection was accepted without authentication. */ if (type == SSH_SMSG_SUCCESS) - return; + goto success; if (type != SSH_SMSG_FAILURE) - packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER", - type); - -#ifdef AFS - /* Try Kerberos tgt passing if the server supports it. */ - if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) && - options.kerberos_tgt_passing) { - if (options.cipher == SSH_CIPHER_NONE) - log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!"); - (void) send_kerberos_tgt(); + packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER", type); + +#ifdef KRB5 + if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) && + options.kerberos_authentication) { + debug("Trying Kerberos v5 authentication."); + + if (try_krb5_authentication(&context, &auth_context)) { + type = packet_read(&payload_len); + if (type == SSH_SMSG_SUCCESS) + goto success; + if (type != SSH_SMSG_FAILURE) + packet_disconnect("Protocol error: got %d in response to Kerberos v5 auth", type); + } } - /* Try AFS token passing if the server supports it. */ - if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) && - options.afs_token_passing && k_hasafs()) { - if (options.cipher == SSH_CIPHER_NONE) - log("WARNING: Encryption is disabled! Token will be transmitted in the clear!"); - send_afs_tokens(); - } -#endif /* AFS */ - +#endif /* KRB5 */ + #ifdef KRB4 if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) && options.kerberos_authentication) { - debug("Trying Kerberos authentication."); - if (try_kerberos_authentication()) { - /* The server should respond with success or failure. */ + debug("Trying Kerberos v4 authentication."); + + if (try_krb4_authentication()) { type = packet_read(&payload_len); if (type == SSH_SMSG_SUCCESS) - return; + goto success; if (type != SSH_SMSG_FAILURE) - packet_disconnect("Protocol error: got %d in response to Kerberos auth", type); + packet_disconnect("Protocol error: got %d in response to Kerberos v4 auth", type); } } #endif /* KRB4 */ - + /* * Use rhosts authentication if running in privileged socket and we * do not wish to remain anonymous. @@ -986,7 +1186,7 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host, /* The server should respond with success or failure. */ type = packet_read(&payload_len); if (type == SSH_SMSG_SUCCESS) - return; + goto success; if (type != SSH_SMSG_FAILURE) packet_disconnect("Protocol error: got %d in response to rhosts auth", type); @@ -1000,7 +1200,7 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host, for (i = 0; i < nkeys; i++) { if (keys[i] != NULL && keys[i]->type == KEY_RSA1 && try_rhosts_rsa_authentication(local_user, keys[i])) - return; + goto success; } } /* Try RSA authentication if the server supports it. */ @@ -1012,20 +1212,20 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host, * it, whereas identity files may require passphrases. */ if (try_agent_authentication()) - return; + goto success; /* Try RSA authentication for each identity. */ for (i = 0; i < options.num_identity_files; i++) if (options.identity_keys[i] != NULL && options.identity_keys[i]->type == KEY_RSA1 && try_rsa_authentication(options.identity_files[i])) - return; + goto success; } /* Try challenge response authentication if the server supports it. */ if ((supported_authentications & (1 << SSH_AUTH_TIS)) && options.challenge_response_authentication && !options.batch_mode) { if (try_challenge_response_authentication()) - return; + goto success; } /* Try password authentication if the server supports it. */ if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) && @@ -1035,9 +1235,41 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host, snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ", server_user, host); if (try_password_authentication(prompt)) - return; + goto success; } /* All authentication methods have failed. Exit with an error message. */ fatal("Permission denied."); /* NOTREACHED */ + + success: +#ifdef KRB5 + /* Try Kerberos v5 TGT passing. */ + if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) && + options.kerberos_tgt_passing && context && auth_context) { + if (options.cipher == SSH_CIPHER_NONE) + log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!"); + send_krb5_tgt(context, auth_context); + } + if (auth_context) + krb5_auth_con_free(context, auth_context); + if (context) + krb5_free_context(context); +#endif + +#ifdef AFS + /* Try Kerberos v4 TGT passing if the server supports it. */ + if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) && + options.kerberos_tgt_passing) { + if (options.cipher == SSH_CIPHER_NONE) + log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!"); + send_krb4_tgt(); + } + /* Try AFS token passing if the server supports it. */ + if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) && + options.afs_token_passing && k_hasafs()) { + if (options.cipher == SSH_CIPHER_NONE) + log("WARNING: Encryption is disabled! Token will be transmitted in the clear!"); + send_afs_tokens(); + } +#endif /* AFS */ } diff --git a/sshd.c b/sshd.c index 936e861a9..dd5d7ab2c 100644 --- a/sshd.c +++ b/sshd.c @@ -40,7 +40,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.201 2001/06/23 19:12:43 markus Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.202 2001/06/26 16:15:25 dugsong Exp $"); #include #include @@ -1160,13 +1160,13 @@ main(int ac, char **av) "originating port not trusted."); options.rhosts_authentication = 0; } -#ifdef KRB4 +#if defined(KRB4) && !defined(KRB5) if (!packet_connection_is_ipv4() && options.kerberos_authentication) { debug("Kerberos Authentication disabled, only available for IPv4."); options.kerberos_authentication = 0; } -#endif /* KRB4 */ +#endif /* KRB4 && !KRB5 */ #ifdef AFS /* If machine has AFS, set process authentication group. */ if (k_hasafs()) { @@ -1186,13 +1186,6 @@ main(int ac, char **av) do_ssh1_kex(); do_authentication(); } - -#ifdef KRB4 - /* Cleanup user's ticket cache file. */ - if (options.kerberos_ticket_cleanup) - (void) dest_tkt(); -#endif /* KRB4 */ - /* The connection has been terminated. */ verbose("Closing connection to %.100s", remote_ip); @@ -1268,13 +1261,15 @@ do_ssh1_kex(void) auth_mask |= 1 << SSH_AUTH_RHOSTS_RSA; if (options.rsa_authentication) auth_mask |= 1 << SSH_AUTH_RSA; -#ifdef KRB4 +#if defined(KRB4) || defined(KRB5) if (options.kerberos_authentication) auth_mask |= 1 << SSH_AUTH_KERBEROS; #endif -#ifdef AFS +#if defined(AFS) || defined(KRB5) if (options.kerberos_tgt_passing) auth_mask |= 1 << SSH_PASS_KERBEROS_TGT; +#endif +#ifdef AFS if (options.afs_token_passing) auth_mask |= 1 << SSH_PASS_AFS_TOKEN; #endif