diff options
author | markm <markm@FreeBSD.org> | 2000-02-28 19:03:50 +0000 |
---|---|---|
committer | markm <markm@FreeBSD.org> | 2000-02-28 19:03:50 +0000 |
commit | 37dce23afc624dfc2ebae4614ddd17d5e376a901 (patch) | |
tree | 08c26b6a05650dd5c73e020a82c50440e973043e /crypto | |
parent | 39a8b7149f0ab399cdd6a6d5f254c70ba2cf6fa6 (diff) | |
download | FreeBSD-src-37dce23afc624dfc2ebae4614ddd17d5e376a901.zip FreeBSD-src-37dce23afc624dfc2ebae4614ddd17d5e376a901.tar.gz |
1) Add kerberos5 functionality.
by Daniel Kouril <kouril@informatics.muni.cz>
2) Add full LOGIN_CAP capability
by Andrey Chernov
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/openssh/auth-krb4.c | 8 | ||||
-rw-r--r-- | crypto/openssh/auth-krb5.c | 249 | ||||
-rw-r--r-- | crypto/openssh/auth-passwd.c | 12 | ||||
-rw-r--r-- | crypto/openssh/readconf.c | 55 | ||||
-rw-r--r-- | crypto/openssh/readconf.h | 11 | ||||
-rw-r--r-- | crypto/openssh/servconf.c | 89 | ||||
-rw-r--r-- | crypto/openssh/servconf.h | 13 | ||||
-rw-r--r-- | crypto/openssh/ssh.c | 3 | ||||
-rw-r--r-- | crypto/openssh/ssh.h | 28 | ||||
-rw-r--r-- | crypto/openssh/sshconnect.c | 298 | ||||
-rw-r--r-- | crypto/openssh/sshd.8 | 16 | ||||
-rw-r--r-- | crypto/openssh/sshd.c | 430 |
12 files changed, 1041 insertions, 171 deletions
diff --git a/crypto/openssh/auth-krb4.c b/crypto/openssh/auth-krb4.c index fb0e20c..8c308bd 100644 --- a/crypto/openssh/auth-krb4.c +++ b/crypto/openssh/auth-krb4.c @@ -1,6 +1,8 @@ /* * Dug Song <dugsong@UMICH.EDU> * Kerberos v4 authentication and ticket-passing routines. + * + * $FreeBSD$ */ #include "includes.h" @@ -114,7 +116,7 @@ auth_krb4_password(struct passwd * pw, const char *password) kerberos_auth_failure: krb4_cleanup_proc(NULL); - if (!options.kerberos_or_local_passwd) + if (!options.krb4_or_local_passwd) return 0; } else { /* Logging in as root or no local Kerberos realm. */ @@ -242,7 +244,7 @@ auth_krb4(const char *server_user, KTEXT auth, char **client) /* Clear session key. */ memset(&adat.session, 0, sizeof(&adat.session)); - packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE); + packet_start(SSH_SMSG_AUTH_KRB4_RESPONSE); packet_put_string((char *) reply.dat, reply.length); packet_send(); packet_write_wait(); @@ -252,7 +254,7 @@ auth_krb4(const char *server_user, KTEXT auth, char **client) #ifdef AFS int -auth_kerberos_tgt(struct passwd *pw, const char *string) +auth_krb4_tgt(struct passwd *pw, const char *string) { CREDENTIALS creds; diff --git a/crypto/openssh/auth-krb5.c b/crypto/openssh/auth-krb5.c new file mode 100644 index 0000000..6030d9a --- /dev/null +++ b/crypto/openssh/auth-krb5.c @@ -0,0 +1,249 @@ +/* + * Kerberos v5 authentication and ticket-passing routines. + * + * $FreeBSD$ + */ + +#include "includes.h" +#include "ssh.h" +#include "packet.h" +#include "xmalloc.h" + +#ifdef KRB5 + +extern krb5_context ssh_context; +krb5_auth_context auth_context; +krb5_ccache mem_ccache = NULL; /* Credential cache for acquired ticket */ + +/* Try krb5 authentication. server_user is passed for logging purposes only, + in auth is received ticket, in client is returned principal from the + ticket */ +int +auth_krb5(const char* server_user, krb5_data *auth, krb5_principal *client) +{ + krb5_error_code problem; + krb5_principal server = NULL; + krb5_principal tkt_client = NULL; + krb5_data reply; + krb5_ticket *ticket = NULL; + int fd; + int ret; + + reply.length = 0; + + problem = krb5_init(); + if (problem) + return 0; + + problem = krb5_auth_con_init(ssh_context, &auth_context); + if (problem) { + log("Kerberos v5 authentication failed: %.100s", + krb5_get_err_text(ssh_context, problem)); + + return 0; + } + + fd = packet_get_connection_in(); + problem = krb5_auth_con_setaddrs_from_fd(ssh_context, auth_context, &fd); + if (problem) { + ret = 0; + goto err; + } + + problem = krb5_sname_to_principal(ssh_context, NULL, NULL , + KRB5_NT_SRV_HST, &server); + if (problem) { + ret = 0; + goto err; + } + + problem = krb5_rd_req(ssh_context, &auth_context, auth, server, NULL, + NULL, &ticket); + if (problem) { + ret = 0; + goto err; + } + + problem = krb5_copy_principal(ssh_context, ticket->client, &tkt_client); + if (problem) { + ret = 0; + goto err; + } + + /* if client wants mutual auth */ + problem = krb5_mk_rep(ssh_context, &auth_context, &reply); + if (problem) { + ret = 0; + goto err; + } + + *client = tkt_client; + + packet_start(SSH_SMSG_AUTH_KRB5_RESPONSE); + packet_put_string((char *) reply.data, reply.length); + packet_send(); + packet_write_wait(); + ret = 1; + +err: + if (server) + krb5_free_principal(ssh_context, server); + if (ticket) + krb5_free_ticket(ssh_context, ticket); + if (reply.length) + xfree(reply.data); + return ret; +} + +int +auth_krb5_tgt(char *server_user, krb5_data *tgt, krb5_principal tkt_client) +{ + krb5_error_code problem; + krb5_ccache ccache = NULL; + + if (ssh_context == NULL) { + goto fail; + } + + problem = krb5_cc_gen_new(ssh_context, &krb5_mcc_ops, &ccache); + if (problem) { + goto fail; + } + + problem = krb5_cc_initialize(ssh_context, ccache, tkt_client); + if (problem) { + goto fail; + } + + problem = krb5_rd_cred(ssh_context, auth_context, ccache, tgt); + if (problem) { + goto fail; + } + + mem_ccache = ccache; + ccache = NULL; + + /* + problem = krb5_cc_copy_cache(ssh_context, ccache, mem_ccache); + if (problem) { + mem_ccache = NULL; + goto fail; + } + + + problem = krb5_cc_destroy(ssh_context, ccache); + if (problem) + goto fail; + */ + +#if 0 + packet_start(SSH_SMSG_SUCCESS); + packet_send(); + packet_write_wait(); +#endif + return 1; + +fail: + if (ccache) + krb5_cc_destroy(ssh_context, ccache); +#if 0 + packet_start(SSH_SMSG_FAILURE); + packet_send(); + packet_write_wait(); +#endif + return 0; +} + +int +auth_krb5_password(struct passwd *pw, const char *password) +{ + krb5_error_code problem; + krb5_ccache ccache = NULL; + krb5_principal client = NULL; + int ret; + + problem = krb5_init(); + if (problem) + return 0; + + problem = krb5_parse_name(ssh_context, pw->pw_name, &client); + if (problem) { + ret = 0; + goto out; + } + + problem = krb5_cc_gen_new(ssh_context, &krb5_mcc_ops, &ccache); + if (problem) { + ret = 0; + goto out; + } + + problem = krb5_cc_initialize(ssh_context, ccache, client); + if (problem) { + ret = 0; + goto out; + } + + problem = krb5_verify_user(ssh_context, client, ccache, password, 1, NULL); + if (problem) { + ret = 0; + goto out; + } + +/* + problem = krb5_cc_copy_cache(ssh_context, ccache, mem_ccache); + if (problem) { + ret = 0; + mem_ccache = NULL; + goto out; + } + */ + mem_ccache = ccache; + ccache = NULL; + + ret = 1; +out: + if (client != NULL) + krb5_free_principal(ssh_context, client); + if (ccache != NULL) + krb5_cc_destroy(ssh_context, ccache); + return ret; +} + +void +krb5_cleanup_proc(void *ignore) +{ + extern krb5_principal tkt_client; + + debug("krb5_cleanup_proc() called"); + if (mem_ccache) + krb5_cc_destroy(ssh_context, mem_ccache); + if (tkt_client) + krb5_free_principal(ssh_context, tkt_client); + if (auth_context) + krb5_auth_con_free(ssh_context, auth_context); + if (ssh_context) + krb5_free_context(ssh_context); +} + +int +krb5_init(void) +{ + krb5_error_code problem; + static cleanup_registered = 0; + + if (ssh_context == NULL) { + problem = krb5_init_context(&ssh_context); + if (problem) + return problem; + krb5_init_ets(ssh_context); + } + + if (!cleanup_registered) { + fatal_add_cleanup(krb4_cleanup_proc, NULL); + cleanup_registered = 1; + } + return 0; +} + +#endif /* KRB5 */ diff --git a/crypto/openssh/auth-passwd.c b/crypto/openssh/auth-passwd.c index de0f640..8622dbc 100644 --- a/crypto/openssh/auth-passwd.c +++ b/crypto/openssh/auth-passwd.c @@ -5,6 +5,8 @@ * Created: Sat Mar 18 05:11:38 1995 ylo * Password authentication. This file contains the functions to check whether * the password is valid for the user. + * + * $FreeBSD$ */ #include "includes.h" @@ -41,8 +43,16 @@ auth_password(struct passwd * pw, const char *password) /* Fall back to ordinary passwd authentication. */ } #endif +#ifdef KRB5 + if (options.krb5_authentication == 1) { + if (auth_krb5_password(pw, password)) + return 1; + /* Fall back to ordinary passwd authentication. */ + } + +#endif /* KRB5 */ #ifdef KRB4 - if (options.kerberos_authentication == 1) { + if (options.krb4_authentication == 1) { int ret = auth_krb4_password(pw, password); if (ret == 1 || ret == 0) return ret; diff --git a/crypto/openssh/readconf.c b/crypto/openssh/readconf.c index b2da36f..f44ee55 100644 --- a/crypto/openssh/readconf.c +++ b/crypto/openssh/readconf.c @@ -93,10 +93,13 @@ typedef enum { oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh, oSkeyAuthentication, #ifdef KRB4 - oKerberosAuthentication, + oKrb4Authentication, #endif /* KRB4 */ +#ifdef KRB5 + oKrb5Authentication, oKrb5TgtPassing, +#endif /* KRB5 */ #ifdef AFS - oKerberosTgtPassing, oAFSTokenPassing, + oKrb4TgtPassing, oAFSTokenPassing, #endif oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, @@ -121,10 +124,14 @@ static struct { { "rsaauthentication", oRSAAuthentication }, { "skeyauthentication", oSkeyAuthentication }, #ifdef KRB4 - { "kerberosauthentication", oKerberosAuthentication }, + { "kerberos4authentication", oKrb4Authentication }, #endif /* KRB4 */ +#ifdef KRB5 + { "kerberos5authentication", oKrb5Authentication }, + { "kerberos5tgtpassing", oKrb5TgtPassing }, +#endif /* KRB5 */ #ifdef AFS - { "kerberostgtpassing", oKerberosTgtPassing }, + { "kerberos4tgtpassing", oKrb4TgtPassing }, { "afstokenpassing", oAFSTokenPassing }, #endif { "fallbacktorsh", oFallBackToRsh }, @@ -298,14 +305,24 @@ parse_flag: goto parse_flag; #ifdef KRB4 - case oKerberosAuthentication: - intptr = &options->kerberos_authentication; + case oKrb4Authentication: + intptr = &options->krb4_authentication; goto parse_flag; #endif /* KRB4 */ +#ifdef KRB5 + case oKrb5Authentication: + intptr = &options->krb5_authentication; + goto parse_flag; + + case oKrb5TgtPassing: + intptr = &options->krb5_tgt_passing; + goto parse_flag; +#endif /* KRB5 */ + #ifdef AFS - case oKerberosTgtPassing: - intptr = &options->kerberos_tgt_passing; + case oKrb4TgtPassing: + intptr = &options->krb4_tgt_passing; goto parse_flag; case oAFSTokenPassing: @@ -596,10 +613,14 @@ initialize_options(Options * options) options->rsa_authentication = -1; options->skey_authentication = -1; #ifdef KRB4 - options->kerberos_authentication = -1; + options->krb4_authentication = -1; #endif +#ifdef KRB5 + options->krb5_authentication = -1; + options->krb5_tgt_passing = -1; +#endif /* KRB5 */ #ifdef AFS - options->kerberos_tgt_passing = -1; + options->krb4_tgt_passing = -1; options->afs_token_passing = -1; #endif options->password_authentication = -1; @@ -651,12 +672,18 @@ fill_default_options(Options * options) if (options->skey_authentication == -1) options->skey_authentication = 0; #ifdef KRB4 - if (options->kerberos_authentication == -1) - options->kerberos_authentication = 1; + if (options->krb4_authentication == -1) + options->krb4_authentication = 1; #endif /* KRB4 */ +#ifdef KRB5 + if (options->krb5_authentication == -1) + options->krb5_authentication = 1; + if (options->krb5_tgt_passing == -1) + options->krb5_tgt_passing = 1; +#endif /* KRB5 */ #ifdef AFS - if (options->kerberos_tgt_passing == -1) - options->kerberos_tgt_passing = 1; + if (options->krb4_tgt_passing == -1) + options->krb4_tgt_passing = 1; if (options->afs_token_passing == -1) options->afs_token_passing = 1; #endif /* AFS */ diff --git a/crypto/openssh/readconf.h b/crypto/openssh/readconf.h index 1d22002..5d511aa 100644 --- a/crypto/openssh/readconf.h +++ b/crypto/openssh/readconf.h @@ -11,6 +11,7 @@ * * Functions for reading the configuration file. * + * $FreeBSD$ */ /* RCSID("$Id: readconf.h,v 1.13 1999/12/01 13:59:15 markus Exp $"); */ @@ -38,11 +39,17 @@ typedef struct { int rsa_authentication; /* Try RSA authentication. */ int skey_authentication; /* Try S/Key or TIS authentication. */ #ifdef KRB4 - int kerberos_authentication; /* Try Kerberos + int krb4_authentication; /* Try Kerberos v4 * authentication. */ #endif + +#ifdef KRB5 + int krb5_authentication; + int krb5_tgt_passing; +#endif /* KRB5 */ + #ifdef AFS - int kerberos_tgt_passing; /* Try Kerberos tgt passing. */ + int krb4_tgt_passing; /* Try Kerberos v4 tgt passing. */ int afs_token_passing; /* Try AFS token passing. */ #endif int password_authentication; /* Try password diff --git a/crypto/openssh/servconf.c b/crypto/openssh/servconf.c index 6ae36e6..7852348 100644 --- a/crypto/openssh/servconf.c +++ b/crypto/openssh/servconf.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$Id: servconf.c,v 1.29 2000/01/04 00:07:59 markus Exp $"); +RCSID("$Id: servconf.c,v 1.30 2000/02/24 18:22:16 markus Exp $"); #include "ssh.h" #include "servconf.h" @@ -50,12 +50,16 @@ initialize_server_options(ServerOptions *options) options->rhosts_rsa_authentication = -1; options->rsa_authentication = -1; #ifdef KRB4 - options->kerberos_authentication = -1; - options->kerberos_or_local_passwd = -1; - options->kerberos_ticket_cleanup = -1; + options->krb4_authentication = -1; + options->krb4_or_local_passwd = -1; + options->krb4_ticket_cleanup = -1; #endif +#ifdef KRB5 + options->krb5_authentication = -1; + options->krb5_tgt_passing = -1; +#endif /* KRB5 */ #ifdef AFS - options->kerberos_tgt_passing = -1; + options->krb4_tgt_passing = -1; options->afs_token_passing = -1; #endif options->password_authentication = -1; @@ -90,7 +94,7 @@ fill_default_server_options(ServerOptions *options) if (options->permit_root_login == -1) options->permit_root_login = 1; /* yes */ if (options->ignore_rhosts == -1) - options->ignore_rhosts = 0; + options->ignore_rhosts = 1; if (options->ignore_user_known_hosts == -1) options->ignore_user_known_hosts = 0; if (options->check_mail == -1) @@ -100,7 +104,7 @@ fill_default_server_options(ServerOptions *options) if (options->x11_forwarding == -1) options->x11_forwarding = 1; if (options->x11_display_offset == -1) - options->x11_display_offset = 1; + options->x11_display_offset = 10; if (options->strict_modes == -1) options->strict_modes = 1; if (options->keepalives == -1) @@ -112,20 +116,26 @@ fill_default_server_options(ServerOptions *options) if (options->rhosts_authentication == -1) options->rhosts_authentication = 0; if (options->rhosts_rsa_authentication == -1) - options->rhosts_rsa_authentication = 1; + options->rhosts_rsa_authentication = 0; if (options->rsa_authentication == -1) options->rsa_authentication = 1; #ifdef KRB4 - 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; + if (options->krb4_authentication == -1) + options->krb4_authentication = (access(KEYFILE, R_OK) == 0); + if (options->krb4_or_local_passwd == -1) + options->krb4_or_local_passwd = 1; + if (options->krb4_ticket_cleanup == -1) + options->krb4_ticket_cleanup = 1; #endif /* KRB4 */ +#ifdef KRB5 + if (options->krb5_authentication == -1) + options->krb5_authentication = 1; + if (options->krb5_tgt_passing == -1) + options->krb5_tgt_passing = 1; +#endif /* KRB5 */ #ifdef AFS - if (options->kerberos_tgt_passing == -1) - options->kerberos_tgt_passing = 0; + if (options->krb4_tgt_passing == -1) + options->krb4_tgt_passing = 0; if (options->afs_token_passing == -1) options->afs_token_passing = k_hasafs(); #endif /* AFS */ @@ -136,7 +146,7 @@ fill_default_server_options(ServerOptions *options) options->skey_authentication = 1; #endif if (options->permit_empty_passwd == -1) - options->permit_empty_passwd = 1; + options->permit_empty_passwd = 0; if (options->use_login == -1) options->use_login = 0; } @@ -150,10 +160,13 @@ typedef enum { sPermitRootLogin, sLogFacility, sLogLevel, sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication, #ifdef KRB4 - sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, + sKrb4Authentication, sKrb4OrLocalPasswd, sKrb4TicketCleanup, #endif +#ifdef KRB5 + sKrb5Authentication, sKrb5TgtPassing, +#endif /* KRB5 */ #ifdef AFS - sKerberosTgtPassing, sAFSTokenPassing, + sKrb4TgtPassing, sAFSTokenPassing, #endif #ifdef SKEY sSkeyAuthentication, @@ -182,12 +195,16 @@ static struct { { "rhostsrsaauthentication", sRhostsRSAAuthentication }, { "rsaauthentication", sRSAAuthentication }, #ifdef KRB4 - { "kerberosauthentication", sKerberosAuthentication }, - { "kerberosorlocalpasswd", sKerberosOrLocalPasswd }, - { "kerberosticketcleanup", sKerberosTicketCleanup }, + { "kerberos4authentication", sKrb4Authentication }, + { "kerberos4orlocalpasswd", sKrb4OrLocalPasswd }, + { "kerberos4ticketcleanup", sKrb4TicketCleanup }, #endif +#ifdef KRB5 + { "kerberos5authentication", sKrb5Authentication }, + { "kerberos5tgtpassing", sKrb5TgtPassing }, +#endif /* KRB5 */ #ifdef AFS - { "kerberostgtpassing", sKerberosTgtPassing }, + { "kerberos4tgtpassing", sKrb4TgtPassing }, { "afstokenpassing", sAFSTokenPassing }, #endif { "passwordauthentication", sPasswordAuthentication }, @@ -425,22 +442,32 @@ parse_flag: goto parse_flag; #ifdef KRB4 - case sKerberosAuthentication: - intptr = &options->kerberos_authentication; + case sKrb4Authentication: + intptr = &options->krb4_authentication; goto parse_flag; - case sKerberosOrLocalPasswd: - intptr = &options->kerberos_or_local_passwd; + case sKrb4OrLocalPasswd: + intptr = &options->krb4_or_local_passwd; goto parse_flag; - case sKerberosTicketCleanup: - intptr = &options->kerberos_ticket_cleanup; + case sKrb4TicketCleanup: + intptr = &options->krb4_ticket_cleanup; goto parse_flag; #endif +#ifdef KRB5 + case sKrb5Authentication: + intptr = &options->krb5_authentication; + goto parse_flag; + + case sKrb5TgtPassing: + intptr = &options->krb5_tgt_passing; + goto parse_flag; +#endif /* KRB5 */ + #ifdef AFS - case sKerberosTgtPassing: - intptr = &options->kerberos_tgt_passing; + case sKrb4TgtPassing: + intptr = &options->krb4_tgt_passing; goto parse_flag; case sAFSTokenPassing: diff --git a/crypto/openssh/servconf.h b/crypto/openssh/servconf.h index e21e7ab..3e765b8 100644 --- a/crypto/openssh/servconf.h +++ b/crypto/openssh/servconf.h @@ -56,18 +56,23 @@ typedef struct { * authentication. */ int rsa_authentication; /* If true, permit RSA authentication. */ #ifdef KRB4 - int kerberos_authentication; /* If true, permit Kerberos + int krb4_authentication; /* If true, permit Kerberos v4 * authentication. */ - int kerberos_or_local_passwd; /* If true, permit kerberos + int krb4_or_local_passwd; /* If true, permit kerberos v4 * and any other password * authentication mechanism, * such as SecurID or * /etc/passwd */ - int kerberos_ticket_cleanup; /* If true, destroy ticket + int krb4_ticket_cleanup; /* If true, destroy ticket * file on logout. */ #endif +#ifdef KRB5 + int krb5_authentication; + int krb5_tgt_passing; + +#endif /* KRB5 */ #ifdef AFS - int kerberos_tgt_passing; /* If true, permit Kerberos tgt + int krb4_tgt_passing; /* If true, permit Kerberos v4 tgt * passing. */ int afs_token_passing; /* If true, permit AFS token passing. */ #endif diff --git a/crypto/openssh/ssh.c b/crypto/openssh/ssh.c index 81ce2ec..e240036 100644 --- a/crypto/openssh/ssh.c +++ b/crypto/openssh/ssh.c @@ -295,7 +295,8 @@ main(int ac, char **av) break; #ifdef AFS case 'k': - options.kerberos_tgt_passing = 0; + options.krb4_tgt_passing = 0; + options.krb5_tgt_passing = 0; options.afs_token_passing = 0; break; #endif diff --git a/crypto/openssh/ssh.h b/crypto/openssh/ssh.h index 8576f2e..8d6267c 100644 --- a/crypto/openssh/ssh.h +++ b/crypto/openssh/ssh.h @@ -182,11 +182,14 @@ #define SSH_AUTH_PASSWORD 3 #define SSH_AUTH_RHOSTS_RSA 4 #define SSH_AUTH_TIS 5 -#define SSH_AUTH_KERBEROS 6 -#define SSH_PASS_KERBEROS_TGT 7 +#define SSH_AUTH_KRB4 6 +#define SSH_PASS_KRB4_TGT 7 /* 8 to 15 are reserved */ #define SSH_PASS_AFS_TOKEN 21 +#define SSH_AUTH_KRB5 29 +#define SSH_PASS_KRB5_TGT 30 + /* Protocol flags. These are bit masks. */ #define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */ #define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain host */ @@ -240,11 +243,15 @@ #define SSH_CMSG_AUTH_TIS 39 /* we use this for s/key */ #define SSH_SMSG_AUTH_TIS_CHALLENGE 40 /* challenge (string) */ #define SSH_CMSG_AUTH_TIS_RESPONSE 41 /* response (string) */ -#define SSH_CMSG_AUTH_KERBEROS 42 /* (KTEXT) */ -#define SSH_SMSG_AUTH_KERBEROS_RESPONSE 43 /* (KTEXT) */ -#define SSH_CMSG_HAVE_KERBEROS_TGT 44 /* credentials (s) */ +#define SSH_CMSG_AUTH_KRB4 42 /* (KTEXT) */ +#define SSH_SMSG_AUTH_KRB4_RESPONSE 43 /* (KTEXT) */ +#define SSH_CMSG_HAVE_KRB4_TGT 44 /* credentials (s) */ #define SSH_CMSG_HAVE_AFS_TOKEN 65 /* token (s) */ +#define SSH_CMSG_AUTH_KRB5 110 +#define SSH_SMSG_AUTH_KRB5_RESPONSE 111 +#define SSH_CMSG_HAVE_KRB5_TGT 112 + /*------------ definitions for login.c -------------*/ /* @@ -690,6 +697,15 @@ struct envstring { */ ssize_t atomicio(ssize_t (*f)(), int fd, void *s, size_t n); +#ifdef KRB5 +#include <krb5.h> +int auth_krb5(); /* XXX Doplnit prototypy */ +int auth_krb5_tgt(); +int krb5_init(); +void krb5_cleanup_proc(void *ignore); +int auth_krb5_password(struct passwd *pw, const char *password); +#endif /* KRB5 */ + #ifdef KRB4 #include <krb.h> /* @@ -706,7 +722,7 @@ int auth_krb4_password(struct passwd * pw, const char *password); #include <kafs.h> /* Accept passed Kerberos v4 ticket-granting ticket and AFS tokens. */ -int auth_kerberos_tgt(struct passwd * pw, const char *string); +int auth_krb4_tgt(struct passwd * pw, const char *string); int auth_afs_token(struct passwd * pw, const char *token_string); int creds_to_radix(CREDENTIALS * creds, unsigned char *buf); diff --git a/crypto/openssh/sshconnect.c b/crypto/openssh/sshconnect.c index 385f4d9..bcbd3af 100644 --- a/crypto/openssh/sshconnect.c +++ b/crypto/openssh/sshconnect.c @@ -626,7 +626,7 @@ try_rhosts_rsa_authentication(const char *local_user, RSA * host_key) #ifdef KRB4 int -try_kerberos_authentication() +try_krb4_authentication() { KTEXT_ST auth; /* Kerberos data */ char *reply; @@ -668,7 +668,7 @@ try_kerberos_authentication() des_key_sched((des_cblock *) cred.session, schedule); /* Send authentication info to server. */ - packet_start(SSH_CMSG_AUTH_KERBEROS); + packet_start(SSH_CMSG_AUTH_KRB4); packet_put_string((char *) auth.dat, auth.length); packet_send(); packet_write_wait(); @@ -693,13 +693,13 @@ try_kerberos_authentication() type = packet_read(&plen); switch (type) { case SSH_SMSG_FAILURE: - /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */ + /* Should really be SSH_SMSG_AUTH_KRB4_FAILURE */ debug("Kerberos V4 authentication failed."); return 0; break; - case SSH_SMSG_AUTH_KERBEROS_RESPONSE: - /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */ + case SSH_SMSG_AUTH_KRB4_RESPONSE: + /* SSH_SMSG_AUTH_KRB4_SUCCESS */ debug("Kerberos V4 authentication accepted."); /* Get server's response. */ @@ -742,7 +742,7 @@ try_kerberos_authentication() #ifdef AFS int -send_kerberos_tgt() +send_krb4_tgt() { CREDENTIALS *creds; char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ]; @@ -771,7 +771,7 @@ send_kerberos_tgt() creds_to_radix(creds, buffer); xfree(creds); - packet_start(SSH_CMSG_HAVE_KERBEROS_TGT); + packet_start(SSH_CMSG_HAVE_KRB4_TGT); packet_put_string((char *) buffer, strlen(buffer)); packet_send(); packet_write_wait(); @@ -856,6 +856,247 @@ send_afs_tokens(void) #endif /* AFS */ +#ifdef KRB5 +int +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; + krb5_creds req_creds; + krb5_creds *new_creds = 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) { + 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) { + ret = 0; + goto out; + } + + memset(&req_creds, 0, sizeof(req_creds)); + + remotehost = get_canonical_hostname(); + + problem = krb5_sname_to_principal(*context, remotehost, + "host", KRB5_NT_SRV_HST, + &req_creds.server); + if (problem) { + ret = 0; + goto out; + + } + + problem = krb5_cc_get_principal(*context, ccache, &req_creds.client); + if (problem) { + ret = 0; + goto out; + } + + /* creds.session.keytype=ETYPE_DES_CBC_CRC; */ + + problem = krb5_get_credentials(*context, 0, ccache, &req_creds, &new_creds); + if (problem) { + ret = 0; + goto out; + } + + problem = krb5_auth_con_init(*context, auth_context); + if (problem) { + ret = 0; + goto out; + } + + /* krb5_auth_con_setflags(ssh_context, auth_context, + KRB5_AUTH_CONTEXT_RET_TIME); + */ + problem = krb5_mk_req_extended(*context, auth_context, + AP_OPTS_MUTUAL_REQUIRED /*| AP_OPTS_USE_SUBKEY*/ , + NULL, new_creds, &ap); + if (problem) { + ret = 0; + goto out; + } + + packet_start(SSH_CMSG_AUTH_KRB5); + 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_KRB5_FAILURE */ + debug("Kerberos V5 authentication failed."); + ret = 0; + break; + + case SSH_SMSG_AUTH_KRB5_RESPONSE: + /* SSH_SMSG_AUTH_KRB5_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 (req_creds.server != NULL) + krb5_free_principal(*context, req_creds.server); + if (req_creds.client != NULL) + krb5_free_principal(*context, req_creds.client); + if (new_creds != NULL) + krb5_free_creds(*context, new_creds); + 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; + +} + +void +send_krb5_tgt(krb5_context context, krb5_auth_context auth_context) +{ + int fd; + int type, payload_len; + krb5_error_code problem; + krb5_data outbuf; + krb5_ccache ccache = NULL; + krb5_creds creds; + krb5_kdc_flags flags; + const char* remotehost = get_canonical_hostname(); + + 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; + } + +#if 0 + 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)."); + goto out; + } +#endif + + 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); + + problem = krb5_get_forwarded_creds (context, + auth_context, + ccache, + flags.i, + remotehost, + &creds, + &outbuf); + if (problem) { + goto out; + } + + packet_start(SSH_CMSG_HAVE_KRB5_TGT); + packet_put_string((char *)outbuf.data, outbuf.length); + packet_send(); + packet_write_wait(); + + type = packet_read(&payload_len); + switch (type) { + case SSH_SMSG_SUCCESS: + break; + case SSH_SMSG_FAILURE: + break; + default: + break; + } + +out: + 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); + + return; +} +#endif /* KRB5 */ + /* * Tries to authenticate with any string-based challenge/response system. * Note that the client code is not tied to s/key or TIS. @@ -1087,11 +1328,9 @@ check_host_key(char *host, struct sockaddr *hostaddr, RSA *host_key) case AF_INET: local = (ntohl(((struct sockaddr_in *)hostaddr)->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; break; -#ifdef INET6 case AF_INET6: local = IN6_IS_ADDR_LOOPBACK(&(((struct sockaddr_in6 *)hostaddr)->sin6_addr)); break; -#endif default: local = 0; break; @@ -1512,11 +1751,11 @@ ssh_userauth(int host_key_valid, RSA *own_host_key, #ifdef AFS /* Try Kerberos tgt passing if the server supports it. */ - if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) && - options.kerberos_tgt_passing) { + if ((supported_authentications & (1 << SSH_PASS_KRB4_TGT)) && + options.krb4_tgt_passing) { if (options.cipher == SSH_CIPHER_NONE) log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!"); - (void) send_kerberos_tgt(); + (void) send_krb4_tgt(); } /* Try AFS token passing if the server supports it. */ if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) && @@ -1528,10 +1767,10 @@ ssh_userauth(int host_key_valid, RSA *own_host_key, #endif /* AFS */ #ifdef KRB4 - if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) && - options.kerberos_authentication) { + if ((supported_authentications & (1 << SSH_AUTH_KRB4)) && + options.krb4_authentication) { debug("Trying Kerberos authentication."); - if (try_kerberos_authentication()) { + if (try_krb4_authentication()) { /* The server should respond with success or failure. */ type = packet_read(&payload_len); if (type == SSH_SMSG_SUCCESS) @@ -1542,6 +1781,35 @@ ssh_userauth(int host_key_valid, RSA *own_host_key, } #endif /* KRB4 */ +#ifdef KRB5 + if ((supported_authentications & (1 << SSH_AUTH_KRB5)) && + options.krb5_authentication){ + krb5_context ssh_context = NULL; + krb5_auth_context auth_context = NULL; + + debug("Trying Kerberos V5 authentication."); + + if (try_krb5_authentication(&ssh_context, &auth_context)) { + type = packet_read(&payload_len); + if (type == SSH_SMSG_SUCCESS) { + if ((supported_authentications & (1 << SSH_PASS_KRB5_TGT)) && + options.krb5_tgt_passing) { + if (options.cipher == SSH_CIPHER_NONE) + log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!"); + send_krb5_tgt(ssh_context, auth_context); + + } + krb5_auth_con_free(ssh_context, auth_context); + krb5_free_context(ssh_context); + return; + } + if (type != SSH_SMSG_FAILURE) + packet_disconnect("Protocol error: got %d in response to Kerberos5 auth", type); + + } + } +#endif /* KRB5 */ + /* * Use rhosts authentication if running in privileged socket and we * do not wish to remain anonymous. diff --git a/crypto/openssh/sshd.8 b/crypto/openssh/sshd.8 index 93ee16b..fc067bc 100644 --- a/crypto/openssh/sshd.8 +++ b/crypto/openssh/sshd.8 @@ -9,7 +9,7 @@ .\" .\" Created: Sat Apr 22 21:55:14 1995 ylo .\" -.\" $Id: sshd.8,v 1.33 2000/02/21 14:19:09 deraadt Exp $ +.\" $Id: sshd.8,v 1.34 2000/02/24 18:22:16 markus Exp $ .\" $FreeBSD$ .\" .Dd September 25, 1999 @@ -284,13 +284,16 @@ Note that .Nm does not start if this file is group/world-accessible. .It Cm IgnoreRhosts -Specifies that rhosts and shosts files will not be used in -authentication. +Specifies that +.Pa .rhosts +and +.Pa .shosts +files will not be used in authentication. .Pa /etc/hosts.equiv and .Pa /etc/shosts.equiv are still used. The default is -.Dq no . +.Dq yes . .It Cm IgnoreUserKnownHosts Specifies whether .Nm @@ -378,7 +381,7 @@ The default is When password authentication is allowed, it specifies whether the server allows login to accounts with empty password strings. The default is -.Dq yes . +.Dq no . .It Cm PermitRootLogin Specifies whether the root can log in using .Xr ssh 1 . @@ -429,7 +432,7 @@ The default is .It Cm RhostsRSAAuthentication Specifies whether rhosts or /etc/hosts.equiv authentication together with successful RSA host authentication is allowed. The default is -.Dq yes . +.Dq no . .It Cm RSAAuthentication Specifies whether pure RSA authentication is allowed. The default is .Dq yes . @@ -468,6 +471,7 @@ Specifies the first display number available for X11 forwarding. This prevents .Nm from interfering with real X11 servers. +The default is 10. .It Cm X11Forwarding Specifies whether X11 forwarding is permitted. The default is .Dq yes . diff --git a/crypto/openssh/sshd.c b/crypto/openssh/sshd.c index 1dfea88..8576bc2 100644 --- a/crypto/openssh/sshd.c +++ b/crypto/openssh/sshd.c @@ -37,9 +37,8 @@ int deny_severity = LOG_WARNING; #endif /* LIBWRAP */ #ifdef __FreeBSD__ -#include <libutil.h> -#include <syslog.h> #define LOGIN_CAP +#define _PATH_CHPASS "/usr/bin/passwd" #endif /* __FreeBSD__ */ #ifdef LOGIN_CAP @@ -50,6 +49,14 @@ int deny_severity = LOG_WARNING; #define O_NOCTTY 0 #endif +#ifdef KRB5 +#include <krb5.h> +krb5_context ssh_context = NULL; +krb5_principal tkt_client = NULL; /* Principal from the received ticket. +Also is used as an indication of succesful krb5 authentization. */ +#endif /* KRB5 */ + + /* Local Xauthority file. */ static char *xauthfile = NULL; @@ -149,7 +156,7 @@ struct magic_connection { const size_t MAGIC_CONNECTIONS_SIZE = 1; static __inline int -magic_hash(struct sockaddr_storage *sa) { +magic_hash(struct sockaddr *sa) { return 0; } @@ -302,9 +309,13 @@ get_authname(int type) case SSH_CMSG_AUTH_RHOSTS: return "rhosts"; #ifdef KRB4 - case SSH_CMSG_AUTH_KERBEROS: - return "kerberos"; + case SSH_CMSG_AUTH_KRB4: + return "kerberosV4"; #endif +#ifdef KRB5 + case SSH_CMSG_AUTH_KRB5: + return "kerberosV5"; +#endif /* KRB5 */ #ifdef SKEY case SSH_CMSG_AUTH_TIS_RESPONSE: return "s/key"; @@ -723,7 +734,7 @@ main(int ac, char **av) struct magic_connection *mc; (void)gettimeofday(&connections_end, NULL); - mc = &magic_connections[magic_hash(&from)]; + mc = &magic_connections[magic_hash((struct sockaddr *)0)]; diff = timevaldiff(&mc->connections_begin, &connections_end); if (diff.tv_sec >= options.connections_period) { /* @@ -948,9 +959,9 @@ main(int ac, char **av) } #ifdef KRB4 if (!packet_connection_is_ipv4() && - options.kerberos_authentication) { + options.krb4_authentication) { debug("Kerberos Authentication disabled, only available for IPv4."); - options.kerberos_authentication = 0; + options.krb4_authentication = 0; } #endif /* KRB4 */ @@ -964,7 +975,7 @@ main(int ac, char **av) #ifdef KRB4 /* Cleanup user's ticket cache file. */ - if (options.kerberos_ticket_cleanup) + if (options.krb4_ticket_cleanup) (void) dest_tkt(); #endif /* KRB4 */ @@ -1042,12 +1053,22 @@ do_ssh_kex() if (options.rsa_authentication) auth_mask |= 1 << SSH_AUTH_RSA; #ifdef KRB4 - if (options.kerberos_authentication) - auth_mask |= 1 << SSH_AUTH_KERBEROS; + if (options.krb4_authentication) + auth_mask |= 1 << SSH_AUTH_KRB4; #endif +#ifdef KRB5 + if (options.krb5_authentication) { + auth_mask |= 1 << SSH_AUTH_KRB5; + /* compatibility with MetaCentre ssh */ + auth_mask |= 1 << SSH_AUTH_KRB4; + } + if (options.krb5_tgt_passing) + auth_mask |= 1 << SSH_PASS_KRB5_TGT; +#endif /* KRB5 */ + #ifdef AFS - if (options.kerberos_tgt_passing) - auth_mask |= 1 << SSH_PASS_KERBEROS_TGT; + if (options.krb4_tgt_passing) + auth_mask |= 1 << SSH_PASS_KRB4_TGT; if (options.afs_token_passing) auth_mask |= 1 << SSH_PASS_AFS_TOKEN; #endif @@ -1246,6 +1267,7 @@ allowed_user(struct passwd * pw) return 0; } } +#ifndef __FreeBSD__ /* FreeBSD handle it later */ /* Fail if the account's expiration time has passed. */ if (pw->pw_expire != 0) { struct timeval tv; @@ -1254,6 +1276,7 @@ allowed_user(struct passwd * pw) if (tv.tv_sec >= pw->pw_expire) return 0; } +#endif /* !__FreeBSD__ */ /* We found no reason not to let this user try to log on... */ return 1; } @@ -1268,6 +1291,12 @@ do_authentication() struct passwd *pw, pwcopy; int plen, ulen; char *user; +#ifdef LOGIN_CAP + login_cap_t *lc; + char *hosts; + const char *from_host, *from_ip; + int denied; +#endif /* LOGIN_CAP */ /* Get the name of the user that we wish to log in as. */ packet_read_expect(&plen, SSH_CMSG_USER); @@ -1316,8 +1345,11 @@ do_authentication() /* If the user has no password, accept authentication immediately. */ if (options.password_authentication && +#ifdef KRB5 + !options.krb5_authentication && +#endif /* KRB5 */ #ifdef KRB4 - (!options.kerberos_authentication || options.kerberos_or_local_passwd) && + (!options.krb4_authentication || options.krb4_or_local_passwd) && #endif /* KRB4 */ auth_password(pw, "")) { /* Authentication with empty password succeeded. */ @@ -1338,6 +1370,38 @@ do_authentication() packet_disconnect("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname()); } + +#ifdef LOGIN_CAP + lc = login_getpwclass(pw); + if (lc == NULL) + lc = login_getclassbyname(NULL, pw); + from_host = get_canonical_hostname(); + from_ip = get_remote_ipaddr(); + + denied = 0; + if ((hosts = login_getcapstr(lc, "host.deny", NULL, NULL)) != NULL) { + denied = match_hostname(from_host, hosts, strlen(hosts)); + if (!denied) + denied = match_hostname(from_ip, hosts, strlen(hosts)); + } + if (!denied && + (hosts = login_getcapstr(lc, "host.allow", NULL, NULL)) != NULL) { + denied = !match_hostname(from_host, hosts, strlen(hosts)); + if (denied) + denied = !match_hostname(from_ip, hosts, strlen(hosts)); + } + login_close(lc); + if (denied) { + log("Denied connection for %.200s from %.200s [%.200s].", + pw->pw_name, from_host, from_ip); + packet_disconnect("Sorry, you are not allowed to connect."); + } +#endif /* LOGIN_CAP */ + + if (pw->pw_uid == 0) + log("ROOT LOGIN as '%.100s' from %.100s", + pw->pw_name, get_canonical_hostname()); + /* The user has been authenticated and accepted. */ packet_start(SSH_SMSG_SUCCESS); packet_send(); @@ -1367,6 +1431,22 @@ do_authloop(struct passwd * pw) int plen, dlen, nlen, ulen, elen; int type = 0; void (*authlog) (const char *fmt,...) = verbose; +#ifdef HAVE_LIBPAM + int pam_retval; +#endif /* HAVE_LIBPAM */ +#if 0 +#ifdef KRB5 + { + krb5_error_code ret; + + ret = krb5_init_context(&ssh_context); + if (ret) + verbose("Error while initializing Kerberos V5."); + krb5_init_ets(ssh_context); + + } +#endif /* KRB5 */ +#endif /* Indicate that authentication is needed. */ packet_start(SSH_SMSG_FAILURE); @@ -1383,17 +1463,17 @@ do_authloop(struct passwd * pw) /* Process the packet. */ switch (type) { #ifdef AFS - case SSH_CMSG_HAVE_KERBEROS_TGT: - if (!options.kerberos_tgt_passing) { + case SSH_CMSG_HAVE_KRB4_TGT: + if (!options.krb4_tgt_passing) { /* packet_get_all(); */ - verbose("Kerberos tgt passing disabled."); + verbose("Kerberos v4 tgt passing disabled."); break; } else { - /* Accept Kerberos tgt. */ + /* Accept Kerberos v4 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 %s", pw->pw_name); + if (!auth_krb4_tgt(pw, tgt)) + verbose("Kerberos v4 tgt REFUSED for %s", pw->pw_name); xfree(tgt); } continue; @@ -1414,10 +1494,10 @@ do_authloop(struct passwd * pw) continue; #endif /* AFS */ #ifdef KRB4 - case SSH_CMSG_AUTH_KERBEROS: - if (!options.kerberos_authentication) { + case SSH_CMSG_AUTH_KRB4: + if (!options.krb4_authentication) { /* packet_get_all(); */ - verbose("Kerberos authentication disabled."); + verbose("Kerberos v4 authentication disabled."); break; } else { /* Try Kerberos v4 authentication. */ @@ -1439,6 +1519,36 @@ do_authloop(struct passwd * pw) } break; #endif /* KRB4 */ +#ifdef KRB5 + case SSH_CMSG_AUTH_KRB5: + if (!options.krb5_authentication) { + verbose("Kerberos v5 authentication disabled."); + break; + } else { + krb5_data k5data; +#if 0 + if (krb5_init_context(&ssh_context)) { + verbose("Error while initializing Kerberos V5."); + break; + } + krb5_init_ets(ssh_context); +#endif + + k5data.data = packet_get_string(&k5data.length); + packet_integrity_check(plen, 4 + k5data.length, type); + if (auth_krb5(pw->pw_name, &k5data, &tkt_client)) { + /* pw->name is passed just for logging purposes + * */ + /* authorize client against .k5login */ + if (krb5_kuserok(ssh_context, + tkt_client, + pw->pw_name)) + authenticated = 1; + } + xfree(k5data.data); + } + break; +#endif /* KRB5 */ case SSH_CMSG_AUTH_RHOSTS: if (!options.rhosts_authentication) { @@ -1908,6 +2018,32 @@ do_authenticated(struct passwd * pw) do_exec_no_pty(command, pw, display, proto, data); xfree(command); return; +#ifdef KRB5 + case SSH_CMSG_HAVE_KRB5_TGT: + /* Passing krb5 ticket */ + if (!options.krb5_tgt_passing + /*|| !options.krb5_authentication */) { + + } + + if (tkt_client == NULL) { + /* passing tgt without krb5 authentication */ + } + + { + krb5_data tgt; + tgt.data = packet_get_string(&tgt.length); + + if (!auth_krb5_tgt(pw->pw_name, &tgt, tkt_client)) { + verbose ("Kerberos V5 TGT refused for %.100s", pw->pw_name); + xfree(tgt.data); + goto fail; + } + xfree(tgt.data); + + break; + } +#endif /* KRB5 */ default: /* @@ -2086,6 +2222,11 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd, login_cap_t *lc; char *fname; #endif /* LOGIN_CAP */ +#ifdef __FreeBSD__ +#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ + struct timeval tv; + time_t warntime = DEFAULT_WARN; +#endif /* __FreeBSD__ */ /* Get remote host name. */ hostname = get_canonical_hostname(); @@ -2157,6 +2298,50 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd, quiet_login = login_getcapbool(lc, "hushlogin", quiet_login); #endif /* LOGIN_CAP */ +#ifdef __FreeBSD__ + if (pw->pw_change || pw->pw_expire) + (void)gettimeofday(&tv, NULL); +#ifdef LOGIN_CAP + warntime = login_getcaptime(lc, "warnpassword", + DEFAULT_WARN, DEFAULT_WARN); +#endif /* LOGIN_CAP */ + /* + * If the password change time is set and has passed, give the + * user a password expiry notice and chance to change it. + */ + if (pw->pw_change != 0) { + if (tv.tv_sec >= pw->pw_change) { + (void)printf( + "Sorry -- your password has expired.\n"); + log("%s Password expired - forcing change", + pw->pw_name); + command = _PATH_CHPASS; + } else if (pw->pw_change - tv.tv_sec < warntime && + !quiet_login) + (void)printf( + "Warning: your password expires on %s", + ctime(&pw->pw_change)); + } +#ifdef LOGIN_CAP + warntime = login_getcaptime(lc, "warnexpire", + DEFAULT_WARN, DEFAULT_WARN); +#endif /* LOGIN_CAP */ + if (pw->pw_expire) { + if (tv.tv_sec >= pw->pw_expire) { + (void)printf( + "Sorry -- your account has expired.\n"); + log( + "LOGIN %.200s REFUSED (EXPIRED) FROM %.200s ON TTY %.200s", + pw->pw_name, hostname, ttyname); + exit(254); + } else if (pw->pw_expire - tv.tv_sec < warntime && + !quiet_login) + (void)printf( + "Warning: your account expires on %s", + ctime(&pw->pw_expire)); + } +#endif /* __FreeBSD__ */ + /* * If the user has logged in before, display the time of last * login. However, don't display anything extra if a command @@ -2203,10 +2388,9 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd, !options.use_login) { #ifdef LOGIN_CAP fname = login_getcapstr(lc, "welcome", NULL, NULL); - login_close(lc); if (fname == NULL || (f = fopen(fname, "r")) == NULL) f = fopen("/etc/motd", "r"); -#else /* LOGIN_CAP */ +#else /* !LOGIN_CAP */ f = fopen("/etc/motd", "r"); #endif /* LOGIN_CAP */ /* Print /etc/motd if it exists. */ @@ -2216,6 +2400,9 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd, fclose(f); } } +#ifdef LOGIN_CAP + login_close(lc); +#endif /* LOGIN_CAP */ /* Do common processing for the child, such as execing the command. */ do_child(command, pw, term, display, auth_proto, auth_data, ttyname); @@ -2363,7 +2550,7 @@ do_child(const char *command, struct passwd * pw, const char *term, char buf[256]; FILE *f; unsigned int envsize, i; - char **env; + char **env = NULL; extern char **environ; struct stat st; char *argv[10]; @@ -2373,29 +2560,24 @@ do_child(const char *command, struct passwd * pw, const char *term, lc = login_getpwclass(pw); if (lc == NULL) lc = login_getclassbyname(NULL, pw); -#endif /* LOGIN_CAP */ - + if (pw->pw_uid != 0) + auth_checknologin(lc); +#else /* !LOGIN_CAP */ f = fopen("/etc/nologin", "r"); -#ifdef __FreeBSD__ - if (f == NULL) - f = fopen("/var/run/nologin", "r"); -#endif /* __FreeBSD__ */ if (f) { /* /etc/nologin exists. Print its contents and exit. */ -#ifdef LOGIN_CAP - /* On FreeBSD, etc., allow overriding nologin via login.conf. */ - if (!login_getcapbool(lc, "ignorenologin", 0)) { -#else /* LOGIN_CAP */ - if (1) { -#endif /* LOGIN_CAP */ - while (fgets(buf, sizeof(buf), f)) - fputs(buf, stderr); - fclose(f); - if (pw->pw_uid != 0) - exit(254); - } + while (fgets(buf, sizeof(buf), f)) + fputs(buf, stderr); + fclose(f); + if (pw->pw_uid != 0) + exit(254); } +#endif /* LOGIN_CAP */ + +#ifdef LOGIN_CAP + if (options.use_login) +#endif /* LOGIN_CAP */ /* Set login name in the kernel. */ if (setlogin(pw->pw_name) < 0) error("setlogin failed: %s", strerror(errno)); @@ -2405,12 +2587,42 @@ do_child(const char *command, struct passwd * pw, const char *term, switch, so we let login(1) to this for us. */ if (!options.use_login) { #ifdef LOGIN_CAP - if (setclasscontext(pw->pw_class, LOGIN_SETPRIORITY | - LOGIN_SETRESOURCES | LOGIN_SETUMASK) == -1) { - perror("setclasscontext"); - exit(1); - } -#endif /* LOGIN_CAP */ + char **tmpenv; + + /* Initialize temp environment */ + envsize = 64; + env = xmalloc(envsize * sizeof(char *)); + env[0] = NULL; + + child_set_env(&env, &envsize, "PATH", + (pw->pw_uid == 0) ? + _PATH_STDPATH : _PATH_DEFPATH); + + snprintf(buf, sizeof buf, "%.200s/%.50s", + _PATH_MAILDIR, pw->pw_name); + child_set_env(&env, &envsize, "MAIL", buf); + + if (getenv("TZ")) + child_set_env(&env, &envsize, "TZ", getenv("TZ")); + + /* Save parent environment */ + tmpenv = environ; + environ = env; + + if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETALL) < 0) + fatal("setusercontext failed: %s", strerror(errno)); + + /* Restore parent environment */ + env = environ; + environ = tmpenv; + + for (envsize = 0; env[envsize] != NULL; ++envsize) + ; + envsize = (envsize < 100) ? 100 : envsize + 16; + env = xrealloc(env, envsize * sizeof(char *)); + +#else /* !LOGIN_CAP */ + if (getuid() == 0 || geteuid() == 0) { if (setgid(pw->pw_gid) < 0) { perror("setgid"); @@ -2428,18 +2640,15 @@ do_child(const char *command, struct passwd * pw, const char *term, } if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) fatal("Failed to set uids to %d.", (int) pw->pw_uid); +#endif /* LOGIN_CAP */ } /* * Get the shell from the password data. An empty shell field is * legal, and means /bin/sh. */ + shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; #ifdef LOGIN_CAP - shell = pw->pw_shell; shell = login_getcapstr(lc, "shell", shell, shell); - if (shell[0] == '\0') - shell = _PATH_BSHELL; -#else /* LOGIN_CAP */ - shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; #endif /* LOGIN_CAP */ #ifdef AFS @@ -2455,29 +2664,31 @@ do_child(const char *command, struct passwd * pw, const char *term, #endif /* AFS */ /* Initialize the environment. */ - envsize = 100; - env = xmalloc(envsize * sizeof(char *)); - env[0] = NULL; + if (env == NULL) { + envsize = 100; + env = xmalloc(envsize * sizeof(char *)); + env[0] = NULL; + } if (!options.use_login) { /* Set basic environment. */ child_set_env(&env, &envsize, "USER", pw->pw_name); child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); child_set_env(&env, &envsize, "HOME", pw->pw_dir); -#ifdef LOGIN_CAP - child_set_env(&env, &envsize, "PATH", - login_getpath(lc, "path", _PATH_STDPATH)); -#else /* LOGIN_CAP */ +#ifndef LOGIN_CAP child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); -#endif /* LOGIN_CAP */ snprintf(buf, sizeof buf, "%.200s/%.50s", _PATH_MAILDIR, pw->pw_name); child_set_env(&env, &envsize, "MAIL", buf); +#endif /* !LOGIN_CAP */ /* Normal systems set SHELL by default. */ child_set_env(&env, &envsize, "SHELL", shell); } +#ifdef LOGIN_CAP + if (options.use_login) +#endif /* LOGIN_CAP */ if (getenv("TZ")) child_set_env(&env, &envsize, "TZ", getenv("TZ")); @@ -2516,6 +2727,32 @@ do_child(const char *command, struct passwd * pw, const char *term, } #endif /* KRB4 */ +#ifdef KRB5 + { + extern krb5_ccache mem_ccache; + + if (mem_ccache) { + krb5_error_code problem; + krb5_ccache ccache; +#ifdef AFS + if (k_hasafs()) + krb5_afslog(ssh_context, mem_ccache, NULL, NULL); +#endif /* AFS */ + + problem = krb5_cc_default(ssh_context, &ccache); + if (problem) {} + else { + problem = krb5_cc_copy_cache(ssh_context, mem_ccache, ccache); + if (problem) {} + } + + krb5_cc_close(ssh_context, ccache); + } + + krb5_cleanup_proc(NULL); + } +#endif /* KRB5 */ + if (xauthfile) child_set_env(&env, &envsize, "XAUTHORITY", xauthfile); if (auth_get_socket_name() != NULL) @@ -2559,10 +2796,6 @@ do_child(const char *command, struct passwd * pw, const char *term, */ endpwent(); -#ifdef LOGIN_CAP - login_close(lc); -#endif /* LOGIN_CAP */ - /* * Close any extra open file descriptors so that we don\'t have them * hanging around in clients. Note that we want to do this after @@ -2573,9 +2806,46 @@ do_child(const char *command, struct passwd * pw, const char *term, close(i); /* Change current directory to the user\'s home directory. */ - if (chdir(pw->pw_dir) < 0) + if ( +#ifdef __FreeBSD__ + !*pw->pw_dir || +#endif /* __FreeBSD__ */ + chdir(pw->pw_dir) < 0 + ) { +#ifdef __FreeBSD__ + int quiet_login = 0; +#endif /* __FreeBSD__ */ +#ifdef LOGIN_CAP + if (login_getcapbool(lc, "requirehome", 0)) { + (void)printf("Home directory not available\n"); + log("LOGIN %.200s REFUSED (HOMEDIR) ON TTY %.200s", + pw->pw_name, ttyname); + exit(254); + } +#endif /* LOGIN_CAP */ +#ifdef __FreeBSD__ + if (chdir("/") < 0) { + (void)printf("Cannot find root directory\n"); + log("LOGIN %.200s REFUSED (ROOTDIR) ON TTY %.200s", + pw->pw_name, ttyname); + exit(254); + } +#ifdef LOGIN_CAP + quiet_login = login_getcapbool(lc, "hushlogin", 0); +#endif /* LOGIN_CAP */ + if (!quiet_login || *pw->pw_dir) + (void)printf( + "No home directory.\nLogging in with home = \"/\".\n"); + +#else /* !__FreeBSD__ */ + fprintf(stderr, "Could not chdir to home directory %s: %s\n", pw->pw_dir, strerror(errno)); +#endif /* __FreeBSD__ */ + } +#ifdef LOGIN_CAP + login_close(lc); +#endif /* LOGIN_CAP */ /* * Must take new environment into use so that .ssh/rc, /etc/sshrc and @@ -2588,26 +2858,6 @@ do_child(const char *command, struct passwd * pw, const char *term, * in this order). */ if (!options.use_login) { -#ifdef __FreeBSD__ - /* - * If the password change time is set and has passed, give the - * user a password expiry notice and chance to change it. - */ - if (pw->pw_change != 0) { - struct timeval tv; - - (void)gettimeofday(&tv, NULL); - if (tv.tv_sec >= pw->pw_change) { - (void)printf( - "Sorry -- your password has expired.\n"); - syslog(LOG_INFO, - "%s Password expired - forcing change", - pw->pw_name); - if (system("/usr/bin/passwd") != 0) - perror("/usr/bin/passwd"); - } - } -#endif /* __FreeBSD__ */ if (stat(SSH_USER_RC, &st) >= 0) { if (debug_flag) fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC); @@ -2675,7 +2925,11 @@ do_child(const char *command, struct passwd * pw, const char *term, mailbox = getenv("MAIL"); if (mailbox != NULL) { if (stat(mailbox, &mailstat) != 0 || mailstat.st_size == 0) +#ifdef __FreeBSD__ + ; +#else /* !__FreeBSD__ */ printf("No mail.\n"); +#endif /* __FreeBSD__ */ else if (mailstat.st_mtime < mailstat.st_atime) printf("You have mail.\n"); else |