Example #1
0
krb5_error_code
k5_pac_validate_client(krb5_context context,
                       const krb5_pac pac,
                       krb5_timestamp authtime,
                       krb5_const_principal principal)
{
    krb5_error_code ret;
    krb5_data client_info;
    char *pac_princname;
    unsigned char *p;
    krb5_timestamp pac_authtime;
    krb5_ui_2 pac_princname_length;
    krb5_int64 pac_nt_authtime;
    krb5_principal pac_principal;

    ret = k5_pac_locate_buffer(context, pac, PAC_CLIENT_INFO, &client_info);
    if (ret != 0)
        return ret;

    if (client_info.length < PAC_CLIENT_INFO_LENGTH)
        return ERANGE;

    p = (unsigned char *)client_info.data;
    pac_nt_authtime = load_64_le(p);
    p += 8;
    pac_princname_length = load_16_le(p);
    p += 2;

    ret = k5_time_to_seconds_since_1970(pac_nt_authtime, &pac_authtime);
    if (ret != 0)
        return ret;

    if (client_info.length < PAC_CLIENT_INFO_LENGTH + pac_princname_length ||
        pac_princname_length % 2)
        return ERANGE;

    ret = krb5int_ucs2lecs_to_utf8s(p, (size_t)pac_princname_length / 2,
                                    &pac_princname, NULL);
    if (ret != 0)
        return ret;

    ret = krb5_parse_name_flags(context, pac_princname, 0, &pac_principal);
    if (ret != 0) {
        free(pac_princname);
        return ret;
    }

    free(pac_princname);

    if (pac_authtime != authtime ||
        !krb5_principal_compare_flags(context,
                                      pac_principal,
                                      principal,
                                      KRB5_PRINCIPAL_COMPARE_IGNORE_REALM))
        ret = KRB5KRB_AP_WRONG_PRINC;

    krb5_free_principal(context, pac_principal);

    return ret;
}
Example #2
0
static int mit_samba_check_s4u2proxy(struct mit_samba_context *ctx,
				     hdb_entry_ex *entry,
				     const char *target_name,
				     bool is_nt_enterprise_name)
{
	krb5_principal target_principal;
	int flags = 0;
	int ret;

	if (is_nt_enterprise_name) {
		flags = KRB5_PRINCIPAL_PARSE_ENTERPRISE;
	}

	ret = krb5_parse_name_flags(ctx->context, target_name,
				    flags, &target_principal);
	if (ret) {
		return ret;
	}

	ret = samba_kdc_check_identical_client_and_server(ctx->context,
							  ctx->db_ctx,
							  entry,
							  target_principal);

	krb5_free_principal(ctx->context, target_principal);

	return ret;
}
Example #3
0
static WERROR dns_domain_from_principal(TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context,
                                        const char *name,
                                        struct drsuapi_DsNameInfo1 *info1)
{
    krb5_error_code ret;
    krb5_principal principal;
    /* perhaps it's a principal with a realm, so return the right 'domain only' response */
    const char *realm;
    ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name,
                                KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
    if (ret) {
        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
        return WERR_OK;
    }

    /* This isn't an allocation assignemnt, so it is free'ed with the krb5_free_principal */
    realm = krb5_principal_get_realm(smb_krb5_context->krb5_context, principal);

    info1->dns_domain_name	= talloc_strdup(mem_ctx, realm);
    krb5_free_principal(smb_krb5_context->krb5_context, principal);

    W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);

    info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
    return WERR_OK;
}
Example #4
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_parse_name(krb5_context context,
		const char *name,
		krb5_principal *principal)
{
    return krb5_parse_name_flags(context, name, 0, principal);
}
Example #5
0
static void
parse_name_realm(krb5_context context,
		 const char *name,
		 int flags,
		 const char *realm,
		 krb5_principal *princ)
{
    krb5_error_code ret;
    
    if (realm)
	flags |= KRB5_PRINCIPAL_PARSE_NO_DEF_REALM;
    if ((ret = krb5_parse_name_flags(context, name, flags, princ)) != 0)
	krb5_err(context, 1, ret, "krb5_parse_name_flags");
    if (realm && krb5_principal_get_realm(context, *princ) == NULL)
	set_princ_realm(context, *princ, realm);
}
Example #6
0
File: sss_krb5.c Project: 3van/sssd
krb5_error_code
sss_krb5_parse_name_flags(krb5_context context, const char *name, int flags,
                          krb5_principal *principal)
{
#ifdef HAVE_KRB5_PARSE_NAME_FLAGS
    return krb5_parse_name_flags(context, name, flags, principal);
#else
    if (flags != 0) {
        DEBUG(SSSDBG_MINOR_FAILURE, "krb5_parse_name_flags not available on " \
                                     "this plattform, names are parsed " \
                                     "without flags. Some features like " \
                                     "enterprise principals might not work " \
                                     "as expected.\n");
    }

    return krb5_parse_name(context, name, principal);
#endif
}
Example #7
0
krb5_error_code
_krb5_get_default_principal_local(krb5_context context,
				  krb5_principal *princ)
{
    /* See if we can get the principal first.  We only expect this to
       work if logged into a domain. */
    {
	char username[1024];
	ULONG sz = sizeof(username);

	if (GetUserNameEx(NameUserPrincipal, username, &sz)) {
	    return krb5_parse_name_flags(context, username,
					 KRB5_PRINCIPAL_PARSE_ENTERPRISE,
					 princ);
	}
    }

    /* Just get the Windows username.  This should pretty much always
       work. */
    {
	char username[1024];
	DWORD dsz = sizeof(username);

	if (GetUserName(username, &dsz)) {
	    return krb5_make_principal(context, princ, NULL, username, NULL);
	}
    }

    /* Failing that, we look at the environment */
    {
	const char * username = get_env_user();

	if (username == NULL) {
	    krb5_set_error_string(context,
				  "unable to figure out current principal");
	    return ENOTTY;	/* Really? */
	}

	return krb5_make_principal(context, princ, NULL, username, NULL);
    }
}
Example #8
0
static int mit_samba_check_s4u2proxy(struct mit_samba_context *ctx,
				     hdb_entry_ex *entry,
				     const char *target_name,
				     bool is_nt_enterprise_name)
{
#if 1
	/*
	 * This is disabled because mit_samba_update_pac_data() does not handle
	 * S4U_DELEGATION_INFO
	 */

	return KRB5KDC_ERR_BADOPTION;
#else
	krb5_principal target_principal;
	int flags = 0;
	int ret;

	if (is_nt_enterprise_name) {
		flags = KRB5_PRINCIPAL_PARSE_ENTERPRISE;
	}

	ret = krb5_parse_name_flags(ctx->context, target_name,
				    flags, &target_principal);
	if (ret) {
		return ret;
	}

	ret = samba_kdc_check_s4u2proxy(ctx->context,
					ctx->db_ctx,
					skdc_entry,
					target_principal);

	krb5_free_principal(ctx->context, target_principal);

	return ret;
#endif
}
Example #9
0
DWORD
VMCALoginUserPrivate(
    PCSTR pszUserName,
    const char* pszPassword
    )
/*
VMCALoginUser Creates a TGT cache for the Process to
communicate with the VMCA
*/
{
    DWORD dwError = 0;
    krb5_context context = NULL;
    krb5_get_init_creds_opt *opt = NULL;
    krb5_principal principal = NULL;
    krb5_ccache ccache = NULL;
    krb5_creds creds = { 0 };
    krb5_error_code err_code = 0;
#ifdef DEBUG_KRB
    PSTR pszErrstr = NULL;
#endif

    err_code = krb5_init_context(&context);
    BAIL_ON_ERROR(err_code);

    // it is assumed that pszUserName is in user@REALM format.
    err_code = krb5_parse_name_flags(
                                    context,
                                    pszUserName,
                                    KRB5_PRINCIPAL_PARSE_REQUIRE_REALM,
                                    &principal);
    BAIL_ON_ERROR(err_code);

    // Find the default cred cache
    err_code = krb5_cc_default(context, &ccache);
    BAIL_ON_ERROR(err_code);

#ifdef DEBUG_KRB
    printf("Default Cache Name is : %s\n", krb5_cc_default_name(context));
#endif

    err_code = krb5_get_init_creds_opt_alloc(context, &opt);
    BAIL_ON_ERROR(err_code);

    krb5_get_init_creds_opt_set_tkt_life(opt, 2 * 60 * 60); //2 hours ticket
    krb5_get_init_creds_opt_set_forwardable(opt, 1);

    // Let us get the Creds from the Kerberos Server

    err_code =  krb5_get_init_creds_password(
                        context,
                        &creds,
                        principal,
                        (PSTR) pszPassword,
                        NULL,
                        NULL,
                        0,
                        NULL,
                        opt);
    BAIL_ON_ERROR(err_code);

    err_code = krb5_cc_store_cred(context, ccache, &creds);
    if ( err_code == KRB5_FCC_NOFILE){
        krb5_cc_initialize(context, ccache, principal);
        err_code = krb5_cc_store_cred(context, ccache, &creds);
        BAIL_ON_ERROR(err_code);
    }
    BAIL_ON_ERROR(err_code);
cleanup:

    if(principal != NULL) {
        krb5_free_principal(context, principal);
    }

    if(opt != NULL){
        krb5_get_init_creds_opt_free(context,opt);
    }

    if ( ccache != NULL) {
        krb5_cc_close(context, ccache);
    }

    krb5_free_cred_contents(context, &creds);

    if(context != NULL){
        krb5_free_context(context);
    }

    return dwError;
error :
#ifdef DEBUG_KRB
        pszErrstr   = (PSTR) krb5_get_error_message(context, err_code);
        printf("Error code : %d\n", err_code);
        printf("Error Message : %s\n", pszErrstr);
        krb5_free_error_message(context, (const char *)pszErrstr);
#endif
    dwError = err_code;
    goto cleanup;

}
Example #10
0
/* Perform one iteration of attempting to get credentials.  This includes
 * searching existing ccache for requested service if INIT_CREDS. */
static kadm5_ret_t
gic_iter(kadm5_server_handle_t handle, enum init_type init_type,
         krb5_ccache ccache, krb5_principal client, char *pass, char *svcname,
         char *realm, krb5_principal *server_out)
{
    kadm5_ret_t code;
    krb5_context ctx;
    krb5_keytab kt;
    krb5_get_init_creds_opt *opt = NULL;
    krb5_creds mcreds, outcreds;

    *server_out = NULL;
    ctx = handle->context;
    kt = NULL;
    memset(&opt, 0, sizeof(opt));
    memset(&mcreds, 0, sizeof(mcreds));
    memset(&outcreds, 0, sizeof(outcreds));

    /* Credentials for kadmin don't need to be forwardable or proxiable. */
    if (init_type != INIT_CREDS) {
        code = krb5_get_init_creds_opt_alloc(ctx, &opt);
        krb5_get_init_creds_opt_set_forwardable(opt, 0);
        krb5_get_init_creds_opt_set_proxiable(opt, 0);
        krb5_get_init_creds_opt_set_out_ccache(ctx, opt, ccache);
        if (init_type == INIT_ANONYMOUS)
            krb5_get_init_creds_opt_set_anonymous(opt, 1);
    }

    if (init_type == INIT_PASS || init_type == INIT_ANONYMOUS) {
        code = krb5_get_init_creds_password(ctx, &outcreds, client, pass,
                                            krb5_prompter_posix,
                                            NULL, 0, svcname, opt);
        if (code)
            goto error;
    } else if (init_type == INIT_SKEY) {
        if (pass) {
            code = krb5_kt_resolve(ctx, pass, &kt);
            if (code)
                goto error;
        }
        code = krb5_get_init_creds_keytab(ctx, &outcreds, client, kt,
                                          0, svcname, opt);
        if (pass)
            krb5_kt_close(ctx, kt);
        if (code)
            goto error;
    } else if (init_type == INIT_CREDS) {
        mcreds.client = client;
        code = krb5_parse_name_flags(ctx, svcname,
                                     KRB5_PRINCIPAL_PARSE_IGNORE_REALM,
                                     &mcreds.server);
        if (code)
            goto error;
        code = krb5_set_principal_realm(ctx, mcreds.server, realm);
        if (code)
            goto error;
        code = krb5_cc_retrieve_cred(ctx, ccache, 0,
                                     &mcreds, &outcreds);
        krb5_free_principal(ctx, mcreds.server);
        if (code)
            goto error;
    } else {
        code = EINVAL;
        goto error;
    }

    /* Steal the server principal of the creds we acquired and return it to the
     * caller, which needs to knows what service to authenticate to. */
    *server_out = outcreds.server;
    outcreds.server = NULL;

error:
    krb5_free_cred_contents(ctx, &outcreds);
    if (opt)
        krb5_get_init_creds_opt_free(ctx, opt);
    return code;
}
Example #11
0
int
main (int argc, char **argv)
{
    krb5_error_code ret;
    krb5_context context;
    krb5_ccache  ccache;
    krb5_principal principal;
    int optidx = 0;
    krb5_deltat ticket_life = 0;
    int parseflags = 0;

    setprogname (argv[0]);

    setlocale (LC_ALL, "");
    bindtextdomain ("heimdal_kuser", HEIMDAL_LOCALEDIR);
    textdomain("heimdal_kuser");

    ret = krb5_init_context (&context);
    if (ret == KRB5_CONFIG_BADFORMAT)
	errx (1, "krb5_init_context failed to parse configuration file");
    else if (ret)
	errx(1, "krb5_init_context failed: %d", ret);

    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
	usage(1);

    if (help_flag)
	usage (0);

    if(version_flag) {
	print_version(NULL);
	exit(0);
    }

    argc -= optidx;
    argv += optidx;

    if (canonicalize_flag || enterprise_flag)
	parseflags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE;

    if (pk_enterprise_flag) {
	ret = krb5_pk_enterprise_cert(context, pk_user_id,
				      argv[0], &principal,
				      &ent_user_id);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pk_enterprise_certs");

	pk_user_id = NULL;

    } else if (anonymous_flag) {

	ret = krb5_make_principal(context, &principal, argv[0],
				  KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME,
				  NULL);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_make_principal");
	krb5_principal_set_type(context, principal, KRB5_NT_WELLKNOWN);

    } else {
	if (argv[0]) {
	    ret = krb5_parse_name_flags (context, argv[0], parseflags,
					 &principal);
	    if (ret)
		krb5_err (context, 1, ret, "krb5_parse_name");
	} else {
	    ret = krb5_get_default_principal (context, &principal);
	    if (ret)
		krb5_err (context, 1, ret, "krb5_get_default_principal");
	}
    }

    if(fcache_version)
	krb5_set_fcache_version(context, fcache_version);

    if(renewable_flag == -1)
	/* this seems somewhat pointless, but whatever */
	krb5_appdefault_boolean(context, "kinit",
				krb5_principal_get_realm(context, principal),
				"renewable", FALSE, &renewable_flag);
    if(do_afslog == -1)
	krb5_appdefault_boolean(context, "kinit",
				krb5_principal_get_realm(context, principal),
				"afslog", TRUE, &do_afslog);

    if(cred_cache)
	ret = krb5_cc_resolve(context, cred_cache, &ccache);
    else {
	if(argc > 1) {
	    char s[1024];
	    ret = krb5_cc_new_unique(context, NULL, NULL, &ccache);
	    if(ret)
		krb5_err(context, 1, ret, "creating cred cache");
	    snprintf(s, sizeof(s), "%s:%s",
		     krb5_cc_get_type(context, ccache),
		     krb5_cc_get_name(context, ccache));
	    setenv("KRB5CCNAME", s, 1);
	} else {
	    ret = krb5_cc_cache_match(context, principal, &ccache);
	    if (ret) {
		const char *type;
		ret = krb5_cc_default (context, &ccache);
		if (ret)
		    krb5_err (context, 1, ret, N_("resolving credentials cache", ""));

		/*
		 * Check if the type support switching, and we do,
		 * then do that instead over overwriting the current
		 * default credential
		 */
		type = krb5_cc_get_type(context, ccache);
		if (krb5_cc_support_switch(context, type)) {
		    krb5_cc_close(context, ccache);
		    ret = krb5_cc_new_unique(context, type, NULL, &ccache);
		}
	    }
	}
    }
    if (ret)
	krb5_err (context, 1, ret, N_("resolving credentials cache", ""));

#ifndef NO_AFS
    if(argc > 1 && k_hasafs ())
	k_setpag();
#endif

    if (lifetime) {
	int tmp = parse_time (lifetime, "s");
	if (tmp < 0)
	    errx (1, N_("unparsable time: %s", ""), lifetime);

	ticket_life = tmp;
    }

    if(addrs_flag == 0 && extra_addresses.num_strings > 0)
	krb5_errx(context, 1,
		  N_("specifying both extra addresses and "
		     "no addresses makes no sense", ""));
    {
	int i;
	krb5_addresses addresses;
	memset(&addresses, 0, sizeof(addresses));
	for(i = 0; i < extra_addresses.num_strings; i++) {
	    ret = krb5_parse_address(context, extra_addresses.strings[i],
				     &addresses);
	    if (ret == 0) {
		krb5_add_extra_addresses(context, &addresses);
		krb5_free_addresses(context, &addresses);
	    }
	}
	free_getarg_strings(&extra_addresses);
    }

    if(renew_flag || validate_flag) {
	ret = renew_validate(context, renew_flag, validate_flag,
			     ccache, server_str, ticket_life);
	exit(ret != 0);
    }

    get_new_tickets(context, principal, ccache, ticket_life, 1);

#ifndef NO_AFS
    if(do_afslog && k_hasafs())
	krb5_afslog(context, ccache, NULL, NULL);
#endif
    if(argc > 1) {
	struct renew_ctx ctx;
	time_t timeout;

	timeout = ticket_lifetime(context, ccache, principal,
				  server_str, NULL) / 2;

	ctx.context = context;
	ctx.ccache = ccache;
	ctx.principal = principal;
	ctx.ticket_life = ticket_life;

	ret = simple_execvp_timed(argv[1], argv+1,
				  renew_func, &ctx, timeout);
#define EX_NOEXEC	126
#define EX_NOTFOUND	127
	if(ret == EX_NOEXEC)
	    krb5_warnx(context, N_("permission denied: %s", ""), argv[1]);
	else if(ret == EX_NOTFOUND)
	    krb5_warnx(context, N_("command not found: %s", ""), argv[1]);

	krb5_cc_destroy(context, ccache);
#ifndef NO_AFS
	if(k_hasafs())
	    k_unlog();
#endif
    } else {
	krb5_cc_close (context, ccache);
	ret = 0;
    }
    krb5_free_principal(context, principal);
    krb5_free_context (context);
    return ret;
}
Example #12
0
static bool torture_pac_self_check(struct torture_context *tctx)
{
	NTSTATUS nt_status;
	DATA_BLOB tmp_blob;
	struct PAC_DATA *pac_data;
	struct PAC_LOGON_INFO *logon_info;
	union netr_Validation validation;

	/* Generate a nice, arbitary keyblock */
	uint8_t server_bytes[16];
	uint8_t krbtgt_bytes[16];
	krb5_keyblock server_keyblock;
	krb5_keyblock krbtgt_keyblock;
	
	krb5_error_code ret;

	struct smb_krb5_context *smb_krb5_context;

	struct auth_serversupplied_info *server_info;
	struct auth_serversupplied_info *server_info_out;

	krb5_principal client_principal;
	time_t logon_time = time(NULL);

	TALLOC_CTX *mem_ctx = tctx;

	torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx, 
							NULL,
							tctx->lp_ctx,
							&smb_krb5_context), 
		       "smb_krb5_init_context");

	generate_random_buffer(server_bytes, 16);
	generate_random_buffer(krbtgt_bytes, 16);

	ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
				 ENCTYPE_ARCFOUR_HMAC,
				 server_bytes, sizeof(server_bytes),
				 &server_keyblock);
	torture_assert(tctx, !ret, talloc_asprintf(tctx, 
						   "(self test) Server Keyblock encoding failed: %s", 
						   smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
									      ret, mem_ctx)));

	ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
				 ENCTYPE_ARCFOUR_HMAC,
				 krbtgt_bytes, sizeof(krbtgt_bytes),
				 &krbtgt_keyblock);
	if (ret) {
		char *err = smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
						       ret, mem_ctx);
	
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);

		torture_fail(tctx, talloc_asprintf(tctx, 
						   "(self test) KRBTGT Keyblock encoding failed: %s", err));
	}

	/* We need an input, and this one requires no underlying database */
	nt_status = auth_anonymous_server_info(mem_ctx, lp_netbios_name(tctx->lp_ctx), &server_info);

	if (!NT_STATUS_IS_OK(nt_status)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &krbtgt_keyblock);
		torture_fail(tctx, "auth_anonymous_server_info");
	}

	ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, 
				    server_info->account_name, 
				    KRB5_PRINCIPAL_PARSE_NO_REALM, 
				    &client_principal);
	if (ret) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &krbtgt_keyblock);
		torture_fail(tctx, "krb5_parse_name_flags(norealm)");
	}

	/* OK, go ahead and make a PAC */
	ret = kerberos_create_pac(mem_ctx, 
				  lp_iconv_convenience(tctx->lp_ctx),
				  server_info, 
				  smb_krb5_context->krb5_context,  
				  &krbtgt_keyblock,
				  &server_keyblock,
				  client_principal,
				  logon_time,
				  &tmp_blob);
	
	if (ret) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &krbtgt_keyblock);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, 
				    client_principal);

		torture_fail(tctx, talloc_asprintf(tctx,
						   "(self test) PAC encoding failed: %s", 
						   smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
									      ret, mem_ctx)));
	}

	dump_data(10,tmp_blob.data,tmp_blob.length);

	/* Now check that we can read it back (using full decode and validate) */
	nt_status = kerberos_decode_pac(mem_ctx, 
					lp_iconv_convenience(tctx->lp_ctx),
					&pac_data,
					tmp_blob,
					smb_krb5_context->krb5_context,
					&krbtgt_keyblock,
					&server_keyblock,
					client_principal, 
					logon_time, NULL);

	if (!NT_STATUS_IS_OK(nt_status)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &krbtgt_keyblock);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, 
				    client_principal);

		torture_fail(tctx, talloc_asprintf(tctx,
						   "(self test) PAC decoding failed: %s", 
						   nt_errstr(nt_status)));
	}

	/* Now check we can read it back (using Heimdal's pac parsing) */
	nt_status = kerberos_pac_blob_to_server_info(mem_ctx, 
						     lp_iconv_convenience(tctx->lp_ctx),
						     tmp_blob, 
						     smb_krb5_context->krb5_context,
						     &server_info_out);

	if (!dom_sid_equal(server_info->account_sid, 
			   server_info_out->account_sid)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &krbtgt_keyblock);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, 
				    client_principal);

		torture_fail(tctx,  
			     talloc_asprintf(tctx, 
					     "(self test) PAC Decode resulted in *different* domain SID: %s != %s",
					     dom_sid_string(mem_ctx, server_info->account_sid), 
					     dom_sid_string(mem_ctx, server_info_out->account_sid)));
	}
	talloc_free(server_info_out);

	/* Now check that we can read it back (yet again) */
	nt_status = kerberos_pac_logon_info(mem_ctx, 
					    lp_iconv_convenience(tctx->lp_ctx),
					    &logon_info,
					    tmp_blob,
					    smb_krb5_context->krb5_context,
					    &krbtgt_keyblock,
					    &server_keyblock,
					    client_principal, 
					    logon_time, 
					    NULL);
	
	if (!NT_STATUS_IS_OK(nt_status)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &krbtgt_keyblock);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, 
				    client_principal);
		
		torture_fail(tctx,  
			     talloc_asprintf(tctx, 
					     "(self test) PAC decoding (for logon info) failed: %s", 
					     nt_errstr(nt_status)));
	}
	
	krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
				    &krbtgt_keyblock);
	krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
				    &server_keyblock);
	krb5_free_principal(smb_krb5_context->krb5_context, 
			    client_principal);

	/* And make a server info from the samba-parsed PAC */
	validation.sam3 = &logon_info->info3;
	nt_status = make_server_info_netlogon_validation(mem_ctx,
							 "",
							 3, &validation,
							 &server_info_out); 
	if (!NT_STATUS_IS_OK(nt_status)) {
		torture_fail(tctx, 
			     talloc_asprintf(tctx, 
					     "(self test) PAC decoding (make server info) failed: %s", 
					     nt_errstr(nt_status)));
	}
	
	if (!dom_sid_equal(server_info->account_sid, 
			   server_info_out->account_sid)) {
		torture_fail(tctx,  
			     talloc_asprintf(tctx, 
					     "(self test) PAC Decode resulted in *different* domain SID: %s != %s",
					     dom_sid_string(mem_ctx, server_info->account_sid), 
					     dom_sid_string(mem_ctx, server_info_out->account_sid)));
	}
	return true;
}
Example #13
0
static WERROR DsCrackNameSPNAlias(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                                  struct smb_krb5_context *smb_krb5_context,
                                  uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
                                  const char *name, struct drsuapi_DsNameInfo1 *info1)
{
    WERROR wret;
    krb5_error_code ret;
    krb5_principal principal;
    const char *service, *dns_name;
    char *new_service;
    char *new_princ;
    enum drsuapi_DsNameStatus namestatus;

    /* parse principal */
    ret = krb5_parse_name_flags(smb_krb5_context->krb5_context,
                                name, KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
    if (ret) {
        DEBUG(2, ("Could not parse principal: %s: %s",
                  name, smb_get_krb5_error_message(smb_krb5_context->krb5_context,
                          ret, mem_ctx)));
        return WERR_NOMEM;
    }

    /* grab cifs/, http/ etc */

    /* This is checked for in callers, but be safe */
    if (principal->name.name_string.len < 2) {
        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
        return WERR_OK;
    }
    service = principal->name.name_string.val[0];
    dns_name = principal->name.name_string.val[1];

    /* MAP it */
    namestatus = LDB_lookup_spn_alias(smb_krb5_context->krb5_context,
                                      sam_ctx, mem_ctx,
                                      service, &new_service);

    if (namestatus == DRSUAPI_DS_NAME_STATUS_NOT_FOUND) {
        info1->status		= DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
        info1->dns_domain_name	= talloc_strdup(mem_ctx, dns_name);
        if (!info1->dns_domain_name) {
            krb5_free_principal(smb_krb5_context->krb5_context, principal);
            return WERR_NOMEM;
        }
        return WERR_OK;
    } else if (namestatus != DRSUAPI_DS_NAME_STATUS_OK) {
        info1->status = namestatus;
        krb5_free_principal(smb_krb5_context->krb5_context, principal);
        return WERR_OK;
    }

    /* ooh, very nasty playing around in the Principal... */
    free(principal->name.name_string.val[0]);
    principal->name.name_string.val[0] = strdup(new_service);
    if (!principal->name.name_string.val[0]) {
        krb5_free_principal(smb_krb5_context->krb5_context, principal);
        return WERR_NOMEM;
    }

    /* reform principal */
    ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal,
                                  KRB5_PRINCIPAL_UNPARSE_NO_REALM, &new_princ);

    if (ret) {
        krb5_free_principal(smb_krb5_context->krb5_context, principal);
        return WERR_NOMEM;
    }

    wret = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, format_offered, format_desired,
                              new_princ, info1);
    free(new_princ);
    if (W_ERROR_IS_OK(wret) && (info1->status == DRSUAPI_DS_NAME_STATUS_NOT_FOUND)) {
        info1->status		= DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
        info1->dns_domain_name	= talloc_strdup(mem_ctx, dns_name);
        if (!info1->dns_domain_name) {
            wret = WERR_NOMEM;
        }
    }
    krb5_free_principal(smb_krb5_context->krb5_context, principal);
    return wret;
}
Example #14
0
krb5_error_code KRB5_CALLCONV
krb5_parse_name(krb5_context context, const char *name,
                krb5_principal *principal_out)
{
    return krb5_parse_name_flags(context, name, 0, principal_out);
}
Example #15
0
static UINT32 transport_krb5_check_account(rdpTransport* transport, char* username, char* domain,
        char* passwd)
{
	krb5_error_code ret;
	krb5_context context = NULL;
	krb5_principal principal = NULL;
	char address[256];
	krb5_ccache ccache;
	krb5_init_creds_context ctx = NULL;
	_snprintf(address, sizeof(address), "%s@%s", username, domain);

	/* Create a krb5 library context */
	if ((ret = krb5_init_context(&context)) != 0)
		WLog_Print(transport->log, WLOG_ERROR, "krb5_init_context failed with error %d", (int)ret);
	else if ((ret = krb5_parse_name_flags(context, address, 0, &principal)) != 0)
		WLog_Print(transport->log, WLOG_ERROR, "krb5_parse_name_flags failed with error %d", (int)ret);
	/* Find a credential cache with a specified client principal */
	else if ((ret = krb5_cc_cache_match(context, principal, &ccache)) != 0)
	{
		if ((ret = krb5_cc_default(context, &ccache)) != 0)
			WLog_Print(transport->log, WLOG_ERROR, "krb5 failed to resolve credentials cache with error %d",
			           (int)ret);
	}

	if (ret != KRB5KDC_ERR_NONE)
		goto out;
	/* Create a context for acquiring initial credentials */
	else if ((ret = krb5_init_creds_init(context, principal, NULL, NULL, 0, NULL, &ctx)) != 0)
	{
		WLog_Print(transport->log, WLOG_WARN, "krb5_init_creds_init returned error %d", (int)ret);
		goto out;
	}
	/* Set a password for acquiring initial credentials */
	else if ((ret = krb5_init_creds_set_password(context, ctx, passwd)) != 0)
	{
		WLog_Print(transport->log, WLOG_WARN, "krb5_init_creds_set_password returned error %d", ret);
		goto out;
	}

	/* Acquire credentials using an initial credential context */
	ret = krb5_init_creds_get(context, ctx);
out:

	switch (ret)
	{
		case KRB5KDC_ERR_NONE:
			break;

		case KRB5_KDC_UNREACH:
			WLog_Print(transport->log, WLOG_WARN, "krb5_init_creds_get: KDC unreachable");
			ret = FREERDP_ERROR_CONNECT_KDC_UNREACHABLE;
			break;

		case KRB5KRB_AP_ERR_BAD_INTEGRITY:
		case KRB5KRB_AP_ERR_MODIFIED:
		case KRB5KDC_ERR_PREAUTH_FAILED:
		case KRB5_GET_IN_TKT_LOOP:
			WLog_Print(transport->log, WLOG_WARN, "krb5_init_creds_get: Password incorrect");
			ret = FREERDP_ERROR_AUTHENTICATION_FAILED;
			break;

		case KRB5KDC_ERR_KEY_EXP:
			WLog_Print(transport->log, WLOG_WARN, "krb5_init_creds_get: Password has expired");
			ret = FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED;
			break;

		case KRB5KDC_ERR_CLIENT_REVOKED:
			WLog_Print(transport->log, WLOG_WARN, "krb5_init_creds_get: Password revoked");
			ret = FREERDP_ERROR_CONNECT_CLIENT_REVOKED;
			break;

		case KRB5KDC_ERR_POLICY:
			ret = FREERDP_ERROR_INSUFFICIENT_PRIVILEGES;
			break;

		default:
			WLog_Print(transport->log, WLOG_WARN, "krb5_init_creds_get");
			ret = FREERDP_ERROR_CONNECT_TRANSPORT_FAILED;
			break;
	}

	if (ctx)
		krb5_init_creds_free(context, ctx);

	krb5_free_context(context);
	return ret;
}
Example #16
0
 NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx,
			      struct smb_iconv_convenience *iconv_convenience,
			      struct PAC_DATA **pac_data_out,
			      DATA_BLOB blob,
			      krb5_context context,
			      const krb5_keyblock *krbtgt_keyblock,
			      const krb5_keyblock *service_keyblock,
			      krb5_const_principal client_principal,
			      time_t tgs_authtime,
			      krb5_error_code *k5ret)
{
	krb5_error_code ret;
	NTSTATUS status;
	enum ndr_err_code ndr_err;
	struct PAC_SIGNATURE_DATA *srv_sig_ptr = NULL;
	struct PAC_SIGNATURE_DATA *kdc_sig_ptr = NULL;
	struct PAC_SIGNATURE_DATA *srv_sig_wipe = NULL;
	struct PAC_SIGNATURE_DATA *kdc_sig_wipe = NULL;
	struct PAC_LOGON_INFO *logon_info = NULL;
	struct PAC_LOGON_NAME *logon_name = NULL;
	struct PAC_DATA *pac_data;
	struct PAC_DATA_RAW *pac_data_raw;

	DATA_BLOB *srv_sig_blob = NULL;
	DATA_BLOB *kdc_sig_blob = NULL;

	DATA_BLOB modified_pac_blob;
	NTTIME tgs_authtime_nttime;
	krb5_principal client_principal_pac;
	int i;

	krb5_clear_error_message(context);

	if (k5ret) {
		*k5ret = KRB5_PARSE_MALFORMED;
	}

	pac_data = talloc(mem_ctx, struct PAC_DATA);
	pac_data_raw = talloc(mem_ctx, struct PAC_DATA_RAW);
	kdc_sig_wipe = talloc(mem_ctx, struct PAC_SIGNATURE_DATA);
	srv_sig_wipe = talloc(mem_ctx, struct PAC_SIGNATURE_DATA);
	if (!pac_data_raw || !pac_data || !kdc_sig_wipe || !srv_sig_wipe) {
		if (k5ret) {
			*k5ret = ENOMEM;
		}
		return NT_STATUS_NO_MEMORY;
	}

	ndr_err = ndr_pull_struct_blob(&blob, pac_data, 
			iconv_convenience, pac_data,
		       (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		status = ndr_map_error2ntstatus(ndr_err);
		DEBUG(0,("can't parse the PAC: %s\n",
			nt_errstr(status)));
		return status;
	}

	if (pac_data->num_buffers < 4) {
		/* we need logon_ingo, service_key and kdc_key */
		DEBUG(0,("less than 4 PAC buffers\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	ndr_err = ndr_pull_struct_blob(&blob, pac_data_raw, 
				       iconv_convenience, pac_data_raw,
				       (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA_RAW);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		status = ndr_map_error2ntstatus(ndr_err);
		DEBUG(0,("can't parse the PAC: %s\n",
			nt_errstr(status)));
		return status;
	}

	if (pac_data_raw->num_buffers < 4) {
		/* we need logon_ingo, service_key and kdc_key */
		DEBUG(0,("less than 4 PAC buffers\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (pac_data->num_buffers != pac_data_raw->num_buffers) {
		/* we need logon_ingo, service_key and kdc_key */
		DEBUG(0,("misparse!  PAC_DATA has %d buffers while PAC_DATA_RAW has %d\n",
			 pac_data->num_buffers, pac_data_raw->num_buffers));
		return NT_STATUS_INVALID_PARAMETER;
	}

	for (i=0; i < pac_data->num_buffers; i++) {
		if (pac_data->buffers[i].type != pac_data_raw->buffers[i].type) {
			DEBUG(0,("misparse!  PAC_DATA buffer %d has type %d while PAC_DATA_RAW has %d\n",
				 i, pac_data->buffers[i].type, pac_data->buffers[i].type));
			return NT_STATUS_INVALID_PARAMETER;
		}
		switch (pac_data->buffers[i].type) {
			case PAC_TYPE_LOGON_INFO:
				if (!pac_data->buffers[i].info) {
					break;
				}
				logon_info = pac_data->buffers[i].info->logon_info.info;
				break;
			case PAC_TYPE_SRV_CHECKSUM:
				if (!pac_data->buffers[i].info) {
					break;
				}
				srv_sig_ptr = &pac_data->buffers[i].info->srv_cksum;
				srv_sig_blob = &pac_data_raw->buffers[i].info->remaining;
				break;
			case PAC_TYPE_KDC_CHECKSUM:
				if (!pac_data->buffers[i].info) {
					break;
				}
				kdc_sig_ptr = &pac_data->buffers[i].info->kdc_cksum;
				kdc_sig_blob = &pac_data_raw->buffers[i].info->remaining;
				break;
			case PAC_TYPE_LOGON_NAME:
				logon_name = &pac_data->buffers[i].info->logon_name;
				break;
			default:
				break;
		}
	}

	if (!logon_info) {
		DEBUG(0,("PAC no logon_info\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!logon_name) {
		DEBUG(0,("PAC no logon_name\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!srv_sig_ptr || !srv_sig_blob) {
		DEBUG(0,("PAC no srv_key\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!kdc_sig_ptr || !kdc_sig_blob) {
		DEBUG(0,("PAC no kdc_key\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	/* Find and zero out the signatures, as required by the signing algorithm */

	/* We find the data blobs above, now we parse them to get at the exact portion we should zero */
	ndr_err = ndr_pull_struct_blob(kdc_sig_blob, kdc_sig_wipe, 
				       iconv_convenience, kdc_sig_wipe,
				       (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		status = ndr_map_error2ntstatus(ndr_err);
		DEBUG(0,("can't parse the KDC signature: %s\n",
			nt_errstr(status)));
		return status;
	}
	
	ndr_err = ndr_pull_struct_blob(srv_sig_blob, srv_sig_wipe, 
				       iconv_convenience, srv_sig_wipe,
				       (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		status = ndr_map_error2ntstatus(ndr_err);
		DEBUG(0,("can't parse the SRV signature: %s\n",
			nt_errstr(status)));
		return status;
	}

	/* Now zero the decoded structure */
	memset(kdc_sig_wipe->signature.data, '\0', kdc_sig_wipe->signature.length);
	memset(srv_sig_wipe->signature.data, '\0', srv_sig_wipe->signature.length);
	
	/* and reencode, back into the same place it came from */
	ndr_err = ndr_push_struct_blob(kdc_sig_blob, pac_data_raw, 
				       iconv_convenience,
				       kdc_sig_wipe,
				       (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		status = ndr_map_error2ntstatus(ndr_err);
		DEBUG(0,("can't repack the KDC signature: %s\n",
			nt_errstr(status)));
		return status;
	}
	ndr_err = ndr_push_struct_blob(srv_sig_blob, pac_data_raw, 
				       iconv_convenience,
				       srv_sig_wipe,
				       (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		status = ndr_map_error2ntstatus(ndr_err);
		DEBUG(0,("can't repack the SRV signature: %s\n",
			nt_errstr(status)));
		return status;
	}

	/* push out the whole structure, but now with zero'ed signatures */
	ndr_err = ndr_push_struct_blob(&modified_pac_blob, pac_data_raw, 
				       iconv_convenience,
				       pac_data_raw,
				       (ndr_push_flags_fn_t)ndr_push_PAC_DATA_RAW);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		status = ndr_map_error2ntstatus(ndr_err);
		DEBUG(0,("can't repack the RAW PAC: %s\n",
			nt_errstr(status)));
		return status;
	}

	/* verify by service_key */
	ret = check_pac_checksum(mem_ctx, 
				 modified_pac_blob, srv_sig_ptr, 
				 context, 
				 service_keyblock);
	if (ret) {
		DEBUG(1, ("PAC Decode: Failed to verify the service signature: %s\n",
			  smb_get_krb5_error_message(context, ret, mem_ctx)));
		if (k5ret) {
			*k5ret = ret;
		}
		return NT_STATUS_ACCESS_DENIED;
	}

	if (krbtgt_keyblock) {
		ret = check_pac_checksum(mem_ctx, 
					    srv_sig_ptr->signature, kdc_sig_ptr, 
					    context, krbtgt_keyblock);
		if (ret) {
			DEBUG(1, ("PAC Decode: Failed to verify the KDC signature: %s\n",
				  smb_get_krb5_error_message(context, ret, mem_ctx)));
			if (k5ret) {
				*k5ret = ret;
			}
			return NT_STATUS_ACCESS_DENIED;
		}
	}

	/* Convert to NT time, so as not to loose accuracy in comparison */
	unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime);

	if (tgs_authtime_nttime != logon_name->logon_time) {
		DEBUG(2, ("PAC Decode: Logon time mismatch between ticket and PAC!\n"));
		DEBUG(2, ("PAC Decode: PAC: %s\n", nt_time_string(mem_ctx, logon_name->logon_time)));
		DEBUG(2, ("PAC Decode: Ticket: %s\n", nt_time_string(mem_ctx, tgs_authtime_nttime)));
		return NT_STATUS_ACCESS_DENIED;
	}

	ret = krb5_parse_name_flags(context, logon_name->account_name, KRB5_PRINCIPAL_PARSE_NO_REALM, 
				    &client_principal_pac);
	if (ret) {
		DEBUG(2, ("Could not parse name from incoming PAC: [%s]: %s\n", 
			  logon_name->account_name, 
			  smb_get_krb5_error_message(context, ret, mem_ctx)));
		if (k5ret) {
			*k5ret = ret;
		}
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!krb5_principal_compare_any_realm(context, client_principal, client_principal_pac)) {
		DEBUG(2, ("Name in PAC [%s] does not match principal name in ticket\n", 
			  logon_name->account_name));
		return NT_STATUS_ACCESS_DENIED;
	}
	
#if 0
	if (strcasecmp(logon_info->info3.base.account_name.string, 
		       "Administrator")== 0) {
		file_save("tmp_pac_data-admin.dat",blob.data,blob.length);
	}
#endif

	DEBUG(3,("Found account name from PAC: %s [%s]\n",
		 logon_info->info3.base.account_name.string, 
		 logon_info->info3.base.full_name.string));
	*pac_data_out = pac_data;

	return NT_STATUS_OK;
}
Example #17
0
int
main(int argc, char **argv)
{
    krb5_error_code ret;
    krb5_context context;
    krb5_pac pac;
    krb5_data data;
    krb5_principal p, p2;

    ret = krb5_init_context(&context);
    if (ret)
	errx(1, "krb5_init_contex");

    krb5_enctype_enable(context, ETYPE_DES_CBC_MD5);

    ret = krb5_parse_name_flags(context, user,
				KRB5_PRINCIPAL_PARSE_NO_REALM, &p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    ret = krb5_pac_parse(context, saved_pac, sizeof(saved_pac), &pac);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_parse");

    ret = krb5_pac_verify(context, pac, authtime, p,
			   &member_keyblock, &kdc_keyblock);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_verify");

    ret = _krb5_pac_sign(context, pac, authtime, p,
			 &member_keyblock, &kdc_keyblock, &data);
    if (ret)
	krb5_err(context, 1, ret, "_krb5_pac_sign");

    krb5_pac_free(context, pac);

    ret = krb5_pac_parse(context, data.data, data.length, &pac);
    krb5_data_free(&data);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_parse 2");

    ret = krb5_pac_verify(context, pac, authtime, p,
			   &member_keyblock, &kdc_keyblock);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_verify 2");

    /* make a copy and try to reproduce it */
    {
	uint32_t *list;
	size_t len, i;
	krb5_pac pac2;

	ret = krb5_pac_init(context, &pac2);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_init");

	/* our two user buffer plus the three "system" buffers */
	ret = krb5_pac_get_types(context, pac, &len, &list);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_get_types");

	for (i = 0; i < len; i++) {
	    /* skip server_cksum, privsvr_cksum, and logon_name */
	    if (list[i] == 6 || list[i] == 7 || list[i] == 10)
		continue;

	    ret = krb5_pac_get_buffer(context, pac, list[i], &data);
	    if (ret)
		krb5_err(context, 1, ret, "krb5_pac_get_buffer");

	    if (list[i] == 1) {
		if (type_1_length != data.length)
		    krb5_errx(context, 1, "type 1 have wrong length: %lu",
			      (unsigned long)data.length);
	    } else
		krb5_errx(context, 1, "unknown type %lu",
			  (unsigned long)list[i]);

	    ret = krb5_pac_add_buffer(context, pac2, list[i], &data);
	    if (ret)
		krb5_err(context, 1, ret, "krb5_pac_add_buffer");
	    krb5_data_free(&data);
	}
	free(list);

	ret = _krb5_pac_sign(context, pac2, authtime, p,
			     &member_keyblock, &kdc_keyblock, &data);
	if (ret)
	    krb5_err(context, 1, ret, "_krb5_pac_sign 4");

	krb5_pac_free(context, pac2);

	ret = krb5_pac_parse(context, data.data, data.length, &pac2);
	krb5_data_free(&data);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_parse 4");

	ret = krb5_pac_verify(context, pac2, authtime, p,
			      &member_keyblock, &kdc_keyblock);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_verify 4");

	krb5_pac_free(context, pac2);
    }

    krb5_pac_free(context, pac);

    /*
     * check pac from Christian
     */

    ret = krb5_parse_name_flags(context, user2,
				KRB5_PRINCIPAL_PARSE_NO_REALM, &p2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    ret = krb5_pac_parse(context, saved_pac2, sizeof(saved_pac2) -1, &pac);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_parse");

    ret = krb5_pac_verify(context, pac, authtime2, p2,
			   &member_keyblock2, NULL);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_verify c1");

    krb5_pac_free(context, pac);
    krb5_free_principal(context, p2);

    /*
     * Test empty free
     */

    ret = krb5_pac_init(context, &pac);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_init");
    krb5_pac_free(context, pac);

    /*
     * Test add remove buffer
     */

    ret = krb5_pac_init(context, &pac);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_init");

    {
	const krb5_data cdata = { 2, "\x00\x01" } ;

	ret = krb5_pac_add_buffer(context, pac, 1, &cdata);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_add_buffer");
    }
    {
	ret = krb5_pac_get_buffer(context, pac, 1, &data);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_get_buffer");
	if (data.length != 2 || memcmp(data.data, "\x00\x01", 2) != 0)
	    krb5_errx(context, 1, "krb5_pac_get_buffer data not the same");
	krb5_data_free(&data);
    }

    {
	const krb5_data cdata = { 2, "\x02\x00" } ;

	ret = krb5_pac_add_buffer(context, pac, 2, &cdata);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_add_buffer");
    }
    {
	ret = krb5_pac_get_buffer(context, pac, 1, &data);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_get_buffer");
	if (data.length != 2 || memcmp(data.data, "\x00\x01", 2) != 0)
	    krb5_errx(context, 1, "krb5_pac_get_buffer data not the same");
	krb5_data_free(&data);
	/* */
	ret = krb5_pac_get_buffer(context, pac, 2, &data);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_get_buffer");
	if (data.length != 2 || memcmp(data.data, "\x02\x00", 2) != 0)
	    krb5_errx(context, 1, "krb5_pac_get_buffer data not the same");
	krb5_data_free(&data);
    }

    ret = _krb5_pac_sign(context, pac, authtime, p,
			 &member_keyblock, &kdc_keyblock, &data);
    if (ret)
	krb5_err(context, 1, ret, "_krb5_pac_sign");

    krb5_pac_free(context, pac);

    ret = krb5_pac_parse(context, data.data, data.length, &pac);
    krb5_data_free(&data);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_parse 3");

    ret = krb5_pac_verify(context, pac, authtime, p,
			   &member_keyblock, &kdc_keyblock);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_verify 3");

    {
	uint32_t *list;
	size_t len;

	/* our two user buffer plus the three "system" buffers */
	ret = krb5_pac_get_types(context, pac, &len, &list);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_get_types");
	if (len != 5)
	    krb5_errx(context, 1, "list wrong length");
	free(list);
    }

    krb5_pac_free(context, pac);

    krb5_free_principal(context, p);
    krb5_free_context(context);

    return 0;
}
Example #18
0
/*
  check that the SPN update should be allowed as an override
  via sam_ctx_system

  This is only called if the client is not a domain controller or
  administrator
 */
static bool writespn_check_spn(struct drsuapi_bind_state *b_state,
			       struct dcesrv_call_state *dce_call,
			       struct ldb_dn *dn,
			       const char *spn)
{
	/*
	 * we only allow SPN updates if:
	 *
	 * 1) they are on the clients own account object
	 * 2) they are of the form SERVICE/dnshostname
	 */
	struct dom_sid *user_sid, *sid;
	TALLOC_CTX *tmp_ctx = talloc_new(dce_call);
	struct ldb_result *res;
	const char *attrs[] = { "objectSID", "dNSHostName", NULL };
	int ret;
	krb5_context krb_ctx;
	krb5_error_code kerr;
	krb5_principal principal;
	const krb5_data *component;
	const char *dns_name, *dnsHostName;

	/* The service principal name shouldn't be NULL */
	if (spn == NULL) {
		talloc_free(tmp_ctx);
		return false;
	}

	/*
	  get the objectSid of the DN that is being modified, and
	  check it matches the user_sid in their token
	 */

	ret = dsdb_search_dn(b_state->sam_ctx, tmp_ctx, &res, dn, attrs,
			     DSDB_SEARCH_ONE_ONLY);
	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return false;
	}

	user_sid = &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
	sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
	if (sid == NULL) {
		talloc_free(tmp_ctx);
		return false;
	}

	dnsHostName = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName",
						  NULL);
	if (dnsHostName == NULL) {
		talloc_free(tmp_ctx);
		return false;
	}

	if (!dom_sid_equal(sid, user_sid)) {
		talloc_free(tmp_ctx);
		return false;
	}

	kerr = smb_krb5_init_context_basic(tmp_ctx,
					   dce_call->conn->dce_ctx->lp_ctx,
					   &krb_ctx);
	if (kerr != 0) {
		talloc_free(tmp_ctx);
		return false;
	}

	ret = krb5_parse_name_flags(krb_ctx, spn, KRB5_PRINCIPAL_PARSE_NO_REALM,
				    &principal);
	if (kerr != 0) {
		krb5_free_context(krb_ctx);
		talloc_free(tmp_ctx);
		return false;
	}

	if (krb5_princ_size(krb_ctx, principal) != 2) {
		krb5_free_principal(krb_ctx, principal);
		krb5_free_context(krb_ctx);
		talloc_free(tmp_ctx);
		return false;
	}

	component = krb5_princ_component(krb_ctx, principal, 1);
	dns_name = (const char *)component->data;

	if (strcasecmp(dns_name, dnsHostName) != 0) {
		krb5_free_principal(krb_ctx, principal);
		krb5_free_context(krb_ctx);
		talloc_free(tmp_ctx);
		return false;
	}

	/* its a simple update on their own account - allow it with
	 * permissions override */
	krb5_free_principal(krb_ctx, principal);
	krb5_free_context(krb_ctx);
	talloc_free(tmp_ctx);

	return true;
}
Example #19
0
WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                          uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
                          const char *name, struct drsuapi_DsNameInfo1 *info1)
{
    krb5_error_code ret;
    const char *domain_filter = NULL;
    const char *result_filter = NULL;
    struct ldb_dn *name_dn = NULL;

    struct smb_krb5_context *smb_krb5_context = NULL;

    info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
    info1->dns_domain_name = NULL;
    info1->result_name = NULL;

    if (!name) {
        return WERR_INVALID_PARAM;
    }

    /* TODO: - fill the correct names in all cases!
     *       - handle format_flags
     */

    /* here we need to set the domain_filter and/or the result_filter */
    switch (format_offered) {
    case DRSUAPI_DS_NAME_FORMAT_UNKNOWN:
    {
        int i;
        enum drsuapi_DsNameFormat formats[] = {
            DRSUAPI_DS_NAME_FORMAT_FQDN_1779, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
            DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, DRSUAPI_DS_NAME_FORMAT_CANONICAL,
            DRSUAPI_DS_NAME_FORMAT_GUID, DRSUAPI_DS_NAME_FORMAT_DISPLAY,
            DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
            DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
            DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
        };
        WERROR werr;
        for (i=0; i < ARRAY_SIZE(formats); i++) {
            werr = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, formats[i], format_desired, name, info1);
            if (!W_ERROR_IS_OK(werr)) {
                return werr;
            }
            if (info1->status != DRSUAPI_DS_NAME_STATUS_NOT_FOUND) {
                return werr;
            }
        }
        return werr;
    }

    case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
    case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
    {
        char *str, *s, *account;

        if (strlen(name) == 0) {
            info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
            return WERR_OK;
        }

        str = talloc_strdup(mem_ctx, name);
        W_ERROR_HAVE_NO_MEMORY(str);

        if (format_offered == DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX) {
            /* Look backwards for the \n, and replace it with / */
            s = strrchr(str, '\n');
            if (!s) {
                info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
                return WERR_OK;
            }
            s[0] = '/';
        }

        s = strchr(str, '/');
        if (!s) {
            /* there must be at least one / */
            info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
            return WERR_OK;
        }

        s[0] = '\0';
        s++;

        domain_filter = talloc_asprintf(mem_ctx, "(&(objectClass=crossRef)(ncName=%s))",
                                        ldb_dn_get_linearized(samdb_dns_domain_to_dn(sam_ctx, mem_ctx, str)));
        W_ERROR_HAVE_NO_MEMORY(domain_filter);

        /* There may not be anything after the domain component (search for the domain itself) */
        if (s[0]) {

            account = strrchr(s, '/');
            if (!account) {
                account = s;
            } else {
                account++;
            }
            account = ldb_binary_encode_string(mem_ctx, account);
            W_ERROR_HAVE_NO_MEMORY(account);
            result_filter = talloc_asprintf(mem_ctx, "(name=%s)",
                                            account);
            W_ERROR_HAVE_NO_MEMORY(result_filter);
        }
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
        char *p;
        char *domain;
        const char *account = NULL;

        domain = talloc_strdup(mem_ctx, name);
        W_ERROR_HAVE_NO_MEMORY(domain);

        p = strchr(domain, '\\');
        if (!p) {
            /* invalid input format */
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }
        p[0] = '\0';

        if (p[1]) {
            account = &p[1];
        }

        domain_filter = talloc_asprintf(mem_ctx,
                                        "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
                                        ldb_binary_encode_string(mem_ctx, domain));
        W_ERROR_HAVE_NO_MEMORY(domain_filter);
        if (account) {
            result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)",
                                            ldb_binary_encode_string(mem_ctx, account));
            W_ERROR_HAVE_NO_MEMORY(result_filter);
        }

        talloc_free(domain);
        break;
    }

    /* A LDAP DN as a string */
    case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
        domain_filter = NULL;
        name_dn = ldb_dn_new(mem_ctx, sam_ctx, name);
        if (! ldb_dn_validate(name_dn)) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }
        break;
    }

    /* A GUID as a string */
    case DRSUAPI_DS_NAME_FORMAT_GUID: {
        struct GUID guid;
        char *ldap_guid;
        NTSTATUS nt_status;
        domain_filter = NULL;

        nt_status = GUID_from_string(name, &guid);
        if (!NT_STATUS_IS_OK(nt_status)) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }

        ldap_guid = ldap_encode_ndr_GUID(mem_ctx, &guid);
        if (!ldap_guid) {
            return WERR_NOMEM;
        }
        result_filter = talloc_asprintf(mem_ctx, "(objectGUID=%s)",
                                        ldap_guid);
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
        domain_filter = NULL;

        result_filter = talloc_asprintf(mem_ctx, "(|(displayName=%s)(samAccountName=%s))",
                                        ldb_binary_encode_string(mem_ctx, name),
                                        ldb_binary_encode_string(mem_ctx, name));
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }

    /* A S-1234-5678 style string */
    case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
        struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, name);
        char *ldap_sid;

        domain_filter = NULL;
        if (!sid) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }
        ldap_sid = ldap_encode_ndr_dom_sid(mem_ctx,
                                           sid);
        if (!ldap_sid) {
            return WERR_NOMEM;
        }
        result_filter = talloc_asprintf(mem_ctx, "(objectSid=%s)",
                                        ldap_sid);
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: {
        krb5_principal principal;
        char *unparsed_name;

        ret = smb_krb5_init_context(mem_ctx,
                                    ldb_get_event_context(sam_ctx),
                                    (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"),
                                    &smb_krb5_context);

        if (ret) {
            return WERR_NOMEM;
        }

        /* Ensure we reject compleate junk first */
        ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
        if (ret) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }

        domain_filter = NULL;

        /* By getting the unparsed name here, we ensure the escaping is correct (and trust the client less) */
        ret = krb5_unparse_name(smb_krb5_context->krb5_context, principal, &unparsed_name);
        if (ret) {
            krb5_free_principal(smb_krb5_context->krb5_context, principal);
            return WERR_NOMEM;
        }

        krb5_free_principal(smb_krb5_context->krb5_context, principal);

        /* The ldb_binary_encode_string() here avoid LDAP filter injection attacks */
        result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(userPrincipalName=%s))",
                                        ldb_binary_encode_string(mem_ctx, unparsed_name));

        free(unparsed_name);
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
        krb5_principal principal;
        char *unparsed_name_short;
        char *service;

        ret = smb_krb5_init_context(mem_ctx,
                                    ldb_get_event_context(sam_ctx),
                                    (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"),
                                    &smb_krb5_context);

        if (ret) {
            return WERR_NOMEM;
        }

        ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
        if (ret == 0 && principal->name.name_string.len < 2) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            krb5_free_principal(smb_krb5_context->krb5_context, principal);
            return WERR_OK;
        }
        ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name,
                                    KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
        if (ret) {
            krb5_free_principal(smb_krb5_context->krb5_context, principal);

            return dns_domain_from_principal(mem_ctx, smb_krb5_context,
                                             name, info1);
        }

        domain_filter = NULL;

        ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal,
                                      KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
        if (ret) {
            krb5_free_principal(smb_krb5_context->krb5_context, principal);
            return WERR_NOMEM;
        }

        service = principal->name.name_string.val[0];
        if ((principal->name.name_string.len == 2) && (strcasecmp(service, "host") == 0)) {
            /* the 'cn' attribute is just the leading part of the name */
            char *computer_name;
            computer_name = talloc_strndup(mem_ctx, principal->name.name_string.val[1],
                                           strcspn(principal->name.name_string.val[1], "."));
            if (computer_name == NULL) {
                return WERR_NOMEM;
            }

            result_filter = talloc_asprintf(mem_ctx, "(|(&(servicePrincipalName=%s)(objectClass=user))(&(cn=%s)(objectClass=computer)))",
                                            ldb_binary_encode_string(mem_ctx, unparsed_name_short),
                                            ldb_binary_encode_string(mem_ctx, computer_name));
        } else {
            result_filter = talloc_asprintf(mem_ctx, "(&(servicePrincipalName=%s)(objectClass=user))",
                                            ldb_binary_encode_string(mem_ctx, unparsed_name_short));
        }
        krb5_free_principal(smb_krb5_context->krb5_context, principal);
        free(unparsed_name_short);
        W_ERROR_HAVE_NO_MEMORY(result_filter);

        break;
    }
    default: {
        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
        return WERR_OK;
    }

    }

    if (format_flags & DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY) {
        return DsCrackNameOneSyntactical(mem_ctx, format_offered, format_desired,
                                         name_dn, name, info1);
    }

    return DsCrackNameOneFilter(sam_ctx, mem_ctx,
                                smb_krb5_context,
                                format_flags, format_offered, format_desired,
                                name_dn, name,
                                domain_filter, result_filter,
                                info1);
}
Example #20
0
static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                             struct smb_krb5_context *smb_krb5_context,
                             uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
                             const char *name, struct drsuapi_DsNameInfo1 *info1)
{
    int ldb_ret;
    WERROR status;
    const char *domain_filter = NULL;
    const char *result_filter = NULL;
    krb5_error_code ret;
    krb5_principal principal;
    const char *realm;
    char *unparsed_name_short;
    const char *domain_attrs[] = { NULL };
    struct ldb_result *domain_res = NULL;

    /* Prevent recursion */
    if (!name) {
        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
        return WERR_OK;
    }

    ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name,
                                KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
    if (ret) {
        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
        return WERR_OK;
    }

    realm = krb5_principal_get_realm(smb_krb5_context->krb5_context, principal);

    ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
                         samdb_partitions_dn(sam_ctx, mem_ctx),
                         LDB_SCOPE_ONELEVEL,
                         domain_attrs,
                         "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",
                         ldb_binary_encode_string(mem_ctx, realm),
                         ldb_binary_encode_string(mem_ctx, realm));

    if (ldb_ret != LDB_SUCCESS) {
        DEBUG(2, ("DsCrackNameUPN domain ref search failed: %s", ldb_errstring(sam_ctx)));
        info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
        return WERR_OK;
    }

    switch (domain_res->count) {
    case 1:
        break;
    case 0:
        return dns_domain_from_principal(mem_ctx, smb_krb5_context,
                                         name, info1);
    default:
        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
        return WERR_OK;
    }

    ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal,
                                  KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
    krb5_free_principal(smb_krb5_context->krb5_context, principal);

    if (ret) {
        free(unparsed_name_short);
        return WERR_NOMEM;
    }

    /* This may need to be extended for more userPrincipalName variations */
    result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(samAccountName=%s))",
                                    ldb_binary_encode_string(mem_ctx, unparsed_name_short));

    domain_filter = talloc_asprintf(mem_ctx, "(distinguishedName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn));

    if (!result_filter || !domain_filter) {
        free(unparsed_name_short);
        return WERR_NOMEM;
    }
    status = DsCrackNameOneFilter(sam_ctx, mem_ctx,
                                  smb_krb5_context,
                                  format_flags, format_offered, format_desired,
                                  NULL, unparsed_name_short, domain_filter, result_filter,
                                  info1);
    free(unparsed_name_short);

    return status;
}
Example #21
0
static krb5_error_code
verify_logonname(krb5_context context,
		 const struct PAC_INFO_BUFFER *logon_name,
		 const krb5_data *data,
		 time_t authtime,
		 krb5_const_principal principal)
{
    krb5_error_code ret;
    krb5_principal p2;
    uint32_t time1, time2;
    krb5_storage *sp;
    uint16_t len;
    char *s;

    sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo,
					logon_name->buffersize);
    if (sp == NULL)
	return krb5_enomem(context);

    krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);

    CHECK(ret, krb5_ret_uint32(sp, &time1), out);
    CHECK(ret, krb5_ret_uint32(sp, &time2), out);

    {
	uint64_t t1, t2;
	t1 = unix2nttime(authtime);
	t2 = ((uint64_t)time2 << 32) | time1;
	if (t1 != t2) {
	    krb5_storage_free(sp);
	    krb5_set_error_message(context, EINVAL, "PAC timestamp mismatch");
	    return EINVAL;
	}
    }
    CHECK(ret, krb5_ret_uint16(sp, &len), out);
    if (len == 0) {
	krb5_storage_free(sp);
	krb5_set_error_message(context, EINVAL, "PAC logon name length missing");
	return EINVAL;
    }

    s = malloc(len);
    if (s == NULL) {
	krb5_storage_free(sp);
	return krb5_enomem(context);
    }
    ret = krb5_storage_read(sp, s, len);
    if (ret != len) {
	krb5_storage_free(sp);
	krb5_set_error_message(context, EINVAL, "Failed to read PAC logon name");
	return EINVAL;
    }
    krb5_storage_free(sp);
    {
	size_t ucs2len = len / 2;
	uint16_t *ucs2;
	size_t u8len;
	unsigned int flags = WIND_RW_LE;

	ucs2 = malloc(sizeof(ucs2[0]) * ucs2len);
	if (ucs2 == NULL)
	    return krb5_enomem(context);

	ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len);
	free(s);
	if (ret) {
	    free(ucs2);
	    krb5_set_error_message(context, ret, "Failed to convert string to UCS-2");
	    return ret;
	}
	ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len);
	if (ret) {
	    free(ucs2);
	    krb5_set_error_message(context, ret, "Failed to count length of UCS-2 string");
	    return ret;
	}
	u8len += 1; /* Add space for NUL */
	s = malloc(u8len);
	if (s == NULL) {
	    free(ucs2);
	    return krb5_enomem(context);
	}
	ret = wind_ucs2utf8(ucs2, ucs2len, s, &u8len);
	free(ucs2);
	if (ret) {
	    free(s);
	    krb5_set_error_message(context, ret, "Failed to convert to UTF-8");
	    return ret;
	}
    }
    ret = krb5_parse_name_flags(context, s, KRB5_PRINCIPAL_PARSE_NO_REALM, &p2);
    free(s);
    if (ret)
	return ret;

    if (krb5_principal_compare_any_realm(context, principal, p2) != TRUE) {
	ret = EINVAL;
	krb5_set_error_message(context, ret, "PAC logon name mismatch");
    }
    krb5_free_principal(context, p2);
    return ret;
out:
    return ret;
}
Example #22
0
static void
test_enterprise(krb5_context context)
{
    krb5_error_code ret;
    char *unparsed;
    krb5_principal p;

    ret = krb5_set_default_realm(context, "SAMBA.ORG");
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    ret = krb5_parse_name_flags(context, "[email protected]@WIN.SU.SE",
				KRB5_PRINCIPAL_PARSE_ENTERPRISE, &p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name_flags");

    ret = krb5_unparse_name(context, p, &unparsed);
    if (ret)
	krb5_err(context, 1, ret, "krb5_unparse_name");

    krb5_free_principal(context, p);

    if (strcmp(unparsed, "lha\\@[email protected]") != 0)
	krb5_errx(context, 1, "enterprise name failed 1");
    free(unparsed);

    /*
     *
     */

    ret = krb5_parse_name_flags(context, "lha\\@[email protected]",
				KRB5_PRINCIPAL_PARSE_ENTERPRISE, &p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name_flags");

    ret = krb5_unparse_name(context, p, &unparsed);
    if (ret)
	krb5_err(context, 1, ret, "krb5_unparse_name");

    krb5_free_principal(context, p);
    if (strcmp(unparsed, "lha\\@su.se\\@[email protected]") != 0)
	krb5_errx(context, 1, "enterprise name failed 2: %s", unparsed);
    free(unparsed);

    /*
     *
     */

    ret = krb5_parse_name_flags(context, "lha\\@[email protected]", 0, &p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name_flags");

    ret = krb5_unparse_name(context, p, &unparsed);
    if (ret)
	krb5_err(context, 1, ret, "krb5_unparse_name");

    krb5_free_principal(context, p);
    if (strcmp(unparsed, "lha\\@[email protected]") != 0)
	krb5_errx(context, 1, "enterprise name failed 3");
    free(unparsed);

    /*
     *
     */

    ret = krb5_parse_name_flags(context, "*****@*****.**",
				KRB5_PRINCIPAL_PARSE_ENTERPRISE, &p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name_flags");

    ret = krb5_unparse_name(context, p, &unparsed);
    if (ret)
	krb5_err(context, 1, ret, "krb5_unparse_name");

    krb5_free_principal(context, p);
    if (strcmp(unparsed, "lha\\@[email protected]") != 0)
	krb5_errx(context, 1, "enterprise name failed 2: %s", unparsed);
    free(unparsed);
}
Example #23
0
static void
test_princ(krb5_context context)
{
    const char *princ = "*****@*****.**";
    const char *princ_short = "lha";
    const char *noquote;
    krb5_error_code ret;
    char *princ_unparsed;
    char *princ_reformed = NULL;
    const char *realm;

    krb5_principal p, p2;

    ret = krb5_parse_name(context, princ, &p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    ret = krb5_unparse_name(context, p, &princ_unparsed);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    if (strcmp(princ, princ_unparsed)) {
	krb5_errx(context, 1, "%s != %s", princ, princ_unparsed);
    }

    free(princ_unparsed);

    ret = krb5_unparse_name_flags(context, p,
				  KRB5_PRINCIPAL_UNPARSE_NO_REALM,
				  &princ_unparsed);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    if (strcmp(princ_short, princ_unparsed))
	krb5_errx(context, 1, "%s != %s", princ_short, princ_unparsed);
    free(princ_unparsed);

    realm = krb5_principal_get_realm(context, p);

    if (asprintf(&princ_reformed, "%s@%s", princ_short, realm) < 0 || princ_reformed == NULL)
	errx(1, "malloc");

    ret = krb5_parse_name(context, princ_reformed, &p2);
    free(princ_reformed);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    if (!krb5_principal_compare(context, p, p2)) {
	krb5_errx(context, 1, "p != p2");
    }

    krb5_free_principal(context, p2);

    ret = krb5_set_default_realm(context, "SU.SE");
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    ret = krb5_unparse_name_flags(context, p,
				  KRB5_PRINCIPAL_UNPARSE_SHORT,
				  &princ_unparsed);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    if (strcmp(princ_short, princ_unparsed))
	krb5_errx(context, 1, "'%s' != '%s'", princ_short, princ_unparsed);
    free(princ_unparsed);

    ret = krb5_parse_name(context, princ_short, &p2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    if (!krb5_principal_compare(context, p, p2))
	krb5_errx(context, 1, "p != p2");
    krb5_free_principal(context, p2);

    ret = krb5_unparse_name(context, p, &princ_unparsed);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    if (strcmp(princ, princ_unparsed))
	krb5_errx(context, 1, "'%s' != '%s'", princ, princ_unparsed);
    free(princ_unparsed);

    ret = krb5_set_default_realm(context, "SAMBA.ORG");
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    ret = krb5_parse_name(context, princ_short, &p2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    if (krb5_principal_compare(context, p, p2))
	krb5_errx(context, 1, "p == p2");

    if (!krb5_principal_compare_any_realm(context, p, p2))
	krb5_errx(context, 1, "(ignoring realms) p != p2");

    ret = krb5_unparse_name(context, p2, &princ_unparsed);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    if (strcmp(princ, princ_unparsed) == 0)
	krb5_errx(context, 1, "%s == %s", princ, princ_unparsed);
    free(princ_unparsed);

    krb5_free_principal(context, p2);

    ret = krb5_parse_name(context, princ, &p2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    if (!krb5_principal_compare(context, p, p2))
	krb5_errx(context, 1, "p != p2");

    ret = krb5_unparse_name(context, p2, &princ_unparsed);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    if (strcmp(princ, princ_unparsed))
	krb5_errx(context, 1, "'%s' != '%s'", princ, princ_unparsed);
    free(princ_unparsed);

    krb5_free_principal(context, p2);

    ret = krb5_unparse_name_flags(context, p,
				  KRB5_PRINCIPAL_UNPARSE_SHORT,
				  &princ_unparsed);
    if (ret)
	krb5_err(context, 1, ret, "krb5_unparse_name_short");

    if (strcmp(princ, princ_unparsed) != 0)
	krb5_errx(context, 1, "'%s' != '%s'", princ, princ_unparsed);
    free(princ_unparsed);

    ret = krb5_unparse_name(context, p, &princ_unparsed);
    if (ret)
	krb5_err(context, 1, ret, "krb5_unparse_name_short");

    if (strcmp(princ, princ_unparsed))
	krb5_errx(context, 1, "'%s' != '%s'", princ, princ_unparsed);
    free(princ_unparsed);

    ret = krb5_parse_name_flags(context, princ,
				KRB5_PRINCIPAL_PARSE_NO_REALM,
				&p2);
    if (!ret)
	krb5_err(context, 1, ret, "Should have failed to parse %s a "
		 "short name", princ);

    ret = krb5_parse_name_flags(context, princ_short,
				KRB5_PRINCIPAL_PARSE_NO_REALM,
				&p2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    ret = krb5_unparse_name_flags(context, p2,
				  KRB5_PRINCIPAL_UNPARSE_NO_REALM,
				  &princ_unparsed);
    krb5_free_principal(context, p2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_unparse_name_norealm");

    if (strcmp(princ_short, princ_unparsed))
	krb5_errx(context, 1, "'%s' != '%s'", princ_short, princ_unparsed);
    free(princ_unparsed);

    ret = krb5_parse_name_flags(context, princ_short,
				KRB5_PRINCIPAL_PARSE_REQUIRE_REALM,
				&p2);
    if (!ret)
	krb5_err(context, 1, ret, "Should have failed to parse %s "
		 "because it lacked a realm", princ_short);

    ret = krb5_parse_name_flags(context, princ,
				KRB5_PRINCIPAL_PARSE_REQUIRE_REALM,
				&p2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    if (!krb5_principal_compare(context, p, p2))
	krb5_errx(context, 1, "p != p2");

    ret = krb5_unparse_name_flags(context, p2,
				  KRB5_PRINCIPAL_UNPARSE_NO_REALM,
				  &princ_unparsed);
    krb5_free_principal(context, p2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_unparse_name_norealm");

    if (strcmp(princ_short, princ_unparsed))
	krb5_errx(context, 1, "'%s' != '%s'", princ_short, princ_unparsed);
    free(princ_unparsed);

    krb5_free_principal(context, p);

    /* test quoting */

    princ = "test\\ [email protected]";
    noquote = "test [email protected]";

    ret = krb5_parse_name_flags(context, princ, 0, &p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    ret = krb5_unparse_name_flags(context, p, 0, &princ_unparsed);
    if (ret)
	krb5_err(context, 1, ret, "krb5_unparse_name_flags");

    if (strcmp(princ, princ_unparsed))
	krb5_errx(context, 1, "q '%s' != '%s'", princ, princ_unparsed);
    free(princ_unparsed);

    ret = krb5_unparse_name_flags(context, p, KRB5_PRINCIPAL_UNPARSE_DISPLAY,
				  &princ_unparsed);
    if (ret)
	krb5_err(context, 1, ret, "krb5_unparse_name_flags");

    if (strcmp(noquote, princ_unparsed))
	krb5_errx(context, 1, "nq '%s' != '%s'", noquote, princ_unparsed);
    free(princ_unparsed);

    krb5_free_principal(context, p);
}
Example #24
0
File: kinit.c Project: gojdic/samba
int
main (int argc, char **argv)
{
    krb5_error_code ret;
    krb5_context context;
    krb5_ccache  ccache;
    krb5_principal principal;
    int optidx = 0;
    krb5_deltat ticket_life = 0;
    int parseflags = 0;

    setprogname (argv[0]);

    setlocale (LC_ALL, "");
#if defined(HEIMDAL_LOCALEDIR)
    bindtextdomain ("heimdal_kuser", HEIMDAL_LOCALEDIR);
    textdomain("heimdal_kuser");
#endif

    ret = krb5_init_context (&context);
    if (ret == KRB5_CONFIG_BADFORMAT)
	errx (1, "krb5_init_context failed to parse configuration file");
    else if (ret)
	errx(1, "krb5_init_context failed: %d", ret);

    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
	usage(1);

    if (help_flag)
	usage (0);

    if(version_flag) {
	print_version(NULL);
	exit(0);
    }

    argc -= optidx;
    argv += optidx;

    if (canonicalize_flag)
	parseflags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE;

    if (argv[0]) {
	ret = krb5_parse_name_flags (context, argv[0], parseflags, &principal);
	if (ret)
	    krb5_err (context, 1, ret, "krb5_parse_name");
    } else {
	ret = krb5_get_default_principal (context, &principal);
	if (ret)
	    krb5_err (context, 1, ret, "krb5_get_default_principal");
    }

    if(fcache_version)
	krb5_set_fcache_version(context, fcache_version);

    if(renewable_flag == -1)
	/* this seems somewhat pointless, but whatever */
	krb5_appdefault_boolean(context, "kinit",
				krb5_principal_get_realm(context, principal),
				"renewable", FALSE, &renewable_flag);
#ifndef HEIMDAL_SMALLER
    if(get_v4_tgt == -1)
	krb5_appdefault_boolean(context, "kinit",
				krb5_principal_get_realm(context, principal),
				"krb4_get_tickets", FALSE, &get_v4_tgt);
#endif
    if(do_afslog == -1)
	krb5_appdefault_boolean(context, "kinit",
				krb5_principal_get_realm(context, principal),
				"afslog", TRUE, &do_afslog);

    if(cred_cache)
	ret = krb5_cc_resolve(context, cred_cache, &ccache);
    else {
	if(argc > 1) {
	    char s[1024];
	    ret = krb5_cc_gen_new(context, &krb5_fcc_ops, &ccache);
	    if(ret)
		krb5_err(context, 1, ret, "creating cred cache");
	    snprintf(s, sizeof(s), "%s:%s",
		     krb5_cc_get_type(context, ccache),
		     krb5_cc_get_name(context, ccache));
	    setenv("KRB5CCNAME", s, 1);
#ifndef HEIMDAL_SMALLER
	    if (get_v4_tgt) {
		int fd;
		if (asprintf(&krb4_cc_name, "%s_XXXXXX", TKT_ROOT) < 0)
		    krb5_errx(context, 1, "out of memory");
		if((fd = mkstemp(krb4_cc_name)) >= 0) {
		    close(fd);
		    setenv("KRBTKFILE", krb4_cc_name, 1);
		} else {
		    free(krb4_cc_name);
		    krb4_cc_name = NULL;
		}
	    }
#endif
	} else {
	    ret = krb5_cc_cache_match(context, principal, &ccache);
	    if (ret)
		ret = krb5_cc_default (context, &ccache);
	}
    }
    if (ret)
	krb5_err (context, 1, ret, N_("resolving credentials cache", ""));

    if(argc > 1 && k_hasafs ())
	k_setpag();

    if (lifetime) {
	int tmp = parse_time (lifetime, "s");
	if (tmp < 0)
	    errx (1, N_("unparsable time: %s", ""), lifetime);

	ticket_life = tmp;
    }

    if(addrs_flag == 0 && extra_addresses.num_strings > 0)
	krb5_errx(context, 1,
		  N_("specifying both extra addresses and "
		     "no addresses makes no sense", ""));
    {
	int i;
	krb5_addresses addresses;
	memset(&addresses, 0, sizeof(addresses));
	for(i = 0; i < extra_addresses.num_strings; i++) {
	    ret = krb5_parse_address(context, extra_addresses.strings[i],
				     &addresses);
	    if (ret == 0) {
		krb5_add_extra_addresses(context, &addresses);
		krb5_free_addresses(context, &addresses);
	    }
	}
	free_getarg_strings(&extra_addresses);
    }

    if(renew_flag || validate_flag) {
	ret = renew_validate(context, renew_flag, validate_flag,
			     ccache, server_str, ticket_life);
	exit(ret != 0);
    }

#ifndef HEIMDAL_SMALLER
    if(!convert_524)
#endif
	get_new_tickets(context, principal, ccache, ticket_life, 1);

#ifndef HEIMDAL_SMALLER
    if(get_v4_tgt || convert_524)
	do_524init(context, ccache, NULL, server_str);
#endif
    if(do_afslog && k_hasafs())
	krb5_afslog(context, ccache, NULL, NULL);
    if(argc > 1) {
	struct renew_ctx ctx;
	time_t timeout;

	timeout = ticket_lifetime(context, ccache, principal, server_str) / 2;

	ctx.context = context;
	ctx.ccache = ccache;
	ctx.principal = principal;
	ctx.ticket_life = ticket_life;

	ret = simple_execvp_timed(argv[1], argv+1,
				  renew_func, &ctx, timeout);
#define EX_NOEXEC	126
#define EX_NOTFOUND	127
	if(ret == EX_NOEXEC)
	    krb5_warnx(context, N_("permission denied: %s", ""), argv[1]);
	else if(ret == EX_NOTFOUND)
	    krb5_warnx(context, N_("command not found: %s", ""), argv[1]);
	
	krb5_cc_destroy(context, ccache);
#ifndef HEIMDAL_SMALLER
	_krb5_krb_dest_tkt(context, krb4_cc_name);
#endif
	if(k_hasafs())
	    k_unlog();
    } else {
	krb5_cc_close (context, ccache);
	ret = 0;
    }
    krb5_free_principal(context, principal);
    krb5_free_context (context);
    return ret;
}
static WERROR DsCrackNameSPNAlias(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
				  struct smb_krb5_context *smb_krb5_context,
				  uint32_t format_flags, enum drsuapi_DsNameFormat format_offered,
				  enum drsuapi_DsNameFormat format_desired,
				  const char *name, struct drsuapi_DsNameInfo1 *info1)
{
	WERROR wret;
	krb5_error_code ret;
	krb5_principal principal;
	const krb5_data *component;
	const char *service, *dns_name;
	char *new_service;
	char *new_princ;
	enum drsuapi_DsNameStatus namestatus;

	/* parse principal */
	ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, 
				    name, KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
	if (ret) {
		DEBUG(2, ("Could not parse principal: %s: %s\n",
			  name, smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
							   ret, mem_ctx)));
		return WERR_NOMEM;
	}

	/* grab cifs/, http/ etc */

	/* This is checked for in callers, but be safe */
	if (krb5_princ_size(smb_krb5_context->krb5_context, principal) < 2) {
		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
		krb5_free_principal(smb_krb5_context->krb5_context, principal);
		return WERR_OK;
	}
	component = krb5_princ_component(smb_krb5_context->krb5_context,
					 principal, 0);
	service = (const char *)component->data;
	component = krb5_princ_component(smb_krb5_context->krb5_context,
					 principal, 1);
	dns_name = (const char *)component->data;

	/* MAP it */
	namestatus = LDB_lookup_spn_alias(smb_krb5_context->krb5_context, 
					  sam_ctx, mem_ctx, 
					  service, &new_service);

	if (namestatus == DRSUAPI_DS_NAME_STATUS_NOT_FOUND) {
		wret = WERR_OK;
		info1->status		= DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
		info1->dns_domain_name	= talloc_strdup(mem_ctx, dns_name);
		if (!info1->dns_domain_name) {
			wret = WERR_NOMEM;
		}
		krb5_free_principal(smb_krb5_context->krb5_context, principal);
		return wret;
	} else if (namestatus != DRSUAPI_DS_NAME_STATUS_OK) {
		info1->status = namestatus;
		krb5_free_principal(smb_krb5_context->krb5_context, principal);
		return WERR_OK;
	}

	/* reform principal */
	new_princ = talloc_asprintf(mem_ctx, "%s/%s", new_service, dns_name);
	if (!new_princ) {
		krb5_free_principal(smb_krb5_context->krb5_context, principal);
		return WERR_NOMEM;
	}

	wret = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, format_offered, format_desired,
				  new_princ, info1);
	talloc_free(new_princ);
	if (W_ERROR_IS_OK(wret) && (info1->status == DRSUAPI_DS_NAME_STATUS_NOT_FOUND)) {
		info1->status		= DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
		info1->dns_domain_name	= talloc_strdup(mem_ctx, dns_name);
		if (!info1->dns_domain_name) {
			wret = WERR_NOMEM;
		}
	}
	krb5_free_principal(smb_krb5_context->krb5_context, principal);
	return wret;
}