Esempio n. 1
0
/*
 * Given a keytab and a list of allowed enctypes, and optionally a known
 * service principal, choose an appropriate enctype, and choose a
 * service principal if one was not given.  Return the keytab entry
 * corresponding to this service principal and enctype.
 *
 * The list of allowed enctypes must be zero-terminated.
 */
static int
pick_enctype_and_principal(krb5_context context, krb5_keytab kt,
			   const int *allowed_enctypes, krb5_enctype *enctype,
			   krb5_principal *service_principal,
			   krb5_keytab_entry *entry)
{
    krb5_error_code code;
    int i;

    if (*service_principal == NULL) {
	code = pick_principal(context, kt, service_principal);
	if (code != 0) {
	    goto cleanup;
	}
    }

    /* We always have a service_principal, now. */
    i = 0;
    do {
	*enctype = allowed_enctypes[i];
	code = krb5_kt_get_entry(context, kt, *service_principal, 0 /* any */,
				 *enctype, entry);
	if (code == 0) {
	    if (*enctype == 0)
		*enctype = deref_entry_enctype(entry);
	    break;
	}
	++i;
    } while(allowed_enctypes[i] != 0);
    if (code != 0)
	goto cleanup;

cleanup:
    return code;
}
mit_krb5_error_code KRB5_CALLCONV
krb5_kt_read_service_key(mit_krb5_context context,
			 mit_krb5_pointer keyprocarg,
			 mit_krb5_principal principal,
			 mit_krb5_kvno vno,
			 mit_krb5_enctype enctype,
			 mit_krb5_keyblock **key)
{
    mit_krb5_keytab keytab;
    mit_krb5_keytab_entry entry;
    mit_krb5_error_code ret;

    LOG_ENTRY();

    if (keyprocarg)
	ret = krb5_kt_resolve (context, keyprocarg, &keytab);
    else
	ret = krb5_kt_default (context, &keytab);

    if (ret)
	return ret;

    ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry);
    krb5_kt_close (context, keytab);
    if (ret)
	return ret;
    ret = krb5_copy_keyblock (context, &entry.key, key);
    krb5_kt_free_entry(context, &entry);
    return ret;
}
Esempio n. 3
0
KRB5_DEPRECATED
KRB5_LIB_FUNCTION krb5_error_code KRB5_CALLCONV
krb5_keytab_key_proc (krb5_context context,
		      krb5_enctype enctype,
		      krb5_salt salt,
		      krb5_const_pointer keyseed,
		      krb5_keyblock **key)
{
    krb5_keytab_key_proc_args *args  = rk_UNCONST(keyseed);
    krb5_keytab keytab = args->keytab;
    krb5_principal principal  = args->principal;
    krb5_error_code ret;
    krb5_keytab real_keytab;
    krb5_keytab_entry entry;

    if(keytab == NULL)
	krb5_kt_default(context, &real_keytab);
    else
	real_keytab = keytab;

    ret = krb5_kt_get_entry (context, real_keytab, principal,
			     0, enctype, &entry);

    if (keytab == NULL)
	krb5_kt_close (context, real_keytab);

    if (ret)
	return ret;

    ret = krb5_copy_keyblock (context, &entry.keyblock, key);
    krb5_kt_free_entry(context, &entry);
    return ret;
}
Esempio n. 4
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_kt_read_service_key(krb5_context context,
			 krb5_pointer keyprocarg,
			 krb5_principal principal,
			 krb5_kvno vno,
			 krb5_enctype enctype,
			 krb5_keyblock **key)
{
    krb5_keytab keytab;
    krb5_keytab_entry entry;
    krb5_error_code ret;

    if (keyprocarg)
	ret = krb5_kt_resolve (context, keyprocarg, &keytab);
    else
	ret = krb5_kt_default (context, &keytab);

    if (ret)
	return ret;

    ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry);
    krb5_kt_close (context, keytab);
    if (ret)
	return ret;
    ret = krb5_copy_keyblock (context, &entry.keyblock, key);
    krb5_kt_free_entry(context, &entry);
    return ret;
}
Esempio n. 5
0
static krb5_error_code copy_one_entry(krb5_context context, 
				      krb5_keytab src_keytab, krb5_keytab dst_keytab, krb5_keytab_entry entry) 
{
    krb5_error_code ret;
    krb5_keytab_entry dummy;

    char *name_str;
    char *etype_str;
    ret = krb5_unparse_name (context, entry.principal, &name_str);
    if(ret) {
	krb5_set_error_message(context, ret, "krb5_unparse_name");
	name_str = NULL; /* XXX */
	return ret;
    }
    ret = krb5_enctype_to_string(context, entry.keyblock.keytype, &etype_str);
    if(ret) {
	krb5_set_error_message(context, ret, "krb5_enctype_to_string");
	etype_str = NULL; /* XXX */
	return ret;
    }
    ret = krb5_kt_get_entry(context, dst_keytab,
			    entry.principal,
			    entry.vno,
			    entry.keyblock.keytype,
			    &dummy);
    if(ret == 0) {
	/* this entry is already in the new keytab, so no need to
	   copy it; if the keyblocks are not the same, something
	   is weird, so complain about that */
	if(!compare_keyblock(&entry.keyblock, &dummy.keyblock)) {
		krb5_warn(context, 0, "entry with different keyvalue "
			  "already exists for %s, keytype %s, kvno %d",
			  name_str, etype_str, entry.vno);
	}
	krb5_kt_free_entry(context, &dummy);
	krb5_kt_free_entry (context, &entry);
	free(name_str);
	free(etype_str);
	return ret;
    } else if(ret != KRB5_KT_NOTFOUND) {
	krb5_set_error_message (context, ret, "fetching %s/%s/%u",
				name_str, etype_str, entry.vno);
	krb5_kt_free_entry (context, &entry);
	free(name_str);
	free(etype_str);
	return ret;
    } 
    ret = krb5_kt_add_entry (context, dst_keytab, &entry);
    krb5_kt_free_entry (context, &entry);
    if (ret) {
	krb5_set_error_message (context, ret, "adding %s/%s/%u",
				name_str, etype_str, entry.vno);
	free(name_str);
	free(etype_str);
	return ret;
    }
    free(name_str);
    free(etype_str);
    return ret;
}
Esempio n. 6
0
static OM_uint32 acquire_acceptor_cred
		  (OM_uint32 * minor_status,
		   krb5_context context,
		   const gss_name_t desired_name,
		   OM_uint32 time_req,
		   const gss_OID_set desired_mechs,
		   gss_cred_usage_t cred_usage,
		   gsskrb5_cred handle,
		   gss_OID_set * actual_mechs,
		   OM_uint32 * time_rec
		  )
{
    OM_uint32 ret;
    krb5_error_code kret;

    ret = GSS_S_FAILURE;
    kret = get_keytab(context, &handle->keytab);
    if (kret)
	goto end;

    /* check that the requested principal exists in the keytab */
    if (handle->principal) {
	krb5_keytab_entry entry;

	kret = krb5_kt_get_entry(context, handle->keytab,
				 handle->principal, 0, 0, &entry);
	if (kret)
	    goto end;
	krb5_kt_free_entry(context, &entry);
	ret = GSS_S_COMPLETE;
    } else {
	/*
	 * Check if there is at least one entry in the keytab before
	 * declaring it as an useful keytab.
	 */
	krb5_keytab_entry tmp;
	krb5_kt_cursor c;

	kret = krb5_kt_start_seq_get (context, handle->keytab, &c);
	if (kret)
	    goto end;
	if (krb5_kt_next_entry(context, handle->keytab, &tmp, &c) == 0) {
	    krb5_kt_free_entry(context, &tmp);
	    ret = GSS_S_COMPLETE; /* ok found one entry */
	}
	krb5_kt_end_seq_get (context, handle->keytab, &c);
    }
end:
    if (ret != GSS_S_COMPLETE) {
	if (handle->keytab != NULL)
	    krb5_kt_close(context, handle->keytab);
	if (kret != 0) {
	    *minor_status = kret;
	}
    }
    return (ret);
}
Esempio n. 7
0
int
kssl_keytab_is_available(KSSL_CTX *kssl_ctx)
{
	krb5_context		krb5context = NULL;
	krb5_keytab 		krb5keytab = NULL;
	krb5_keytab_entry           entry;
	krb5_principal              princ = NULL;
	krb5_error_code  		krb5rc = KRB5KRB_ERR_GENERIC;
	int rc = 0;

	if ((krb5rc = krb5_init_context(&krb5context)))
		return (0);

    /*	kssl_ctx->keytab_file == NULL ==> use Kerberos default
    */
	if (kssl_ctx->keytab_file) {
		krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
		    &krb5keytab);
		if (krb5rc)
			goto exit;
	} else {
		krb5rc = krb5_kt_default(krb5context, &krb5keytab);
		if (krb5rc)
			goto exit;
	}

	/* the host key we are looking for */
	krb5rc = krb5_sname_to_principal(krb5context, NULL,
	    kssl_ctx->service_name ? kssl_ctx->service_name : KRB5SVC,
	    KRB5_NT_SRV_HST, &princ);

	if (krb5rc)
		goto exit;

	krb5rc = krb5_kt_get_entry(krb5context, krb5keytab, princ,
	    0 /* IGNORE_VNO */,
	    0 /* IGNORE_ENCTYPE */,
	    &entry);
	if (krb5rc == KRB5_KT_NOTFOUND) {
		rc = 1;
		goto exit;
	} else if (krb5rc)
		goto exit;

	krb5_kt_free_entry(krb5context, &entry);
	rc = 1;

	exit:
	if (krb5keytab)
		krb5_kt_close(krb5context, krb5keytab);
	if (princ)
		krb5_free_principal(krb5context, princ);
	if (krb5context)
		krb5_free_context(krb5context);
	return (rc);
}
Esempio n. 8
0
static krb5_error_code
hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal,
	       unsigned flags, krb5_kvno kvno, hdb_entry_ex * entry)
{
    hdb_keytab k = (hdb_keytab)db->hdb_db;
    krb5_error_code ret;
    krb5_keytab_entry ktentry;

    if (!(flags & HDB_F_KVNO_SPECIFIED)) {
	    /* Preserve previous behaviour if no kvno specified */
	    kvno = 0;
    }

    memset(&ktentry, 0, sizeof(ktentry));

    entry->entry.flags.server = 1;
    entry->entry.flags.forwardable = 1;
    entry->entry.flags.renewable = 1;

    /* Not recorded in the OD backend, make something up */
    ret = krb5_parse_name(context, "hdb/keytab@WELL-KNOWN:KEYTAB-BACKEND",
			  &entry->entry.created_by.principal);
    if (ret)
	goto out;

    /*
     * XXX really needs to try all enctypes and just not pick the
     * first one, even if that happens to be des3-cbc-sha1 (ie best
     * enctype) in the Apple case. A while loop over all known
     * enctypes should work.
     */

    ret = krb5_kt_get_entry(context, k->keytab, principal, kvno, 0, &ktentry);
    if (ret) {
	ret = HDB_ERR_NOENTRY;
	goto out;
    }

    ret = krb5_copy_principal(context, principal, &entry->entry.principal);
    if (ret)
	goto out;

    ret = _hdb_keytab2hdb_entry(context, &ktentry, entry);

 out:
    if (ret) {
	free_hdb_entry(&entry->entry);
	memset(&entry->entry, 0, sizeof(entry->entry));
    }
    krb5_kt_free_entry(context, &ktentry);

    return ret;
}
Esempio n. 9
0
static krb5_error_code
get_as_key_keytab(krb5_context context,
                  krb5_principal client,
                  krb5_enctype etype,
                  krb5_prompter_fct prompter,
                  void *prompter_data,
                  krb5_data *salt,
                  krb5_data *params,
                  krb5_keyblock *as_key,
                  void *gak_data,
                  k5_response_items *ritems)
{
    krb5_keytab keytab = (krb5_keytab) gak_data;
    krb5_error_code ret;
    krb5_keytab_entry kt_ent;
    krb5_keyblock *kt_key;

    /* We don't need the password from the responder to create the AS key. */
    if (as_key == NULL)
        return 0;

    /* if there's already a key of the correct etype, we're done.
       if the etype is wrong, free the existing key, and make
       a new one. */

    if (as_key->length) {
        if (as_key->enctype == etype)
            return(0);

        krb5_free_keyblock_contents(context, as_key);
        as_key->length = 0;
    }

    if (!krb5_c_valid_enctype(etype))
        return(KRB5_PROG_ETYPE_NOSUPP);

    if ((ret = krb5_kt_get_entry(context, keytab, client,
                                 0, /* don't have vno available */
                                 etype, &kt_ent)))
        return(ret);

    ret = krb5_copy_keyblock(context, &kt_ent.key, &kt_key);

    /* again, krb5's memory management is lame... */

    *as_key = *kt_key;
    free(kt_key);

    (void) krb5_kt_free_entry(context, &kt_ent);

    return(ret);
}
Esempio n. 10
0
static OM_uint32 acquire_acceptor_cred
		  (OM_uint32 * minor_status,
		   const gss_name_t desired_name,
		   OM_uint32 time_req,
		   const gss_OID_set desired_mechs,
		   gss_cred_usage_t cred_usage,
		   gss_cred_id_t handle,
		   gss_OID_set * actual_mechs,
		   OM_uint32 * time_rec
		  )
{
    OM_uint32 ret;
    krb5_error_code kret;

    kret = 0;
    ret = GSS_S_FAILURE;
    kret = get_keytab(&handle->keytab);
    if (kret)
	goto end;
    
    /* check that the requested principal exists in the keytab */
    if (handle->principal) {
	krb5_keytab_entry entry;

	kret = krb5_kt_get_entry(gssapi_krb5_context, handle->keytab, 
				 handle->principal, 0, 0, &entry);
	if (kret)
	    goto end;
	krb5_kt_free_entry(gssapi_krb5_context, &entry);
    }
    ret = GSS_S_COMPLETE;
 
end:
    if (ret != GSS_S_COMPLETE) {
	if (handle->keytab != NULL)
	    krb5_kt_close(gssapi_krb5_context, handle->keytab);
	if (kret != 0) {
	    *minor_status = kret;
	    gssapi_krb5_set_error_string ();
	}
    }
    return (ret);
}
Esempio n. 11
0
static krb5_error_code
krb5_rd_req_decrypt_tkt_part(krb5_context context, const krb5_ap_req *req, krb5_keytab keytab)
{
    krb5_error_code 	  retval;
    krb5_enctype 	  enctype;
    krb5_keytab_entry 	  ktent;

    enctype = req->ticket->enc_part.enctype;

    if ((retval = krb5_kt_get_entry(context, keytab, req->ticket->server,
				    req->ticket->enc_part.kvno,
				    enctype, &ktent)))
	return retval;

    retval = krb5_decrypt_tkt_part(context, &ktent.key, req->ticket);
    /* Upon error, Free keytab entry first, then return */

    (void) krb5_kt_free_entry(context, &ktent);
    return retval;
}
Esempio n. 12
0
/* Decrypt the ticket in req using a principal looked up from keytab. */
static krb5_error_code
try_one_princ(krb5_context context, const krb5_ap_req *req,
              krb5_const_principal princ, krb5_keytab keytab,
              krb5_keyblock *keyblock_out)
{
    krb5_error_code ret;
    krb5_keytab_entry ent;

    ret = krb5_kt_get_entry(context, keytab, princ,
                            req->ticket->enc_part.kvno,
                            req->ticket->enc_part.enctype, &ent);
    if (ret)
        return ret;
    ret = try_one_entry(context, req, &ent, keyblock_out);
    if (ret == 0)
        TRACE_RD_REQ_DECRYPT_SPECIFIC(context, ent.principal, &ent.key);
    (void)krb5_free_keytab_entry_contents(context, &ent);
    if (ret)
        return ret;

    return 0;
}
Esempio n. 13
0
static krb5_error_code
get_key_from_keytab(krb5_context context,
		    krb5_auth_context *auth_context,
		    krb5_ap_req *ap_req,
		    krb5_const_principal server,
		    krb5_keytab keytab,
		    krb5_keyblock **out_key)
{
    krb5_keytab_entry entry;
    krb5_error_code ret;
    int kvno;
    krb5_keytab real_keytab;

    if(keytab == NULL)
	krb5_kt_default(context, &real_keytab);
    else
	real_keytab = keytab;
    
    if (ap_req->ticket.enc_part.kvno)
	kvno = *ap_req->ticket.enc_part.kvno;
    else
	kvno = 0;

    ret = krb5_kt_get_entry (context,
			     real_keytab,
			     server,
			     kvno,
			     ap_req->ticket.enc_part.etype,
			     &entry);
    if(ret)
	goto out;
    ret = krb5_copy_keyblock(context, &entry.keyblock, out_key);
    krb5_kt_free_entry (context, &entry);
out:    
    if(keytab == NULL)
	krb5_kt_close(context, real_keytab);
    
    return ret;
}
Esempio n. 14
0
krb5_error_code	KRB5_CALLCONV
krb5_server_decrypt_ticket_keytab(krb5_context context,
				  const krb5_keytab kt,
				  krb5_ticket *ticket)
{
    krb5_error_code       retval;
    krb5_enctype          enctype;
    krb5_keytab_entry     ktent;

    enctype = ticket->enc_part.enctype;

    if ((retval = krb5_kt_get_entry(context, kt, ticket->server,
                                    ticket->enc_part.kvno,
                                    enctype, &ktent)))
        return retval;

    retval = krb5int_server_decrypt_ticket_keyblock(context,
						    &ktent.key, ticket);
    /* Upon error, Free keytab entry first, then return */

    (void) krb5_kt_free_entry(context, &ktent);
    return retval;
}
Esempio n. 15
0
/*
 * effects: If keyprocarg is not NULL, it is taken to be the name of a 
 *	keytab.  Otherwise, the default keytab will be used.  This 
 *	routine opens the keytab and finds the principal associated with
 *	principal, vno, and enctype and returns the resulting key in *key 
 *	or returning an error code if it is not	found. 
 * returns: Either KSUCCESS or error code.
 * errors: error code if not found or keyprocarg is invalid.
 */
krb5_error_code KRB5_CALLCONV
krb5_kt_read_service_key(krb5_context context, krb5_pointer keyprocarg, krb5_principal principal, krb5_kvno vno, krb5_enctype enctype, krb5_keyblock **key)
{
    krb5_error_code kerror = KSUCCESS;
    char keytabname[MAX_KEYTAB_NAME_LEN + 1]; /* + 1 for NULL termination */
    krb5_keytab id;
    krb5_keytab_entry entry;
        
    /*
     * Get the name of the file that we should use. 
     */
    if (!keyprocarg) {
	if ((kerror = krb5_kt_default_name(context, (char *)keytabname, 
					   sizeof(keytabname) - 1))!= KSUCCESS)
	    return (kerror);
    } else {
	memset(keytabname, 0, sizeof(keytabname));
	(void) strncpy(keytabname, (char *)keyprocarg, 
		       sizeof(keytabname) - 1);
    }

    if ((kerror = krb5_kt_resolve(context, (char *)keytabname, &id)))
	return (kerror);

    kerror = krb5_kt_get_entry(context, id, principal, vno, enctype, &entry);
    krb5_kt_close(context, id);

    if (kerror)
	return(kerror);

    krb5_copy_keyblock(context, &entry.key, key);

    krb5_kt_free_entry(context, &entry);

    return (KSUCCESS);
}
Esempio n. 16
0
/* Decrypt the ticket in req using a principal looked up from keytab.
 * explicit_server should be true if this is the only usable principal. */
static krb5_error_code
try_one_princ(krb5_context context, const krb5_ap_req *req,
              krb5_const_principal princ, krb5_keytab keytab,
              krb5_boolean explicit_server, krb5_keyblock *keyblock_out)
{
    krb5_error_code ret;
    krb5_keytab_entry ent;
    krb5_kvno tkt_kvno = req->ticket->enc_part.kvno;
    krb5_enctype tkt_etype = req->ticket->enc_part.enctype;
    krb5_principal tkt_server = req->ticket->server;

    ret = krb5_kt_get_entry(context, keytab, princ, tkt_kvno, tkt_etype, &ent);
    if (ret) {
        return keytab_fetch_error(context, ret, princ, tkt_server, tkt_kvno,
                                  explicit_server);
    }
    ret = try_one_entry(context, req, &ent, keyblock_out);
    if (ret == 0)
        TRACE_RD_REQ_DECRYPT_SPECIFIC(context, ent.principal, &ent.key);
    (void)krb5_free_keytab_entry_contents(context, &ent);
    if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
        return integrity_error(context, princ, req->ticket->server);
    return ret;
}
Esempio n. 17
0
static krb5_error_code
get_key_from_keytab(krb5_context context,
		    krb5_const_principal server,
		    krb5_enctype enctype,
		    krb5_kvno kvno,
		    krb5_keyblock **out_key)
{
	krb5_keytab_entry entry;
	krb5_error_code ret;
	krb5_keytab keytab;
	char *name = NULL;

	/* We have to open a new keytab handle here, as MIT does
	   an implicit open/getnext/close on krb5_kt_get_entry. We
	   may be in the middle of a keytab enumeration when this is
	   called. JRA. */

	ret = krb5_kt_default(context, &keytab);
	if (ret) {
		DEBUG(0,("get_key_from_keytab: failed to open keytab: %s\n", error_message(ret)));
		return ret;
	}

	if ( DEBUGLEVEL >= 10 ) {
		if (smb_krb5_unparse_name(context, server, &name) == 0) {
			DEBUG(10,("get_key_from_keytab: will look for kvno %d, enctype %d and name: %s\n", 
				kvno, enctype, name));
			SAFE_FREE(name);
		}
	}

	ret = krb5_kt_get_entry(context,
				keytab,
				server,
				kvno,
				enctype,
				&entry);

	if (ret) {
		DEBUG(0,("get_key_from_keytab: failed to retrieve key: %s\n", error_message(ret)));
		goto out;
	}

#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */
	ret = krb5_copy_keyblock(context, &entry.keyblock, out_key);
#elif defined(HAVE_KRB5_KEYTAB_ENTRY_KEY) /* MIT */
	ret = krb5_copy_keyblock(context, &entry.key, out_key);
#else
#error UNKNOWN_KRB5_KEYTAB_ENTRY_FORMAT
#endif

	if (ret) {
		DEBUG(0,("get_key_from_keytab: failed to copy key: %s\n", error_message(ret)));
		goto out;
	}
		
	smb_krb5_kt_free_entry(context, &entry);
	
out:    
	krb5_kt_close(context, keytab);
	return ret;
}
Esempio n. 18
0
static int gss_create_principal(AFPObj *obj)
{
    int rv = -1;
#ifdef HAVE_KERBEROS
    krb5_context context;
    krb5_error_code ret;
    const char *error_msg;
    krb5_keytab keytab;
    krb5_keytab_entry entry;
    krb5_principal service_principal;
    char *principal;
    krb5_kt_cursor cursor;

    if (krb5_init_context(&context)) {
        LOG(log_error, logtype_afpd, "gss_create_principal: failed to intialize a krb5_context");
        goto exit;
    }
    if ((ret = krb5_kt_default(context, &keytab)))
        goto krb5_error;

    if (obj->options.k5service && obj->options.fqdn && obj->options.k5realm) {
        LOG(log_debug, logtype_afpd, "gss_create_principal: using service principal specified in options");
            
        if ((ret = krb5_build_principal(context,
                                        &service_principal,
                                        strlen(obj->options.k5realm),
                                        obj->options.k5realm,
                                        obj->options.k5service,
                                        obj->options.fqdn,
                                        NULL)))
            goto krb5_error;

        if ((ret = krb5_kt_get_entry(context,
                                     keytab,
                                     service_principal,
                                     0, // kvno - wildcard
                                     0, // enctype - wildcard
                                     &entry)) == KRB5_KT_NOTFOUND) {
            krb5_unparse_name(context, service_principal, &principal);
            LOG(log_error, logtype_afpd, "gss_create_principal: specified service principal '%s' not found in keytab", principal);
#ifdef HAVE_KRB5_FREE_UNPARSED_NAME
            krb5_free_unparsed_name(context, principal);
#else
            krb5_xfree(principal);
#endif
            goto krb5_cleanup;
        }
        krb5_free_principal(context, service_principal);
        if (ret)
            goto krb5_error;
    } else {
        LOG(log_debug, logtype_afpd, "gss_create_principal: using first entry from keytab as service principal");
        if ((ret = krb5_kt_start_seq_get(context, keytab, &cursor)))
            goto krb5_error;
        ret = krb5_kt_next_entry(context, keytab, &entry, &cursor);
        krb5_kt_end_seq_get(context, keytab, &cursor);
        if (ret)
            goto krb5_error;
    }

    krb5_unparse_name(context, entry.principal, &principal);
#ifdef HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS
    krb5_free_keytab_entry_contents(context, &entry);
#elif defined(HAVE_KRB5_KT_FREE_ENTRY)
    krb5_kt_free_entry(context, &entry);
#endif
    set_principal(obj, principal);
    free(principal);
    rv = 0;
    goto krb5_cleanup;

krb5_error:
    if (ret) {
        error_msg = krb5_get_error_message(context, ret);
        LOG(log_note, logtype_afpd, "Can't get principal from default keytab: %s",
            (char *)error_msg);
#ifdef HAVE_KRB5_FREE_ERROR_MESSAGE
        krb5_free_error_message(context, error_msg);
#else
        krb5_xfree(error_msg);
#endif
    }

krb5_cleanup:
    krb5_kt_close(context, keytab);
    krb5_free_context(context);

#else /* ! HAVE_KERBEROS */
    if (!obj->options.k5service || !obj->options.fqdn || !obj->options.k5realm)
        goto exit;

    char principal[255];
    size_t len = snprintf(principal, sizeof(principal), "%s/%s@%s",
                          obj->options.k5service, obj->options.fqdn, obj->options.k5realm);
    (void)set_principal(obj, principal);
    rv = 0;
#endif /* HAVE_KERBEROS */

exit:
    return rv;
}
Esempio n. 19
0
static void
remove_principal(char *keytab_str, krb5_keytab keytab,
                 char *princ_str, char *kvno_str)
{
    krb5_principal princ;
    krb5_keytab_entry entry;
    krb5_kt_cursor cursor;
    enum { UNDEF, SPEC, HIGH, ALL, OLD } mode;
    int code, did_something;
    krb5_kvno kvno;

    code = krb5_parse_name(context, princ_str, &princ);
    if (code != 0) {
        com_err(whoami, code, "while parsing principal name %s", princ_str);
        return;
    }

    mode = UNDEF;
    if (kvno_str == NULL) {
        mode = HIGH;
        kvno = 0;
    } else if (strcmp(kvno_str, "all") == 0) {
        mode = ALL;
        kvno = 0;
    } else if (strcmp(kvno_str, "old") == 0) {
        mode = OLD;
        kvno = 0;
    } else {
        mode = SPEC;
        kvno = atoi(kvno_str);
    }

    /* kvno is set to specified value for SPEC, 0 otherwise */
    code = krb5_kt_get_entry(context, keytab, princ, kvno, 0, &entry);
    if (code != 0) {
        if (code == ENOENT) {
            fprintf(stderr, "%s: Keytab %s does not exist.\n",
                    whoami, keytab_str);
        } else if (code == KRB5_KT_NOTFOUND) {
            if (mode != SPEC) {
                fprintf(stderr, "%s: No entry for principal "
                        "%s exists in keytab %s\n",
                        whoami, princ_str, keytab_str);
            } else {
                fprintf(stderr, "%s: No entry for principal "
                        "%s with kvno %d exists in keytab "
                        "%s.\n", whoami, princ_str, kvno, keytab_str);
            }
        } else
            com_err(whoami, code, "while retrieving highest kvno from keytab");
        return;
    }

    /* set kvno to spec'ed value for SPEC, highest kvno otherwise */
    kvno = entry.vno;
    krb5_kt_free_entry(context, &entry);

    code = krb5_kt_start_seq_get(context, keytab, &cursor);
    if (code != 0) {
        com_err(whoami, code, "while starting keytab scan");
        return;
    }

    did_something = 0;
    while ((code = krb5_kt_next_entry(context, keytab, &entry,
                                      &cursor)) == 0) {
        if (krb5_principal_compare(context, princ, entry.principal) &&
            ((mode == ALL) ||
             (mode == SPEC && entry.vno == kvno) ||
             (mode == OLD && entry.vno != kvno) ||
             (mode == HIGH && entry.vno == kvno))) {

            /*
             * Ack!  What a kludge... the scanning functions lock
             * the keytab so entries cannot be removed while they
             * are operating.
             */
            code = krb5_kt_end_seq_get(context, keytab, &cursor);
            if (code != 0) {
                com_err(whoami, code, "while temporarily ending keytab scan");
                return;
            }
            code = krb5_kt_remove_entry(context, keytab, &entry);
            if (code != 0) {
                com_err(whoami, code, "while deleting entry from keytab");
                return;
            }
            code = krb5_kt_start_seq_get(context, keytab, &cursor);
            if (code != 0) {
                com_err(whoami, code, "while restarting keytab scan");
                return;
            }

            did_something++;
            if (!quiet)
                printf("Entry for principal %s with kvno %d "
                       "removed from keytab %s.\n",
                       princ_str, entry.vno, keytab_str);
        }
        krb5_kt_free_entry(context, &entry);
    }
    if (code && code != KRB5_KT_END) {
        com_err(whoami, code, "while scanning keytab");
        return;
    }
    code = krb5_kt_end_seq_get(context, keytab, &cursor);
    if (code) {
        com_err(whoami, code, "while ending keytab scan");
        return;
    }

    /*
     * If !did_someting then mode must be OLD or we would have
     * already returned with an error.  But check it anyway just to
     * prevent unexpected error messages...
     */
    if (!did_something && mode == OLD) {
        fprintf(stderr, "%s: There is only one entry for principal "
                "%s in keytab %s\n", whoami, princ_str, keytab_str);
    }
}
Esempio n. 20
0
static void do_v5_kvno (int count, char *names[], 
                        char * ccache_name, char *etype_str, char *keytab_name,
			char *sname)
{
    krb5_error_code ret;
    krb5_context context = 0;
    int i, errors;
    krb5_enctype etype;
    krb5_ccache ccache;
    krb5_principal me;
    krb5_creds in_creds, *out_creds = NULL;
    Ticket ticket;
    size_t len;
    char *princ = NULL;
    krb5_keytab keytab = NULL;

    ret = krb5_init_context(&context);
    if (ret)
	errx(1, "krb5_init_context failed: %d", ret);

    if (etype_str) {
        ret = krb5_string_to_enctype(context, etype_str, &etype);
	if (ret)
	    krb5_err(context, 1, ret, "Failed to convert encryption type %s", etype_str);
    } else {
	etype = 0;
    }

    if (ccache_name)
        ret = krb5_cc_resolve(context, ccache_name, &ccache);
    else
        ret = krb5_cc_default(context, &ccache);
    if (ret)
        krb5_err(context, 1, ret, "Failed to open credentials cache %s",
                 (ccache_name) ? ccache_name : "(Default)");

    if (keytab_name) {
	ret = krb5_kt_resolve(context, keytab_name, &keytab);
	if (ret)
            krb5_err(context, 1, ret, "Can't resolve keytab %s", keytab_name);
    }

    ret = krb5_cc_get_principal(context, ccache, &me);
    if (ret)
        krb5_err(context, 1, ret, "krb5_cc_get_principal");

    errors = 0;

    for (i = 0; i < count; i++) {
	memset(&in_creds, 0, sizeof(in_creds));
        memset(&ticket, 0, sizeof(ticket));

	in_creds.client = me;

	if (sname != NULL) {
	    ret = krb5_sname_to_principal(context, names[i],
					  sname, KRB5_NT_SRV_HST,
					  &in_creds.server);
	} else {
	    ret = krb5_parse_name(context, names[i], &in_creds.server);
	}
	if (ret) {
	    if (!quiet_flag)
                krb5_warn(context, ret, "Couldn't parse principal name %s", names[i]);
            errors++;
	    continue;
	}

	ret = krb5_unparse_name(context, in_creds.server, &princ);
	if (ret) {
            krb5_warn(context, ret, "Couldn't format parsed principal name for '%s'",
                      names[i]);
	    errors++;
            goto next;
	}

	in_creds.session.keytype = etype;

	ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds);

	if (ret) {
            krb5_warn(context, ret, "Couldn't get credentials for %s", princ);
	    errors++;
	    goto next;
	}

	ret = decode_Ticket(out_creds->ticket.data, out_creds->ticket.length,
                            &ticket, &len);
	if (ret) {
	    krb5_err(context, 1, ret, "Can't decode ticket for %s", princ);
	    errors++;
            goto next;
	    continue;
	}

	if (keytab) {
            krb5_keytab_entry   kte;
            krb5_crypto         crypto;
            krb5_data           dec_data;
            EncTicketPart       decr_part;

            ret = krb5_kt_get_entry(context, keytab, in_creds.server,
                                    (ticket.enc_part.kvno != NULL)?
                                    *ticket.enc_part.kvno : 0,
                                    ticket.enc_part.etype,
                                    &kte);
            if (ret) {
                krb5_warn(context, ret, "Can't decrypt ticket for %s", princ);
                if (!quiet_flag)
                    printf("%s: kvno = %d, keytab entry invalid", princ,
                           (ticket.enc_part.kvno != NULL)?
                           *ticket.enc_part.kvno : 0);
                errors ++;
                goto next;
            }

            ret = krb5_crypto_init(context, &kte.keyblock, 0, &crypto);
            if (ret) {
                krb5_warn(context, ret, "krb5_crypto_init");
                errors ++;
                krb5_kt_free_entry(context, &kte);
                goto next;
            }

            ret = krb5_decrypt_EncryptedData (context, crypto, KRB5_KU_TICKET,
                                              &ticket.enc_part, &dec_data);
            krb5_crypto_destroy(context, crypto);
            krb5_kt_free_entry(context, &kte);

            if (ret) {
                krb5_warn(context, ret, "krb5_decrypt_EncryptedData");
                errors ++;
                goto next;
            }

            ret = decode_EncTicketPart(dec_data.data, dec_data.length,
                                       &decr_part, &len);
            krb5_data_free(&dec_data);
            if (ret) {
                krb5_warn(context, ret, "decode_EncTicketPart");
                errors ++;
                goto next;
            }

            if (!quiet_flag)
		printf("%s: kvno = %d, keytab entry valid\n", princ,
                       (ticket.enc_part.kvno != NULL)?
                       *ticket.enc_part.kvno : 0);

            free_EncTicketPart(&decr_part);
	} else {
	    if (!quiet_flag)
		printf("%s: kvno = %d\n", princ,
                       (ticket.enc_part.kvno != NULL)? *ticket.enc_part.kvno : 0);
	}

    next:
        if (out_creds) {
            krb5_free_creds(context, out_creds);
            out_creds = NULL;
        }

        if (princ) {
            krb5_free_unparsed_name(context, princ);
            princ = NULL;
        }

	krb5_free_principal(context, in_creds.server);

        free_Ticket(&ticket);
    }

    if (keytab)
	krb5_kt_close(context, keytab);
    krb5_free_principal(context, me);
    krb5_cc_close(context, ccache);
    krb5_free_context(context);

    if (errors)
	exit(1);

    exit(0);
}
Esempio n. 21
0
krb5_error_code KRB5_CALLCONV
krb5_verify_init_creds(krb5_context context,
                       krb5_creds *creds,
                       krb5_principal server_arg,
                       krb5_keytab keytab_arg,
                       krb5_ccache *ccache_arg,
                       krb5_verify_init_creds_opt *options)
{
    krb5_error_code ret;
    krb5_principal server;
    krb5_keytab keytab;
    krb5_ccache ccache;
    krb5_keytab_entry kte;
    krb5_creds in_creds, *out_creds;
    krb5_auth_context authcon;
    krb5_data ap_req;

    /* KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN */

    server = NULL;
    keytab = NULL;
    ccache = NULL;
    out_creds = NULL;
    authcon = NULL;
    ap_req.data = NULL;

    if (keytab_arg) {
        keytab = keytab_arg;
    } else {
        if ((ret = krb5_kt_default(context, &keytab)))
            goto cleanup;
    }

    if (server_arg) {
        ret = krb5_copy_principal(context, server_arg, &server);
        if (ret)
            goto cleanup;
    } else {
        /* Use a principal name from the keytab. */
        ret = k5_kt_get_principal(context, keytab, &server);
        if (ret) {
            /* There's no keytab, or it's empty, or we can't read it.
             * Allow this unless configuration demands verification. */
            if (!nofail(context, options, creds))
                ret = 0;
            goto cleanup;
        }
    }

    /* first, check if the server is in the keytab.  If not, there's
       no reason to continue.  rd_req does all this, but there's
       no way to know that a given error is caused by a missing
       keytab or key, and not by some other problem. */

    if (krb5_is_referral_realm(&server->realm)) {
        krb5_free_data_contents(context, &server->realm);
        ret = krb5_get_default_realm(context, &server->realm.data);
        if (ret) goto cleanup;
        server->realm.length = strlen(server->realm.data);
    }

    if ((ret = krb5_kt_get_entry(context, keytab, server, 0, 0, &kte))) {
        /* this means there is no keying material.  This is ok, as long as
           it is not prohibited by the configuration */
        if (!nofail(context, options, creds))
            ret = 0;
        goto cleanup;
    }

    krb5_kt_free_entry(context, &kte);

    /* If the creds are for the server principal, we're set, just do a mk_req.
     * Otherwise, do a get_credentials first.
     */

    if (krb5_principal_compare(context, server, creds->server)) {
        /* make an ap_req */
        if ((ret = krb5_mk_req_extended(context, &authcon, 0, NULL, creds,
                                        &ap_req)))
            goto cleanup;
    } else {
        /* this is unclean, but it's the easiest way without ripping the
           library into very small pieces.  store the client's initial cred
           in a memory ccache, then call the library.  Later, we'll copy
           everything except the initial cred into the ccache we return to
           the user.  A clean implementation would involve library
           internals with a coherent idea of "in" and "out". */

        /* insert the initial cred into the ccache */

        if ((ret = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))) {
            ccache = NULL;
            goto cleanup;
        }

        if ((ret = krb5_cc_initialize(context, ccache, creds->client)))
            goto cleanup;

        if ((ret = krb5_cc_store_cred(context, ccache, creds)))
            goto cleanup;

        /* set up for get_creds */
        memset(&in_creds, 0, sizeof(in_creds));
        in_creds.client = creds->client;
        in_creds.server = server;
        if ((ret = krb5_timeofday(context, &in_creds.times.endtime)))
            goto cleanup;
        in_creds.times.endtime += 5*60;

        if ((ret = krb5_get_credentials(context, 0, ccache, &in_creds,
                                        &out_creds)))
            goto cleanup;

        /* make an ap_req */
        if ((ret = krb5_mk_req_extended(context, &authcon, 0, NULL, out_creds,
                                        &ap_req)))
            goto cleanup;
    }

    /* wipe the auth context for mk_req */
    if (authcon) {
        krb5_auth_con_free(context, authcon);
        authcon = NULL;
    }

    /* verify the ap_req */

    if ((ret = krb5_rd_req(context, &authcon, &ap_req, server, keytab,
                           NULL, NULL)))
        goto cleanup;

    /* if we get this far, then the verification succeeded.  We can
       still fail if the library stuff here fails, but that's it */

    if (ccache_arg && ccache) {
        if (*ccache_arg == NULL) {
            krb5_ccache retcc;

            retcc = NULL;

            if ((ret = krb5_cc_resolve(context, "MEMORY:rd_req2", &retcc)) ||
                (ret = krb5_cc_initialize(context, retcc, creds->client)) ||
                (ret = copy_creds_except(context, ccache, retcc,
                                         creds->server))) {
                if (retcc)
                    krb5_cc_destroy(context, retcc);
            } else {
                *ccache_arg = retcc;
            }
        } else {
            ret = copy_creds_except(context, ccache, *ccache_arg,
                                    server);
        }
    }

    /* if any of the above paths returned an errors, then ret is set accordingly.
     * Either that, or it's zero, which is fine, too
     */

cleanup:
    if ( server)
        krb5_free_principal(context, server);
    if (!keytab_arg && keytab)
        krb5_kt_close(context, keytab);
    if (ccache)
        krb5_cc_destroy(context, ccache);
    if (out_creds)
        krb5_free_creds(context, out_creds);
    if (authcon)
        krb5_auth_con_free(context, authcon);
    if (ap_req.data)
        free(ap_req.data);

    return(ret);
}
Esempio n. 22
0
int
kt_copy (void *opt, int argc, char **argv)
{
    krb5_error_code ret;
    krb5_keytab src_keytab, dst_keytab;
    krb5_kt_cursor cursor;
    krb5_keytab_entry entry, dummy;
    const char *from = argv[0];
    const char *to = argv[1];

    ret = krb5_kt_resolve (context, from, &src_keytab);
    if (ret) {
	krb5_warn (context, ret, "resolving src keytab `%s'", from);
	return 1;
    }

    ret = krb5_kt_resolve (context, to, &dst_keytab);
    if (ret) {
	krb5_kt_close (context, src_keytab);
	krb5_warn (context, ret, "resolving dst keytab `%s'", to);
	return 1;
    }

    ret = krb5_kt_start_seq_get (context, src_keytab, &cursor);
    if (ret) {
	krb5_warn (context, ret, "krb5_kt_start_seq_get %s", keytab_string);
	goto out;
    }

    if (verbose_flag)
	fprintf(stderr, "copying %s to %s\n", from, to);

    while((ret = krb5_kt_next_entry(context, src_keytab,
				    &entry, &cursor)) == 0) {
	char *name_str;
	char *etype_str;
	ret = krb5_unparse_name (context, entry.principal, &name_str);
	if(ret) {
	    krb5_warn(context, ret, "krb5_unparse_name");
	    name_str = NULL; /* XXX */
	}
	ret = krb5_enctype_to_string(context, entry.keyblock.keytype, &etype_str);
	if(ret) {
	    krb5_warn(context, ret, "krb5_enctype_to_string");
	    etype_str = NULL; /* XXX */
	}
	ret = krb5_kt_get_entry(context, dst_keytab,
				entry.principal,
				entry.vno,
				entry.keyblock.keytype,
				&dummy);
	if(ret == 0) {
	    /* this entry is already in the new keytab, so no need to
               copy it; if the keyblocks are not the same, something
               is weird, so complain about that */
	    if(!compare_keyblock(&entry.keyblock, &dummy.keyblock)) {
		krb5_warnx(context, "entry with different keyvalue "
			   "already exists for %s, keytype %s, kvno %d",
			   name_str, etype_str, entry.vno);
	    }
	    krb5_kt_free_entry(context, &dummy);
	    krb5_kt_free_entry (context, &entry);
	    free(name_str);
	    free(etype_str);
	    continue;
	} else if(ret != KRB5_KT_NOTFOUND) {
	    krb5_warn (context, ret, "%s: fetching %s/%s/%u",
		       to, name_str, etype_str, entry.vno);
	    krb5_kt_free_entry (context, &entry);
	    free(name_str);
	    free(etype_str);
	    break;
	}
	if (verbose_flag)
	    fprintf (stderr, "copying %s, keytype %s, kvno %d\n", name_str,
		     etype_str, entry.vno);
	ret = krb5_kt_add_entry (context, dst_keytab, &entry);
	krb5_kt_free_entry (context, &entry);
	if (ret) {
	    krb5_warn (context, ret, "%s: adding %s/%s/%u",
		       to, name_str, etype_str, entry.vno);
	    free(name_str);
	    free(etype_str);
	    break;
	}
	free(name_str);
	free(etype_str);
    }
    krb5_kt_end_seq_get (context, src_keytab, &cursor);

  out:
    krb5_kt_close (context, src_keytab);
    krb5_kt_close (context, dst_keytab);
    return ret != 0;
}
Esempio n. 23
0
File: sss_krb5.c Progetto: 3van/sssd
krb5_error_code sss_extract_pac(krb5_context ctx,
                                krb5_ccache ccache,
                                krb5_principal server_principal,
                                krb5_principal client_principal,
                                krb5_keytab keytab,
                                krb5_authdata ***_pac_authdata)
{
#ifdef HAVE_PAC_RESPONDER
    krb5_error_code kerr;
    krb5_creds mcred;
    krb5_creds cred;
    krb5_authdata **pac_authdata = NULL;
    krb5_pac pac = NULL;
    int ret;
    krb5_ticket *ticket = NULL;
    krb5_keytab_entry entry;

    memset(&entry, 0, sizeof(entry));
    memset(&mcred, 0, sizeof(mcred));
    memset(&cred, 0, sizeof(mcred));

    mcred.server = server_principal;
    mcred.client = client_principal;

    kerr = krb5_cc_retrieve_cred(ctx, ccache, 0, &mcred, &cred);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_cc_retrieve_cred failed.\n");
        goto done;
    }

    kerr = krb5_decode_ticket(&cred.ticket, &ticket);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_decode_ticket failed.\n");
        goto done;
    }

    kerr = krb5_server_decrypt_ticket_keytab(ctx, keytab, ticket);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_server_decrypt_ticket_keytab failed.\n");
        goto done;
    }

    kerr = sss_krb5_find_authdata(ctx,
                                  ticket->enc_part2->authorization_data, NULL,
                                  KRB5_AUTHDATA_WIN2K_PAC, &pac_authdata);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_find_authdata failed.\n");
        goto done;
    }

    if (pac_authdata == NULL || pac_authdata[0] == NULL) {
        DEBUG(SSSDBG_OP_FAILURE, "No PAC authdata available.\n");
        kerr = ENOENT;
        goto done;
    }

    if (pac_authdata[1] != NULL) {
        DEBUG(SSSDBG_OP_FAILURE, "More than one PAC autdata found.\n");
        kerr = EINVAL;
        goto done;
    }

    kerr = krb5_pac_parse(ctx, pac_authdata[0]->contents,
                          pac_authdata[0]->length, &pac);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_pac_parse failed.\n");
        goto done;
    }

    kerr = krb5_kt_get_entry(ctx, keytab, ticket->server,
                             ticket->enc_part.kvno, ticket->enc_part.enctype,
                             &entry);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_kt_get_entry failed.\n");
        goto done;
    }

    kerr = krb5_pac_verify(ctx, pac, 0, NULL, &entry.key, NULL);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_pac_verify failed.\n");
        goto done;
    }

    ret = unsetenv("_SSS_LOOPS");
    if (ret != EOK) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to unset _SSS_LOOPS, "
                  "sss_pac_make_request will most certainly fail.\n");
    }

    *_pac_authdata = pac_authdata;
    kerr = 0;

done:
    if (kerr != 0) {
        krb5_free_authdata(ctx, pac_authdata);
    }
    if (entry.magic != 0) {
        krb5_free_keytab_entry_contents(ctx, &entry);
    }
    krb5_pac_free(ctx, pac);
    if (ticket != NULL) {
        krb5_free_ticket(ctx, ticket);
    }

    krb5_free_cred_contents(ctx, &cred);
    return kerr;
#else
    return ENOTSUP;
#endif
}
Esempio n. 24
0
static void
kt_test(krb5_context context, const char *name)
{
    krb5_error_code kret;
    krb5_keytab kt;
    const char *type;
    char buf[BUFSIZ];
    char *p;
    krb5_keytab_entry kent, kent2;
    krb5_principal princ;
    krb5_kt_cursor cursor, cursor2;
    int cnt;

    kret = krb5_kt_resolve(context, name, &kt);
    CHECK(kret, "resolve");

    type = krb5_kt_get_type(context, kt);
    CHECK_STR(type, "getting kt type");
    printf("  Type is: %s\n", type);

    kret = krb5_kt_get_name(context, kt, buf, sizeof(buf));
    CHECK(kret, "get_name");
    printf("  Name is: %s\n", buf);

    /* Check that length checks fail */
    /* The buffer is allocated too small - to allow for valgrind test of
       overflows
    */
    p = malloc(strlen(buf));
    kret = krb5_kt_get_name(context, kt, p, 1);
    if(kret != KRB5_KT_NAME_TOOLONG) {
        CHECK(kret, "get_name - size 1");
    }


    kret = krb5_kt_get_name(context, kt, p, strlen(buf));
    if(kret != KRB5_KT_NAME_TOOLONG) {
        CHECK(kret, "get_name");
    }
    free(p);

    /* Try to lookup unknown principal - when keytab does not exist*/
    kret = krb5_parse_name(context, "test/[email protected]", &princ);
    CHECK(kret, "parsing principal");


    kret = krb5_kt_get_entry(context, kt, princ, 0, 0, &kent);
    if((kret != KRB5_KT_NOTFOUND) && (kret != ENOENT)) {
        CHECK(kret, "Getting non-existant entry");
    }


    /* ===================   Add entries to keytab ================= */
    /*
     * Add the following for this principal
     * enctype 1, kvno 1, key = "1"
     * enctype 2, kvno 1, key = "1"
     * enctype 1, kvno 2, key = "2"
     */
    memset(&kent, 0, sizeof(kent));
    kent.magic = KV5M_KEYTAB_ENTRY;
    kent.principal = princ;
    kent.timestamp = 327689;
    kent.vno = 1;
    kent.key.magic = KV5M_KEYBLOCK;
    kent.key.enctype = 1;
    kent.key.length = 1;
    kent.key.contents = (krb5_octet *) "1";


    kret = krb5_kt_add_entry(context, kt, &kent);
    CHECK(kret, "Adding initial entry");

    kent.key.enctype = 2;
    kret = krb5_kt_add_entry(context, kt, &kent);
    CHECK(kret, "Adding second entry");

    kent.key.enctype = 1;
    kent.vno = 2;
    kent.key.contents = (krb5_octet *) "2";
    kret = krb5_kt_add_entry(context, kt, &kent);
    CHECK(kret, "Adding third entry");

    /* Free memory */
    krb5_free_principal(context, princ);

    /* ==============   Test iterating over contents of keytab ========= */

    kret = krb5_kt_start_seq_get(context, kt, &cursor);
    CHECK(kret, "Start sequence get");


    memset(&kent, 0, sizeof(kent));
    cnt = 0;
    while((kret = krb5_kt_next_entry(context, kt, &kent, &cursor)) == 0) {
        if(((kent.vno != 1) && (kent.vno != 2)) ||
           ((kent.key.enctype != 1) && (kent.key.enctype != 2)) ||
           (kent.key.length != 1) ||
           (kent.key.contents[0] != kent.vno +'0')) {
            fprintf(stderr, "Error in read contents\n");
            exit(1);
        }

        if((kent.magic != KV5M_KEYTAB_ENTRY) ||
           (kent.key.magic != KV5M_KEYBLOCK)) {
            fprintf(stderr, "Magic number in sequence not proper\n");
            exit(1);
        }

        cnt++;
        krb5_free_keytab_entry_contents(context, &kent);
    }
    if (kret != KRB5_KT_END) {
        CHECK(kret, "getting next entry");
    }

    if(cnt != 3) {
        fprintf(stderr, "Mismatch in number of entries in keytab");
    }

    kret = krb5_kt_end_seq_get(context, kt, &cursor);
    CHECK(kret, "End sequence get");


    /* ==========================   get_entry tests ============== */

    /* Try to lookup unknown principal  - now that keytab exists*/
    kret = krb5_parse_name(context, "test3/[email protected]", &princ);
    CHECK(kret, "parsing principal");


    kret = krb5_kt_get_entry(context, kt, princ, 0, 0, &kent);
    if((kret != KRB5_KT_NOTFOUND)) {
        CHECK(kret, "Getting non-existant entry");
    }

    krb5_free_principal(context, princ);

    /* Try to lookup known principal */
    kret = krb5_parse_name(context, "test/[email protected]", &princ);
    CHECK(kret, "parsing principal");

    kret = krb5_kt_get_entry(context, kt, princ, 0, 0, &kent);
    CHECK(kret, "looking up principal");

    /* Ensure a valid answer  - we did not specify an enctype or kvno */
    if (!krb5_principal_compare(context, princ, kent.principal) ||
        ((kent.vno != 1) && (kent.vno != 2)) ||
        ((kent.key.enctype != 1) && (kent.key.enctype != 2)) ||
        (kent.key.length != 1) ||
        (kent.key.contents[0] != kent.vno +'0')) {
        fprintf(stderr, "Retrieved principal does not check\n");
        exit(1);
    }

    krb5_free_keytab_entry_contents(context, &kent);

    /* Try to lookup a specific enctype - but unspecified kvno - should give
     * max kvno
     */
    kret = krb5_kt_get_entry(context, kt, princ, 0, 1, &kent);
    CHECK(kret, "looking up principal");

    /* Ensure a valid answer  - we did specified an enctype */
    if (!krb5_principal_compare(context, princ, kent.principal) ||
        (kent.vno != 2) || (kent.key.enctype != 1) ||
        (kent.key.length != 1) ||
        (kent.key.contents[0] != kent.vno +'0')) {
        fprintf(stderr, "Retrieved principal does not check\n");

        exit(1);

    }

    krb5_free_keytab_entry_contents(context, &kent);

    /* Try to lookup unspecified enctype, but a specified kvno */

    kret = krb5_kt_get_entry(context, kt, princ, 2, 0, &kent);
    CHECK(kret, "looking up principal");

    /* Ensure a valid answer  - we did not specify a kvno */
    if (!krb5_principal_compare(context, princ, kent.principal) ||
        (kent.vno != 2) || (kent.key.enctype != 1) ||
        (kent.key.length != 1) ||
        (kent.key.contents[0] != kent.vno +'0')) {
        fprintf(stderr, "Retrieved principal does not check\n");

        exit(1);

    }

    krb5_free_keytab_entry_contents(context, &kent);



    /* Try to lookup specified enctype and kvno */

    kret = krb5_kt_get_entry(context, kt, princ, 1, 1, &kent);
    CHECK(kret, "looking up principal");

    if (!krb5_principal_compare(context, princ, kent.principal) ||
        (kent.vno != 1) || (kent.key.enctype != 1) ||
        (kent.key.length != 1) ||
        (kent.key.contents[0] != kent.vno +'0')) {
        fprintf(stderr, "Retrieved principal does not check\n");

        exit(1);

    }

    krb5_free_keytab_entry_contents(context, &kent);


    /* Try lookup with active iterators.  */
    kret = krb5_kt_start_seq_get(context, kt, &cursor);
    CHECK(kret, "Start sequence get(2)");
    kret = krb5_kt_start_seq_get(context, kt, &cursor2);
    CHECK(kret, "Start sequence get(3)");
    kret = krb5_kt_next_entry(context, kt, &kent, &cursor);
    CHECK(kret, "getting next entry(2)");
    krb5_free_keytab_entry_contents(context, &kent);
    kret = krb5_kt_next_entry(context, kt, &kent, &cursor);
    CHECK(kret, "getting next entry(3)");
    kret = krb5_kt_next_entry(context, kt, &kent2, &cursor2);
    CHECK(kret, "getting next entry(4)");
    krb5_free_keytab_entry_contents(context, &kent2);
    kret = krb5_kt_get_entry(context, kt, kent.principal, 0, 0, &kent2);
    CHECK(kret, "looking up principal(2)");
    krb5_free_keytab_entry_contents(context, &kent2);
    kret = krb5_kt_next_entry(context, kt, &kent2, &cursor2);
    CHECK(kret, "getting next entry(5)");
    if (!krb5_principal_compare(context, kent.principal, kent2.principal)) {
        fprintf(stderr, "iterators not in sync\n");
        exit(1);
    }
    krb5_free_keytab_entry_contents(context, &kent);
    krb5_free_keytab_entry_contents(context, &kent2);
    kret = krb5_kt_next_entry(context, kt, &kent, &cursor);
    CHECK(kret, "getting next entry(6)");
    kret = krb5_kt_next_entry(context, kt, &kent2, &cursor2);
    CHECK(kret, "getting next entry(7)");
    krb5_free_keytab_entry_contents(context, &kent);
    krb5_free_keytab_entry_contents(context, &kent2);
    kret = krb5_kt_end_seq_get(context, kt, &cursor);
    CHECK(kret, "ending sequence get(1)");
    kret = krb5_kt_end_seq_get(context, kt, &cursor2);
    CHECK(kret, "ending sequence get(2)");

    /* Try to lookup specified enctype and kvno  - that does not exist*/

    kret = krb5_kt_get_entry(context, kt, princ, 3, 1, &kent);
    if(kret != KRB5_KT_KVNONOTFOUND) {
        CHECK(kret, "looking up specific principal, kvno, enctype");
    }

    krb5_free_principal(context, princ);


    /* =========================   krb5_kt_remove_entry =========== */
    /* Lookup the keytab entry w/ 2 kvno - and delete version 2 -
       ensure gone */
    kret = krb5_parse_name(context, "test/[email protected]", &princ);
    CHECK(kret, "parsing principal");

    kret = krb5_kt_get_entry(context, kt, princ, 0, 1, &kent);
    CHECK(kret, "looking up principal");

    /* Ensure a valid answer  - we are looking for max(kvno) and enc=1 */
    if (!krb5_principal_compare(context, princ, kent.principal) ||
        (kent.vno != 2) || (kent.key.enctype != 1) ||
        (kent.key.length != 1) ||
        (kent.key.contents[0] != kent.vno +'0')) {
        fprintf(stderr, "Retrieved principal does not check\n");

        exit(1);

    }

    /* Delete it */
    kret = krb5_kt_remove_entry(context, kt, &kent);
    CHECK(kret, "Removing entry");

    krb5_free_keytab_entry_contents(context, &kent);
    /* And ensure gone */

    kret = krb5_kt_get_entry(context, kt, princ, 0, 1, &kent);
    CHECK(kret, "looking up principal");

    /* Ensure a valid answer - kvno should now be 1 - we deleted 2 */
    if (!krb5_principal_compare(context, princ, kent.principal) ||
        (kent.vno != 1) || (kent.key.enctype != 1) ||
        (kent.key.length != 1) ||
        (kent.key.contents[0] != kent.vno +'0')) {
        fprintf(stderr, "Delete principal check failed\n");

        exit(1);

    }
    krb5_free_keytab_entry_contents(context, &kent);

    krb5_free_principal(context, princ);

    /* =======================  Finally close =======================  */

    kret = krb5_kt_close(context, kt);
    CHECK(kret, "close");

}
Esempio n. 25
0
static void
test_memory_keytab(krb5_context context, const char *keytab, const char *keytab2)
{
    krb5_error_code ret;
    krb5_keytab id, id2, id3;
    krb5_keytab_entry entry, entry2, entry3;

    ret = krb5_kt_resolve(context, keytab, &id);
    if (ret)
	krb5_err(context, 1, ret, "krb5_kt_resolve");

    memset(&entry, 0, sizeof(entry));
    ret = krb5_parse_name(context, "*****@*****.**", &entry.principal);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");
    entry.vno = 1;
    ret = krb5_generate_random_keyblock(context,
					ETYPE_AES256_CTS_HMAC_SHA1_96,
					&entry.keyblock);
    if (ret)
	krb5_err(context, 1, ret, "krb5_generate_random_keyblock");

    krb5_kt_add_entry(context, id, &entry);

    ret = krb5_kt_resolve(context, keytab, &id2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_kt_resolve");

    ret = krb5_kt_get_entry(context, id,
			    entry.principal,
			    0,
			    ETYPE_AES256_CTS_HMAC_SHA1_96,
			    &entry2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_kt_get_entry");
    krb5_kt_free_entry(context, &entry2);

    ret = krb5_kt_close(context, id);
    if (ret)
	krb5_err(context, 1, ret, "krb5_kt_close");

    ret = krb5_kt_get_entry(context, id2,
			    entry.principal,
			    0,
			    ETYPE_AES256_CTS_HMAC_SHA1_96,
			    &entry2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_kt_get_entry");
    krb5_kt_free_entry(context, &entry2);

    ret = krb5_kt_close(context, id2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_kt_close");


    ret = krb5_kt_resolve(context, keytab2, &id3);
    if (ret)
	krb5_err(context, 1, ret, "krb5_kt_resolve");

    memset(&entry3, 0, sizeof(entry3));
    ret = krb5_parse_name(context, "*****@*****.**", &entry3.principal);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");
    entry3.vno = 1;
    ret = krb5_generate_random_keyblock(context,
					ETYPE_AES256_CTS_HMAC_SHA1_96,
					&entry3.keyblock);
    if (ret)
	krb5_err(context, 1, ret, "krb5_generate_random_keyblock");

    krb5_kt_add_entry(context, id3, &entry3);


    ret = krb5_kt_resolve(context, keytab, &id);
    if (ret)
	krb5_err(context, 1, ret, "krb5_kt_resolve");

    ret = krb5_kt_get_entry(context, id,
			    entry.principal,
			    0,
			    ETYPE_AES256_CTS_HMAC_SHA1_96,
			    &entry2);
    if (ret == 0)
	krb5_errx(context, 1, "krb5_kt_get_entry when if should fail");

    krb5_kt_remove_entry(context, id, &entry);

    ret = krb5_kt_close(context, id);
    if (ret)
	krb5_err(context, 1, ret, "krb5_kt_close");

    krb5_kt_free_entry(context, &entry);

    krb5_kt_remove_entry(context, id3, &entry3);

    ret = krb5_kt_close(context, id3);
    if (ret)
	krb5_err(context, 1, ret, "krb5_kt_close");

    krb5_free_principal(context, entry3.principal);
    krb5_free_keyblock_contents(context, &entry3.keyblock);
}
Esempio n. 26
0
static int
create_krb5_tickets (krb5_context context, krb5_keytab kt)
{
    krb5_error_code ret;
    krb5_keytab_entry entry;
    krb5_creds cred;
    krb5_enctype etype;
    krb5_ccache ccache;

    memset (&cred, 0, sizeof(cred));

    ret = krb5_string_to_enctype (context, enc_type, &etype);
    if (ret)
	krb5_err (context, 1, ret, "krb5_string_to_enctype");
    ret = krb5_kt_get_entry (context, kt, server_principal,
			     0, etype, &entry);
    if (ret)
	krb5_err (context, 1, ret, "krb5_kt_get_entry");

    /*
     * setup cred
     */


    ret = krb5_copy_principal (context, client_principal, &cred.client);
    if (ret)
	krb5_err (context, 1, ret, "krb5_copy_principal");
    ret = krb5_copy_principal (context, server_principal, &cred.server);
    if (ret)
	krb5_err (context, 1, ret, "krb5_copy_principal");
    krb5_generate_random_keyblock(context, etype, &cred.session);

    cred.times.authtime = time(NULL);
    cred.times.starttime = time(NULL);
    cred.times.endtime = time(NULL) + expiration_time;
    cred.times.renew_till = 0;
    krb5_data_zero(&cred.second_ticket);

    ret = krb5_get_all_client_addrs (context, &cred.addresses);
    if (ret)
	krb5_err (context, 1, ret, "krb5_get_all_client_addrs");
    cred.flags.b = ticket_flags;


    /*
     * Encode encrypted part of ticket
     */

    encode_ticket (context, &entry.keyblock, etype, entry.vno, &cred);

    /*
     * Write to cc
     */

    if (ccache_str) {
	ret = krb5_cc_resolve(context, ccache_str, &ccache);
	if (ret)
	    krb5_err (context, 1, ret, "krb5_cc_resolve");
    } else {
	ret = krb5_cc_default (context, &ccache);
	if (ret)
	    krb5_err (context, 1, ret, "krb5_cc_default");
    }

    ret = krb5_cc_initialize (context, ccache, cred.client);
    if (ret)
	krb5_err (context, 1, ret, "krb5_cc_initialize");

    ret = krb5_cc_store_cred (context, ccache, &cred);
    if (ret)
	krb5_err (context, 1, ret, "krb5_cc_store_cred");

    krb5_free_cred_contents (context, &cred);
    krb5_cc_close (context, ccache);

    return 0;
}
Esempio n. 27
0
/*
 * Find a keytab entry to use for a given target hostname.
 * Tries to find the most appropriate keytab to use given the
 * name of the host we are trying to connect with.
 */
static int find_keytab_entry(krb5_context context, krb5_keytab kt,
			     const char *hostname, krb5_keytab_entry *kte,
			     const char **svcnames)
{
	krb5_error_code code;
	char **realmnames = NULL;
	char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST];
	char myhostad[NI_MAXHOST + 1];
	int i, j, retval;
	char *default_realm = NULL;
	char *realm;
	char *k5err = NULL;
	int tried_all = 0, tried_default = 0;
	krb5_principal princ;

	/* Get full target hostname */
	retval =
	    get_full_hostname(hostname, targethostname, sizeof(targethostname));
	if (retval)
		goto out;

	/* Get full local hostname */
	retval = gethostname(myhostname, sizeof(myhostname));
	if (retval) {
		k5err = gssd_k5_err_msg(context, retval);
		printerr(1, "%s while getting local hostname\n", k5err);
		gsh_free(k5err);
		goto out;
	}

	/* Compute the active directory machine name HOST$ */
	strcpy(myhostad, myhostname);
	for (i = 0; myhostad[i] != 0; ++i)
		myhostad[i] = toupper(myhostad[i]);
	myhostad[i] = '$';
	myhostad[i + 1] = 0;

	retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname));
	if (retval)
		goto out;

	code = krb5_get_default_realm(context, &default_realm);
	if (code) {
		retval = code;
		k5err = gssd_k5_err_msg(context, code);
		printerr(1, "%s while getting default realm name\n", k5err);
		gsh_free(k5err);
		goto out;
	}

	/*
	 * Get the realm name(s) for the target hostname.
	 * In reality, this function currently only returns a
	 * single realm, but we code with the assumption that
	 * someday it may actually return a list.
	 */
	code = krb5_get_host_realm(context, targethostname, &realmnames);
	if (code) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0, "ERROR: %s while getting realm(s) for host '%s'\n",
			 k5err, targethostname);
		gsh_free(k5err);
		retval = code;
		goto out;
	}

	/*
	 * Try the "appropriate" realm first, and if nothing found for that
	 * realm, try the default realm (if it hasn't already been tried).
	 */
	i = 0;
	realm = realmnames[i];
	while (1) {
		if (realm == NULL) {
			tried_all = 1;
			if (!tried_default)
				realm = default_realm;
		}
		if (tried_all && tried_default)
			break;
		if (strcmp(realm, default_realm) == 0)
			tried_default = 1;
		for (j = 0; svcnames[j] != NULL; j++) {
			char spn[300];

			/*
			 * The special svcname "$" means 'try the active
			 * directory machine account'
			 */
			if (strcmp(svcnames[j], "$") == 0) {
				snprintf(spn, sizeof(spn), "%s@%s", myhostad,
					 realm);
				code =
				    krb5_build_principal_ext(context, &princ,
							     strlen(realm),
							     realm,
							     strlen(myhostad),
							     myhostad, NULL);
			} else {
				snprintf(spn, sizeof(spn), "%s/%s@%s",
					 svcnames[j], myhostname, realm);
				code =
				    krb5_build_principal_ext(context, &princ,
							     strlen(realm),
							     realm,
							     strlen(svcnames
								    [j]),
							     svcnames[j],
							     strlen(myhostname),
							     myhostname, NULL);
			}

			if (code) {
				k5err = gssd_k5_err_msg(context, code);
				printerr(1,
					 "%s while building principal for '%s'\n",
					 k5err, spn);
				gsh_free(k5err);
				continue;
			}
			code = krb5_kt_get_entry(context, kt, princ, 0, 0, kte);
			krb5_free_principal(context, princ);
			if (code) {
				k5err = gssd_k5_err_msg(context, code);
				printerr(3,
					 "%s while getting keytab entry for '%s'\n",
					 k5err, spn);
				gsh_free(k5err);
			} else {
				printerr(3,
					 "Success getting keytab entry for '%s'\n",
					 spn);
				retval = 0;
				goto out;
			}
			retval = code;
		}
		/*
		 * Nothing found with our hostname instance, now look for
		 * names with any instance (they must have an instance)
		 */
		for (j = 0; svcnames[j] != NULL; j++) {
			int found = 0;
			if (strcmp(svcnames[j], "$") == 0)
				continue;
			code =
			    gssd_search_krb5_keytab(context, kt, realm,
						    svcnames[j], &found, kte);
			if (!code && found) {
				printerr(3,
					 "Success getting keytab entry for "
					 "%s/*@%s\n", svcnames[j], realm);
				retval = 0;
				goto out;
			}
		}
		if (!tried_all) {
			i++;
			realm = realmnames[i];
		}
	}
 out:
	if (default_realm)
		k5_free_default_realm(context, default_realm);
	if (realmnames)
		krb5_free_host_realm(context, realmnames);

	return retval;
}
Esempio n. 28
0
krb5_error_code kt_copy_one_principal (krb5_context context, const char *from, const char *to, 
				       const char *principal, krb5_kvno kvno, krb5_enctype *enctypes)
{
    krb5_error_code ret;
    krb5_keytab src_keytab, dst_keytab;
    krb5_keytab_entry entry;
    krb5_principal princ;
    int i;
    bool found_one = false;

    ret = krb5_parse_name (context, principal, &princ);
    if(ret) {
	    krb5_set_error_message(context, ret, "krb5_unparse_name");
	    return ret;
    }

    ret = krb5_kt_resolve (context, from, &src_keytab);
    if (ret) {
	krb5_set_error_message(context, ret, "resolving src keytab `%s'", from);
	return ret;
    }

    ret = krb5_kt_resolve (context, to, &dst_keytab);
    if (ret) {
	krb5_kt_close (context, src_keytab);
	krb5_set_error_message(context, ret, "resolving dst keytab `%s'", to);
	return ret;
    }

    for (i=0; enctypes[i]; i++) {
  	ret = krb5_kt_get_entry(context, src_keytab,
				princ,
				kvno,
				enctypes[i],
				&entry);
	if (ret == KRB5_KT_NOTFOUND) {
	    continue;
	} else if (ret) {
	    break;
	}
	found_one = true;
	ret = copy_one_entry(context, src_keytab, dst_keytab, entry);
	if (ret) {
	    break;
	}
    }
    if (ret == KRB5_KT_NOTFOUND) {
	if (!found_one) {
	    char *princ_string;
	    int ret2 = krb5_unparse_name (context, princ, &princ_string);
	    if (ret2) {
		krb5_set_error_message(context, ret, "failed to fetch principal %s", princ_string);
	    }
	} else {
	    /* Not finding an enc type is not an error, as long as we copied one for the principal */
	    ret = 0;
	}
    }

    krb5_kt_close (context, src_keytab);
    krb5_kt_close (context, dst_keytab);
    return ret;
}
static krb5_error_code
get_keytab(krb5_context context, gsskrb5_cred handle, int require_lkdc)
{
    krb5_error_code kret;

    HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);

    if (_gsskrb5_keytab != NULL) {
	char *name = NULL;

	kret = krb5_kt_get_full_name(context, _gsskrb5_keytab, &name);
	if (kret == 0) {
	    kret = krb5_kt_resolve(context, name, &handle->keytab);
	    krb5_xfree(name);
	}
    } else
	kret = krb5_kt_default(context, &handle->keytab);

    if (kret)
	goto out;

    /*
     * If caller requested, check that we have the user in the keytab.
     */

    if (handle->principal) {
	krb5_keytab_entry entry;

	if (krb5_principal_is_gss_hostbased_service(context, handle->principal)) {
	    /* 
	     * check if we have a service in the keytab
	     */
	    const char *service = handle->principal->name.name_string.val[0];

	    if (!check_keytab(context, handle, service, require_lkdc)) {
		kret = KRB5_KT_NOTFOUND;
		krb5_set_error_message(context, kret,
				       "Didn't find service %s in keytab", service);
		goto out;
	    }
	} else {
	    kret = krb5_kt_get_entry(context, handle->keytab, handle->principal,
				     0, 0, &entry);
	    if (kret)
		goto out;

	    /*
	     * Update the name with the entry from the keytab in case we
	     * have a gss hostname service name principal
	     */
	    krb5_free_principal(context, handle->principal);
	    kret = krb5_copy_principal(context, entry.principal, &handle->principal);
	    krb5_kt_free_entry(context, &entry);
	    if (kret)
		goto out;
	}

    } else {
	if (!check_keytab(context, handle, NULL, require_lkdc)) {
	    kret = KRB5_KT_NOTFOUND;
	    goto out;
	}
    }

 out:
    if (kret && handle->keytab) {
	krb5_kt_close(context, handle->keytab);
	handle->keytab = NULL;
    }

    HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);

    return (kret);
}
Esempio n. 30
0
/*	Given krb5 service name in KSSL_CTX *kssl_ctx (typically "kssl"),
**		and krb5 AP_REQ message & message length,
**	Return Kerberos session key and client principle
**		to SSL Server in KSSL_CTX *kssl_ctx.
**
**	19990702	VRS 	Started.
*/
krb5_error_code
kssl_sget_tkt(
	/* UPDATE */	KSSL_CTX		*kssl_ctx,
	/* IN     */	krb5_data		*indata,
	/* OUT    */	krb5_ticket_times	*ttimes,
	/* OUT    */	KSSL_ERR		*kssl_err  )
{
        krb5_error_code			krb5rc = KRB5KRB_ERR_GENERIC;
        static krb5_context		krb5context = NULL;
	static krb5_auth_context	krb5auth_context = NULL;
	krb5_ticket 			*krb5ticket = NULL;
	KRB5_TKTBODY 			*asn1ticket = NULL;
	const unsigned char		*p;
	krb5_keytab 			krb5keytab = NULL;
	krb5_keytab_entry		kt_entry;
	krb5_principal			krb5server;
        krb5_rcache                     rcache = NULL;

	kssl_err_set(kssl_err, 0, "");

	if (!kssl_ctx) {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
		    "No kssl_ctx defined.\n");
		goto err;
	}

#ifdef KSSL_DEBUG
	printf("in kssl_sget_tkt(%s)\n", kstring(kssl_ctx->service_name));
#endif	/* KSSL_DEBUG */

	if (!krb5context && (krb5rc = krb5_init_context(&krb5context))) {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
		    "krb5_init_context() fails.\n");
		goto err;
	}
	if (krb5auth_context &&
	    (krb5rc = krb5_auth_con_free(krb5context, krb5auth_context))) {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
		    "krb5_auth_con_free() fails.\n");
		goto err;
	} else
		krb5auth_context = NULL;
	if (!krb5auth_context &&
	    (krb5rc = krb5_auth_con_init(krb5context, &krb5auth_context))) {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
		    "krb5_auth_con_init() fails.\n");
		goto err;
	}

	if ((krb5rc = krb5_auth_con_getrcache(krb5context, krb5auth_context,
	    &rcache))) {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
		    "krb5_auth_con_getrcache() fails.\n");
		goto err;
	}

	if ((krb5rc = krb5_sname_to_principal(krb5context, NULL,
	    (kssl_ctx->service_name) ? kssl_ctx->service_name : KRB5SVC,
	    KRB5_NT_SRV_HST, &krb5server)) != 0) {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
		    "krb5_sname_to_principal() fails.\n");
		goto err;
	}

	if (rcache == NULL) {
		if ((krb5rc = krb5_get_server_rcache(krb5context,
		    krb5_princ_component(krb5context, krb5server, 0),
		    &rcache))) {
			kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
			    "krb5_get_server_rcache() fails.\n");
			goto err;
		}
	}

	if ((krb5rc = krb5_auth_con_setrcache(krb5context, krb5auth_context,
	    rcache))) {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
		    "krb5_auth_con_setrcache() fails.\n");
		goto err;
	}


	/*	kssl_ctx->keytab_file == NULL ==> use Kerberos default
	*/
	if (kssl_ctx->keytab_file) {
		krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
		    &krb5keytab);
		if (krb5rc) {
			kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
			    "krb5_kt_resolve() fails.\n");
			goto err;
		}
	} else {
		krb5rc = krb5_kt_default(krb5context, &krb5keytab);
		if (krb5rc) {
			kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
			    "krb5_kt_default() fails.\n");
			goto err;
		}
	}

	/*	Actual Kerberos5 krb5_recvauth() has initial conversation here
	**	o	check KRB5_SENDAUTH_BADAUTHVERS
	**		unless KRB5_RECVAUTH_SKIP_VERSION
	**	o	check KRB5_SENDAUTH_BADAPPLVERS
	**	o	send "0" msg if all OK
	*/

	/*  20010411 was using AP_REQ instead of true KerberosWrapper
	**
	**  if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context,
	**			&krb5in_data, krb5server, krb5keytab,
	**			&ap_option, &krb5ticket)) != 0)  { Error }
	*/

	p = (unsigned char *)indata->data;
	if ((asn1ticket = (KRB5_TKTBODY *) d2i_KRB5_TICKET(NULL, &p,
	    (long)indata->length)) == NULL) {
		(void) snprintf(kssl_err->text, KSSL_ERR_MAX,
		    "d2i_KRB5_TICKET() ASN.1 decode failure.\n");
		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
		goto err;
	}

	/* Was:  krb5rc = krb5_decode_ticket(krb5in_data,&krb5ticket)) != 0) */
	if ((krb5rc = kssl_TKT2tkt(krb5context, asn1ticket, &krb5ticket,
	    kssl_err)) != 0) {
		(void) snprintf(kssl_err->text, KSSL_ERR_MAX,
		    "Error converting ASN.1 ticket to krb5_ticket.\n");
		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
		goto err;
	}

	if (!krb5_principal_compare(krb5context, krb5server,
	    krb5ticket->server))  {
		krb5rc = KRB5_PRINC_NOMATCH;
		(void) snprintf(kssl_err->text, KSSL_ERR_MAX,
		    "server principal != ticket principal\n");
		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
		goto err;
	}
	if ((krb5rc = krb5_kt_get_entry(krb5context, krb5keytab,
	    krb5ticket->server, krb5ticket->enc_part.kvno,
	    krb5ticket->enc_part.enctype, &kt_entry)) != 0)  {
		(void) snprintf(kssl_err->text, KSSL_ERR_MAX,
		    "krb5_kt_get_entry() fails with %x.\n", krb5rc);
		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
		goto err;
	}
	if ((krb5rc = krb5_decrypt_tkt_part(krb5context, &kt_entry.key,
	    krb5ticket)) != 0)  {
		(void) snprintf(kssl_err->text, KSSL_ERR_MAX,
		    "krb5_decrypt_tkt_part() failed.\n");
		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
		goto err;
	} else {
		krb5_kt_free_entry(krb5context, &kt_entry);
#ifdef KSSL_DEBUG
		{
			int i;
			krb5_address **paddr = krb5ticket->enc_part2->caddrs;
			printf("Decrypted ticket fields:\n");
			printf("\tflags: %X, transit-type: %X",
			krb5ticket->enc_part2->flags,
			krb5ticket->enc_part2->transited.tr_type);
			print_krb5_data("\ttransit-data: ",
			&(krb5ticket->enc_part2->transited.tr_contents));
			printf("\tcaddrs: %p, authdata: %p\n",
			krb5ticket->enc_part2->caddrs,
			krb5ticket->enc_part2->authorization_data);
			if (paddr) {
				printf("\tcaddrs:\n");
				for (i = 0; paddr[i] != NULL; i++) {
					krb5_data d;
					d.length = paddr[i]->length;
					d.data = paddr[i]->contents;
					print_krb5_data("\t\tIP: ", &d);
				}
			}
			printf("\tstart/auth/end times: %d / %d / %d\n",
			krb5ticket->enc_part2->times.starttime,
			krb5ticket->enc_part2->times.authtime,
			krb5ticket->enc_part2->times.endtime);
		}
#endif	/* KSSL_DEBUG */
	}

	krb5rc = KRB5_NO_TKT_SUPPLIED;
	if (!krb5ticket || !krb5ticket->enc_part2 ||
	    !krb5ticket->enc_part2->client ||
	    !krb5ticket->enc_part2->client->data ||
	    !krb5ticket->enc_part2->session) {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
		    "bad ticket from krb5_rd_req.\n");
	} else if (kssl_ctx_setprinc(kssl_ctx, KSSL_CLIENT,
	    &krb5ticket->enc_part2->client->realm,
	    krb5ticket->enc_part2->client->data,
	    krb5ticket->enc_part2->client->length)) {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
		    "kssl_ctx_setprinc() fails.\n");
	} else if (kssl_ctx_setkey(kssl_ctx, krb5ticket->enc_part2->session)) {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
		    "kssl_ctx_setkey() fails.\n");
	} else if (krb5ticket->enc_part2->flags & TKT_FLG_INVALID) {
		krb5rc = KRB5KRB_AP_ERR_TKT_INVALID;
		kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
		    "invalid ticket from krb5_rd_req.\n");
	} else
		krb5rc = 0;

	kssl_ctx->enctype = krb5ticket->enc_part.enctype;
	ttimes->authtime = krb5ticket->enc_part2->times.authtime;
	ttimes->starttime = krb5ticket->enc_part2->times.starttime;
	ttimes->endtime = krb5ticket->enc_part2->times.endtime;
	ttimes->renew_till = krb5ticket->enc_part2->times.renew_till;

	err:
#ifdef KSSL_DEBUG
	kssl_ctx_show(kssl_ctx);
#endif	/* KSSL_DEBUG */

	if (asn1ticket)
		KRB5_TICKET_free((KRB5_TICKET *) asn1ticket);
	if (krb5keytab)
		krb5_kt_close(krb5context, krb5keytab);
	if (krb5ticket)
		krb5_free_ticket(krb5context, krb5ticket);
	if (krb5server)
		krb5_free_principal(krb5context, krb5server);
	return (krb5rc);
}