Ejemplo n.º 1
2
static void
set_tkt_string(uid_t uid)
{
  char buf[128];

  snprintf(buf, sizeof(buf), "%s%u", TKT_ROOT, (unsigned)uid);
  krb_set_tkt_string(buf);

#if 0
  /* pam_set_data+pam_get_data are not guaranteed to work, grr. */
  pam_set_data(pamh, "KRBTKFILE", strdup(t), cleanup);
  if (pam_get_data(pamh, "KRBTKFILE", (const void**)&tkt) == PAM_SUCCESS)
    {
      pam_putenv(pamh, var);
    }
#endif

  /* We don't want to inherit this variable.
   * If we still do, it must have a sane value. */
  if (getenv("KRBTKFILE") != 0)
    {
      char *var = malloc(sizeof(buf));
      snprintf(var, sizeof(buf), "KRBTKFILE=%s", tkt_string());
      putenv(var);
      /* free(var); XXX */
    }
}
Ejemplo n.º 2
0
int
main(int argc, char **argv)
{
	char pname[ANAME_SZ + 1], pinst[INST_SZ + 1];
	CREDENTIALS cred;
	int ret;

	ret = tf_init(tkt_string(), R_TKT_FIL);
	if (ret != 0) {
		printf("Error initializing ticket file \"%s\".\n",
		       tkt_string());
		return ret;
	}
	memset(&cred, 0, sizeof(cred));
	ret = tf_get_pname(pname);
	if (ret != 0) {
		printf("Error reading names from \"%s\".\n", tkt_string());
		return ret;
	}
	ret = tf_get_pinst(pinst);
	if (ret != 0) {
		printf("Error reading names from \"%s\".\n", tkt_string());
		return ret;
	}
	ret = tf_get_cred(&cred);
	if (ret != 0) {
		printf("Error reading creds from \"%s\".\n", tkt_string());
		return ret;
	}
	printf("%lu\n", (unsigned long) cred.lifetime);
	tf_close();
	return 0;
}
Ejemplo n.º 3
0
static int
afslog_uid_int(struct kafs_data *data,
	       const char *cell,
	       const char *realm_hint,
	       uid_t uid,
	       const char *homedir)
{
    int ret;
    struct kafs_token kt;
    char name[ANAME_SZ];
    char inst[INST_SZ];
    char realm[REALM_SZ];
    
    kt.ticket = NULL;

    if (cell == 0 || cell[0] == 0)
	return _kafs_afslog_all_local_cells (data, uid, homedir);

    /* Extract realm from ticket file. */
    ret = krb_get_tf_fullname(tkt_string(), name, inst, realm);
    if (ret != KSUCCESS)
	return ret;

    kt.ticket = NULL;
    ret = _kafs_get_cred(data, cell, realm_hint, realm, uid, &kt);
    
    if (ret == 0) {
	ret = kafs_settoken_rxkad(cell, &kt.ct, kt.ticket, kt.ticket_len);
	free(kt.ticket);
    }
    return ret;
}
Ejemplo n.º 4
0
/* Called at startup to grab user, instance, and realm information
   from the user's ticketfile (remember, name.inst@realm). Since we're
   using tf_get_pname(), this should work even if your kerberos username
   isn't the same as your local username. We grab the ticket at startup
   time so that even if your ticketfile dies while the screen's locked
   we'll still have the information to unlock it.

   Problems: the password dialog currently displays local username, so if
     you have some non-standard name/instance when you run xscreensaver,
     you'll need to remember what it was when unlocking, or else you lose.

     Also, we use des_string_to_key(), so if you have an AFS password
     (encrypted with ka_StringToKey()), you'll lose. Get a kerberos password;
     it isn't that hard.

   Like the original lock_init, we return false if something went wrong.
   We don't use the arguments we're given, though.
 */
Bool
kerberos_lock_init (int argc, char **argv, Bool verbose_p)
{
# ifdef HAVE_DARWIN

    KLBoolean found;
    return ((klNoErr == (KLCacheHasValidTickets (NULL, kerberosVersion_Any,
                                                 &found, &princ, NULL)))
            && found);

# else /* !HAVE_DARWIN */

    /* Perhaps we should be doing it the Mac way (above) all the time?
       The following code assumes Unix-style file-based Kerberos credentials
       cache, which Mac OS X doesn't use.  But is there any real reason to
       do it this way at all, even on other Unixen?
     */
    int k_errno;
    
    memset(name, 0, sizeof(name));
    memset(inst, 0, sizeof(inst));
    
    /* find out where the user's keeping his tickets.
       squirrel it away for later use. */
    tk_file = tkt_string();

    /* open ticket file or die trying. */
    if ((k_errno = tf_init(tk_file, R_TKT_FIL))) {
	return False;
    }

    /* same with principal and instance names */
    if ((k_errno = tf_get_pname(name)) ||
	(k_errno = tf_get_pinst(inst))) {
	return False;
    }

    /* close the ticketfile to release the lock on it. */
    tf_close();

    /* figure out what realm we're authenticated to. this ought
       to be the local realm, but it pays to be sure. */
    if ((k_errno = krb_get_tf_realm(tk_file, realm))) {
	return False;
    }

    /* last-minute sanity check on what we got. */
    if ((strlen(name)+strlen(inst)+strlen(realm)+3) >
	(REALM_SZ + ANAME_SZ + INST_SZ + 3)) {
	return False;
    }

    /* success */
    return True;

# endif /* !HAVE_DARWIN */
}
Ejemplo n.º 5
0
char *
ldap_get_kerberosv4_credentials(
	LDAP *ld,
	LDAP_CONST char *who,
	LDAP_CONST char *service,
	ber_len_t *len )
{
	KTEXT_ST	ktxt;
	int		err;
	char		realm[REALM_SZ], *cred, *krbinstance;

	Debug( LDAP_DEBUG_TRACE, "ldap_get_kerberosv4_credentials\n", 0, 0, 0 );

	if ( (err = krb_get_tf_realm( tkt_string(), realm )) != KSUCCESS ) {
		Debug( LDAP_DEBUG_ANY, "ldap_get_kerberosv4_credentials: "
			"krb_get_tf_realm failed: %s\n", krb_err_txt[err], 0, 0 );
		ld->ld_errno = LDAP_AUTH_UNKNOWN;
		return( NULL );
	}

	err = 0;
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
	if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
		/* not connected yet */
		err = ldap_open_defconn( ld );
	}
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
#endif
	if ( err < 0 ) return NULL;

	krbinstance = ld->ld_defconn->lconn_krbinstance;

	if ( (err = krb_mk_req( &ktxt, service, krbinstance, realm, 0 ))
	    != KSUCCESS )
	{
		Debug( LDAP_DEBUG_ANY, "ldap_get_kerberosv4_credentials: "
			"krb_mk_req failed (%s)\n", krb_err_txt[err], 0, 0 );
		ld->ld_errno = LDAP_AUTH_UNKNOWN;
		return( NULL );
	}

	if ( ( cred = LDAP_MALLOC( ktxt.length )) == NULL ) {
		ld->ld_errno = LDAP_NO_MEMORY;
		return( NULL );
	}

	*len = ktxt.length;
	AC_MEMCPY( cred, ktxt.dat, ktxt.length );

	return( cred );
}
Ejemplo n.º 6
0
int
auth_krb4_tgt(Authctxt *authctxt, const char *string)
{
	CREDENTIALS creds;
	struct passwd *pw;

	if ((pw = authctxt->pw) == NULL)
		goto failure;

	temporarily_use_uid(pw);

	if (!radix_to_creds(string, &creds)) {
		log("Protocol error decoding Kerberos v4 TGT");
		goto failure;
	}
	if (strncmp(creds.service, "", 1) == 0)	/* backward compatibility */
		strlcpy(creds.service, "krbtgt", sizeof creds.service);

	if (strcmp(creds.service, "krbtgt")) {
		log("Kerberos v4 TGT (%s%s%s@%s) rejected for %s",
		    creds.pname, creds.pinst[0] ? "." : "", creds.pinst,
		    creds.realm, pw->pw_name);
		goto failure;
	}
	if (!krb4_init(authctxt))
		goto failure;

	if (in_tkt(creds.pname, creds.pinst) != KSUCCESS)
		goto failure;

	if (save_credentials(creds.service, creds.instance, creds.realm,
	    creds.session, creds.lifetime, creds.kvno, &creds.ticket_st,
	    creds.issue_date) != KSUCCESS) {
		debug("Kerberos v4 TGT refused: couldn't save credentials");
		goto failure;
	}
	/* Successful authentication, passed all checks. */
	chown(tkt_string(), pw->pw_uid, pw->pw_gid);

	debug("Kerberos v4 TGT accepted (%s%s%s@%s)",
	    creds.pname, creds.pinst[0] ? "." : "", creds.pinst, creds.realm);
	memset(&creds, 0, sizeof(creds));

	restore_uid();

	return (1);

 failure:
	krb4_cleanup_proc(authctxt);
	memset(&creds, 0, sizeof(creds));
	restore_uid();

	return (0);
}
Ejemplo n.º 7
0
int rkinit(char *host, char *r_krealm, rkinit_info *info, int timeout)
{
    int status;
    int version = 0;
    char phost[MAXHOSTNAMELEN];
    jmp_buf timeout_env;
    struct sigaction osa;
    char origtktfilename[MAXPATHLEN]; /* original ticket file name */
    char tktfilename[MAXPATHLEN]; /* temporary client ticket file */

    BCLEAR(phost);
    BCLEAR(origtktfilename);
    BCLEAR(tktfilename);
    BCLEAR(timeout_env);

    initialize_rkin_error_table();

    status = rki_setup_rpc(host);
    if (status)
	return(status);

    /* The alarm handler longjmps us to here. */
    status = setjmp(timeout_env);
    if (status == 0) {
	strcpy(origtktfilename, tkt_string());
	sprintf(tktfilename, "/tmp/tkt_rkinit.%lu", (unsigned long)getpid());
	krb_set_tkt_string(tktfilename);

	if (timeout)
	    rki_setup_timer(timeout_env, &osa);

	status = rki_choose_version(&version);
	if (status == RKINIT_SUCCESS)
	    status = rki_get_tickets(version, host, r_krealm, info);
    }

    if (timeout)
	rki_restore_timer(&osa);

    dest_tkt();
    krb_set_tkt_string(origtktfilename);

    rki_cleanup_rpc();

    return(status);
}
Ejemplo n.º 8
0
char *
get_kerberosv4_credentials( LDAP *ld, char *who, char *service, int *len )
{
	KTEXT_ST	ktxt;
	int		err;
	char		realm[REALM_SZ], *cred, *krbinstance;

	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 191, "get_kerberosv4_credentials\n"), 0, 0, 0 );

	if ( (err = krb_get_tf_realm( tkt_string(), realm )) != KSUCCESS ) {
#ifndef NO_USERINTERFACE
		fprintf( stderr, "krb_get_tf_realm failed (%s)\n",
		    krb_err_txt[err] );
#endif /* NO_USERINTERFACE */
		ld->ld_errno = LDAP_INVALID_CREDENTIALS;
		return( NULL );
	}

#ifdef LDAP_REFERRALS
	krbinstance = ld->ld_defconn->lconn_krbinstance;
#else /* LDAP_REFERRALS */
	krbinstance = ld->ld_host;
#endif /* LDAP_REFERRALS */

	if ( (err = krb_mk_req( &ktxt, service, krbinstance, realm, 0 ))
	    != KSUCCESS ) {
#ifndef NO_USERINTERFACE
		fprintf( stderr, "krb_mk_req failed (%s)\n", krb_err_txt[err] );
#endif /* NO_USERINTERFACE */
		ld->ld_errno = LDAP_INVALID_CREDENTIALS;
		return( NULL );
	}

	if ( ( cred = malloc( ktxt.length )) == NULL ) {
		ld->ld_errno = LDAP_NO_MEMORY;
		return( NULL );
	}

	*len = ktxt.length;
	memcpy( cred, ktxt.dat, ktxt.length );

	return( cred );
}
Ejemplo n.º 9
0
/*
 * pg_krb4_init -- initialization performed before any Kerberos calls are made
 *
 * For v4, all we need to do is make sure the library routines get the right
 * ticket file if we want them to see a special one.  (They will open the file
 * themselves.)
 */
static void
pg_krb4_init()
{
	char	   *realm;
	static int	init_done = 0;

	if (init_done)
		return;
	init_done = 1;

	/*
	 * If the user set PGREALM, then we use a ticket file with a special
	 * name: <usual-ticket-file-name>@<PGREALM-value>
	 */
	if ((realm = getenv("PGREALM")))
	{
		char		tktbuf[MAXPGPATH];

		(void) snprintf(tktbuf, sizeof(tktbuf), "%s@%s", tkt_string(), realm);
		krb_set_tkt_string(tktbuf);
	}
}
Ejemplo n.º 10
0
/*
 * pg_krb4_authname -- returns a pointer to static space containing whatever
 *					   name the user has authenticated to the system
 *
 * We obtain this information by digging around in the ticket file.
 */
static char *
pg_krb4_authname(char *PQerrormsg)
{
	char		instance[INST_SZ + 1];
	char		realm[REALM_SZ + 1];
	int			status;
	static char name[SNAME_SZ + 1] = "";

	if (name[0])
		return name;

	pg_krb4_init();

	name[SNAME_SZ] = '\0';
	status = krb_get_tf_fullname(tkt_string(), name, instance, realm);
	if (status != KSUCCESS)
	{
		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
				 "pg_krb4_authname: krb_get_tf_fullname: %s\n",
				 krb_err_txt[status]);
		return NULL;
	}
	return name;
}
Ejemplo n.º 11
0
int
pam_sm_authenticate(pam_handle_t *pamh,
		    int flags,
		    int argc,
		    const char **argv)
{
  char *user;
  int ret;
  struct pam_conv *conv;
  struct passwd *pw;
  uid_t uid = -1;
  const char *name, *inst;
  char realm[REALM_SZ];
  realm[0] = 0;

  parse_ctrl(argc, argv);
  ENTRY("pam_sm_authenticate");

  ret = pam_get_user(pamh, &user, "login: "******"root") == 0)
    return PAM_AUTHINFO_UNAVAIL;

  ret = pam_get_item(pamh, PAM_CONV, (void*)&conv);
  if (ret != PAM_SUCCESS)
    return ret;

  pw = getpwnam(user);
  if (pw != 0)
    {
      uid = pw->pw_uid;
      set_tkt_string(uid);
    }
    
  if (strcmp(user, "root") == 0 && getuid() != 0)
    {
      pw = getpwuid(getuid());
      if (pw != 0)
	{
	  name = strdup(pw->pw_name);
	  inst = "root";
	}
    }
  else
    {
      name = user;
      inst = "";
    }

  ret = krb4_auth(pamh, flags, name, inst, conv);

  /*
   * The realm was lost inside krb_verify_user() so we can't simply do
   * a krb_kuserok() when inst != "".
   */
  if (ret == PAM_SUCCESS && inst[0] != 0)
    {
      uid_t old_euid = geteuid();
      uid_t old_ruid = getuid();

      setreuid(0, 0);		/* To read ticket file. */
      if (krb_get_tf_fullname(tkt_string(), 0, 0, realm) != KSUCCESS)
	ret = PAM_SERVICE_ERR;
      else if (krb_kuserok(name, inst, realm, user) != KSUCCESS)
	{
	  setreuid(0, uid);	/*  To read ~/.klogin. */
	  if (krb_kuserok(name, inst, realm, user) != KSUCCESS)
	    ret = PAM_PERM_DENIED;
	}

      if (ret != PAM_SUCCESS)
	{
	  dest_tkt();		/* Passwd known, ok to kill ticket. */
	  psyslog(LOG_NOTICE,
		  "%s.%s@%s is not allowed to log in as %s",
		  name, inst, realm, user);
	}

      setreuid(old_ruid, old_euid);
      if (getuid() != old_ruid || geteuid() != old_euid)
	{
	  psyslog(LOG_ALERT , "setreuid(%d, %d) failed at line %d",
		  old_ruid, old_euid, __LINE__);
	  exit(1);
	}
    }

  if (ret == PAM_SUCCESS)
    {
      psyslog(LOG_INFO,
	      "%s.%s@%s authenticated as user %s",
	      name, inst, realm, user);
      if (chown(tkt_string(), uid, -1) == -1)
	{
	  dest_tkt();
	  psyslog(LOG_ALERT , "chown(%s, %d, -1) failed", tkt_string(), uid);
	  exit(1);
	}
    }

  /*
   * Kludge alert!!! Sun dtlogin unlock screen fails to call
   * pam_setcred(3) with PAM_REFRESH_CRED after a successful
   * authentication attempt, sic.
   *
   * This hack is designed as a workaround to that problem.
   */
  if (ctrl_on(KRB4_REAFSLOG))
    if (ret == PAM_SUCCESS)
      pam_sm_setcred(pamh, PAM_REFRESH_CRED, argc, argv);
  
  return ret;
}
Ejemplo n.º 12
0
void
kerberos4_is(Authenticator *ap, unsigned char *data, int cnt)
{
    struct sockaddr_in addr;
    char realm[REALM_SZ];
    char instance[INST_SZ];
    int r;
    int addr_len;

    if (cnt-- < 1)
	return;
    switch (*data++) {
    case KRB_AUTH:
	if (krb_get_lrealm(realm, 1) != KSUCCESS) {
	    Data(ap, KRB_REJECT, (void *)"No local V4 Realm.", -1);
	    auth_finished(ap, AUTH_REJECT);
	    if (auth_debug_mode)
		printf("No local realm\r\n");
	    return;
	}
	memmove(auth.dat, data, auth.length = cnt);
	if (auth_debug_mode) {
	    printf("Got %d bytes of authentication data\r\n", cnt);
	    printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length));
	    printd(auth.dat, auth.length);
	    printf("\r\n");
	}
	k_getsockinst(0, instance, sizeof(instance));
	addr_len = sizeof(addr);
	if(getpeername(0, (struct sockaddr *)&addr, &addr_len) < 0) {
	    if(auth_debug_mode)
		printf("getpeername failed\r\n");
	    Data(ap, KRB_REJECT, "getpeername failed", -1);
	    auth_finished(ap, AUTH_REJECT);
	    return;
	}
	r = krb_rd_req(&auth, KRB_SERVICE_NAME,
		       instance, addr.sin_addr.s_addr, &adat, "");
	if (r) {
	    if (auth_debug_mode)
		printf("Kerberos failed him as %s\r\n", name);
	    Data(ap, KRB_REJECT, (void *)krb_get_err_text(r), -1);
	    auth_finished(ap, AUTH_REJECT);
	    return;
	}
	/* save the session key */
	memmove(session_key, adat.session, sizeof(adat.session));
	krb_kntoln(&adat, name);

	if (UserNameRequested && !kuserok(&adat, UserNameRequested)){
	    char ts[MAXPATHLEN];
	    struct passwd *pw = getpwnam(UserNameRequested);

	    if(pw){
		snprintf(ts, sizeof(ts),
			 "%s%u",
			 TKT_ROOT,
			 (unsigned)pw->pw_uid);
		setenv("KRBTKFILE", ts, 1);
	    }
	    Data(ap, KRB_ACCEPT, NULL, 0);
	} else {
	    char *msg;

	    asprintf (&msg, "user `%s' is not authorized to "
		      "login as `%s'", 
		      krb_unparse_name_long(adat.pname, 
					    adat.pinst, 
					    adat.prealm), 
		      UserNameRequested ? UserNameRequested : "<nobody>");
	    if (msg == NULL)
		Data(ap, KRB_REJECT, NULL, 0);
	    else {
		Data(ap, KRB_REJECT, (void *)msg, -1);
		free(msg);
	    }
	}
	auth_finished(ap, AUTH_USER);
	break;
	
    case KRB_CHALLENGE:
#ifndef ENCRYPTION
	Data(ap, KRB_RESPONSE, NULL, 0);
#else
	if(!VALIDKEY(session_key)){
	    Data(ap, KRB_RESPONSE, NULL, 0);
	    break;
	}
	des_key_sched(&session_key, sched);
	{
	    des_cblock d_block;
	    int i;
	    Session_Key skey;

	    memmove(d_block, data, sizeof(d_block));

	    /* make a session key for encryption */
	    des_ecb_encrypt(&d_block, &session_key, sched, 1);
	    skey.type=SK_DES;
	    skey.length=8;
	    skey.data=session_key;
	    encrypt_session_key(&skey, 1);

	    /* decrypt challenge, add one and encrypt it */
	    des_ecb_encrypt(&d_block, &challenge, sched, 0);
	    for (i = 7; i >= 0; i--)
		if(++challenge[i] != 0)
		    break;
	    des_ecb_encrypt(&challenge, &challenge, sched, 1);
	    Data(ap, KRB_RESPONSE, (void *)challenge, sizeof(challenge));
	}
#endif
	break;

    case KRB_FORWARD:
	{
	    des_key_schedule ks;
	    unsigned char netcred[sizeof(CREDENTIALS)];
	    CREDENTIALS cred;
	    int ret;
	    if(cnt > sizeof(cred))
		abort();

	    des_set_key(&session_key, ks);
	    des_pcbc_encrypt((void*)data, (void*)netcred, cnt, 
			     ks, &session_key, DES_DECRYPT);
	    unpack_cred(netcred, cnt, &cred);
	    {
		if(strcmp(cred.service, KRB_TICKET_GRANTING_TICKET) ||
		   strncmp(cred.instance, cred.realm, sizeof(cred.instance)) ||
		   cred.lifetime < 0 || cred.lifetime > 255 ||
		   cred.kvno < 0 || cred.kvno > 255 ||
		   cred.issue_date < 0 || 
		   cred.issue_date > time(0) + CLOCK_SKEW ||
		   strncmp(cred.pname, adat.pname, sizeof(cred.pname)) ||
		   strncmp(cred.pinst, adat.pinst, sizeof(cred.pname))){
		    Data(ap, KRB_FORWARD_REJECT, "Bad credentials", -1);
		}else{
		    if((ret = tf_setup(&cred,
				       cred.pname,
				       cred.pinst)) == KSUCCESS){
		        struct passwd *pw = getpwnam(UserNameRequested);

			if (pw)
			  chown(tkt_string(), pw->pw_uid, pw->pw_gid);
			Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
		    } else{
			Data(ap, KRB_FORWARD_REJECT, 
			     krb_get_err_text(ret), -1);
		    }
		}
	    }
	    memset(data, 0, cnt);
	    memset(ks, 0, sizeof(ks));
	    memset(&cred, 0, sizeof(cred));
	}
	
	break;

    default:
	if (auth_debug_mode)
	    printf("Unknown Kerberos option %d\r\n", data[-1]);
	Data(ap, KRB_REJECT, 0, 0);
	break;
    }
}
Ejemplo n.º 13
0
/*
 * try krb4 authentication,
 * return 1 on success, 0 on failure, -1 if krb4 is not available
 */
int
auth_krb4_password(Authctxt *authctxt, const char *password)
{
	AUTH_DAT adata;
	KTEXT_ST tkt;
	struct hostent *hp;
	struct passwd *pw;
	char localhost[MAXHOSTNAMELEN], phost[INST_SZ], realm[REALM_SZ];
	u_int32_t faddr;
	int r;

	if ((pw = authctxt->pw) == NULL)
		return (0);

	/*
	 * Try Kerberos password authentication only for non-root
	 * users and only if Kerberos is installed.
	 */
	if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) {
		/* Set up our ticket file. */
		if (!krb4_init(authctxt)) {
			log("Couldn't initialize Kerberos ticket file for %s!",
			    pw->pw_name);
			goto failure;
		}
		/* Try to get TGT using our password. */
		r = krb_get_pw_in_tkt((char *) pw->pw_name, "", realm,
		    "krbtgt", realm, DEFAULT_TKT_LIFE, (char *)password);
		if (r != INTK_OK) {
			debug("Kerberos v4 password authentication for %s "
			    "failed: %s", pw->pw_name, krb_err_txt[r]);
			goto failure;
		}
		/* Successful authentication. */
		chown(tkt_string(), pw->pw_uid, pw->pw_gid);

		/*
		 * Now that we have a TGT, try to get a local
		 * "rcmd" ticket to ensure that we are not talking
		 * to a bogus Kerberos server.
		 */
		gethostname(localhost, sizeof(localhost));
		strlcpy(phost, (char *)krb_get_phost(localhost),
		    sizeof(phost));
		r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);

		if (r == KSUCCESS) {
			if ((hp = gethostbyname(localhost)) == NULL) {
				log("Couldn't get local host address!");
				goto 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. Disallow login.
				 */
				log("Kerberos v4 TGT for %s unverifiable, "
				    "no srvtab installed? krb_rd_req: %s",
				    pw->pw_name, krb_err_txt[r]);
				goto failure;
			} else if (r != KSUCCESS) {
				log("Kerberos v4 %s ticket unverifiable: %s",
				    KRB4_SERVICE_NAME, krb_err_txt[r]);
				goto failure;
			}
		} else if (r == KDC_PR_UNKNOWN) {
			/*
			 * Disallow login if no rcmd service exists, and
			 * log the error.
			 */
			log("Kerberos v4 TGT for %s unverifiable: %s; %s.%s "
			    "not registered, or srvtab is wrong?", pw->pw_name,
			    krb_err_txt[r], KRB4_SERVICE_NAME, phost);
			goto failure;
		} else {
			/*
			 * TGT is bad, forget it. Possibly spoofed!
			 */
			debug("WARNING: Kerberos v4 TGT possibly spoofed "
			    "for %s: %s", pw->pw_name, krb_err_txt[r]);
			goto failure;
		}
		/* Authentication succeeded. */
		return (1);
	} else
		/* Logging in as root or no local Kerberos realm. */
		debug("Unable to authenticate to Kerberos.");

 failure:
	krb4_cleanup_proc(authctxt);

	if (!options.kerberos_or_local_passwd)
		return (0);

	/* Fall back to ordinary passwd authentication. */
	return (-1);
}
Ejemplo n.º 14
0
static int
try_krb4_authentication(void)
{
	KTEXT_ST auth;		/* Kerberos data */
	char *reply;
	char inst[INST_SZ];
	char *realm;
	CREDENTIALS cred;
	int r, type;
	socklen_t slen;
	Key_schedule schedule;
	u_long checksum, cksum;
	MSG_DAT msg_data;
	struct sockaddr_in local, foreign;
	struct stat st;

	/* Don't do anything if we don't have any tickets. */
	if (stat(tkt_string(), &st) < 0)
		return 0;

	strlcpy(inst, (char *)krb_get_phost(get_canonical_hostname(1)),
	    INST_SZ);

	realm = (char *)krb_realmofhost(get_canonical_hostname(1));
	if (!realm) {
		debug("Kerberos v4: no realm for %s", get_canonical_hostname(1));
		return 0;
	}
	/* This can really be anything. */
	checksum = (u_long)getpid();

	r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum);
	if (r != KSUCCESS) {
		debug("Kerberos v4 krb_mk_req failed: %s", krb_err_txt[r]);
		return 0;
	}
	/* Get session key to decrypt the server's reply with. */
	r = krb_get_cred(KRB4_SERVICE_NAME, inst, realm, &cred);
	if (r != KSUCCESS) {
		debug("get_cred failed: %s", krb_err_txt[r]);
		return 0;
	}
	des_key_sched((des_cblock *) cred.session, schedule);

	/* Send authentication info to server. */
	packet_start(SSH_CMSG_AUTH_KERBEROS);
	packet_put_string((char *) auth.dat, auth.length);
	packet_send();
	packet_write_wait();

	/* Zero the buffer. */
	(void) memset(auth.dat, 0, MAX_KTXT_LEN);

	slen = sizeof(local);
	memset(&local, 0, sizeof(local));
	if (getsockname(packet_get_connection_in(),
	    (struct sockaddr *)&local, &slen) < 0)
		debug("getsockname failed: %s", strerror(errno));

	slen = sizeof(foreign);
	memset(&foreign, 0, sizeof(foreign));
	if (getpeername(packet_get_connection_in(),
	    (struct sockaddr *)&foreign, &slen) < 0) {
		debug("getpeername failed: %s", strerror(errno));
		cleanup_exit(255);
	}
	/* Get server reply. */
	type = packet_read();
	switch (type) {
	case SSH_SMSG_FAILURE:
		/* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */
		debug("Kerberos v4 authentication failed.");
		return 0;
		break;

	case SSH_SMSG_AUTH_KERBEROS_RESPONSE:
		/* SSH_SMSG_AUTH_KERBEROS_SUCCESS */
		debug("Kerberos v4 authentication accepted.");

		/* Get server's response. */
		reply = packet_get_string((u_int *) &auth.length);
		if (auth.length >= MAX_KTXT_LEN)
			fatal("Kerberos v4: Malformed response from server");
		memcpy(auth.dat, reply, auth.length);
		free(reply);

		packet_check_eom();

		/*
		 * If his response isn't properly encrypted with the session
		 * key, and the decrypted checksum fails to match, he's
		 * bogus. Bail out.
		 */
		r = krb_rd_priv(auth.dat, auth.length, (void *)schedule,
		    &cred.session, &foreign, &local, &msg_data);
		if (r != KSUCCESS) {
			debug("Kerberos v4 krb_rd_priv failed: %s",
			    krb_err_txt[r]);
			packet_disconnect("Kerberos v4 challenge failed!");
		}
		/* Fetch the (incremented) checksum that we supplied in the request. */
		memcpy((char *)&cksum, (char *)msg_data.app_data,
		    sizeof(cksum));
		cksum = ntohl(cksum);

		/* If it matches, we're golden. */
		if (cksum == checksum + 1) {
			debug("Kerberos v4 challenge successful.");
			return 1;
		} else
			packet_disconnect("Kerberos v4 challenge failed!");
		break;

	default:
		packet_disconnect("Protocol error on Kerberos v4 response: %d", type);
	}
	return 0;
}
Ejemplo n.º 15
0
static int
v4_save(krb5_context ctx,
	struct _pam_krb5_stash *stash,
	struct _pam_krb5_user_info *userinfo,
	struct _pam_krb5_options *options,
	uid_t uid, gid_t gid,
	const char **ccname,
	int clone_cc)
{
	char name[ANAME_SZ + 1], instance[INST_SZ + 1], realm[REALM_SZ + 1];
	char tktfile[PATH_MAX];
	char *saved_tktstring;
	int i, fd;
	struct stat st;

	if (ccname != NULL) {
		*ccname = NULL;
	}

	/* Convert the v5 principal name into v4 notation. */
	memset(name, '\0', sizeof(name));
	memset(instance, '\0', sizeof(instance));
	memset(realm, '\0', sizeof(realm));
	if (stash->v5creds.client != NULL) {
		/* Use the client principal of the creds we have, which we
		 * can assume are always correct, even if "external" somehow
		 * got us to the point where the principal name in "userinfo"
		 * is incorrect. */
		i = krb5_524_conv_principal(ctx, stash->v5creds.client,
					    name, instance, realm);
	} else {
		/* Use the parsed principal as a fallback.  We should never
		 * really get here, but just in case. */
		i = krb5_524_conv_principal(ctx, userinfo->principal_name,
					    name, instance, realm);
	}
	if (i != 0) {
		warn("error converting %s to a Kerberos IV principal "
		     "(shouldn't happen)", userinfo->unparsed_name);
		return PAM_SERVICE_ERR;
	}

	/* Create a new ticket file. */
#ifdef HAVE_LONG_LONG
	snprintf(tktfile, sizeof(tktfile), "%s/tkt%llu_XXXXXX",
		 options->ccache_dir,
		 options->user_check ?
		 (unsigned long long) userinfo->uid :
		 (unsigned long long) getuid());
#else
	snprintf(tktfile, sizeof(tktfile), "%s/tkt%lu_XXXXXX",
		 options->ccache_dir,
		 options->user_check ?
		 (unsigned long) userinfo->uid :
		 (unsigned long) getuid());
#endif
	fd = mkstemp(tktfile);
	if (fd == -1) {
		warn("error creating unique Kerberos IV ticket file "
		     "(shouldn't happen)");
		return PAM_SERVICE_ERR;
	}
	if (fchown(fd, getuid(), getgid()) != 0) {
		warn("error setting permissions on \"%s\" (%s), attempting "
		     "to continue", tktfile, strerror(errno));
	}
	if (options->debug) {
		debug("saving v4 tickets to '%s'", tktfile);
	}

	/* Open the ticket file. */
	saved_tktstring = xstrdup(tkt_string());
	krb_set_tkt_string(tktfile);
	i = tf_init(tktfile, W_TKT_FIL);
	if (i != 0) {
		const char *tferror;
		switch (i) {
		case NO_TKT_FIL:
			tferror = "no ticket file";
			break;
		case TKT_FIL_ACC:
			tferror = "ticket file had wrong permissions";
			break;
		case TKT_FIL_LCK:
			tferror = "error locking ticket file";
			break;
		default:
			tferror = strerror(errno);
			break;
		}
		warn("error opening ticket file '%s': %s",
		     tktfile, tferror);
		if ((i == TKT_FIL_ACC) && (options->debug)) {
			if (stat(tktfile, &st) == 0) {
				debug("file owner is %lu:%lu, "
				      "we are effective %lu:%lu, "
				      "real %lu:%lu",
				      (unsigned long) st.st_uid,
				      (unsigned long) st.st_gid,
				      (unsigned long) geteuid(),
				      (unsigned long) getegid(),
				      (unsigned long) getuid(),
				      (unsigned long) getgid());
			}
		}
		krb_set_tkt_string(saved_tktstring);
		xstrfree(saved_tktstring);
		unlink(tktfile);
		close(fd);
		return PAM_SERVICE_ERR;
	}

	/* Store the user's name. */
	if (v4_in_tkt(name, instance, realm) != 0) {
		warn("error initializing ticket file '%s'", tktfile);
		tf_close();
		krb_set_tkt_string(saved_tktstring);
		xstrfree(saved_tktstring);
		unlink(tktfile);
		close(fd);
		return PAM_SERVICE_ERR;
	}

	/* Store the v4 credentials. */
	if (v4_save_credentials(KRB5_TGS_NAME, realm, realm,
				stash->v4creds.session,
				stash->v4creds.lifetime,
				stash->v4creds.kvno,
				&stash->v4creds.ticket_st,
				stash->v4creds.issue_date) != 0) {
		warn("error saving tickets to '%s'", tktfile);
		tf_close();
		krb_set_tkt_string(saved_tktstring);
		xstrfree(saved_tktstring);
		unlink(tktfile);
		close(fd);
		return PAM_SERVICE_ERR;
	}

	/* Close the new file. */
	tf_close();
	xstrfree(saved_tktstring);
	close(fd);

	/* Save the new file's name in the stash, and optionally return it to
	 * the caller. */
	if (_pam_krb5_stash_push_v4(ctx, stash, options, tktfile) == 0) {
		/* Generate a *new* ticket file with the same contents as this
		 * one. */
		if (clone_cc) {
			_pam_krb5_stash_clone_v4(stash, uid, gid);
		}
		krb_set_tkt_string(stash->v4tktfiles->name);
		if (ccname != NULL) {
			*ccname = stash->v4tktfiles->name;
		}
	}

	return PAM_SUCCESS;
}
Ejemplo n.º 16
0
static int
_pam_krb5_v4_init(krb5_context ctx,
		  struct _pam_krb5_stash *stash,
		  struct _pam_krb5_user_info *user,
		  struct _pam_krb5_options *options,
		  char *sname, char *sinstance,
		  char *password,
		  int *result) 
{
	char name[ANAME_SZ + 1], instance[INST_SZ + 1], realm[REALM_SZ + 1];
	char pname[ANAME_SZ + 1], pinstance[INST_SZ + 1];
	char tktfile[PATH_MAX];
	char *saved_tktstring;
	int life, i, fd;
	struct stat st;

	/* Convert the krb5 version of the principal's name to a v4 principal
	 * name.  This may involve changing "host" to "rcmd" and so on, so let
	 * libkrb5 handle it. */
	memset(name, '\0', sizeof(name));
	memset(instance, '\0', sizeof(instance));
	memset(realm, '\0', sizeof(realm));
	i = krb5_524_conv_principal(ctx, user->principal_name,
				    name, instance, realm);
	if (i != 0) {
		if (result) {
			*result = i;
		}
		return PAM_SERVICE_ERR;
	}
	if (options->debug) {
		debug("converted principal to '%s%s%s%s@'%s'", name,
		      strlen(instance) ? "'.'" : "'", instance,
		      strlen(instance) ? "'" : "", realm);
	}

#ifdef HAVE_KRB_TIME_TO_LIFE
	/* Convert the ticket lifetime of the v5 credentials into a v4
	 * lifetime, which is the X coordinate along a curve where Y is the
	 * actual length.  Again, this is magic. */
	life = krb_time_to_life(stash->v5creds.times.starttime,
				stash->v5creds.times.endtime); 
#else
	/* No life_to_time() function means that we have to estimate the
	 * intended lifetime, in 5-minute increments.  We also have a maximum
	 * value to contend with, because the lifetime is expressed in a single
	 * byte. */
	life = stash->v5creds.times.endtime -
	       stash->v5creds.times.starttime;
	life /= (60 * 5);
	if (life > 0xff) {
		life = 0xff;
	}
#endif

	/* Create the ticket file.  One of two things will happen here.  Either
	 * libkrb[4] will just use the file, and we're safer because it
	 * wouldn't have used O_EXCL to do so, or it will nuke the file and
	 * reopen it with O_EXCL.  In the latter case, the descriptor we have
	 * will become useless, so we don't actually use it for anything. */
#ifdef HAVE_LONG_LONG
	snprintf(tktfile, sizeof(tktfile), "%s/tkt%llu_XXXXXX",
		 options->ccache_dir,
		 options->user_check ?
		 (unsigned long long) user->uid :
		 (unsigned long long) getuid());
#else
	snprintf(tktfile, sizeof(tktfile), "%s/tkt%lu_XXXXXX",
		 options->ccache_dir,
		 options->user_check ?
		 (unsigned long) user->uid :
		 (unsigned long) getuid());
#endif
	fd = mkstemp(tktfile);
	if (fd == -1) {
		if (result) {
			*result = errno;
		}
		return PAM_SERVICE_ERR;
	}
	if (fchown(fd, getuid(), getgid()) != 0) {
		warn("error setting permissions on \"%s\" (%s), attempting "
		     "to continue", tktfile, strerror(errno));
	}
	if (options->debug) {
		debug("preparing to place v4 credentials in '%s'", tktfile);
	}
	/* Save the old default ticket file name, and set the default to use
	 * our just-created empty file. */
	saved_tktstring = xstrdup(tkt_string());
	krb_set_tkt_string(tktfile);
	/* Get the initial credentials. */
	i = krb_get_pw_in_tkt(name, instance, realm,
			      sname, sinstance ? sinstance : realm,
			      life, password);
	if (result) {
		*result = i;
	}
	/* Restore the original default ticket file name. */
	krb_set_tkt_string(saved_tktstring);
	xstrfree(saved_tktstring);
	saved_tktstring = NULL;
	/* If we got credentials, read them from the file, and then remove the
	 * file. */
	if (i == 0) {
		i = tf_init(tktfile, R_TKT_FIL);
		if (i == 0) {
			i = tf_get_pname(pname);
			if (i == 0) {
				i = tf_get_pinst(pinstance);
				if (i == 0) {
					i = tf_get_cred(&stash->v4creds);
					if (i == 0) {
						tf_close();
						unlink(tktfile);
						close(fd);
						return PAM_SUCCESS;
					} else {
						warn("error reading creds "
						     "from '%s': %d (%s)",
						     tktfile,
						     i, v5_error_message(i));
					}
				} else {
					warn("error reading instance from '%s'"
					     ": %d (%s)",
					     tktfile, i, v5_error_message(i));
				}
			} else {
				warn("error reading principal name from '%s'"
				     ": %d (%s)",
				     tktfile, i, v5_error_message(i));
			}
			tf_close();
		} else {
			const char *tferror;
			switch (i) {
			case NO_TKT_FIL:
				tferror = "no ticket file";
				break;
			case TKT_FIL_ACC:
				tferror = "ticket file had wrong permissions";
				break;
			case TKT_FIL_LCK:
				tferror = "error locking ticket file";
				break;
			default:
				tferror = strerror(errno);
				break;
			}
			warn("error opening '%s' for reading: %s",
			     tktfile, tferror);
			if ((i == TKT_FIL_ACC) && (options->debug)) {
				if (stat(tktfile, &st) == 0) {
					debug("file owner is %lu:%lu, "
					      "we are effective %lu:%lu, "
					      "real %lu:%lu",
					      (unsigned long) st.st_uid,
					      (unsigned long) st.st_gid,
					      (unsigned long) geteuid(),
					      (unsigned long) getegid(),
					      (unsigned long) getuid(),
					      (unsigned long) getgid());
				}
			}
		}
	}
	unlink(tktfile);
	close(fd);
	return PAM_AUTH_ERR;
}