source: trunk/third/ssh/auth-passwd.c @ 12648

Revision 12648, 27.3 KB checked in by danw, 26 years ago (diff)
merge changes
Line 
1/*
2
3auth-passwd.c
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8                   All rights reserved
9
10Created: Sat Mar 18 05:11:38 1995 ylo
11
12Password authentication.  This file contains the functions to check whether
13the password is valid for the user.
14
15*/
16
17/*
18 * $Id: auth-passwd.c,v 1.14 1999-03-08 18:20:01 danw Exp $
19 * $Log: not supported by cvs2svn $
20 * Revision 1.13  1998/12/31 23:53:20  ghudson
21 * Revert 1.11.  We have a krb5 master KDC now, so we don't need to
22 * prefer krb4 reuslts.
23 *
24 * Revision 1.12  1998/08/03 21:49:57  danw
25 * don't free saved_pw_name and saved_pw_passwd until krb4 auth has
26 * succeeded.
27 *
28 * Revision 1.11  1998/05/14 19:23:39  danw
29 * Deal with potential krb5/krb4 password skew (by ignoring errors when
30 * getting krb5 tickets)
31 *
32 * Revision 1.10  1998/05/13 20:18:46  danw
33 * merge in changes from 1.2.23
34 *
35 * Revision 1.9  1998/04/09 22:51:45  ghudson
36 * Support local accounts as determined by libal.
37 *
38 * Revision 1.8  1998/03/08 17:52:01  danw
39 * From nathanw: use same krb5 options (proxy+forward) as other programs.
40 * Use krb_set_tkt_string before get_pw_in_tkt in case the krb4 lib has
41 * already cached another ticket location (while trying to do ticket forwarding,
42 * for example)
43 *
44 * Revision 1.7  1998/01/24 01:47:21  danw
45 * merge in changes for 1.2.22
46 *
47 * Revision 1.6  1998/01/09 22:57:55  danw
48 * fix krb4 ticket lifetime bug
49 *
50 * Revision 1.5  1997/11/19 20:52:24  danw
51 * small security fix (originally from Matt Power)
52 *
53 * Revision 1.4  1997/11/19 20:44:43  danw
54 * do chown later
55 *
56 * Revision 1.3  1997/11/15 00:04:13  danw
57 * Use atexit() functions to destroy tickets and call al_acct_revert.
58 * Work around Solaris lossage with libucb and grantpt.
59 *
60 * Revision 1.2  1997/11/12 21:16:09  danw
61 * Athena-login changes (including some krb4 stuff)
62 *
63 * Revision 1.1.1.1  1997/10/17 22:26:01  danw
64 * Import of ssh 1.2.21
65 *
66 * Revision 1.1.1.2  1998/01/24 01:25:19  danw
67 * Import of ssh 1.2.22
68 *
69 * Revision 1.1.1.3  1998/05/13 19:11:11  danw
70 * Import of ssh 1.2.23
71 *
72 * Revision 1.1.1.4  1999/03/08 17:43:03  danw
73 * Import of ssh 1.2.26
74 *
75 * Revision 1.19  1998/07/08 01:44:46  kivinen
76 *      Added one missing space.
77 *
78 * Revision 1.18  1998/07/08 00:36:44  kivinen
79 *      Changed to use PASSWD_PATH. Better HPUX TCB AUTH support.
80 *
81 * Revision 1.17  1998/06/11 00:03:38  kivinen
82 *      Added username to /bin/password commands.
83 *
84 * Revision 1.16  1998/05/23  20:19:40  kivinen
85 *      Removed #define uint32 rpc_unt32, because md5 uint32 is now
86 *      md5_uint32. Changed () -> (void). Changed osf1c2_getprpwent
87 *      function to return true/false. Added
88 *      forced_empty_passwd_change support.
89 *
90 * Revision 1.15  1998/05/11  21:27:47  kivinen
91 *      Set correct_passwd to contain 255...255 so even if some
92 *      function doesn't set it, it cannot contain empty password.
93 *
94 * Revision 1.14  1998/04/30 01:50:20  kivinen
95 *      Added code that will force /bin/passwd command if password is
96 *      expired.
97 *
98 * Revision 1.13  1998/03/27 16:53:09  kivinen
99 *      Added aix authenticate function support.
100 *
101 * Revision 1.12  1998/01/02 06:14:31  kivinen
102 *      Fixed kerberos ticket name handling. Added OSF C2 account
103 *      locking and expiration support.
104 *
105 * Revision 1.11  1997/04/17 03:57:05  kivinen
106 *      Kept FILE: prefix in kerberos ticket filename as DCE cache
107 *      code requires it (patch from Doug Engert <DEEngert@anl.gov>).
108 *
109 * Revision 1.10  1997/04/05 21:45:25  kivinen
110 *      Changed verify_krb_v5_tgt to take *error_code instead of
111 *      error_code.
112 *
113 * Revision 1.9  1997/03/27 03:09:20  kivinen
114 *      Added kerberos patches from Glenn Machin.
115 *
116 * Revision 1.8  1997/03/26 06:59:18  kivinen
117 *      Changed uid 0 to UID_ROOT.
118 *
119 * Revision 1.7  1997/03/19 15:57:21  kivinen
120 *      Added SECURE_RPC, SECURE_NFS and NIS_PLUS support from Andy
121 *      Polyakov <appro@fy.chalmers.se>.
122 *
123 * Revision 1.6  1996/10/30 04:22:43  kivinen
124 *      Added #ifdef HAVE_SHADOW_H around shadow.h including.
125 *
126 * Revision 1.5  1996/10/29 22:33:59  kivinen
127 *      log -> log_msg.
128 *
129 * Revision 1.4  1996/10/08 13:50:44  ttsalo
130 *      Allow long passwords for HP-UX TCB authentication
131 *
132 * Revision 1.3  1996/09/08 17:36:51  ttsalo
133 *      Patches for HPUX 10.x shadow passwords from
134 *      vincent@ucthpx.uct.ac.za (Russell Vincent) merged.
135 *
136 * Revision 1.2  1996/02/18 21:53:45  ylo
137 *      Test for HAVE_ULTRIX_SHADOW_PASSWORDS instead of ultrix
138 *      (mips-dec-mach3 has ultrix defined, but does not support the
139 *      shadow password stuff).
140 *
141 * Revision 1.1.1.1  1996/02/18 21:38:12  ylo
142 *      Imported ssh-1.2.13.
143 *
144 * Revision 1.8  1995/09/27  02:10:34  ylo
145 *      Added support for SCO unix shadow passwords.
146 *
147 * Revision 1.7  1995/09/10  22:44:41  ylo
148 *      Added OSF/1 C2 extended security stuff.
149 *
150 * Revision 1.6  1995/08/21  23:20:29  ylo
151 *      Fixed a typo.
152 *
153 * Revision 1.5  1995/08/19  13:15:56  ylo
154 *      Changed securid code to initialize itself only once.
155 *
156 * Revision 1.4  1995/08/18  22:42:51  ylo
157 *      Added General Dynamics SecurID support from Donald McKillican
158 *      <dmckilli@qc.bell.ca>.
159 *
160 * Revision 1.3  1995/07/13  01:12:34  ylo
161 *      Removed the "Last modified" header.
162 *
163 * Revision 1.2  1995/07/13  01:09:50  ylo
164 *      Added cvs log.
165 *
166 * $Endlog$
167 */
168
169#include "includes.h"
170#ifdef HAVE_SCO_ETC_SHADOW
171# include <sys/security.h>
172# include <sys/audit.h>
173# include <prot.h>
174#else /* HAVE_SCO_ETC_SHADOW */
175#ifdef HAVE_HPUX_TCB_AUTH
176# include <sys/types.h>
177# include <hpsecurity.h>
178# include <prot.h>
179#else /* HAVE_HPUX_TCB_AUTH */
180#ifdef HAVE_ETC_SHADOW
181#ifdef HAVE_SHADOW_H
182#include <shadow.h>
183#endif
184#endif /* HAVE_ETC_SHADOW */
185#endif /* HAVE_HPUX_TCB_AUTH */
186#endif /* HAVE_SCO_ETC_SHADOW */
187#ifdef HAVE_ETC_SECURITY_PASSWD_ADJUNCT
188#include <sys/label.h>
189#include <sys/audit.h>
190#include <pwdadj.h>
191#endif /* HAVE_ETC_SECURITY_PASSWD_ADJUNCT */
192#ifdef HAVE_ULTRIX_SHADOW_PASSWORDS
193#include <auth.h>
194#include <sys/svcinfo.h>
195#endif /* HAVE_ULTRIX_SHADOW_PASSWORDS */
196#include "packet.h"
197#include "ssh.h"
198#include "servconf.h"
199#include "xmalloc.h"
200
201extern int al_local_acct;
202
203#ifdef SECURE_RPC
204/*
205 * refer to ftp://playground.sun.com/pub/rpc/tirpcsrc2.3.tar.Z for
206 * detailed information about stuff you can't find in manual pages:-)
207 */
208#ifdef KEYBYTES
209#undef KEYBYTES       /* conflicts with blowfish.h */
210#endif
211
212#include <rpc/rpc.h>
213#include <rpc/key_prot.h>
214
215static uid_t uid_keylogged = 0;
216
217#ifdef SECURE_NFS
218#include <nfs/export.h>
219#include <nfs/nfs.h>
220#include <nfs/nfssys.h>
221
222void nfs_revauth(uid_t uid)
223{
224  struct nfs_revauth_args _nfssysarg;
225 
226  _nfssysarg.authtype = AUTH_DES;
227  _nfssysarg.uid      = uid;
228  _nfssys (NFS_REVAUTH,&_nfssysarg);
229}
230#endif /* SECURE_NFS */
231
232/* do /usr/bin/keylogout's job */
233/* caller sets effective uid!  */
234void keylogout(void)
235{
236  char secret [HEXKEYBYTES];
237 
238  if (!uid_keylogged || uid_keylogged != geteuid())
239    return;
240 
241  /* revoke secret key from keyserv(1m) */
242  memset(secret, '\0', sizeof(secret));
243  key_setsecret(secret);     /* this one is keyserv.1 interface,
244                                but it does the job even for keyserv.2
245                                and takes the only argument:-) */
246#ifdef SECURE_NFS
247  /* as well as from nfs client module */
248  nfs_revauth(uid_keylogged);
249#endif /* SECURE_NFS */
250 
251  uid_keylogged = 0;
252}
253
254void keylogout_atexit (void)
255{
256  if (!uid_keylogged || seteuid(uid_keylogged))
257    return;
258  keylogout();
259  seteuid(UID_ROOT);
260}
261
262#ifdef KEY_VERS2      /* keyserv protocol version 2 */
263int my_secretkey_is_set(char *netname)
264{
265  return key_secretkey_is_set();
266}
267#else /* KEY_VERS2 */
268/*
269 * for keyserv.1 we just try to encrypt a session key to talk to ourselves.
270 * this should fail if keyserv doesn't have our secret key. well, we can't
271 * say if it's the right one, but we can't do any better anyway:-)
272 */
273int my_secretkey_is_set(char *netname)
274{
275  des_block block;
276  memcpy (block.c, netname, sizeof(block.c));   /* well, whatever... */
277  return (key_encryptsession(netname, &block) == 0);
278}
279#endif /* KEY_VERS2 */
280
281/* do /usr/bin/keylogin's job */
282/* caller sets effective uid! */
283int keylogin(const char *passwd)
284{
285  int  ret = 0;
286  char netnam[MAXNETNAMELEN+1], phrase[9];
287#ifdef KEY_VERS2
288  key_netstarg key_setnet_arg;
289#define secret key_setnet_arg.st_priv_key
290#define public key_setnet_arg.st_pub_key
291  key_setnet_arg.st_netname = netnam;
292#else /* KEY_VERS2 */
293  char secret[HEXKEYBYTES], public[HEXKEYBYTES];
294#endif /* KEY_VERS2 */
295 
296  if (getnetname(netnam) &&     /* do i exists?            */
297      !(ret = my_secretkey_is_set(netnam)) && /* is it already set?      */
298      passwd)                   /* do i have the password? */
299    {
300      strncpy(phrase, passwd, 8);
301      phrase[8] = '\0';
302      memset(public, '\0', sizeof(public));
303      memset(secret, '\0', sizeof(secret));
304      if (getsecretkey(netnam, secret, phrase) && *secret)
305        {
306#ifdef KEY_VERS2
307          /*
308           * key_setnet is keyserv.2 interface and is not documented,
309           * but used by keylogin(1). and it's real mess with return
310           * values:-( so far, namely up to Solaris 2.5.1, it returns
311           * 1 on success and -1 when fails.
312           */
313          if (ret = (key_setnet(&key_setnet_arg) > 0))
314#else /* KEY_VERS2 */
315          if (ret = !key_setsecret(secret))
316#endif /* KEY_VERS2 */
317            {
318              uid_keylogged = geteuid(); /* save it for keylogout */
319              atexit(keylogout_atexit); /* clean up after ourselves */
320            }
321          memset(secret, '\0', sizeof (secret));
322        }
323      memset(phrase, '\0', sizeof(phrase));
324    }
325  return ret; /* secret key was set by whomever */
326}
327#endif /* SECURE_RPC */
328
329#ifdef HAVE_SECURID
330/* Support for Security Dynamics SecurID card.
331   Contributed by Donald McKillican <dmckilli@qc.bell.ca>. */
332#define SECURID_USERS "/etc/securid.users"
333#include "sdi_athd.h"
334#include "sdi_size.h"
335#include "sdi_type.h"
336#include "sdacmvls.h"
337#include "sdconf.h"
338union config_record configure;
339static int securid_initialized = 0;
340#endif /* HAVE_SECURID */
341
342#ifdef KERBEROS
343#if defined(KRB5)
344#include <krb5.h>
345extern  krb5_context ssh_context;
346extern  krb5_auth_context auth_context;
347extern  int havecred;
348void    krb_cleanup(void);
349#else
350#include <krb.h>
351#endif /* KRB5 */
352#endif /* KERBEROS */
353
354#ifdef AFS
355#include <afs/param.h>
356#include <afs/kautils.h>
357#endif /* AFS */
358
359#if defined(KERBEROS) || defined(AFS_KERBEROS)
360extern char *ticket;
361#endif /* KERBEROS || AFS_KERBEROS */
362
363/* Tries to authenticate the user using password.  Returns true if
364   authentication succeeds. */
365
366#if defined(KERBEROS) && defined(KRB5)
367/*
368 * This routine with some modification is from the MIT V5B6 appl/bsd/login.c
369 *
370 * Verify the Kerberos ticket-granting ticket just retrieved for the
371 * user.  If the Kerberos server doesn't respond, assume the user is
372 * trying to fake us out (since we DID just get a TGT from what is
373 * supposedly our KDC).  If the host/<host> service is unknown (i.e.,
374 * the local keytab doesn't have it), let her in.
375 *
376 * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
377 */
378static
379int verify_krb_v5_tgt (krb5_context c, krb5_ccache ccache,
380                       krb5_error_code *error_code)
381{
382  char phost[BUFSIZ];
383  int retval, have_keys;
384  krb5_principal princ;
385  krb5_keyblock *kb = 0;
386  krb5_error_code krbval;
387  krb5_data packet;
388  krb5_auth_context auth_context = NULL;
389  krb5_ticket *ticket = NULL;
390 
391  /* Set packet.data so that we do not free bogus memory below */
392  packet.data = 0;
393 
394  /* get the server principal for the local host */
395  /* (use defaults of "host" and canonicalized local name) */
396  krbval = krb5_sname_to_principal(c, 0, 0, KRB5_NT_SRV_HST, &princ);
397  if (krbval)
398    {
399      *error_code = krbval;
400      return -1;
401    }
402 
403  /* since krb5_sname_to_principal has done the work for us, just
404     extract the name directly */
405  strncpy(phost, krb5_princ_component(c, princ, 1)->data, BUFSIZ);
406  phost[BUFSIZ - 1] = '\0';
407 
408  /* Do we have host/<host> keys? */
409  /* (use default keytab, kvno IGNORE_VNO to get the first match,
410     and enctype is currently ignored anyhow.) */
411  krbval = krb5_kt_read_service_key (c, NULL, princ, 0,
412                                     ENCTYPE_DES_CBC_CRC, &kb);
413  if (kb)
414    krb5_free_keyblock (c, kb);
415  /* any failure means we don't have keys at all. */
416  have_keys = krbval ? 0 : 1;
417 
418  /* talk to the kdc and construct the ticket */
419  krbval = krb5_mk_req(c, &auth_context, 0, "host", phost,
420                       0, ccache, &packet);
421  /* wipe the auth context for mk_req */
422  if (auth_context)
423    {
424      krb5_auth_con_free(c, auth_context);
425      auth_context = NULL;
426    }
427  if (krbval == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
428    {
429      /* we have a service key, so something should be
430         in the database, therefore this error packet could
431         have come from an attacker. */
432      if (have_keys)
433        {
434          retval = -1;
435          goto EGRESS;
436        }
437      /* but if it is unknown and we've got no key, we don't
438         have any security anyhow, so it is ok. */
439      else
440        {
441          retval = 0;
442          goto EGRESS;
443        }
444    }
445  else
446    if (krbval)
447      {
448        *error_code = krbval;
449        retval = -1;
450        goto EGRESS;
451      }
452  /* got ticket, try to use it */
453  krbval = krb5_rd_req(c, &auth_context, &packet,
454                       princ, NULL, NULL, &ticket);
455 
456 
457  if (krbval)
458    {
459      if (!have_keys)
460        /* The krb5 errors aren't specified well, but I think
461           these values cover the cases we expect.  */
462        switch (krbval)
463          {
464            /* no keytab */
465          case KRB5_KT_NOTFOUND:
466          case ENOENT:
467            /* keytab found, missing entry */
468            retval = 0;
469            break;
470          default:
471            /* unexpected error: fail */
472            retval = -1;
473            break;
474          }
475      else
476        /* Any error here is bad.  */
477        retval = -1;
478      *error_code = krbval;
479      goto EGRESS;
480    }
481  /*
482   * The host/<host> ticket has been received _and_ verified.
483   */
484  retval = 1;
485  /* do cleanup and return */
486EGRESS:
487  if (auth_context)
488    krb5_auth_con_free(c, auth_context);
489  if (ticket)
490    krb5_free_ticket(c, ticket);
491  if (packet.data)
492    {
493      free(packet.data);
494      packet.data = 0;
495    }
496  krb5_free_principal(c, princ);
497  /* possibly ticket and packet need freeing here as well */
498  /* memset (&ticket, 0, sizeof (ticket)); */
499  return retval;
500}
501
502krb5_data tgtname = {
503  0,
504  KRB5_TGS_NAME_SIZE,
505  KRB5_TGS_NAME
506};
507
508/*
509 * Preauthentication types should be listed prior to 0.
510 * The last one tried will be no preauthentication
511 * Type 5 is compatible with DCE timestamp
512 * Type 2 is MIT current timestamp implementation
513 */
514#ifdef KRB5_PADATA_ENC_UNIX_TIME
515krb5_preauthtype preauth_list[3] = { KRB5_PADATA_ENC_UNIX_TIME,
516                                     KRB5_PADATA_ENC_TIMESTAMP,
517                                     0 };
518#else
519krb5_preauthtype preauth_list[2] = { KRB5_PADATA_ENC_TIMESTAMP,
520                                     0 };
521#endif
522krb5_preauthtype * preauth = preauth_list;
523#endif /* KERBEROS */
524
525/* Tries to authenticate the user using password.  Returns true if
526   authentication succeeds. */
527#ifdef KERBEROS
528int auth_password(const char *server_user, const char *password,
529                  krb5_principal client)
530#else  /* KERBEROS */
531int auth_password(const char *server_user, const char *password)
532#endif /* KERBEROS */
533{
534#if defined(_AIX) && defined(HAVE_AUTHENTICATE)
535  char *message;
536  int reenter;
537
538  reenter = 1;
539  if (authenticate(server_user, password, &reenter, &message) == 0)
540    {
541      return 1;
542    }
543  else
544    {
545      return 0;
546    }
547#else /* _AIX41 && HAVE_AUTHENTICATE */
548
549#ifdef KERBEROS
550  krb5_error_code problem;
551  int krb5_options = KDC_OPT_PROXIABLE | KDC_OPT_FORWARDABLE;
552  krb5_deltat rlife = 0;
553  krb5_principal server = 0;
554  krb5_creds my_creds;
555  krb5_timestamp now;
556  krb5_ccache ccache;
557  char ccname[80], krbtkfile[80], krbtkenv[80];
558  int results, status;
559#endif  /* KERBEROS */
560  extern ServerOptions options;
561  extern char *crypt(const char *key, const char *salt);
562  struct passwd *pw;
563  char *encrypted_password;
564  char correct_passwd[200];
565  char *saved_pw_name, *saved_pw_passwd;
566
567  memset(correct_passwd, 255, sizeof(correct_passwd));
568  if (*password == '\0' && options.permit_empty_passwd == 0)
569  {
570      packet_send_debug("Server does not permit empty password login.");
571      return 0;
572  }
573
574  /* Get the encrypted password for the user. */
575  pw = getpwnam(server_user);
576  if (!pw)
577    return 0;
578  saved_pw_name = xstrdup(pw->pw_name);
579  saved_pw_passwd = xstrdup(pw->pw_passwd);
580 
581#if defined(KERBEROS)
582  if (options.kerberos_authentication && !al_local_acct)
583    {
584#if defined(KRB5)
585      sprintf(ccname, "FILE:/tmp/krb5cc_l%d", getpid());
586     
587      if (problem = krb5_cc_resolve(ssh_context, ccname, &ccache))
588        goto errout2;
589     
590      if (problem = krb5_cc_initialize(ssh_context, ccache, client))
591        goto errout;
592     
593      problem =
594        krb5_build_principal_ext(ssh_context, &server,
595                                 krb5_princ_realm(ssh_context, client)->length,
596                                 krb5_princ_realm(ssh_context, client)->data,
597                                 tgtname.length, tgtname.data,
598                                 krb5_princ_realm(ssh_context, client)->length,
599                                 krb5_princ_realm(ssh_context, client)->data,
600                                 0);
601      if (problem)
602        goto errout;
603     
604      memset(&my_creds, 0, sizeof(my_creds));
605      my_creds.client = client;
606      my_creds.server = server;
607      problem = krb5_timeofday(ssh_context, &now);
608      if (problem)
609        goto errout;
610      my_creds.times.starttime = 0; /* start timer when
611                                       request gets to KDC */
612      my_creds.times.endtime = now + 60*60*10;   /* 10 hours */
613     
614      problem = krb5_string_to_deltat("7d", &rlife); /* 7 days renew time */
615      if (problem || rlife == 0)
616        goto errout;
617     
618      my_creds.times.renew_till = now + rlife;
619     
620     
621      problem = krb5_get_in_tkt_with_password(ssh_context, krb5_options, 0,
622                                              NULL, preauth,
623                                              password, ccache,
624                                              &my_creds, 0);
625     
626      /* If not successful try no preauthentication */
627      if (problem)
628        problem = krb5_get_in_tkt_with_password(ssh_context,
629                                                krb5_options, 0,
630                                                NULL, 0,
631                                                password, ccache,
632                                                &my_creds, 0);
633      krb5_free_principal(ssh_context, server);
634      server = 0;
635      if (problem)
636        goto errout;
637      else
638        {
639          /* Verify tgt just obtained */
640          results = verify_krb_v5_tgt(ssh_context, ccache, &problem);
641         
642          if (results  >= 0)
643            {
644              /* If results is 0 then put out a log message that
645                 the TGT was not verified, pass this back to the
646                 user as well */
647              if (results == 0)
648                {
649                  log_msg("TGT for user %s was not verified.", server_user);
650                  packet_send_debug("Kerberos TGT could not be verified.");
651                }
652             
653            /* get_name pulls out just the name not the
654               type */
655              strcpy(ccname + 5, krb5_cc_get_name(ssh_context, ccache));
656             
657              /* If tgt was passed, destroy it */
658              if (ticket)
659                {
660                  if (strcmp(ticket,"none"))
661                    {
662                      krb5_ccache fwd_ccache;
663
664                      if (!krb5_cc_resolve(ssh_context, ticket, &fwd_ccache))
665                        krb5_cc_destroy(ssh_context, fwd_ccache);
666                      dest_tkt();
667                    }
668                  else
669                    ticket = NULL;
670                }
671             
672              ticket = xmalloc(strlen(ccname) + 1);
673              (void) sprintf(ticket, "%s", ccname);
674             
675              /* Now get v4 tickets */
676              sprintf(krbtkfile, "/tmp/tkt_p%d", getpid());
677              krb_set_tkt_string(krbtkfile);
678
679              status =
680                krb_get_pw_in_tkt(pw->pw_name, "",
681                                  krb5_princ_realm(ssh_context, client)->data,
682                                  "krbtgt",
683                                  krb5_princ_realm(ssh_context, client)->data,
684                                  12*10,  /* 10 hours in 5-minute increments */
685                                  password);
686              if (status)
687                goto errout;
688
689              /* Put the name of the ticket file in the environment
690                 for parts of the login that need it between here
691                 and the environment variable setting code in do_child(). */
692              sprintf(krbtkenv, "KRBTKFILE=%s", krbtkfile);
693              putenv(xstrdup(krbtkenv));
694
695              /* We do not need this so free them up */
696              xfree(saved_pw_name);
697              xfree(saved_pw_passwd);
698             
699              havecred = 1;
700              atexit(krb_cleanup);
701              return 1;
702            }
703          if (problem == KRB5_KT_NOTFOUND)
704            {
705              /* We have potential KDC spoofing here - log it */
706              log_msg("WARNING: Verification of TGT indicates potential KDC spoofing: user %s address %s", server_user, get_remote_ipaddr());
707              packet_send_debug("Verification of TGT indicates potential KDC spoofing.");
708            }
709        }
710    errout:
711      krb5_cc_destroy (ssh_context, ccache);
712      dest_tkt();
713    errout2:
714      if (problem)
715        {
716          log_msg("Password authentication of user %s using Kerberos failed: %s",
717                  server_user, error_message(problem));
718          if (server)
719            krb5_free_principal(ssh_context, server);
720          if (!options.kerberos_or_local_passwd )
721            {
722              /* We do not need this so free them up */
723              xfree(saved_pw_name);
724              xfree(saved_pw_passwd);
725              return 0;
726            }
727        }
728#endif /* KRB5 */
729    }
730#endif /* KERBEROS */
731 
732#ifdef HAVE_SECURID
733  /* Support for Security Dynamics SecurId card.
734     Contributed by Donald McKillican <dmckilli@qc.bell.ca>. */
735  {
736    /*
737     * the way we decide if this user is a securid user or not is
738     * to check to see if they are included in /etc/securid.users
739     */
740    int found = 0;
741    FILE *securid_users = fopen(SECURID_USERS, "r");
742    char *c;
743    char su_user[257];
744   
745    if (securid_users)
746      {
747        while (fgets(su_user, sizeof(su_user), securid_users))
748          {
749            if (c = strchr(su_user, '\n'))
750              *c = '\0';
751            if (strcmp(su_user, server_user) == 0)
752              {
753                found = 1;
754                break;
755              }
756          }
757      }
758    fclose(securid_users);
759
760    if (found)
761      {
762        /* The user has a SecurID card. */
763        struct SD_CLIENT sd_dat, *sd;
764        log_msg("SecurID authentication for %.100s required.", server_user);
765
766        /*
767         * if no pass code has been supplied, fail immediately: passing
768         * a null pass code to sd_check causes a core dump
769         */
770        if (*password == '\0')
771          {
772            log_msg("No pass code given, authentication rejected.");
773            return 0;
774          }
775
776        sd = &sd_dat;
777        if (!securid_initialized)
778          {
779            memset(&sd_dat, 0, sizeof(sd_dat));   /* clear struct */
780            creadcfg();         /*  accesses sdconf.rec  */
781            if (sd_init(sd))
782              packet_disconnect("Cannot contact securid server.");
783            securid_initialized = 1;
784          }
785        return sd_check(password, server_user, sd) == ACM_OK;
786      }
787  }
788  /* If the user has no SecurID card specified, we fall to normal
789     password code. */
790#endif /* HAVE_SECURID */
791
792  /* Save the encrypted password. */
793  strncpy(correct_passwd, saved_pw_passwd, sizeof(correct_passwd));
794
795#ifdef SECURE_RPC
796  /* try to register secret key for secure RPC */
797  seteuid(pw->pw_uid);       /* just let it fail if ran by user */
798  keylogin(password);
799  seteuid(UID_ROOT);                /* just let it fail if ran by user */
800#endif /* SECURE_RPC */
801
802#ifdef HAVE_OSF1_C2_SECURITY
803  if (osf1c2_getprpwent(correct_passwd, saved_pw_name,
804                        sizeof(correct_passwd)))
805    {
806      if (options.forced_passwd_change)
807        {
808          extern char *forced_command;
809          forced_command = xmalloc(sizeof(PASSWD_PATH) +
810                                   strlen(server_user) + 1);
811          sprintf(forced_command, "%s %s", PASSWD_PATH, server_user);
812          packet_send_debug("Password expired, forcing it to be changed.");
813        }
814      else
815        {
816          packet_send_debug("\n\tYour password has expired.");
817        }
818    }
819#else /* HAVE_OSF1_C2_SECURITY */
820  /* If we have shadow passwords, lookup the real encrypted password from
821     the shadow file, and replace the saved encrypted password with the
822     real encrypted password. */
823#if defined(HAVE_SCO_ETC_SHADOW) || defined(HAVE_HPUX_TCB_AUTH)
824  {
825    struct pr_passwd *pr = getprpwnam(saved_pw_name);
826    pr = getprpwnam(saved_pw_name);
827    if (pr)
828      {
829        strncpy(correct_passwd, pr->ufld.fd_encrypt, sizeof(correct_passwd));
830        endprpwent();
831        if ( (!pr->uflg.fg_nullpw || !pr->ufld.fd_nullpw)
832             && !pr->uflg.fg_pw_admin_num
833             && strcmp(correct_passwd,"")==0 )
834          {
835            debug("User %.100s not permitted to login with null passwd",
836                  saved_pw_name);
837            packet_send_debug("\n\tNot permitted null passwd.");
838            return 0;
839          }
840      }
841    else
842      {       
843        endprpwent();
844        return 0;
845      }
846  }
847#else /* defined(HAVE_SCO_ETC_SHADOW) || defined(HAVE_HPUX_TCB_AUTH) */
848#ifdef HAVE_ETC_SHADOW
849  {
850    struct spwd *sp = getspnam(saved_pw_name);
851#if defined(SECURE_RPC) && defined(NIS_PLUS)
852    if (!geteuid() && pw->pw_uid && /* do we have guts? */
853        (!sp || !sp->sp_pwdp || !strcmp(sp->sp_pwdp,"*NP*")))
854      if (seteuid(pw->pw_uid) == UID_ROOT)
855        {
856          sp = getspnam(saved_pw_name); /* retry as user */   
857          seteuid(UID_ROOT);
858        }
859#endif /* SECURE_RPC && NIS_PLUS */
860     if (sp)
861      strncpy(correct_passwd, sp->sp_pwdp, sizeof(correct_passwd));
862    endspent();
863  }
864#else /* HAVE_ETC_SHADOW */
865#ifdef HAVE_ETC_SECURITY_PASSWD_ADJUNCT
866  {
867    struct passwd_adjunct *sp = getpwanam(saved_pw_name);
868    if (sp)
869      strncpy(correct_passwd, sp->pwa_passwd, sizeof(correct_passwd));
870    endpwaent();
871  }
872#else /* HAVE_ETC_SECURITY_PASSWD_ADJUNCT */
873#ifdef HAVE_ETC_SECURITY_PASSWD
874  {
875    FILE *f;
876    char line[1024], looking_for_user[200], *cp;
877    int found_user = 0;
878    f = fopen("/etc/security/passwd", "r");
879    if (f)
880      {
881        sprintf(looking_for_user, "%.190s:", server_user);
882        while (fgets(line, sizeof(line), f))
883          {
884            if (strchr(line, '\n'))
885              *strchr(line, '\n') = 0;
886            if (strcmp(line, looking_for_user) == 0)
887              found_user = 1;
888            else
889              if (line[0] != '\t' && line[0] != ' ')
890                found_user = 0;
891              else
892                if (found_user)
893                  {
894                    for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
895                      ;
896                    if (strncmp(cp, "password = ", strlen("password = ")) == 0)
897                      {
898                        strncpy(correct_passwd, cp + strlen("password = "),
899                                sizeof(correct_passwd));
900                        correct_passwd[sizeof(correct_passwd) - 1] = 0;
901                        break;
902                      }
903                  }
904          }
905        fclose(f);
906      }
907  }
908#endif /* HAVE_ETC_SECURITY_PASSWD */
909#endif /* HAVE_ETC_SECURITY_PASSWD_ADJUNCT */
910#endif /* HAVE_ETC_SHADOW */
911#endif /* HAVE_SCO_ETC_SHADOW */
912#endif /* HAVE_OSF1_C2_SECURITY */
913
914  /* Check for users with no password. */
915  if (strcmp(password, "") == 0 && strcmp(correct_passwd, "") == 0)
916    {
917      if (options.forced_empty_passwd_change)
918        {
919          extern char *forced_command;
920          forced_command = xmalloc(sizeof(PASSWD_PATH) +
921                                   strlen(server_user) + 1);
922          sprintf(forced_command, "%s %s", PASSWD_PATH, server_user);
923          packet_send_debug("Password if forced to be set at first login.");
924        }
925      else
926        {
927          packet_send_debug("Login permitted without a password because the account has no password.");
928        }
929      return 1; /* The user has no password and an empty password was tried. */
930    }
931
932  xfree(saved_pw_name);
933  xfree(saved_pw_passwd);
934
935#ifdef HAVE_ULTRIX_SHADOW_PASSWORDS
936  {
937    /* Note: we are assuming that pw from above is still valid. */
938    struct svcinfo *svp;
939    svp = getsvc();
940    if (svp == NULL)
941      {
942        error("getsvc() failed in ultrix code in auth_passwd");
943        return 0;
944      }
945    if ((svp->svcauth.seclevel == SEC_UPGRADE &&
946         strcmp(pw->pw_passwd, "*") == 0) ||
947        svp->svcauth.seclevel == SEC_ENHANCED)
948      return authenticate_user(pw, password, "/dev/ttypXX") >= 0;
949  }
950#endif /* HAVE_ULTRIX_SHADOW_PASSWORDS */
951
952  /* Encrypt the candidate password using the proper salt. */
953#ifdef HAVE_OSF1_C2_SECURITY
954  encrypted_password = (char *)osf1c2crypt(password,
955                                   (correct_passwd[0] && correct_passwd[1]) ?
956                                   correct_passwd : "xx");
957#else /* HAVE_OSF1_C2_SECURITY */
958#if defined(HAVE_SCO_ETC_SHADOW) || defined(HAVE_HPUX_TCB_AUTH)
959  encrypted_password = bigcrypt(password,
960                             (correct_passwd[0] && correct_passwd[1]) ?
961                             correct_passwd : "xx");
962#else /* defined(HAVE_SCO_ETC_SHADOW) || defined(HAVE_HPUX_TCB_AUTH) */
963  encrypted_password = crypt(password,
964                             (correct_passwd[0] && correct_passwd[1]) ?
965                             correct_passwd : "xx");
966#endif /* HAVE_SCO_ETC_SHADOW */
967#endif /* HAVE_OSF1_C2_SECURITY */
968
969  /* Authentication is accepted if the encrypted passwords are identical. */
970  return strcmp(encrypted_password, correct_passwd) == 0;
971#endif /* _AIX && HAVE_AUTHENTICATE */
972}
Note: See TracBrowser for help on using the repository browser.