summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/kadm5/unit-test/api.current/init.exp27
-rw-r--r--src/lib/krb5/krb/get_in_tkt.c5
-rw-r--r--src/lib/krb5/krb/gic_pwd.c107
-rw-r--r--src/lib/krb5/krb/init_creds_ctx.h7
-rw-r--r--src/tests/Makefile.in11
-rw-r--r--src/tests/deps2
-rwxr-xr-xsrc/tests/t_general.py9
-rw-r--r--src/tests/t_init_creds.c88
8 files changed, 166 insertions, 90 deletions
diff --git a/src/lib/kadm5/unit-test/api.current/init.exp b/src/lib/kadm5/unit-test/api.current/init.exp
index b324df887c..d9ae3fbd82 100644
--- a/src/lib/kadm5/unit-test/api.current/init.exp
+++ b/src/lib/kadm5/unit-test/api.current/init.exp
@@ -99,33 +99,6 @@ proc test6 {} {
}
if { $RPC } { test6 }
-test "init 7"
-proc test7 {} {
- global test
-
- send "kadm5_init admin \"\" \$KADM5_ADMIN_SERVICE null \$KADM5_STRUCT_VERSION \$KADM5_API_VERSION_3 server_handle\n"
-
- expect {
- -re "assword\[^\r\n\]*:" { }
- -re "key:$" { }
- eof {
- fail "$test: eof instead of password prompt"
- api_exit
- api_start
- return
- }
- timeout {
- fail "$test: timeout instead of password prompt"
- return
- }
- }
- one_line_succeed_test "admin"
- if {! [cmd {kadm5_destroy $server_handle}]} {
- error_and_restart "$test: couldn't close database"
- }
-}
-if { $RPC } { test7 }
-
test "init 8"
proc test8 {} {
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
index 59614e7135..20bc689398 100644
--- a/src/lib/krb5/krb/get_in_tkt.c
+++ b/src/lib/krb5/krb/get_in_tkt.c
@@ -493,8 +493,7 @@ krb5_init_creds_free(krb5_context context,
}
k5_response_items_free(ctx->rctx.items);
free(ctx->in_tkt_service);
- zap(ctx->password.data, ctx->password.length);
- krb5_free_data_contents(context, &ctx->password);
+ zapfree(ctx->gakpw.storage.data, ctx->gakpw.storage.length);
krb5_free_error(context, ctx->err_reply);
krb5_free_pa_data(context, ctx->err_padata);
krb5_free_cred_contents(context, &ctx->cred);
@@ -788,7 +787,7 @@ krb5_init_creds_init(krb5_context context,
ctx->prompter = prompter;
ctx->prompter_data = data;
ctx->gak_fct = krb5_get_as_key_password;
- ctx->gak_data = &ctx->password;
+ ctx->gak_data = &ctx->gakpw;
ctx->request_time = 0; /* filled in later */
ctx->start_time = start_time;
diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c
index 22db2b5b4b..a97823f6b5 100644
--- a/src/lib/krb5/krb/gic_pwd.c
+++ b/src/lib/krb5/krb/gic_pwd.c
@@ -17,22 +17,19 @@ krb5_get_as_key_password(krb5_context context,
void *gak_data,
k5_response_items *ritems)
{
- krb5_data *password;
+ struct gak_password *gp = gak_data;
krb5_error_code ret;
krb5_data defsalt;
char *clientstr;
- char promptstr[1024];
+ char promptstr[1024], pwbuf[1024];
+ krb5_data pw;
krb5_prompt prompt;
krb5_prompt_type prompt_type;
const char *rpass;
- password = (krb5_data *) gak_data;
- assert(password->length > 0);
-
/* If we need to get the AS key via the responder, ask for it. */
if (as_key == NULL) {
- /* However, if we already have a password, don't ask. */
- if (password->data[0] != '\0')
+ if (gp->password != NULL)
return 0;
return k5_response_items_ask_question(ritems,
@@ -55,17 +52,20 @@ krb5_get_as_key_password(krb5_context context,
}
}
- if (password->data[0] == '\0') {
+ if (gp->password == NULL) {
/* Check the responder for the password. */
rpass = k5_response_items_get_answer(ritems,
KRB5_RESPONDER_QUESTION_PASSWORD);
if (rpass != NULL) {
- strlcpy(password->data, rpass, password->length);
- password->length = strlen(password->data);
+ ret = alloc_data(&gp->storage, strlen(rpass));
+ if (ret)
+ return ret;
+ memcpy(gp->storage.data, rpass, strlen(rpass));
+ gp->password = &gp->storage;
}
}
- if (password->data[0] == '\0') {
+ if (gp->password == NULL) {
if (prompter == NULL)
return(EIO);
@@ -76,9 +76,10 @@ krb5_get_as_key_password(krb5_context context,
clientstr);
free(clientstr);
+ pw = make_data(pwbuf, sizeof(pwbuf));
prompt.prompt = promptstr;
prompt.hidden = 1;
- prompt.reply = password;
+ prompt.reply = &pw;
prompt_type = KRB5_PROMPT_TYPE_PASSWORD;
/* PROMPTER_INVOCATION */
@@ -87,6 +88,12 @@ krb5_get_as_key_password(krb5_context context,
k5_set_prompt_types(context, 0);
if (ret)
return(ret);
+
+ ret = krb5int_copy_data_contents(context, &pw, &gp->storage);
+ zap(pw.data, pw.length);
+ if (ret)
+ return ret;
+ gp->password = &gp->storage;
}
if (salt == NULL) {
@@ -98,7 +105,7 @@ krb5_get_as_key_password(krb5_context context,
defsalt.length = 0;
}
- ret = krb5_c_string_to_key_with_params(context, etype, password, salt,
+ ret = krb5_c_string_to_key_with_params(context, etype, gp->password, salt,
params->data?params:NULL, as_key);
if (defsalt.length)
@@ -118,16 +125,11 @@ krb5_init_creds_set_password(krb5_context context,
if (s == NULL)
return ENOMEM;
- if (ctx->password.data != NULL) {
- zap(ctx->password.data, ctx->password.length);
- krb5_free_data_contents(context, &ctx->password);
- }
-
- ctx->password.data = s;
- ctx->password.length = strlen(s);
+ zapfree(ctx->gakpw.storage.data, ctx->gakpw.storage.length);
+ ctx->gakpw.storage = string2data(s);
+ ctx->gakpw.password = &ctx->gakpw.storage;
ctx->gak_fct = krb5_get_as_key_password;
- ctx->gak_data = &ctx->password;
-
+ ctx->gak_data = &ctx->gakpw;
return 0;
}
@@ -257,6 +259,7 @@ krb5_get_init_creds_password(krb5_context context,
int tries;
krb5_creds chpw_creds;
krb5_get_init_creds_opt *chpw_opts = NULL;
+ struct gak_password gakpw;
krb5_data pw0, pw1;
char banner[1024], pw0array[1024], pw1array[1024];
krb5_prompt prompt[2];
@@ -267,29 +270,18 @@ krb5_get_init_creds_password(krb5_context context,
use_master = 0;
as_reply = NULL;
memset(&chpw_creds, 0, sizeof(chpw_creds));
+ memset(&gakpw, 0, sizeof(gakpw));
- pw0.data = pw0array;
-
- if (password && password[0]) {
- if (strlcpy(pw0.data, password, sizeof(pw0array)) >= sizeof(pw0array)) {
- ret = EINVAL;
- goto cleanup;
- }
- pw0.length = strlen(password);
- } else {
- pw0.data[0] = '\0';
- pw0.length = sizeof(pw0array);
+ if (password != NULL) {
+ pw0 = string2data((char *)password);
+ gakpw.password = &pw0;
}
- pw1.data = pw1array;
- pw1.data[0] = '\0';
- pw1.length = sizeof(pw1array);
-
/* first try: get the requested tkt from any kdc */
ret = k5_get_init_creds(context, creds, client, prompter, data, start_time,
in_tkt_service, options, krb5_get_as_key_password,
- (void *) &pw0, &use_master, &as_reply);
+ &gakpw, &use_master, &as_reply);
/* check for success */
@@ -318,8 +310,8 @@ krb5_get_init_creds_password(krb5_context context,
}
ret = k5_get_init_creds(context, creds, client, prompter, data,
start_time, in_tkt_service, options,
- krb5_get_as_key_password, (void *) &pw0,
- &use_master, &as_reply);
+ krb5_get_as_key_password, &gakpw, &use_master,
+ &as_reply);
if (ret == 0)
goto cleanup;
@@ -365,16 +357,22 @@ krb5_get_init_creds_password(krb5_context context,
ret = k5_get_init_creds(context, &chpw_creds, client, prompter, data,
start_time, "kadmin/changepw", chpw_opts,
- krb5_get_as_key_password, (void *) &pw0,
- &use_master, NULL);
+ krb5_get_as_key_password, &gakpw, &use_master,
+ NULL);
if (ret)
goto cleanup;
+ pw0.data = pw0array;
+ pw0.data[0] = '\0';
+ pw0.length = sizeof(pw0array);
prompt[0].prompt = _("Enter new password");
prompt[0].hidden = 1;
prompt[0].reply = &pw0;
prompt_types[0] = KRB5_PROMPT_TYPE_NEW_PASSWORD;
+ pw1.data = pw1array;
+ pw1.data[0] = '\0';
+ pw1.length = sizeof(pw1array);
prompt[1].prompt = _("Enter it again");
prompt[1].hidden = 1;
prompt[1].reply = &pw1;
@@ -460,10 +458,11 @@ krb5_get_init_creds_password(krb5_context context,
is final. */
TRACE_GIC_PWD_CHANGED(context);
+ gakpw.password = &pw0;
ret = k5_get_init_creds(context, creds, client, prompter, data,
start_time, in_tkt_service, options,
- krb5_get_as_key_password, (void *) &pw0,
- &use_master, &as_reply);
+ krb5_get_as_key_password, &gakpw, &use_master,
+ &as_reply);
if (ret)
goto cleanup;
@@ -474,6 +473,7 @@ cleanup:
if (chpw_opts)
krb5_get_init_creds_opt_free(context, chpw_opts);
+ zapfree(gakpw.storage.data, gakpw.storage.length);
memset(pw0array, 0, sizeof(pw0array));
memset(pw1array, 0, sizeof(pw1array));
krb5_free_cred_contents(context, &chpw_creds);
@@ -512,21 +512,17 @@ krb5_get_in_tkt_with_password(krb5_context context, krb5_flags options,
krb5_creds *creds, krb5_kdc_rep **ret_as_reply)
{
krb5_error_code retval;
- krb5_data pw0;
- char pw0array[1024];
+ struct gak_password gakpw;
+ krb5_data pw;
char * server;
krb5_principal server_princ, client_princ;
int use_master = 0;
krb5_get_init_creds_opt *opts = NULL;
- pw0.data = pw0array;
- if (password && password[0]) {
- if (strlcpy(pw0.data, password, sizeof(pw0array)) >= sizeof(pw0array))
- return EINVAL;
- pw0.length = strlen(password);
- } else {
- pw0.data[0] = '\0';
- pw0.length = sizeof(pw0array);
+ memset(&gakpw, 0, sizeof(gakpw));
+ if (password != NULL) {
+ pw = string2data((char *)password);
+ gakpw.password = &pw;
}
retval = k5_populate_gic_opt(context, &opts, options, addrs, ktypes,
pre_auth_types, creds);
@@ -541,10 +537,11 @@ krb5_get_in_tkt_with_password(krb5_context context, krb5_flags options,
client_princ = creds->client;
retval = k5_get_init_creds(context, creds, creds->client,
krb5_prompter_posix, NULL, 0, server, opts,
- krb5_get_as_key_password, &pw0, &use_master,
+ krb5_get_as_key_password, &gakpw, &use_master,
ret_as_reply);
krb5_free_unparsed_name( context, server);
krb5_get_init_creds_opt_free(context, opts);
+ zapfree(gakpw.storage.data, gakpw.storage.length);
if (retval) {
return (retval);
}
diff --git a/src/lib/krb5/krb/init_creds_ctx.h b/src/lib/krb5/krb/init_creds_ctx.h
index d886c7ae9e..4dbb0e92a5 100644
--- a/src/lib/krb5/krb/init_creds_ctx.h
+++ b/src/lib/krb5/krb/init_creds_ctx.h
@@ -10,6 +10,11 @@ struct krb5_responder_context_st {
k5_response_items *items;
};
+struct gak_password {
+ krb5_data storage;
+ const krb5_data *password;
+};
+
struct _krb5_init_creds_context {
krb5_gic_opt_ext *opte;
char *in_tkt_service;
@@ -23,7 +28,7 @@ struct _krb5_init_creds_context {
krb5_deltat renew_life;
krb5_boolean complete;
unsigned int loopcount;
- krb5_data password;
+ struct gak_password gakpw;
krb5_error *err_reply;
krb5_pa_data **err_padata;
krb5_creds cred;
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 2358c898b4..91f312eb9c 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -5,8 +5,8 @@ SUBDIRS = resolve asn.1 create hammer verify gssapi dejagnu shlib \
RUN_SETUP = @KRB5_RUN_ENV@ KRB5_KDC_PROFILE=kdc.conf KRB5_CONFIG=krb5.conf
-OBJS= gcred.o hist.o kdbtest.o t_localauth.o
-EXTRADEPSRCS= gcred.c hist.c kdbtest.c t_localauth.c
+OBJS= gcred.o hist.o kdbtest.o t_init_creds.o t_localauth.o
+EXTRADEPSRCS= gcred.c hist.c kdbtest.c t_init_creds.c t_localauth.c
TEST_DB = ./testdb
TEST_REALM = FOO.TEST.REALM
@@ -28,6 +28,9 @@ kdbtest: kdbtest.o $(KDB5_DEPLIBS) $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS)
$(CC_LINK) -o $@ kdbtest.o $(KDB5_LIBS) $(KADMSRV_LIBS) \
$(KRB5_BASE_LIBS)
+t_init_creds: t_init_creds.o $(KRB5_BASE_DEPLIBS)
+ $(CC_LINK) -o $@ t_init_creds.o $(KRB5_BASE_LIBS)
+
t_localauth: t_localauth.o $(KRB5_BASE_DEPLIBS)
$(CC_LINK) -o $@ t_localauth.o $(KRB5_BASE_LIBS)
@@ -73,7 +76,7 @@ kdb_check: kdc.conf krb5.conf
$(RUN_SETUP) $(VALGRIND) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) destroy -f
$(RM) $(TEST_DB)* stash_file
-check-pytests:: gcred hist kdbtest t_localauth
+check-pytests:: gcred hist kdbtest t_init_creds t_localauth
$(RUNPYTEST) $(srcdir)/t_general.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_dump.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_iprop.py $(PYTESTFLAGS)
@@ -101,5 +104,5 @@ check-pytests:: gcred hist kdbtest t_localauth
$(RUNPYTEST) $(srcdir)/t_cve-2013-1416.py $(PYTESTFLAGS)
clean::
- $(RM) gcred hist kdbtest krb5.conf kdc.conf t_localauth
+ $(RM) gcred hist kdbtest krb5.conf kdc.conf t_init_creds t_localauth
$(RM) -rf kdc_realm/sandbox ldap
diff --git a/src/tests/deps b/src/tests/deps
index e21779e333..b50d0df3ef 100644
--- a/src/tests/deps
+++ b/src/tests/deps
@@ -40,5 +40,7 @@ $(OUTPRE)kdbtest.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
$(top_srcdir)/include/gssrpc/svc.h $(top_srcdir)/include/gssrpc/svc_auth.h \
$(top_srcdir)/include/gssrpc/xdr.h $(top_srcdir)/include/kdb.h \
$(top_srcdir)/include/krb5.h kdbtest.c
+$(OUTPRE)t_init_creds.$(OBJEXT): $(BUILDTOP)/include/krb5/krb5.h \
+ $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h t_init_creds.c
$(OUTPRE)t_localauth.$(OBJEXT): $(BUILDTOP)/include/krb5/krb5.h \
$(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h t_localauth.c
diff --git a/src/tests/t_general.py b/src/tests/t_general.py
index bb7a543c75..98e77a2f74 100755
--- a/src/tests/t_general.py
+++ b/src/tests/t_general.py
@@ -22,6 +22,15 @@ for realm in multipass_realms(create_host=False):
# Test kinit against kdb keytab
realm.run([kinit, "-k", "-t", "KDB:", realm.user_princ])
+# Test that we can get initial creds with an empty password via the
+# API. We have to disable the "empty" pwqual module to create a
+# principal with an empty password. (Regression test for #7642.)
+conf={'plugins': {'pwqual': {'disable': 'empty'}}}
+realm = K5Realm(create_user=False, create_host=False, krb5_conf=conf)
+realm.run_kadminl('addprinc -pw "" user')
+realm.run(['./t_init_creds', 'user', ''])
+realm.stop()
+
realm = K5Realm(create_host=False)
# Spot-check KRB5_TRACE output
diff --git a/src/tests/t_init_creds.c b/src/tests/t_init_creds.c
new file mode 100644
index 0000000000..6be8340f15
--- /dev/null
+++ b/src/tests/t_init_creds.c
@@ -0,0 +1,88 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* tests/t_init_creds.c - test harness for getting initial creds */
+/*
+ * Copyright (C) 2013 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This program exercises the init_creds APIs in ways kinit doesn't. Right now
+ * it is very simplistic, but it can be extended as needed.
+ */
+
+#include <krb5.h>
+#include <stdio.h>
+
+static krb5_context ctx;
+
+static void
+check(krb5_error_code code)
+{
+ const char *errmsg;
+
+ if (code) {
+ errmsg = krb5_get_error_message(ctx, code);
+ fprintf(stderr, "%s\n", errmsg);
+ krb5_free_error_message(ctx, errmsg);
+ exit(1);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ const char *princstr, *password;
+ krb5_principal client;
+ krb5_init_creds_context icc;
+ krb5_creds creds;
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: t_init_creds princname password\n");
+ exit(1);
+ }
+ princstr = argv[1];
+ password = argv[2];
+
+ check(krb5_init_context(&ctx));
+ check(krb5_parse_name(ctx, princstr, &client));
+
+ /* Try once with the traditional interface. */
+ check(krb5_get_init_creds_password(ctx, &creds, client, password, NULL,
+ NULL, 0, NULL, NULL));
+ krb5_free_cred_contents(ctx, &creds);
+
+ /* Try again with the step interface. */
+ check(krb5_init_creds_init(ctx, client, NULL, NULL, 0, NULL, &icc));
+ check(krb5_init_creds_set_password(ctx, icc, password));
+ check(krb5_init_creds_get(ctx, icc));
+ krb5_init_creds_free(ctx, icc);
+
+ krb5_free_principal(ctx, client);
+ krb5_free_context(ctx);
+ return 0;
+}