Пример #1
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_kt_get_full_name(krb5_context context,
		      krb5_keytab keytab,
		      char **str)
{
    char type[KRB5_KT_PREFIX_MAX_LEN];
    char name[MAXPATHLEN];
    krb5_error_code ret;

    *str = NULL;

    ret = krb5_kt_get_type(context, keytab, type, sizeof(type));
    if (ret)
	return ret;

    ret = krb5_kt_get_name(context, keytab, name, sizeof(name));
    if (ret)
	return ret;

    if (asprintf(str, "%s:%s", type, name) == -1) {
	*str = NULL;
	return krb5_enomem(context);
    }

    return 0;
}
Пример #2
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_kt_get_full_name(krb5_context context,
		      krb5_keytab keytab,
		      char **str)
{
    char type[KRB5_KT_PREFIX_MAX_LEN];
    char name[MAXPATHLEN];
    krb5_error_code ret;
	
    *str = NULL;

    ret = krb5_kt_get_type(context, keytab, type, sizeof(type));
    if (ret)
	return ret;

    ret = krb5_kt_get_name(context, keytab, name, sizeof(name));
    if (ret)
	return ret;

    if (asprintf(str, "%s:%s", type, name) == -1) {
	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
	*str = NULL;
	return ENOMEM;
    }

    return 0;
}
std::string Krb5Keytab::getName() const {
  char name[kKeytabNameMaxLength];
  krb5_error_code code = krb5_kt_get_name(context_,
                                          keytab_,
                                          name,
                                          sizeof(name));
  raiseIf(context_, code, "getting keytab name");
  return name;
}
Пример #4
0
static int
process_keytab(krb5_context my_context, char **keytab_str,
               krb5_keytab *keytab)
{
    int code;
    char *name = *keytab_str;

    if (name == NULL) {
        name = malloc(BUFSIZ);
        if (!name) {
            com_err(whoami, ENOMEM, "while creating keytab name");
            return 1;
        }
        code = krb5_kt_default(my_context, keytab);
        if (code != 0) {
            com_err(whoami, code, "while opening default keytab");
            free(name);
            return 1;
        }
        code = krb5_kt_get_name(my_context, *keytab, name, BUFSIZ);
        if (code != 0) {
            com_err(whoami, code, "while getting keytab name");
            free(name);
            return 1;
        }
    } else {
        if (strchr(name, ':') != NULL)
            name = strdup(name);
        else if (asprintf(&name, "WRFILE:%s", name) < 0)
            name = NULL;
        if (name == NULL) {
            com_err(whoami, ENOMEM, "while creating keytab name");
            return 1;
        }

        code = krb5_kt_resolve(my_context, name, keytab);
        if (code != 0) {
            com_err(whoami, code, "while resolving keytab %s", name);
            free(name);
            return 1;
        }
    }

    *keytab_str = name;
    return 0;
}
Пример #5
0
static krb5_error_code
get_keytab(krb5_keytab *keytab)
{
    char kt_name[256];
    krb5_error_code kret;

    HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);

    if (gssapi_krb5_keytab != NULL) {
	kret = krb5_kt_get_name(gssapi_krb5_context,
				gssapi_krb5_keytab,
				kt_name, sizeof(kt_name));
	if (kret == 0)
	    kret = krb5_kt_resolve(gssapi_krb5_context, kt_name, keytab);
    } else
	kret = krb5_kt_default(gssapi_krb5_context, keytab);

    HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);

    return (kret);
}
Пример #6
0
int print_keytab (const char *in_name)
{
    krb5_error_code err = 0;
    krb5_keytab kt;
    krb5_keytab_entry entry;
    krb5_kt_cursor cursor;
    char keytab_name[BUFSIZ]; /* hopefully large enough for any type */

    if (!err) {
        if (!in_name) {
            err = krb5_kt_default (kcontext, &kt);
            printiferr (err, "while resolving default keytab");
        } else {
            err = krb5_kt_resolve (kcontext, in_name, &kt);
            printiferr (err, "while resolving keytab %s", in_name);
        }
    }

    if (!err) {
        err = krb5_kt_get_name (kcontext, kt, keytab_name, sizeof (keytab_name));
        printiferr (err, "while getting keytab name");
    }

    if (!err) {
        printmsg ("Keytab name: %s\n", keytab_name);
    }

    if (!err) {
        err = krb5_kt_start_seq_get (kcontext, kt, &cursor);
        printiferr (err, "while starting scan of keytab %s", keytab_name);
    }

    if (!err) {
        if (show_entry_timestamps) {
            printmsg ("KVNO Timestamp");
            printfiller (' ', get_timestamp_width () - sizeof ("Timestamp") + 2);
            printmsg ("Principal\n");
            printmsg ("---- ");
            printfiller ('-', get_timestamp_width ());
            printmsg (" ");
            printfiller ('-', 78 - get_timestamp_width () - sizeof ("KVNO"));
            printmsg ("\n");
        } else {
            printmsg("KVNO Principal\n");
            printmsg("---- --------------------------------------------------------------------------\n");
        }
    }

    while (!err) {
        char *principal_name = NULL;

        err = krb5_kt_next_entry (kcontext, kt, &entry, &cursor);
	if (err == KRB5_KT_END) {
	    err = 0;
	    break;
	}
 
        if (!err) {
            err = krb5_unparse_name (kcontext, entry.principal, &principal_name);
            printiferr (err, "while unparsing principal name");
        }
        
        if (!err) {
            printmsg ("%4d ", entry.vno);
            if (show_entry_timestamps) {
                printtime (entry.timestamp);
                printmsg (" ");
            }
            printmsg ("%s", principal_name);
            if (show_enctypes) {
                printmsg (" (%s) ", enctype_to_string (entry.key.enctype));
            }
            if (show_entry_DES_keys) {
                unsigned int i;
                
                printmsg (" (0x");
                for (i = 0; i < entry.key.length; i++) {
                    printmsg ("%02x", entry.key.contents[i]);
                }
                printmsg (")");
            }
            printmsg ("\n");
        }
	printiferr (err, "while scanning keytab %s", keytab_name);

        if (principal_name) { krb5_free_unparsed_name (kcontext, principal_name); }
    }

    if (!err) {
        err = krb5_kt_end_seq_get (kcontext, kt, &cursor);
        printiferr (err, "while ending scan of keytab %s", keytab_name);
    }

    return err ? 1 : 0;
}
Пример #7
0
/*
 * Search the given keytab file looking for an entry with the given
 * service name and realm, ignoring hostname (instance).
 *
 * Returns:
 *	0 => No error
 *	non-zero => An error occurred
 *
 * If a keytab entry is found, "found" is set to one, and the keytab
 * entry is returned in "kte".  Otherwise, "found" is zero, and the
 * value of "kte" is unpredictable.
 */
static int gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
				   const char *realm, const char *service,
				   int *found, krb5_keytab_entry *kte)
{
	krb5_kt_cursor cursor;
	krb5_error_code code;
	struct gssd_k5_kt_princ *ple;
	int retval = -1, status;
	char kt_name[BUFSIZ];
	char *pname;
	char *k5err = NULL;

	if (found == NULL) {
		retval = EINVAL;
		goto out;
	}
	*found = 0;

	/*
	 * Look through each entry in the keytab file and determine
	 * if we might want to use it as machine credentials.  If so,
	 * save info in the global principal list (gssd_k5_kt_princ_list).
	 */
	code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ);
	if (code != 0) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0, "ERROR: %s attempting to get keytab name\n",
			 k5err);
		gsh_free(k5err);
		retval = code;
		goto out;
	}
	code = krb5_kt_start_seq_get(context, kt, &cursor);
	if (code != 0) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0,
			 "ERROR: %s while beginning keytab scan "
			 "for keytab '%s'\n", k5err, kt_name);
		gsh_free(k5err);
		retval = code;
		goto out;
	}

	while ((code = krb5_kt_next_entry(context, kt, kte, &cursor)) == 0) {
		code = krb5_unparse_name(context, kte->principal, &pname);
		if (code != 0) {
			k5err = gssd_k5_err_msg(context, code);
			printerr(0,
				 "WARNING: Skipping keytab entry because "
				 "we failed to unparse principal name: %s\n",
				 k5err);
			k5_free_kt_entry(context, kte);
			gsh_free(k5err);
			continue;
		}
		printerr(4, "Processing keytab entry for principal '%s'\n",
			 pname);
		/* Use the first matching keytab entry found */
#ifdef HAVE_KRB5
		status =
		    realm_and_service_match(kte->principal, realm, service);
#else
		status =
		    realm_and_service_match(context, kte->principal, realm,
					    service);
#endif
		if (status) {
			printerr(4, "We WILL use this entry (%s)\n", pname);
			ple = get_ple_by_princ(context, kte->principal);
			/*
			 * Return, don't free, keytab entry if
			 * we were successful!
			 */
			if (ple == NULL) {
				retval = ENOMEM;
				k5_free_kt_entry(context, kte);
			} else {
				retval = 0;
				*found = 1;
			}
			k5_free_unparsed_name(context, pname);
			break;
		} else {
			printerr(4, "We will NOT use this entry (%s)\n", pname);
		}
		k5_free_unparsed_name(context, pname);
		k5_free_kt_entry(context, kte);
	}

	code = krb5_kt_end_seq_get(context, kt, &cursor);
	if (code != 0) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0,
			 "WARNING: %s while ending keytab scan for "
			 "keytab '%s'\n", k5err, kt_name);
		gsh_free(k5err);
	}

	retval = 0;
 out:
	return retval;
}
Пример #8
0
/*
 * Obtain credentials via a key in the keytab given
 * a keytab handle and a gssd_k5_kt_princ structure.
 * Checks to see if current credentials are expired,
 * if not, uses the keytab to obtain new credentials.
 *
 * Returns:
 *	0 => success (or credentials have not expired)
 *	nonzero => error
 */
static int gssd_get_single_krb5_cred(krb5_context context, krb5_keytab kt,
				     struct gssd_k5_kt_princ *ple, int nocache)
{
#if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS
	krb5_get_init_creds_opt *init_opts = NULL;
#else
	krb5_get_init_creds_opt options;
#endif
	krb5_get_init_creds_opt *opts;
	krb5_creds my_creds;
	krb5_ccache ccache = NULL;
	char kt_name[BUFSIZ];
	char cc_name[BUFSIZ];
	int code;
	time_t now = time(0);
	char *cache_type;
	char *pname = NULL;
	char *k5err = NULL;

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

	if (ple->ccname && ple->endtime > now && !nocache) {
		printerr(2, "INFO: Credentials in CC '%s' are good until %d\n",
			 ple->ccname, ple->endtime);
		code = 0;
		goto out;
	}

	code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ);
	if (code != 0) {
		printerr(0,
			 "ERROR: Unable to get keytab name in "
			 "gssd_get_single_krb5_cred\n");
		goto out;
	}

	if ((krb5_unparse_name(context, ple->princ, &pname)))
		pname = NULL;

#if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS
	code = krb5_get_init_creds_opt_alloc(context, &init_opts);
	if (code) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0, "ERROR: %s allocating gic options\n", k5err);
		goto out;
	}
	if (krb5_get_init_creds_opt_set_addressless(context, init_opts, 1))
		printerr(1,
			 "WARNING: Unable to set option for addressless "
			 "tickets.  May have problems behind a NAT.\n");
#ifdef TEST_SHORT_LIFETIME
	/* set a short lifetime (for debugging only!) */
	printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n");
	krb5_get_init_creds_opt_set_tkt_life(init_opts, 5 * 60);
#endif
	opts = init_opts;

#else /* HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS */

	krb5_get_init_creds_opt_init(&options);
	krb5_get_init_creds_opt_set_address_list(&options, NULL);
#ifdef TEST_SHORT_LIFETIME
	/* set a short lifetime (for debugging only!) */
	printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n");
	krb5_get_init_creds_opt_set_tkt_life(&options, 5 * 60);
#endif
	opts = &options;
#endif

	code = krb5_get_init_creds_keytab(context, &my_creds,
					  ple->princ, kt, 0,
					  NULL, opts);
	if (code != 0) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(1,
			 "WARNING: %s while getting initial ticket for "
			 "principal '%s' using keytab '%s'\n", k5err,
			 pname ? pname : "<unparsable>", kt_name);
		goto out;
	}

	/*
	 * Initialize cache file which we're going to be using
	 */

	if (use_memcache)
		cache_type = "MEMORY";
	else
		cache_type = "FILE";
	snprintf(cc_name, sizeof(cc_name), "%s:%s/%s%s_%s", cache_type,
		 ccachesearch[0], GSSD_DEFAULT_CRED_PREFIX,
		 GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm);
	ple->endtime = my_creds.times.endtime;
	if (ple->ccname != NULL)
		gsh_free(ple->ccname);
	ple->ccname = gsh_strdup(cc_name);
	if (ple->ccname == NULL) {
		printerr(0,
			 "ERROR: no storage to duplicate credentials "
			 "cache name '%s'\n", cc_name);
		code = ENOMEM;
		goto out;
	}
	code = krb5_cc_resolve(context, cc_name, &ccache);
	if (code != 0) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0, "ERROR: %s while opening credential cache '%s'\n",
			 k5err, cc_name);
		goto out;
	}
	code = krb5_cc_initialize(context, ccache, ple->princ);
	if (code != 0) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0,
			 "ERROR: %s while initializing credential "
			 "cache '%s'\n", k5err, cc_name);
	}
	code = krb5_cc_store_cred(context, ccache, &my_creds);
	if (code != 0) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0, "ERROR: %s while storing credentials in '%s'\n",
			 k5err, cc_name);
		goto out;
	}
	/* if we get this far, let gss mech know */
	gssd_set_krb5_ccache_name(cc_name);
	code = 0;
	printerr(2,
		 "Successfully obtained machine credentials for "
		 "principal '%s' stored in ccache '%s'\n", pname, cc_name);
 out:
#if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS
	if (init_opts)
		krb5_get_init_creds_opt_free(context, init_opts);
#endif
	if (pname)
		k5_free_unparsed_name(context, pname);
	if (ccache)
		krb5_cc_close(context, ccache);
	krb5_free_cred_contents(context, &my_creds);
	gsh_free(k5err);
	return code;
}
Пример #9
0
static void
kt_test(krb5_context context, const char *name)
{
    krb5_error_code kret;
    krb5_keytab kt;
    const char *type;
    char buf[BUFSIZ];
    char *p;
    krb5_keytab_entry kent, kent2;
    krb5_principal princ;
    krb5_kt_cursor cursor, cursor2;
    int cnt;

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

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

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

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


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

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


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


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


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

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

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

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

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

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


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

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

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

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

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


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

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


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

    krb5_free_principal(context, princ);

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

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

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

    krb5_free_keytab_entry_contents(context, &kent);

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

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

        exit(1);

    }

    krb5_free_keytab_entry_contents(context, &kent);

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

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

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

        exit(1);

    }

    krb5_free_keytab_entry_contents(context, &kent);



    /* Try to lookup specified enctype and kvno */

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

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

        exit(1);

    }

    krb5_free_keytab_entry_contents(context, &kent);


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

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

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

    krb5_free_principal(context, princ);


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

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

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

        exit(1);

    }

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

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

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

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

        exit(1);

    }
    krb5_free_keytab_entry_contents(context, &kent);

    krb5_free_principal(context, princ);

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

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

}
Пример #10
0
static void
do_keytab(const char *name)
{
    krb5_error_code ret;
    krb5_keytab kt;
    krb5_keytab_entry entry;
    krb5_kt_cursor cursor;
    unsigned int i;
    char buf[BUFSIZ]; /* Hopefully large enough for any type */
    char *pname;

    if (name == NULL && use_client_keytab) {
        ret = krb5_kt_client_default(context, &kt);
        if (ret) {
            com_err(progname, ret, _("while getting default client keytab"));
            exit(1);
        }
    } else if (name == NULL) {
        ret = krb5_kt_default(context, &kt);
        if (ret) {
            com_err(progname, ret, _("while getting default keytab"));
            exit(1);
        }
    } else {
        ret = krb5_kt_resolve(context, name, &kt);
        if (ret) {
            com_err(progname, ret, _("while resolving keytab %s"), name);
            exit(1);
        }
    }

    ret = krb5_kt_get_name(context, kt, buf, BUFSIZ);
    if (ret) {
        com_err(progname, ret, _("while getting keytab name"));
        exit(1);
    }

    printf("Keytab name: %s\n", buf);

    ret = krb5_kt_start_seq_get(context, kt, &cursor);
    if (ret) {
        com_err(progname, ret, _("while starting keytab scan"));
        exit(1);
    }

    /* XXX Translating would disturb table alignment; skip for now. */
    if (show_time) {
        printf("KVNO Timestamp");
        fillit(stdout, timestamp_width - sizeof("Timestamp") + 2, (int) ' ');
        printf("Principal\n");
        printf("---- ");
        fillit(stdout, timestamp_width, (int) '-');
        printf(" ");
        fillit(stdout, 78 - timestamp_width - sizeof("KVNO"), (int) '-');
        printf("\n");
    } else {
        printf("KVNO Principal\n");
        printf("---- ------------------------------------------------"
               "--------------------------\n");
    }

    while ((ret = krb5_kt_next_entry(context, kt, &entry, &cursor)) == 0) {
        ret = krb5_unparse_name(context, entry.principal, &pname);
        if (ret) {
            com_err(progname, ret, _("while unparsing principal name"));
            exit(1);
        }
        printf("%4d ", entry.vno);
        if (show_time) {
            printtime(entry.timestamp);
            printf(" ");
        }
        printf("%s", pname);
        if (show_etype)
            printf(" (%s) " , etype_string(entry.key.enctype));
        if (show_keys) {
            printf(" (0x");
            for (i = 0; i < entry.key.length; i++)
                printf("%02x", entry.key.contents[i]);
            printf(")");
        }
        printf("\n");
        krb5_free_unparsed_name(context, pname);
        krb5_free_keytab_entry_contents(context, &entry);
    }
    if (ret && ret != KRB5_KT_END) {
        com_err(progname, ret, _("while scanning keytab"));
        exit(1);
    }
    ret = krb5_kt_end_seq_get(context, kt, &cursor);
    if (ret) {
        com_err(progname, ret, _("while ending keytab scan"));
        exit(1);
    }
    exit(0);
}
Пример #11
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_kt_get_entry(krb5_context context,
		  krb5_keytab id,
		  krb5_const_principal principal,
		  krb5_kvno kvno,
		  krb5_enctype enctype,
		  krb5_keytab_entry *entry)
{
    krb5_keytab_entry tmp;
    krb5_error_code ret;
    krb5_kt_cursor cursor;

    if(id->get)
	return (*id->get)(context, id, principal, kvno, enctype, entry);

    ret = krb5_kt_start_seq_get (context, id, &cursor);
    if (ret) {
	krb5_clear_error_string(context);
	return KRB5_KT_NOTFOUND; /* XXX i.e. file not found */
    }

    entry->vno = 0;
    while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) {
	if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) {
	    /* the file keytab might only store the lower 8 bits of
	       the kvno, so only compare those bits */
	    if (kvno == tmp.vno
		|| (tmp.vno < 256 && kvno % 256 == tmp.vno)) {
		krb5_kt_copy_entry_contents (context, &tmp, entry);
		krb5_kt_free_entry (context, &tmp);
		krb5_kt_end_seq_get(context, id, &cursor);
		return 0;
	    } else if (kvno == 0 && tmp.vno > entry->vno) {
		if (entry->vno)
		    krb5_kt_free_entry (context, entry);
		krb5_kt_copy_entry_contents (context, &tmp, entry);
	    }
	}
	krb5_kt_free_entry(context, &tmp);
    }
    krb5_kt_end_seq_get (context, id, &cursor);
    if (entry->vno) {
	return 0;
    } else {
	char princ[256], kt_name[256], kvno_str[25];
	char *enctype_str = NULL;

	krb5_unparse_name_fixed (context, principal, princ, sizeof(princ));
	krb5_kt_get_name (context, id, kt_name, sizeof(kt_name));
	krb5_enctype_to_string(context, enctype, &enctype_str);

	if (kvno)
	    snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno);
	else
	    kvno_str[0] = '\0';

	krb5_set_error_string (context,
 			       "failed to find %s%s in keytab %s (%s)",
			       princ,
			       kvno_str,
			       kt_name,
			       enctype_str ? enctype_str : "unknown enctype");
	free(enctype_str);
	return KRB5_KT_NOTFOUND;
    }
}
Пример #12
0
static krb5_error_code
process_chpw_request(krb5_context context, void *server_handle,
			char *realm, int s, krb5_keytab keytab,
			struct sockaddr_in *sin, krb5_data *req,
			krb5_data *rep)
{
	krb5_error_code ret;
	char *ptr;
	int plen, vno;
	krb5_address local_kaddr, remote_kaddr;
	int allocated_mem = 0;
	krb5_data ap_req, ap_rep;
	krb5_auth_context auth_context;
	krb5_principal changepw;
	krb5_ticket *ticket;
	krb5_data cipher, clear;
	struct sockaddr local_addr, remote_addr;
	int addrlen;
	krb5_replay_data replay;
	krb5_error krberror;
	int numresult;
	char strresult[1024];

	ret = 0;
	rep->length = 0;

	auth_context = NULL;
	changepw = NULL;
	ap_rep.length = 0;
	ap_rep.data = NULL;
	ticket = NULL;
	clear.length = 0;
	clear.data = NULL;
	cipher.length = 0;
	cipher.data = NULL;

	if (req->length < 4) {
		/*
		 * either this, or the server is printing bad messages,
		 * or the caller passed in garbage
		 */
		ret = KRB5KRB_AP_ERR_MODIFIED;
		numresult = KRB5_KPASSWD_MALFORMED;
		(void) strlcpy(strresult, "Request was truncated",
				sizeof (strresult));
		goto chpwfail;
	}

	ptr = req->data;

	/*
	 * Verify length
	 */
	plen = (*ptr++ & 0xff);
	plen = (plen<<8) | (*ptr++ & 0xff);

	if (plen != req->length)
		return (KRB5KRB_AP_ERR_MODIFIED);

	/*
	 * Verify version number
	 */
	vno = (*ptr++ & 0xff);
	vno = (vno<<8) | (*ptr++ & 0xff);

	if (vno != 1) {
		ret = KRB5KDC_ERR_BAD_PVNO;
		numresult = KRB5_KPASSWD_MALFORMED;
		(void) snprintf(strresult, sizeof (strresult),
		    "Request contained unknown protocol version number %d",
		    vno);
		goto chpwfail;
	}

	/*
	 * Read, check ap-req length
	 */
	ap_req.length = (*ptr++ & 0xff);
	ap_req.length = (ap_req.length<<8) | (*ptr++ & 0xff);

	if (ptr + ap_req.length >= req->data + req->length) {
		ret = KRB5KRB_AP_ERR_MODIFIED;
		numresult = KRB5_KPASSWD_MALFORMED;
		(void) strlcpy(strresult, "Request was truncated in AP-REQ",
					sizeof (strresult));
		goto chpwfail;
	}

	/*
	 * Verify ap_req
	 */
	ap_req.data = ptr;
	ptr += ap_req.length;

	if (ret = krb5_auth_con_init(context, &auth_context)) {
		krb5_klog_syslog(LOG_ERR,
				gettext("Change password request failed. "
					"Failed initializing auth context: %s"),
				error_message(ret));
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult, "Failed initializing auth context",
					sizeof (strresult));
		goto chpwfail;
	}

	if (ret = krb5_auth_con_setflags(context, auth_context,
					KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
		krb5_klog_syslog(LOG_ERR,
				gettext("Change password request failed. "
						"Failed setting auth "
					    "context flags: %s"),
				error_message(ret));
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult, "Failed initializing auth context",
					sizeof (strresult));
		goto chpwfail;
	}

	if (ret = krb5_build_principal(context, &changepw, strlen(realm), realm,
				    "kadmin", "changepw", NULL)) {
		krb5_klog_syslog(LOG_ERR,
			gettext("Change password request failed "
					"Failed to build kadmin/changepw "
					"principal: %s"),
			error_message(ret));
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult,
				"Failed building kadmin/changepw principal",
				sizeof (strresult));
		goto chpwfail;
	}

	ret = krb5_rd_req(context, &auth_context, &ap_req, changepw, keytab,
			NULL, &ticket);

	if (ret) {
		char kt_name[MAX_KEYTAB_NAME_LEN];
		if (krb5_kt_get_name(context, keytab,
				kt_name, sizeof (kt_name)))
			strncpy(kt_name, "default keytab", sizeof (kt_name));

		switch (ret) {
		case KRB5_KT_NOTFOUND:
		krb5_klog_syslog(LOG_ERR,
			gettext("Change password request failed because "
					"keytab entry \"kadmin/changepw\" "
					"is missing from \"%s\""),
			kt_name);
		break;
		case ENOENT:
		krb5_klog_syslog(LOG_ERR,
			gettext("Change password request failed because "
					"keytab file \"%s\" does not exist"),
			kt_name);
		break;
		default:
		krb5_klog_syslog(LOG_ERR,
			gettext("Change password request failed. "
				"Failed to parse Kerberos AP_REQ message: %s"),
			error_message(ret));
		}

		numresult = KRB5_KPASSWD_AUTHERROR;
		(void) strlcpy(strresult, "Failed reading application request",
					sizeof (strresult));
		goto chpwfail;
	}

	/*
	 * Set up address info
	 */
	addrlen = sizeof (local_addr);

	if (getsockname(s, &local_addr, &addrlen) < 0) {
		ret = errno;
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult,
				"Failed getting server internet address",
				sizeof (strresult));
		goto chpwfail;
	}

	/*
	 * Some brain-dead OS's don't return useful information from
	 * the getsockname call.  Namely, windows and solaris.
	 */
	if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0) {
		local_kaddr.addrtype = ADDRTYPE_INET;
		local_kaddr.length = sizeof (((struct sockaddr_in *)
						&local_addr)->sin_addr);
		/* CSTYLED */
		local_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *)&local_addr)->sin_addr);
	} else {
		krb5_address **addrs;

		krb5_os_localaddr(context, &addrs);

		local_kaddr.magic = addrs[0]->magic;
		local_kaddr.addrtype = addrs[0]->addrtype;
		local_kaddr.length = addrs[0]->length;
		if ((local_kaddr.contents = malloc(addrs[0]->length)) == 0) {
			ret = errno;
			numresult = KRB5_KPASSWD_HARDERROR;
			(void) strlcpy(strresult,
				"Malloc failed for local_kaddr",
				sizeof (strresult));
			goto chpwfail;
		}

		(void) memcpy(local_kaddr.contents, addrs[0]->contents,
				addrs[0]->length);
		allocated_mem++;

		krb5_free_addresses(context, addrs);
	}

	addrlen = sizeof (remote_addr);

	if (getpeername(s, &remote_addr, &addrlen) < 0) {
		ret = errno;
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult,
				"Failed getting client internet address",
				sizeof (strresult));
		goto chpwfail;
	}

	remote_kaddr.addrtype = ADDRTYPE_INET;
	remote_kaddr.length = sizeof (((struct sockaddr_in *)
					&remote_addr)->sin_addr);
	/* CSTYLED */
	remote_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *)&remote_addr)->sin_addr);
	remote_kaddr.addrtype = ADDRTYPE_INET;
	remote_kaddr.length = sizeof (sin->sin_addr);
	remote_kaddr.contents = (krb5_octet *) &sin->sin_addr;

	/*
	 * mk_priv requires that the local address be set.
	 * getsockname is used for this.  rd_priv requires that the
	 * remote address be set.  recvfrom is used for this.  If
	 * rd_priv is given a local address, and the message has the
	 * recipient addr in it, this will be checked.  However, there
	 * is simply no way to know ahead of time what address the
	 * message will be delivered *to*.  Therefore, it is important
	 * that either no recipient address is in the messages when
	 * mk_priv is called, or that no local address is passed to
	 * rd_priv.  Both is a better idea, and I have done that.  In
	 * summary, when mk_priv is called, *only* a local address is
	 * specified.  when rd_priv is called, *only* a remote address
	 * is specified.  Are we having fun yet?
	 */
	if (ret = krb5_auth_con_setaddrs(context, auth_context, NULL,
					&remote_kaddr)) {
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult,
				"Failed storing client internet address",
				sizeof (strresult));
		goto chpwfail;
	}

	/*
	 * Verify that this is an AS_REQ ticket
	 */
	if (!(ticket->enc_part2->flags & TKT_FLG_INITIAL)) {
		numresult = KRB5_KPASSWD_AUTHERROR;
		(void) strlcpy(strresult,
				"Ticket must be derived from a password",
				sizeof (strresult));
		goto chpwfail;
	}

	/*
	 * Construct the ap-rep
	 */
	if (ret = krb5_mk_rep(context, auth_context, &ap_rep)) {
		numresult = KRB5_KPASSWD_AUTHERROR;
		(void) strlcpy(strresult,
				"Failed replying to application request",
				sizeof (strresult));
		goto chpwfail;
	}

	/*
	 * Decrypt the new password
	 */
	cipher.length = (req->data + req->length) - ptr;
	cipher.data = ptr;

	if (ret = krb5_rd_priv(context, auth_context, &cipher,
				&clear, &replay)) {
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult, "Failed decrypting request",
					sizeof (strresult));
		goto chpwfail;
	}

	/*
	 * Change the password
	 */
	if ((ptr = (char *)malloc(clear.length + 1)) == NULL) {
		ret = errno;
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult, "Malloc failed for ptr",
			sizeof (strresult));
		goto chpwfail;
	}
	(void) memcpy(ptr, clear.data, clear.length);
	ptr[clear.length] = '\0';

	ret = (kadm5_ret_t)kadm5_chpass_principal_util(server_handle,
						ticket->enc_part2->client,
						ptr, NULL, strresult,
						sizeof (strresult));
	/*
	 * Zap the password
	 */
	(void) memset(clear.data, 0, clear.length);
	(void) memset(ptr, 0, clear.length);
	if (clear.data != NULL) {
		krb5_xfree(clear.data);
		clear.data = NULL;
	}
	free(ptr);
	clear.length = 0;

	if (ret) {
		if ((ret != KADM5_PASS_Q_TOOSHORT) &&
		    (ret != KADM5_PASS_REUSE) &&
		    (ret != KADM5_PASS_Q_CLASS) &&
		    (ret != KADM5_PASS_Q_DICT) &&
		    (ret != KADM5_PASS_TOOSOON))
			numresult = KRB5_KPASSWD_HARDERROR;
		else
			numresult = KRB5_KPASSWD_SOFTERROR;
		/*
		 * strresult set by kadb5_chpass_principal_util()
		 */
		goto chpwfail;
	}

	/*
	 * Success!
	 */
	numresult = KRB5_KPASSWD_SUCCESS;
	(void) strlcpy(strresult, "", sizeof (strresult));

chpwfail:

	clear.length = 2 + strlen(strresult);
	if (clear.data != NULL) {
		krb5_xfree(clear.data);
		clear.data = NULL;
	}
	if ((clear.data = (char *)malloc(clear.length)) == NULL) {
		ret = errno;
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult, "Malloc failed for clear.data",
			sizeof (strresult));
	}

	cipher.length = 0;

	if (ap_rep.length) {
		if (ret = krb5_auth_con_setaddrs(context, auth_context,
					&local_kaddr, NULL)) {
		    numresult = KRB5_KPASSWD_HARDERROR;
		    (void) strlcpy(strresult,
			"Failed storing client and server internet addresses",
			sizeof (strresult));
		} else {
			if (ret = krb5_mk_priv(context, auth_context, &clear,
						&cipher, &replay)) {
				numresult = KRB5_KPASSWD_HARDERROR;
				(void) strlcpy(strresult,
					"Failed encrypting reply",
					sizeof (strresult));
			}
		}
	}

	ptr = clear.data;
	*ptr++ = (numresult>>8) & 0xff;
	*ptr++ = numresult & 0xff;

	(void) memcpy(ptr, strresult, strlen(strresult));

	/*
	 * If no KRB-PRIV was constructed, then we need a KRB-ERROR.
	 * If this fails, just bail.  There's nothing else we can do.
	 */
	if (cipher.length == 0) {
		/*
		 * Clear out ap_rep now, so that it won't be inserted
		 * in the reply
		 */
		if (ap_rep.length) {
			if (ap_rep.data != NULL)
				krb5_xfree(ap_rep.data);
			ap_rep.data = NULL;
			ap_rep.length = 0;
		}

		krberror.ctime = 0;
		krberror.cusec = 0;
		krberror.susec = 0;
		if (ret = krb5_timeofday(context, &krberror.stime))
			goto bailout;

		/*
		 * This is really icky.  but it's what all the other callers
		 * to mk_error do.
		 */
		krberror.error = ret;
		krberror.error -= ERROR_TABLE_BASE_krb5;
		if (krberror.error < 0 || krberror.error > 128)
			krberror.error = KRB_ERR_GENERIC;

		krberror.client = NULL;
		if (ret = krb5_build_principal(context, &krberror.server,
					    strlen(realm), realm,
					    "kadmin", "changepw", NULL)) {
			goto bailout;
		}

		krberror.text.length = 0;
		krberror.e_data = clear;

		ret = krb5_mk_error(context, &krberror, &cipher);

		krb5_free_principal(context, krberror.server);

		if (ret)
			goto bailout;
	}

	/*
	 * Construct the reply
	 */
	rep->length = 6 + ap_rep.length + cipher.length;
	if ((rep->data = (char *)malloc(rep->length)) == NULL)  {
		ret = errno;
		goto bailout;
	}
	ptr = rep->data;

	/*
	 * Length
	 */
	*ptr++ = (rep->length>>8) & 0xff;
	*ptr++ = rep->length & 0xff;

	/*
	 * Version == 0x0001 big-endian
	 */
	*ptr++ = 0;
	*ptr++ = 1;

	/*
	 * ap_rep length, big-endian
	 */
	*ptr++ = (ap_rep.length>>8) & 0xff;
	*ptr++ = ap_rep.length & 0xff;

	/*
	 * ap-rep data
	 */
	if (ap_rep.length) {
		(void) memcpy(ptr, ap_rep.data, ap_rep.length);
		ptr += ap_rep.length;
	}

	/*
	 * krb-priv or krb-error
	 */
	(void) memcpy(ptr, cipher.data, cipher.length);

bailout:
	if (auth_context)
		krb5_auth_con_free(context, auth_context);
	if (changepw)
		krb5_free_principal(context, changepw);
	if (ap_rep.data != NULL)
		krb5_xfree(ap_rep.data);
	if (ticket)
		krb5_free_ticket(context, ticket);
	if (clear.data != NULL)
		krb5_xfree(clear.data);
	if (cipher.data != NULL)
		krb5_xfree(cipher.data);
	if (allocated_mem)
		krb5_xfree(local_kaddr.contents);

	return (ret);
}