Exemplo n.º 1
0
static krb5_error_code libnet_keytab_add_entry(krb5_context context,
					       krb5_keytab keytab,
					       krb5_kvno kvno,
					       const char *princ_s,
					       krb5_enctype enctype,
					       krb5_data password)
{
	krb5_keyblock *keyp;
	krb5_keytab_entry kt_entry;
	krb5_error_code ret;

	/* remove duplicates first ... */
	ret = libnet_keytab_remove_entries(context, keytab, princ_s, kvno,
					   enctype, false);
	if (ret) {
		DEBUG(1, ("libnet_keytab_remove_entries failed: %s\n",
			  error_message(ret)));
	}

	ZERO_STRUCT(kt_entry);

	kt_entry.vno = kvno;

	ret = smb_krb5_parse_name(context, princ_s, &kt_entry.principal);
	if (ret) {
		DEBUG(1, ("smb_krb5_parse_name(%s) failed (%s)\n",
			  princ_s, error_message(ret)));
		return ret;
	}

	keyp = KRB5_KT_KEY(&kt_entry);

	if (create_kerberos_key_from_string(context, kt_entry.principal,
					    &password, keyp, enctype, true))
	{
		ret = KRB5KRB_ERR_GENERIC;
		goto done;
	}

	ret = krb5_kt_add_entry(context, keytab, &kt_entry);
	if (ret) {
		DEBUG(1, ("adding entry to keytab failed (%s)\n",
			  error_message(ret)));
	}

done:
	krb5_free_keyblock_contents(context, keyp);
	krb5_free_principal(context, kt_entry.principal);
	ZERO_STRUCT(kt_entry);
	smb_krb5_kt_free_entry(context, &kt_entry);

	return ret;
}
Exemplo n.º 2
0
static BOOL make_krb5_skew_error(DATA_BLOB *pblob_out)
{
	krb5_context context = NULL;
	krb5_error_code kerr = 0;
	krb5_data reply;
	krb5_principal host_princ = NULL;
	char *host_princ_s = NULL;
	BOOL ret = False;

	*pblob_out = data_blob(NULL,0);

	initialize_krb5_error_table();
	kerr = krb5_init_context(&context);
	if (kerr) {
		return False;
	}
	/* Create server principal. */
	asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
	if (!host_princ_s) {
		goto out;
	}
	strlower_m(host_princ_s);

	kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
	if (kerr) {
		DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed for name %s: Error %s\n",
			host_princ_s, error_message(kerr) ));
		goto out;
	}
	
	kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW, host_princ, &reply);
	if (kerr) {
		DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error failed: Error %s\n",
			error_message(kerr) ));
		goto out;
	}

	*pblob_out = data_blob(reply.data, reply.length);
	kerberos_free_data_contents(context,&reply);
	ret = True;

  out:

	if (host_princ_s) {
		SAFE_FREE(host_princ_s);
	}
	if (host_princ) {
		krb5_free_principal(context, host_princ);
	}
	krb5_free_context(context);
	return ret;
}
Exemplo n.º 3
0
 krb5_error_code smb_krb5_parse_name_norealm(krb5_context context, 
					    const char *name, 
					    krb5_principal *principal)
{
#ifdef HAVE_KRB5_PARSE_NAME_NOREALM
	return smb_krb5_parse_name_norealm_conv(context, name, principal);
#endif

	/* we are cheating here because parse_name will in fact set the realm.
	 * We don't care as the only caller of smb_krb5_parse_name_norealm
	 * ignores the realm anyway when calling
	 * smb_krb5_principal_compare_any_realm later - Guenther */

	return smb_krb5_parse_name(context, name, principal);
}
Exemplo n.º 4
0
static ADS_STATUS ads_krb5_chg_password(const char *kdc_host,
					const char *principal,
					const char *oldpw, 
					const char *newpw, 
					int time_offset)
{
    ADS_STATUS aret;
    krb5_error_code ret;
    krb5_context context = NULL;
    krb5_principal princ;
    krb5_get_init_creds_opt opts;
    krb5_creds creds;
    char *chpw_princ = NULL, *password;
    const char *realm = NULL;

    initialize_krb5_error_table();
    ret = krb5_init_context(&context);
    if (ret) {
	DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
	return ADS_ERROR_KRB5(ret);
    }

    if ((ret = smb_krb5_parse_name(context, principal,
                                    &princ))) {
	krb5_free_context(context);
	DEBUG(1,("Failed to parse %s (%s)\n", principal, error_message(ret)));
	return ADS_ERROR_KRB5(ret);
    }

    krb5_get_init_creds_opt_init(&opts);
    krb5_get_init_creds_opt_set_tkt_life(&opts, 5*60);
    krb5_get_init_creds_opt_set_renew_life(&opts, 0);
    krb5_get_init_creds_opt_set_forwardable(&opts, 0);
    krb5_get_init_creds_opt_set_proxiable(&opts, 0);

    realm = smb_krb5_principal_get_realm(context, princ);

    /* We have to obtain an INITIAL changepw ticket for changing password */
    if (asprintf(&chpw_princ, "kadmin/changepw@%s", realm) == -1) {
	krb5_free_context(context);
	DEBUG(1,("ads_krb5_chg_password: asprintf fail\n"));
	return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
    }

    password = SMB_STRDUP(oldpw);
    ret = krb5_get_init_creds_password(context, &creds, princ, password,
					   kerb_prompter, NULL, 
					   0, chpw_princ, &opts);
    SAFE_FREE(chpw_princ);
    SAFE_FREE(password);

    if (ret) {
      if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
	DEBUG(1,("Password incorrect while getting initial ticket"));
      else
	DEBUG(1,("krb5_get_init_creds_password failed (%s)\n", error_message(ret)));

	krb5_free_principal(context, princ);
	krb5_free_context(context);
	return ADS_ERROR_KRB5(ret);
    }

    aret = do_krb5_kpasswd_request(context, kdc_host,
				   KRB5_KPASSWD_VERS_CHANGEPW,
				   &creds, principal, newpw);

    krb5_free_principal(context, princ);
    krb5_free_context(context);

    return aret;
}
Exemplo n.º 5
0
NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
			   const char *realm,
			   time_t time_offset,
			   const DATA_BLOB *ticket,
			   char **principal,
			   struct PAC_DATA **pac_data,
			   DATA_BLOB *ap_rep,
			   DATA_BLOB *session_key,
			   bool use_replay_cache)
{
	NTSTATUS sret = NT_STATUS_LOGON_FAILURE;
	NTSTATUS pac_ret;
	DATA_BLOB auth_data;
	krb5_context context = NULL;
	krb5_auth_context auth_context = NULL;
	krb5_data packet;
	krb5_ticket *tkt = NULL;
	krb5_rcache rcache = NULL;
	krb5_keyblock *keyblock = NULL;
	time_t authtime;
	krb5_error_code ret = 0;
	int flags = 0;	
	krb5_principal host_princ = NULL;
	krb5_const_principal client_principal = NULL;
	char *host_princ_s = NULL;
	bool auth_ok = False;
	bool got_auth_data = False;
	struct named_mutex *mutex = NULL;

	ZERO_STRUCT(packet);
	ZERO_STRUCT(auth_data);

	*principal = NULL;
	*pac_data = NULL;
	*ap_rep = data_blob_null;
	*session_key = data_blob_null;

	initialize_krb5_error_table();
	ret = krb5_init_context(&context);
	if (ret) {
		DEBUG(1,("ads_verify_ticket: krb5_init_context failed (%s)\n", error_message(ret)));
		return NT_STATUS_LOGON_FAILURE;
	}

	if (time_offset != 0) {
		krb5_set_real_time(context, time(NULL) + time_offset, 0);
	}

	ret = krb5_set_default_realm(context, realm);
	if (ret) {
		DEBUG(1,("ads_verify_ticket: krb5_set_default_realm failed (%s)\n", error_message(ret)));
		goto out;
	}

	/* This whole process is far more complex than I would
           like. We have to go through all this to allow us to store
           the secret internally, instead of using /etc/krb5.keytab */

	ret = krb5_auth_con_init(context, &auth_context);
	if (ret) {
		DEBUG(1,("ads_verify_ticket: krb5_auth_con_init failed (%s)\n", error_message(ret)));
		goto out;
	}

	krb5_auth_con_getflags( context, auth_context, &flags );
	if ( !use_replay_cache ) {
		/* Disable default use of a replay cache */
		flags &= ~KRB5_AUTH_CONTEXT_DO_TIME;
		krb5_auth_con_setflags( context, auth_context, flags );
	}

	if (asprintf(&host_princ_s, "%s$", global_myname()) == -1) {
		goto out;
	}

	strlower_m(host_princ_s);
	ret = smb_krb5_parse_name(context, host_princ_s, &host_princ);
	if (ret) {
		DEBUG(1,("ads_verify_ticket: smb_krb5_parse_name(%s) failed (%s)\n",
					host_princ_s, error_message(ret)));
		goto out;
	}


	if ( use_replay_cache ) {
		
		/* Lock a mutex surrounding the replay as there is no 
		   locking in the MIT krb5 code surrounding the replay 
		   cache... */

		mutex = grab_named_mutex(talloc_tos(), "replay cache mutex",
					 10);
		if (mutex == NULL) {
			DEBUG(1,("ads_verify_ticket: unable to protect "
				 "replay cache with mutex.\n"));
			ret = KRB5_CC_IO;
			goto out;
		}

		/* JRA. We must set the rcache here. This will prevent 
		   replay attacks. */
		
		ret = krb5_get_server_rcache(context, 
					     krb5_princ_component(context, host_princ, 0), 
					     &rcache);
		if (ret) {
			DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache "
				 "failed (%s)\n", error_message(ret)));
			goto out;
		}

		ret = krb5_auth_con_setrcache(context, auth_context, rcache);
		if (ret) {
			DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache "
				 "failed (%s)\n", error_message(ret)));
			goto out;
		}
	}

	/* Try secrets.tdb first and fallback to the krb5.keytab if
	   necessary */

	auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ,
					    ticket, &tkt, &keyblock, &ret);

	if (!auth_ok &&
	    (ret == KRB5KRB_AP_ERR_TKT_NYV ||
	     ret == KRB5KRB_AP_ERR_TKT_EXPIRED ||
	     ret == KRB5KRB_AP_ERR_SKEW)) {
		goto auth_failed;
	}

	if (!auth_ok && lp_use_kerberos_keytab()) {
		auth_ok = ads_keytab_verify_ticket(context, auth_context, 
						   ticket, &tkt, &keyblock, &ret);
	}

	if ( use_replay_cache ) {		
		TALLOC_FREE(mutex);
#if 0
		/* Heimdal leaks here, if we fix the leak, MIT crashes */
		if (rcache) {
			krb5_rc_close(context, rcache);
		}
#endif
	}	

 auth_failed:
	if (!auth_ok) {
		DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", 
			 error_message(ret)));
		/* Try map the error return in case it's something like
		 * a clock skew error.
		 */
		sret = krb5_to_nt_status(ret);
		if (NT_STATUS_IS_OK(sret) || NT_STATUS_EQUAL(sret,NT_STATUS_UNSUCCESSFUL)) {
			sret = NT_STATUS_LOGON_FAILURE;
		}
		DEBUG(10,("ads_verify_ticket: returning error %s\n",
			nt_errstr(sret) ));
		goto out;
	} 
	
	authtime = get_authtime_from_tkt(tkt);
	client_principal = get_principal_from_tkt(tkt);

	ret = krb5_mk_rep(context, auth_context, &packet);
	if (ret) {
		DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n",
			error_message(ret)));
		goto out;
	}

	*ap_rep = data_blob(packet.data, packet.length);
	if (packet.data) {
		kerberos_free_data_contents(context, &packet);
		ZERO_STRUCT(packet);
	}

	get_krb5_smb_session_key(context, auth_context, session_key, True);
	dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length);

#if 0
	file_save("/tmp/ticket.dat", ticket->data, ticket->length);
#endif

	/* continue when no PAC is retrieved or we couldn't decode the PAC 
	   (like accounts that have the UF_NO_AUTH_DATA_REQUIRED flag set, or
	   Kerberos tickets encrypted using a DES key) - Guenther */

	got_auth_data = get_auth_data_from_tkt(mem_ctx, &auth_data, tkt);
	if (!got_auth_data) {
		DEBUG(3,("ads_verify_ticket: did not retrieve auth data. continuing without PAC\n"));
	}

	if (got_auth_data) {
		pac_ret = decode_pac_data(mem_ctx, &auth_data, context, keyblock, client_principal, authtime, pac_data);
		if (!NT_STATUS_IS_OK(pac_ret)) {
			DEBUG(3,("ads_verify_ticket: failed to decode PAC_DATA: %s\n", nt_errstr(pac_ret)));
			*pac_data = NULL;
		}
		data_blob_free(&auth_data);
	}

#if 0
#if defined(HAVE_KRB5_TKT_ENC_PART2)
	/* MIT */
	if (tkt->enc_part2) {
		file_save("/tmp/authdata.dat",
			  tkt->enc_part2->authorization_data[0]->contents,
			  tkt->enc_part2->authorization_data[0]->length);
	}
#else
	/* Heimdal */
	if (tkt->ticket.authorization_data) {
		file_save("/tmp/authdata.dat",
			  tkt->ticket.authorization_data->val->ad_data.data,
			  tkt->ticket.authorization_data->val->ad_data.length);
	}
#endif
#endif

	if ((ret = smb_krb5_unparse_name(context, client_principal, principal))) {
		DEBUG(3,("ads_verify_ticket: smb_krb5_unparse_name failed (%s)\n", 
			 error_message(ret)));
		sret = NT_STATUS_LOGON_FAILURE;
		goto out;
	}

	sret = NT_STATUS_OK;

 out:

	TALLOC_FREE(mutex);

	if (!NT_STATUS_IS_OK(sret)) {
		data_blob_free(&auth_data);
	}

	if (!NT_STATUS_IS_OK(sret)) {
		data_blob_free(ap_rep);
	}

	if (host_princ) {
		krb5_free_principal(context, host_princ);
	}

	if (keyblock) {
		krb5_free_keyblock(context, keyblock);
	}

	if (tkt != NULL) {
		krb5_free_ticket(context, tkt);
	}

	SAFE_FREE(host_princ_s);

	if (auth_context) {
		krb5_auth_con_free(context, auth_context);
	}

	if (context) {
		krb5_free_context(context);
	}

	return sret;
}
Exemplo n.º 6
0
ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *principal,
				 const char *newpw, int time_offset)
{

	ADS_STATUS aret;
	krb5_error_code ret = 0;
	krb5_context context = NULL;
	krb5_principal princ = NULL;
	krb5_ccache ccache = NULL;
	int result_code;
	krb5_data result_code_string = { 0 };
	krb5_data result_string = { 0 };

	initialize_krb5_error_table();
	ret = krb5_init_context(&context);
	if (ret) {
		DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}

	if (principal) {
		ret = smb_krb5_parse_name(context, principal, &princ);
		if (ret) {
			krb5_free_context(context);
			DEBUG(1, ("Failed to parse %s (%s)\n", principal,
				  error_message(ret)));
			return ADS_ERROR_KRB5(ret);
		}
	}

	if (time_offset != 0) {
		krb5_set_real_time(context, time(NULL) + time_offset, 0);
	}

	ret = krb5_cc_default(context, &ccache);
	if (ret) {
		krb5_free_principal(context, princ);
	        krb5_free_context(context);
		DEBUG(1,("Failed to get default creds (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}

	ret = krb5_set_password_using_ccache(context,
					     ccache,
					     discard_const_p(char, newpw),
					     princ,
					     &result_code,
					     &result_code_string,
					     &result_string);
	if (ret) {
		DEBUG(1, ("krb5_set_password failed (%s)\n", error_message(ret)));
		aret = ADS_ERROR_KRB5(ret);
		goto done;
	}

	if (result_code != KRB5_KPASSWD_SUCCESS) {
		ret = kpasswd_err_to_krb5_err(result_code);
		DEBUG(1, ("krb5_set_password failed (%s)\n", error_message(ret)));
		aret = ADS_ERROR_KRB5(ret);
		goto done;
	}

	aret = ADS_SUCCESS;

done:
	kerberos_free_data_contents(context, &result_code_string);
	kerberos_free_data_contents(context, &result_string);
	krb5_free_principal(context, princ);
	krb5_cc_close(context, ccache);
	krb5_free_context(context);

	return aret;
}
Exemplo n.º 7
0
static ADS_STATUS ads_krb5_chg_password(const char *kdc_host,
					const char *principal,
					const char *oldpw, 
					const char *newpw, 
					int time_offset)
{
    ADS_STATUS aret;
    krb5_error_code ret;
    krb5_context context = NULL;
    krb5_principal princ;
    krb5_get_init_creds_opt opts;
    krb5_creds creds;
    char *chpw_princ = NULL, *password;
    char *realm = NULL;
    int result_code;
    krb5_data result_code_string = { 0 };
    krb5_data result_string = { 0 };
    smb_krb5_addresses *addr = NULL;

    initialize_krb5_error_table();
    ret = krb5_init_context(&context);
    if (ret) {
	DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
	return ADS_ERROR_KRB5(ret);
    }

    if ((ret = smb_krb5_parse_name(context, principal,
                                    &princ))) {
	krb5_free_context(context);
	DEBUG(1,("Failed to parse %s (%s)\n", principal, error_message(ret)));
	return ADS_ERROR_KRB5(ret);
    }

    krb5_get_init_creds_opt_init(&opts);

    krb5_get_init_creds_opt_set_tkt_life(&opts, 5*60);
    krb5_get_init_creds_opt_set_renew_life(&opts, 0);
    krb5_get_init_creds_opt_set_forwardable(&opts, 0);
    krb5_get_init_creds_opt_set_proxiable(&opts, 0);

    /* note that heimdal will fill in the local addresses if the addresses
     * in the creds_init_opt are all empty and then later fail with invalid
     * address, sending our local netbios krb5 address - just like windows
     * - avoids this - gd */
    ret = smb_krb5_gen_netbios_krb5_address(&addr, lp_netbios_name());
    if (ret) {
        krb5_free_principal(context, princ);
        krb5_free_context(context);
        return ADS_ERROR_KRB5(ret);
    }
    krb5_get_init_creds_opt_set_address_list(&opts, addr->addrs);

    realm = smb_krb5_principal_get_realm(context, princ);

    /* We have to obtain an INITIAL changepw ticket for changing password */
    if (asprintf(&chpw_princ, "kadmin/changepw@%s", realm) == -1) {
	krb5_free_context(context);
	free(realm);
	DEBUG(1,("ads_krb5_chg_password: asprintf fail\n"));
	return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
    }

    free(realm);
    password = SMB_STRDUP(oldpw);
    ret = krb5_get_init_creds_password(context, &creds, princ, password,
					   kerb_prompter, NULL, 
					   0, chpw_princ, &opts);
    SAFE_FREE(chpw_princ);
    SAFE_FREE(password);

    if (ret) {
      if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
	DEBUG(1,("Password incorrect while getting initial ticket"));
      else
	DEBUG(1,("krb5_get_init_creds_password failed (%s)\n", error_message(ret)));

	krb5_free_principal(context, princ);
	krb5_free_context(context);
	return ADS_ERROR_KRB5(ret);
    }

    ret = krb5_change_password(context,
			       &creds,
			       discard_const_p(char, newpw),
			       &result_code,
			       &result_code_string,
			       &result_string);
    if (ret) {
	DEBUG(1, ("krb5_change_password failed (%s)\n", error_message(ret)));
	aret = ADS_ERROR_KRB5(ret);
	goto done;
    }

    if (result_code != KRB5_KPASSWD_SUCCESS) {
	ret = kpasswd_err_to_krb5_err(result_code);
	DEBUG(1, ("krb5_change_password failed (%s)\n", error_message(ret)));
	aret = ADS_ERROR_KRB5(ret);
	goto done;
    }

    aret = ADS_SUCCESS;

done:
    kerberos_free_data_contents(context, &result_code_string);
    kerberos_free_data_contents(context, &result_string);
    krb5_free_principal(context, princ);
    krb5_free_context(context);

    return aret;
}
Exemplo n.º 8
0
/* this performs a SASL/gssapi bind
   we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
   is very dependent on correctly configured DNS whereas
   this routine is much less fragile
   see RFC2078 and RFC2222 for details
*/
static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
{
	uint32 minor_status;
	gss_name_t serv_name;
	gss_buffer_desc input_name;
	gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
	gss_OID mech_type = GSS_C_NULL_OID;
	gss_buffer_desc output_token, input_token;
	uint32 ret_flags, conf_state;
	struct berval cred;
	struct berval *scred = NULL;
	int i=0;
	int gss_rc, rc;
	uint8 *p;
	uint32 max_msg_size = 0;
	char *sname = NULL;
	ADS_STATUS status;
	krb5_principal principal = NULL;
	krb5_context ctx = NULL;
	krb5_enctype enc_types[] = {
#ifdef ENCTYPE_ARCFOUR_HMAC
			ENCTYPE_ARCFOUR_HMAC,
#endif
			ENCTYPE_DES_CBC_MD5,
			ENCTYPE_NULL};
	gss_OID_desc nt_principal = 
	{10, CONST_DISCARD(char *, "\052\206\110\206\367\022\001\002\002\002")};

	/* we need to fetch a service ticket as the ldap user in the
	   servers realm, regardless of our realm */
	asprintf(&sname, "ldap/%s@%s", ads->config.ldap_server_name, ads->config.realm);

	initialize_krb5_error_table();
	status = ADS_ERROR_KRB5(krb5_init_context(&ctx));
	if (!ADS_ERR_OK(status)) {
		SAFE_FREE(sname);
		return status;
	}
	status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(ctx, enc_types));
	if (!ADS_ERR_OK(status)) {
		SAFE_FREE(sname);
		krb5_free_context(ctx);	
		return status;
	}
	status = ADS_ERROR_KRB5(smb_krb5_parse_name(ctx, sname, &principal));
	if (!ADS_ERR_OK(status)) {
		SAFE_FREE(sname);
		krb5_free_context(ctx);	
		return status;
	}

	input_name.value = &principal;
	input_name.length = sizeof(principal);

	gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &serv_name);

	/*
	 * The MIT libraries have a *HORRIBLE* bug - input_value.value needs
	 * to point to the *address* of the krb5_principal, and the gss libraries
	 * to a shallow copy of the krb5_principal pointer - so we need to keep
	 * the krb5_principal around until we do the gss_release_name. MIT *SUCKS* !
	 * Just one more way in which MIT engineers screwed me over.... JRA.
	 */

	SAFE_FREE(sname);

	if (gss_rc) {
		krb5_free_principal(ctx, principal);
		krb5_free_context(ctx);	
		return ADS_ERROR_GSS(gss_rc, minor_status);
	}

	input_token.value = NULL;
	input_token.length = 0;

	for (i=0; i < MAX_GSS_PASSES; i++) {
		gss_rc = gss_init_sec_context(&minor_status,
					  GSS_C_NO_CREDENTIAL,
					  &context_handle,
					  serv_name,
					  mech_type,
					  GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
					  0,
					  NULL,
					  &input_token,
					  NULL,
					  &output_token,
					  &ret_flags,
					  NULL);

		if (input_token.value) {
			gss_release_buffer(&minor_status, &input_token);
		}

		if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
			status = ADS_ERROR_GSS(gss_rc, minor_status);
			goto failed;
		}

		cred.bv_val = (char *)output_token.value;
		cred.bv_len = output_token.length;

		rc = ldap_sasl_bind_s(ads->ld, NULL, "GSSAPI", &cred, NULL, NULL, 
				      &scred);
		if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
			status = ADS_ERROR(rc);
			goto failed;
		}

		if (output_token.value) {
			gss_release_buffer(&minor_status, &output_token);
		}

		if (scred) {
			input_token.value = scred->bv_val;
			input_token.length = scred->bv_len;
		} else {
			input_token.value = NULL;
			input_token.length = 0;
		}

		if (gss_rc == 0) break;
	}

	gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
			    (int *)&conf_state,NULL);
	if (gss_rc) {
		status = ADS_ERROR_GSS(gss_rc, minor_status);
		goto failed;
	}

	gss_release_buffer(&minor_status, &input_token);

	p = (uint8 *)output_token.value;

#if 0
	file_save("sasl_gssapi.dat", output_token.value, output_token.length);
#endif

	if (p) {
		max_msg_size = (p[1]<<16) | (p[2]<<8) | p[3];
	}

	gss_release_buffer(&minor_status, &output_token);

	output_token.value = SMB_MALLOC(strlen(ads->config.bind_path) + 8);
	p = (uint8 *)output_token.value;

	*p++ = 1; /* no sign & seal selection */
	/* choose the same size as the server gave us */
	*p++ = max_msg_size>>16;
	*p++ = max_msg_size>>8;
	*p++ = max_msg_size;
	snprintf((char *)p, strlen(ads->config.bind_path)+4, "dn:%s", ads->config.bind_path);
	p += strlen((const char *)p);

	output_token.length = PTR_DIFF(p, output_token.value);

	gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
			  &output_token, (int *)&conf_state,
			  &input_token);
	if (gss_rc) {
		status = ADS_ERROR_GSS(gss_rc, minor_status);
		goto failed;
	}

	free(output_token.value);

	cred.bv_val = (char *)input_token.value;
	cred.bv_len = input_token.length;

	rc = ldap_sasl_bind_s(ads->ld, NULL, "GSSAPI", &cred, NULL, NULL, 
			      &scred);
	status = ADS_ERROR(rc);

	gss_release_buffer(&minor_status, &input_token);

failed:

	gss_release_name(&minor_status, &serv_name);
	if (context_handle != GSS_C_NO_CONTEXT)
		gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
	krb5_free_principal(ctx, principal);
	krb5_free_context(ctx);	

	if(scred)
		ber_bvfree(scred);
	return status;
}
Exemplo n.º 9
0
/*
  we can't use krb5_mk_req because w2k wants the service to be in a particular format
*/
static krb5_error_code ads_krb5_mk_req(krb5_context context, 
				       krb5_auth_context *auth_context, 
				       const krb5_flags ap_req_options,
				       const char *principal,
				       krb5_ccache ccache, 
				       krb5_data *outbuf, 
				       time_t *expire_time)
{
	krb5_error_code 	  retval;
	krb5_principal	  server;
	krb5_creds 		* credsp;
	krb5_creds 		  creds;
	krb5_data in_data;
	BOOL creds_ready = False;
	int i = 0, maxtries = 3;
	
	retval = smb_krb5_parse_name(context, principal, &server);
	if (retval) {
		DEBUG(1,("ads_krb5_mk_req: Failed to parse principal %s\n", principal));
		return retval;
	}
	
	/* obtain ticket & session key */
	ZERO_STRUCT(creds);
	if ((retval = krb5_copy_principal(context, server, &creds.server))) {
		DEBUG(1,("ads_krb5_mk_req: krb5_copy_principal failed (%s)\n", 
			 error_message(retval)));
		goto cleanup_princ;
	}
	
	if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) {
		/* This can commonly fail on smbd startup with no ticket in the cache.
		 * Report at higher level than 1. */
		DEBUG(3,("ads_krb5_mk_req: krb5_cc_get_principal failed (%s)\n", 
			 error_message(retval)));
		goto cleanup_creds;
	}

	while (!creds_ready && (i < maxtries)) {

		if ((retval = krb5_get_credentials(context, 0, ccache, 
						   &creds, &credsp))) {
			DEBUG(1,("ads_krb5_mk_req: krb5_get_credentials failed for %s (%s)\n",
				 principal, error_message(retval)));
			goto cleanup_creds;
		}

		/* cope with ticket being in the future due to clock skew */
		if ((unsigned)credsp->times.starttime > time(NULL)) {
			time_t t = time(NULL);
			int time_offset =(int)((unsigned)credsp->times.starttime-t);
			DEBUG(4,("ads_krb5_mk_req: Advancing clock by %d seconds to cope with clock skew\n", time_offset));
			krb5_set_real_time(context, t + time_offset + 1, 0);
		}

		if (!ads_cleanup_expired_creds(context, ccache, credsp)) {
			creds_ready = True;
		}

		i++;
	}

	DEBUG(10,("ads_krb5_mk_req: Ticket (%s) in ccache (%s:%s) is valid until: (%s - %u)\n",
		  principal, krb5_cc_get_type(context, ccache), krb5_cc_get_name(context, ccache),
		  http_timestring((unsigned)credsp->times.endtime), 
		  (unsigned)credsp->times.endtime));

	if (expire_time) {
		*expire_time = (time_t)credsp->times.endtime;
	}

	in_data.length = 0;
	retval = krb5_mk_req_extended(context, auth_context, ap_req_options, 
				      &in_data, credsp, outbuf);
	if (retval) {
		DEBUG(1,("ads_krb5_mk_req: krb5_mk_req_extended failed (%s)\n", 
			 error_message(retval)));
	}
	
	krb5_free_creds(context, credsp);

cleanup_creds:
	krb5_free_cred_contents(context, &creds);

cleanup_princ:
	krb5_free_principal(context, server);

	return retval;
}
Exemplo n.º 10
0
 krb5_error_code smb_krb5_renew_ticket(const char *ccache_string,	/* FILE:/tmp/krb5cc_0 */
				       const char *client_string,	/* [email protected] */
				       const char *service_string,	/* krbtgt/[email protected] */
				       time_t *expire_time)
{
	krb5_error_code ret;
	krb5_context context = NULL;
	krb5_ccache ccache = NULL;
	krb5_principal client = NULL;

	initialize_krb5_error_table();
	ret = krb5_init_context(&context);
	if (ret) {
		goto done;
	}

	if (!ccache_string) {
		ccache_string = krb5_cc_default_name(context);
	}

	DEBUG(10,("smb_krb5_renew_ticket: using %s as ccache\n", ccache_string));

	/* FIXME: we should not fall back to defaults */
	ret = krb5_cc_resolve(context, CONST_DISCARD(char *, ccache_string), &ccache);
	if (ret) {
		goto done;
	}

#ifdef HAVE_KRB5_GET_RENEWED_CREDS	/* MIT */
	{
		krb5_creds creds;
	
		if (client_string) {
			ret = smb_krb5_parse_name(context, client_string, &client);
			if (ret) {
				goto done;
			}
		} else {
			ret = krb5_cc_get_principal(context, ccache, &client);
			if (ret) {
				goto done;
			}
		}
	
		ret = krb5_get_renewed_creds(context, &creds, client, ccache, CONST_DISCARD(char *, service_string));
		if (ret) {
			DEBUG(10,("smb_krb5_renew_ticket: krb5_get_kdc_cred failed: %s\n", error_message(ret)));
			goto done;
		}

		/* hm, doesn't that create a new one if the old one wasn't there? - Guenther */
		ret = krb5_cc_initialize(context, ccache, client);
		if (ret) {
			goto done;
		}
	
		ret = krb5_cc_store_cred(context, ccache, &creds);

		if (expire_time) {
			*expire_time = (time_t) creds.times.endtime;
		}

		krb5_free_cred_contents(context, &creds);
	}
#elif defined(HAVE_KRB5_GET_KDC_CRED)	/* Heimdal */
	{
		krb5_kdc_flags flags;
		krb5_creds creds_in;
		krb5_realm *client_realm;
		krb5_creds *creds;

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

		if (client_string) {
			ret = smb_krb5_parse_name(context, client_string, &creds_in.client);
			if (ret) {
				goto done;
			}
		} else {
			ret = krb5_cc_get_principal(context, ccache, &creds_in.client);
			if (ret) {
				goto done;
			}
		}

		if (service_string) {
			ret = smb_krb5_parse_name(context, service_string, &creds_in.server);
			if (ret) { 
				goto done;
			}
		} else {
			/* build tgt service by default */
			client_realm = krb5_princ_realm(context, creds_in.client);
			if (!client_realm) {
				ret = ENOMEM;
				goto done;
			}
			ret = krb5_make_principal(context, &creds_in.server, *client_realm, KRB5_TGS_NAME, *client_realm, NULL);
			if (ret) {
				goto done;
			}
		}

		flags.i = 0;
		flags.b.renewable = flags.b.renew = True;

		ret = krb5_get_kdc_cred(context, ccache, flags, NULL, NULL, &creds_in, &creds);
		if (ret) {
			DEBUG(10,("smb_krb5_renew_ticket: krb5_get_kdc_cred failed: %s\n", error_message(ret)));
			goto done;
		}
		
		/* hm, doesn't that create a new one if the old one wasn't there? - Guenther */
		ret = krb5_cc_initialize(context, ccache, creds_in.client);
		if (ret) {
			goto done;
		}
	
		ret = krb5_cc_store_cred(context, ccache, creds);

		if (expire_time) {
			*expire_time = (time_t) creds->times.endtime;
		}
						
		krb5_free_cred_contents(context, &creds_in);
		krb5_free_creds(context, creds);
	}
#else
#error No suitable krb5 ticket renew function available
#endif


done:
	if (client) {
		krb5_free_principal(context, client);
	}
	if (context) {
		krb5_free_context(context);
	}
	if (ccache) {
		krb5_cc_close(context, ccache);
	}

	return ret;
    
}
Exemplo n.º 11
0
ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ, 
				 const char *newpw, int time_offset)
{

	ADS_STATUS aret;
	krb5_error_code ret = 0;
	krb5_context context = NULL;
	krb5_principal principal = NULL;
	char *princ_name = NULL;
	char *realm = NULL;
	krb5_creds creds, *credsp = NULL;
#if KRB5_PRINC_REALM_RETURNS_REALM
	krb5_realm orig_realm;
#else
	krb5_data orig_realm;
#endif
	krb5_ccache ccache = NULL;

	ZERO_STRUCT(creds);
	
	initialize_krb5_error_table();
	ret = krb5_init_context(&context);
	if (ret) {
		DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}
	
	if (time_offset != 0) {
		krb5_set_real_time(context, time(NULL) + time_offset, 0);
	}

	ret = krb5_cc_default(context, &ccache);
	if (ret) {
	        krb5_free_context(context);
		DEBUG(1,("Failed to get default creds (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}

	realm = strchr_m(princ, '@');
	if (!realm) {
		krb5_cc_close(context, ccache);
	        krb5_free_context(context);
		DEBUG(1,("Failed to get realm\n"));
		return ADS_ERROR_KRB5(-1);
	}
	realm++;

	asprintf(&princ_name, "kadmin/changepw@%s", realm);
	ret = smb_krb5_parse_name(context, princ_name, &creds.server);
	if (ret) {
		krb5_cc_close(context, ccache);
                krb5_free_context(context);
		DEBUG(1,("Failed to parse kadmin/changepw (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}

	/* parse the principal we got as a function argument */
	ret = smb_krb5_parse_name(context, princ, &principal);
	if (ret) {
		krb5_cc_close(context, ccache);
	        krb5_free_principal(context, creds.server);
                krb5_free_context(context);
		DEBUG(1,("Failed to parse %s (%s)\n", princ_name, error_message(ret)));
		free(princ_name);
		return ADS_ERROR_KRB5(ret);
	}

	free(princ_name);

	/* The creds.server principal takes ownership of this memory.
		Remember to set back to original value before freeing. */
	orig_realm = *krb5_princ_realm(context, creds.server);
	krb5_princ_set_realm(context, creds.server, krb5_princ_realm(context, principal));
	
	ret = krb5_cc_get_principal(context, ccache, &creds.client);
	if (ret) {
		krb5_cc_close(context, ccache);
		krb5_princ_set_realm(context, creds.server, &orig_realm);
	        krb5_free_principal(context, creds.server);
	        krb5_free_principal(context, principal);
                krb5_free_context(context);
		DEBUG(1,("Failed to get principal from ccache (%s)\n", 
			 error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}
	
	ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp); 
	if (ret) {
		krb5_cc_close(context, ccache);
	        krb5_free_principal(context, creds.client);
		krb5_princ_set_realm(context, creds.server, &orig_realm);
	        krb5_free_principal(context, creds.server);
	        krb5_free_principal(context, principal);
	        krb5_free_context(context);
		DEBUG(1,("krb5_get_credentials failed (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}
	
	/* we might have to call krb5_free_creds(...) from now on ... */

	aret = do_krb5_kpasswd_request(context, kdc_host,
				       KRB5_KPASSWD_VERS_SETPW,
				       credsp, princ, newpw);

	krb5_free_creds(context, credsp);
	krb5_free_principal(context, creds.client);
	krb5_princ_set_realm(context, creds.server, &orig_realm);
        krb5_free_principal(context, creds.server);
	krb5_free_principal(context, principal);
	krb5_cc_close(context, ccache);
	krb5_free_context(context);

	return aret;
}