1) Add kerberos5 functionality.

by Daniel Kouril <kouril@informatics.muni.cz>
2) Add full LOGIN_CAP capability
   by Andrey Chernov
This commit is contained in:
markm 2000-02-28 19:03:50 +00:00
parent 898821d318
commit e54fe4cc8e
12 changed files with 1042 additions and 172 deletions

View File

@ -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;

249
crypto/openssh/auth-krb5.c Normal file
View File

@ -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 */

View File

@ -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;

View File

@ -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 @@ process_config_line(Options *options, const char *host,
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 */

View File

@ -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

View File

@ -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 @@ read_server_config(ServerOptions *options, const char *filename)
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:

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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.

View File

@ -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 .

View File

@ -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.
*/
#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;
#ifdef LOGIN_CAP
shell = login_getcapstr(lc, "shell", shell, 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