Example #1
0
krb5_error_code libnet_keytab_init(TALLOC_CTX *mem_ctx,
				   const char *keytab_name,
				   struct libnet_keytab_context **ctx)
{
	krb5_error_code ret = 0;
	krb5_context context = NULL;
	krb5_keytab keytab = NULL;
	const char *keytab_string = NULL;

	struct libnet_keytab_context *r;

	r = talloc_zero(mem_ctx, struct libnet_keytab_context);
	if (!r) {
		return ENOMEM;
	}

	talloc_set_destructor(r, keytab_close);

	initialize_krb5_error_table();
	ret = krb5_init_context(&context);
	if (ret) {
		DEBUG(1,("keytab_init: could not krb5_init_context: %s\n",
			error_message(ret)));
		return ret;
	}

	ret = smb_krb5_open_keytab(context, keytab_name, true, &keytab);
	if (ret) {
		DEBUG(1,("keytab_init: smb_krb5_open_keytab failed (%s)\n",
			error_message(ret)));
		krb5_free_context(context);
		return ret;
	}

	ret = smb_krb5_keytab_name(mem_ctx, context, keytab, &keytab_string);
	if (ret) {
		krb5_kt_close(context, keytab);
		krb5_free_context(context);
		return ret;
	}

	r->context = context;
	r->keytab = keytab;
	r->keytab_name = keytab_string;
	r->clean_old_entries = false;

	*ctx = r;

	return 0;
}
Example #2
0
_PUBLIC_ int smb_krb5_create_memory_keytab(TALLOC_CTX *parent_ctx,
					   struct cli_credentials *machine_account,
					   struct smb_krb5_context *smb_krb5_context,
					   const char **enctype_strings,
					   struct keytab_container **keytab_container) 
{
	krb5_error_code ret;
	TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
	const char *rand_string;
	const char *keytab_name;
	if (!mem_ctx) {
		return ENOMEM;
	}
	
	*keytab_container = talloc(mem_ctx, struct keytab_container);

	rand_string = generate_random_str(mem_ctx, 16);
	if (!rand_string) {
		talloc_free(mem_ctx);
		return ENOMEM;
	}

	keytab_name = talloc_asprintf(mem_ctx, "MEMORY:%s", 
				      rand_string);
	if (!keytab_name) {
		talloc_free(mem_ctx);
		return ENOMEM;
	}

	ret = smb_krb5_open_keytab(mem_ctx, smb_krb5_context, keytab_name, keytab_container);
	if (ret) {
		return ret;
	}

	ret = smb_krb5_update_keytab(mem_ctx, machine_account, smb_krb5_context, enctype_strings, *keytab_container);
	if (ret == 0) {
		talloc_steal(parent_ctx, *keytab_container);
	} else {
		*keytab_container = NULL;
	}
	talloc_free(mem_ctx);
	return ret;
}
int cli_credentials_set_keytab_name(struct cli_credentials *cred, 
				    const char *keytab_name, 
				    enum credentials_obtained obtained) 
{
	krb5_error_code ret;
	struct keytab_container *ktc;
	struct smb_krb5_context *smb_krb5_context;
	TALLOC_CTX *mem_ctx;

	if (cred->keytab_obtained >= obtained) {
		return 0;
	}

	ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
	if (ret) {
		return ret;
	}

	mem_ctx = talloc_new(cred);
	if (!mem_ctx) {
		return ENOMEM;
	}

	ret = smb_krb5_open_keytab(mem_ctx, smb_krb5_context, 
				   keytab_name, &ktc);
	if (ret) {
		return ret;
	}

	cred->keytab_obtained = obtained;

	talloc_steal(cred, ktc);
	cred->keytab = ktc;
	talloc_free(mem_ctx);

	return ret;
}
Example #4
0
static bool ads_keytab_verify_ticket(krb5_context context,
					krb5_auth_context auth_context,
					const DATA_BLOB *ticket,
					krb5_ticket **pp_tkt,
					krb5_keyblock **keyblock,
					krb5_error_code *perr)
{
	krb5_error_code ret = 0;
	bool auth_ok = False;
	krb5_keytab keytab = NULL;
	krb5_kt_cursor kt_cursor;
	krb5_keytab_entry kt_entry;
	char *valid_princ_formats[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
	char *entry_princ_s = NULL;
	fstring my_name, my_fqdn;
	int i;
	int number_matched_principals = 0;
	krb5_data packet;

	*pp_tkt = NULL;
	*keyblock = NULL;
	*perr = 0;

	/* Generate the list of principal names which we expect
	 * clients might want to use for authenticating to the file
	 * service.  We allow name$,{host,cifs}/{name,fqdn,name.REALM}. */

	fstrcpy(my_name, global_myname());

	my_fqdn[0] = '\0';
	name_to_fqdn(my_fqdn, global_myname());

	if (asprintf(&valid_princ_formats[0], "%s$@%s", my_name, lp_realm()) == -1) {
		goto out;
	}
	if (asprintf(&valid_princ_formats[1], "host/%s@%s", my_name, lp_realm()) == -1) {
		goto out;
	}
	if (asprintf(&valid_princ_formats[2], "host/%s@%s", my_fqdn, lp_realm()) == -1) {
		goto out;
	}
	if (asprintf(&valid_princ_formats[3], "host/%s.%s@%s", my_name, lp_realm(), lp_realm()) == -1) {
		goto out;
	}
	if (asprintf(&valid_princ_formats[4], "cifs/%s@%s", my_name, lp_realm()) == -1) {
		goto out;
	}
	if (asprintf(&valid_princ_formats[5], "cifs/%s@%s", my_fqdn, lp_realm()) == -1) {
		goto out;
	}
	if (asprintf(&valid_princ_formats[6], "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm()) == -1) {
		goto out;
	}

	ZERO_STRUCT(kt_entry);
	ZERO_STRUCT(kt_cursor);

	ret = smb_krb5_open_keytab(context, NULL, False, &keytab);
	if (ret) {
		DEBUG(1, ("ads_keytab_verify_ticket: smb_krb5_open_keytab failed (%s)\n", error_message(ret)));
		goto out;
	}

	/* Iterate through the keytab.  For each key, if the principal
	 * name case-insensitively matches one of the allowed formats,
	 * try verifying the ticket using that principal. */

	ret = krb5_kt_start_seq_get(context, keytab, &kt_cursor);
	if (ret) {
		DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_start_seq_get failed (%s)\n", error_message(ret)));
		goto out;
	}
  
	while (!auth_ok && (krb5_kt_next_entry(context, keytab, &kt_entry, &kt_cursor) == 0)) {
		ret = smb_krb5_unparse_name(context, kt_entry.principal, &entry_princ_s);
		if (ret) {
			DEBUG(1, ("ads_keytab_verify_ticket: smb_krb5_unparse_name failed (%s)\n",
				error_message(ret)));
			goto out;
		}

		for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) {

			if (!strequal(entry_princ_s, valid_princ_formats[i])) {
				continue;
			}

			number_matched_principals++;
			packet.length = ticket->length;
			packet.data = (char *)ticket->data;
			*pp_tkt = NULL;

			ret = krb5_rd_req_return_keyblock_from_keytab(context, &auth_context, &packet,
							  	      kt_entry.principal, keytab,
								      NULL, pp_tkt, keyblock);

			if (ret) {
				DEBUG(10,("ads_keytab_verify_ticket: "
					"krb5_rd_req_return_keyblock_from_keytab(%s) failed: %s\n",
					entry_princ_s, error_message(ret)));

				/* workaround for MIT: 
				* as krb5_ktfile_get_entry will explicitly
				* close the krb5_keytab as soon as krb5_rd_req
				* has successfully decrypted the ticket but the
				* ticket is not valid yet (due to clockskew)
				* there is no point in querying more keytab
				* entries - Guenther */
					
				if (ret == KRB5KRB_AP_ERR_TKT_NYV || 
				    ret == KRB5KRB_AP_ERR_TKT_EXPIRED ||
				    ret == KRB5KRB_AP_ERR_SKEW) {
					break;
				}
			} else {
				DEBUG(3,("ads_keytab_verify_ticket: "
					"krb5_rd_req_return_keyblock_from_keytab succeeded for principal %s\n",
					entry_princ_s));
				auth_ok = True;
				break;
			}
		}

		/* Free the name we parsed. */
		SAFE_FREE(entry_princ_s);

		/* Free the entry we just read. */
		smb_krb5_kt_free_entry(context, &kt_entry);
		ZERO_STRUCT(kt_entry);
	}
	krb5_kt_end_seq_get(context, keytab, &kt_cursor);

	ZERO_STRUCT(kt_cursor);

  out:
	
	for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) {
		SAFE_FREE(valid_princ_formats[i]);
	}
	
	if (!auth_ok) {
		if (!number_matched_principals) {
			DEBUG(3, ("ads_keytab_verify_ticket: no keytab principals matched expected file service name.\n"));
		} else {
			DEBUG(3, ("ads_keytab_verify_ticket: krb5_rd_req failed for all %d matched keytab principals\n",
				number_matched_principals));
		}
	}

	SAFE_FREE(entry_princ_s);

	{
		krb5_keytab_entry zero_kt_entry;
		ZERO_STRUCT(zero_kt_entry);
		if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
			smb_krb5_kt_free_entry(context, &kt_entry);
		}
	}

	{
		krb5_kt_cursor zero_csr;
		ZERO_STRUCT(zero_csr);
		if ((memcmp(&kt_cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
			krb5_kt_end_seq_get(context, keytab, &kt_cursor);
		}
	}

	if (keytab) {
		krb5_kt_close(context, keytab);
	}
	*perr = ret;
	return auth_ok;
}
Example #5
0
static bool ads_dedicated_keytab_verify_ticket(krb5_context context,
					  krb5_auth_context auth_context,
					  const DATA_BLOB *ticket,
					  krb5_ticket **pp_tkt,
					  krb5_keyblock **keyblock,
					  krb5_error_code *perr)
{
	krb5_error_code ret = 0;
	bool auth_ok = false;
	krb5_keytab keytab = NULL;
	krb5_keytab_entry kt_entry;
	krb5_ticket *dec_ticket = NULL;

	krb5_data packet;
	krb5_kvno kvno = 0;
	krb5_enctype enctype;

	*pp_tkt = NULL;
	*keyblock = NULL;
	*perr = 0;

	ZERO_STRUCT(kt_entry);

	ret = smb_krb5_open_keytab(context, lp_dedicated_keytab_file(), true,
	    &keytab);
	if (ret) {
		DEBUG(1, ("smb_krb5_open_keytab failed (%s)\n",
			error_message(ret)));
		goto out;
	}

	packet.length = ticket->length;
	packet.data = (char *)ticket->data;

	ret = krb5_rd_req(context, &auth_context, &packet, NULL, keytab,
	    NULL, &dec_ticket);
	if (ret) {
		DEBUG(0, ("krb5_rd_req failed (%s)\n", error_message(ret)));
		goto out;
	}

#ifdef HAVE_ETYPE_IN_ENCRYPTEDDATA /* Heimdal */
	enctype = dec_ticket->ticket.key.keytype;
#else /* MIT */
	enctype = dec_ticket->enc_part.enctype;
	kvno    = dec_ticket->enc_part.kvno;
#endif

	/* Get the key for checking the pac signature */
	ret = krb5_kt_get_entry(context, keytab, dec_ticket->server,
				kvno, enctype, &kt_entry);
	if (ret) {
		DEBUG(0, ("krb5_kt_get_entry failed (%s)\n",
			  error_message(ret)));
		goto out;
	}

	ret = krb5_copy_keyblock(context, KRB5_KT_KEY(&kt_entry), keyblock);
	smb_krb5_kt_free_entry(context, &kt_entry);

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

	auth_ok = true;
	*pp_tkt = dec_ticket;
	dec_ticket = NULL;

  out:
	if (dec_ticket)
		krb5_free_ticket(context, dec_ticket);

	if (keytab)
		krb5_kt_close(context, keytab);

	*perr = ret;
	return auth_ok;
}