summaryrefslogtreecommitdiff
path: root/auth-passwd.c
blob: a08bab3af5eb594feb7ac36f2aebd9e4333872ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/*

auth-passwd.c

Author: Tatu Ylonen <ylo@cs.hut.fi>

Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
                   All rights reserved

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.

*/

#include "includes.h"

#ifndef HAVE_PAM

RCSID("$Id: auth-passwd.c,v 1.5 1999/11/19 04:53:20 damien Exp $");

#include "packet.h"
#include "ssh.h"
#include "servconf.h"
#include "xmalloc.h"
#include "config.h"

#ifdef HAVE_SHADOW_H
#include <shadow.h>
#endif

#ifdef HAVE_MD5_PASSWORDS
#include "md5crypt.h"
#endif

/* Don't need anything from here if we are using PAM */

/* Tries to authenticate the user using password.  Returns true if
   authentication succeeds. */

int auth_password(struct passwd *pw, const char *password)
{
  extern ServerOptions options;
  char *encrypted_password;
#ifdef HAVE_SHADOW_H
  struct spwd *spw;
#endif

  if (pw->pw_uid == 0 && options.permit_root_login == 2)
  {
      /*packet_send_debug("Server does not permit root login with password.");*/
      return 0;
  }

  if (*password == '\0' && options.permit_empty_passwd == 0)
  {
      /*packet_send_debug("Server does not permit empty password login.");*/
      return 0;
  }

  /* deny if no user. */
  if (pw == NULL)
    return 0;

#ifdef SKEY
  if (options.skey_authentication == 1) {
    if (strncasecmp(password, "s/key", 5) == 0) {
      char *skeyinfo = skey_keyinfo(pw->pw_name);
      if(skeyinfo == NULL){
	debug("generating fake skeyinfo for %.100s.", pw->pw_name);
        skeyinfo = skey_fake_keyinfo(pw->pw_name);
      }
      if(skeyinfo != NULL)
        packet_send_debug(skeyinfo);
      /* Try again. */
      return 0;
    }
    else if (skey_haskey(pw->pw_name) == 0 && 
	     skey_passcheck(pw->pw_name, (char *)password) != -1) {
      /* Authentication succeeded. */
      return 1;
    }
    /* Fall back to ordinary passwd authentication. */
  }
#endif

#if defined(KRB4)
  /* Support for Kerberos v4 authentication - Dug Song <dugsong@UMICH.EDU> */
  if (options.kerberos_authentication)
    {
      AUTH_DAT adata;
      KTEXT_ST tkt;
      struct hostent *hp;
      unsigned long faddr;
      char localhost[MAXHOSTNAMELEN];
      char phost[INST_SZ];
      char realm[REALM_SZ];
      int r;
      
      /* Try Kerberos password authentication only for non-root
	 users and only if Kerberos is installed. */
      if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) {

	/* Set up our ticket file. */
	if (!krb4_init(pw->pw_uid)) {
	  log("Couldn't initialize Kerberos ticket file for %s!", pw->pw_name);
	  goto kerberos_auth_failure;
	}
	/* Try to get TGT using our password. */
	r = krb_get_pw_in_tkt((char *)pw->pw_name, "", realm, "krbtgt", realm,
			      DEFAULT_TKT_LIFE, (char *)password);
	if (r != INTK_OK) {
	  packet_send_debug("Kerberos V4 password authentication for %s "
			    "failed: %s", pw->pw_name, krb_err_txt[r]);
	  goto kerberos_auth_failure;
	}
	/* Successful authentication. */
	chown(tkt_string(), pw->pw_uid, pw->pw_gid);
	
	/* Now that we have a TGT, try to get a local "rcmd" ticket to
	   ensure that we are not talking to a bogus Kerberos server. */
	(void) gethostname(localhost, sizeof(localhost));
	(void) strlcpy(phost, (char *)krb_get_phost(localhost), INST_SZ);
	r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);

	if (r == KSUCCESS) {
	  if (!(hp = gethostbyname(localhost))) {
	    log("Couldn't get local host address!");
	    goto kerberos_auth_failure;
	  }
	  memmove((void *)&faddr, (void *)hp->h_addr, sizeof(faddr));

	  /* Verify our "rcmd" ticket. */
	  r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost, faddr, &adata, "");
	  if (r == RD_AP_UNDEC) {
	    /* Probably didn't have a srvtab on localhost. Allow login. */
	    log("Kerberos V4 TGT for %s unverifiable, no srvtab installed? "
		"krb_rd_req: %s", pw->pw_name, krb_err_txt[r]);
	  }
	  else if (r != KSUCCESS) {
	    log("Kerberos V4 %s ticket unverifiable: %s",
		KRB4_SERVICE_NAME, krb_err_txt[r]);
	    goto kerberos_auth_failure;
	  }
	}
	else if (r == KDC_PR_UNKNOWN) {
	  /* Allow login if no rcmd service exists, but log the error. */
	  log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s "
	      "not registered, or srvtab is wrong?", pw->pw_name,
	      krb_err_txt[r], KRB4_SERVICE_NAME, phost);
	}
	else {
	  /* TGT is bad, forget it. Possibly spoofed! */
	  packet_send_debug("WARNING: Kerberos V4 TGT possibly spoofed for"
			    "%s: %s", pw->pw_name, krb_err_txt[r]);
	  goto kerberos_auth_failure;
	}
	
	/* Authentication succeeded. */
	return 1;
	
      kerberos_auth_failure:
	krb4_cleanup_proc(NULL);
	
	if (!options.kerberos_or_local_passwd)
	  return 0;
      }
      else {
	/* Logging in as root or no local Kerberos realm. */
	packet_send_debug("Unable to authenticate to Kerberos.");
      }
      /* Fall back to ordinary passwd authentication. */
    }
#endif /* KRB4 */
  
  /* Check for users with no password. */
  if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0)
    {
      packet_send_debug("Login permitted without a password because the account has no password.");
      return 1; /* The user has no password and an empty password was tried. */
    }

#ifdef HAVE_SHADOW_H
  spw = getspnam(pw->pw_name);
  if (spw == NULL)
    return(0);

  if ((spw->sp_namp == NULL) || (strcmp(pw->pw_name, spw->sp_namp) != 0))
    fatal("Shadow lookup returned garbage.");

  if (strlen(spw->sp_pwdp) < 3)
    return(0);

  /* Encrypt the candidate password using the proper salt. */
#ifdef HAVE_MD5_PASSWORDS
  if (is_md5_salt(spw->sp_pwdp))
    encrypted_password = md5_crypt(password, spw->sp_pwdp);
  else
    encrypted_password = crypt(password, spw->sp_pwdp);
#else /* HAVE_MD5_PASSWORDS */    
  encrypted_password = crypt(password, spw->sp_pwdp);
#endif /* HAVE_MD5_PASSWORDS */    

  /* Authentication is accepted if the encrypted passwords are identical. */
  return (strcmp(encrypted_password, spw->sp_pwdp) == 0);
#else /* !HAVE_SHADOW_H */

  /* Encrypt the candidate password using the proper salt. */
  encrypted_password = crypt(password, 
			     (pw->pw_passwd[0] && pw->pw_passwd[1]) ?
			     pw->pw_passwd : "xx");
  /* Authentication is accepted if the encrypted passwords are identical. */
  return (strcmp(encrypted_password, pw->pw_passwd) == 0);
#endif /* !HAVE_SHADOW_H */
}

#endif /* !HAVE_PAM */